def plot_cluster_fan_stereographically(self, northsign=1, north=None, right=None, colors=None): from sage.plot.graphics import Graphics from sage.plot.point import point from sage.misc.flatten import flatten from sage.plot.line import line from sage.misc.functional import norm if self.rk !=3: raise ValueError("Can only stereographically project fans in 3d.") if not self.is_finite() and self._depth == infinity: raise ValueError("For infinite algebras you must specify the depth.") if north == None: if self.is_affine(): north = vector(self.delta()) else: north = vector( (-1,-1,-1) ) if right == None: if self.is_affine(): right = vector(self.gamma()) else: right = vector( (1,0,0) ) if colors == None: colors = dict([(0,'red'),(1,'green'),(2,'blue'),(3,'cyan'),(4,'yellow')]) G = Graphics() roots = list(self.g_vectors()) compatible = [] while roots: x = roots.pop() for y in roots: if self.compatibility_degree(x,y) == 0: compatible.append((x,y)) for (u,v) in compatible: G += _stereo_arc(vector(u),vector(v),vector(u+v),north=northsign*north,right=right,thickness=0.5,color='black') for i in range(3): orbit = self.ith_orbit(i) for j in orbit: G += point(_stereo_coordinates(vector(orbit[j]),north=northsign*north,right=right),color=colors[i],zorder=len(G)) if self.is_affine(): tube_vectors = map(vector,flatten(self.affine_tubes())) for v in tube_vectors: G += point(_stereo_coordinates(v,north=northsign*north,right=right),color=colors[3],zorder=len(G)) if north != vector(self.delta()): G += _stereo_arc(tube_vectors[0],tube_vectors[1],vector(self.delta()),north=northsign*north,right=right,thickness=2,color=colors[4],zorder=0) else: # FIXME: refactor this before publishing tube_projections = [ _stereo_coordinates(v,north=northsign*north,right=right) for v in tube_vectors ] t=min((G.get_minmax_data()['xmax'],G.get_minmax_data()['ymax'])) G += line([tube_projections[0],tube_projections[0]+t*(_normalize(tube_projections[0]-tube_projections[1]))],thickness=2,color=colors[4],zorder=0) G += line([tube_projections[1],tube_projections[1]+t*(_normalize(tube_projections[1]-tube_projections[0]))],thickness=2,color=colors[4],zorder=0) G.set_aspect_ratio(1) G._show_axes = False return G
def _arc(p,q,s,**kwds): #rewrite this to use polar_plot and get points to do filled triangles from sage.misc.functional import det from sage.plot.line import line from sage.misc.functional import norm from sage.symbolic.all import pi from sage.plot.arc import arc p,q,s = map( lambda x: vector(x), [p,q,s]) # to avoid running into division by 0 we set to be colinear vectors that are # almost colinear if abs(det(matrix([p-s,q-s])))<0.01: return line((p,q),**kwds) (cx,cy)=var('cx','cy') equations=[ 2*cx*(s[0]-p[0])+2*cy*(s[1]-p[1]) == s[0]**2+s[1]**2-p[0]**2-p[1]**2, 2*cx*(s[0]-q[0])+2*cy*(s[1]-q[1]) == s[0]**2+s[1]**2-q[0]**2-q[1]**2 ] c = vector( [solve( equations, (cx,cy), solution_dict=True )[0][i] for i in [cx,cy]] ) r = norm(p-c) a_p,a_q,a_s = map( _to_angle, [p-c,q-c,s-c]) angles = [a_p,a_q,a_s] angles.sort() if a_s == angles[0]: return arc( c, r, angle=angles[2], sector=(0,2*pi-angles[2]+angles[1]), **kwds) if a_s == angles[1]: return arc( c, r, angle=angles[0], sector=(0,angles[2]-angles[0]), **kwds) if a_s == angles[2]: return arc( c, r, angle=angles[1], sector=(0,2*pi-angles[1]+angles[0]), **kwds)
def plot_y(self, plot_points=128, **kwds): r"""Plot the y-part of the path in the complex y-plane. Additional arguments and keywords are passed to ``matplotlib.pyplot.plot``. Parameters ---------- N : int The number of interpolating points used to plot. t0 : double Starting t-value in [0,1]. t1 : double Ending t-value in [0,1]. Returns ------- plt : Sage plot. A plot of the complex y-projection of the path. """ s = numpy.linspace(0, 1, plot_points, dtype=double) vals = numpy.array([self.get_y(si)[0] for si in s], dtype=complex) pts = [(real_part(y), imag_part(y)) for y in vals] plt = line(pts, **kwds) return plt
def plot_n_matrices_eigenvectors(self, n, side='right', color_index=0, draw_line=False): r""" INPUT: - ``n`` -- integer, length - ``side`` -- ``'left'`` or ``'right'``, drawing left or right eigenvectors - ``color_index`` -- 0 for first letter, -1 for last letter - ``draw_line`` -- boolean EXAMPLES:: sage: from slabbe.matrix_cocycle import cocycles sage: ARP = cocycles.ARP() sage: G = ARP.plot_n_matrices_eigenvectors(2) """ from sage.plot.graphics import Graphics from sage.plot.point import point from sage.plot.line import line from sage.plot.text import text from sage.plot.colors import hue from sage.modules.free_module_element import vector from .matrices import M3to2 R = self.n_matrices_eigenvectors(n) L = [(w, M3to2*(a/sum(a)), M3to2*(b/sum(b))) for (w,a,b) in R] G = Graphics() alphabet = self._language._alphabet color_ = dict( (letter, hue(i/float(len(alphabet)))) for i,letter in enumerate(alphabet)) for letter in alphabet: L_filtered = [(w,p1,p2) for (w,p1,p2) in L if w[color_index] == letter] words,rights,lefts = zip(*L_filtered) if side == 'right': G += point(rights, color=color_[letter], legend_label=letter) elif side == 'left': G += point(lefts, color=color_[letter], legend_label=letter) else: raise ValueError("side(=%s) should be left or right" % side) if draw_line: for (a,b) in L: G += line([a,b], color='black', linestyle=":") G += line([M3to2*vector(a) for a in [(1,0,0), (0,1,0), (0,0,1), (1,0,0)]]) title = "%s eigenvectors, colored by letter w[%s] of cylinder w" % (side, color_index) G += text(title, (0.5, 1.05), axis_coords=True) G.axes(False) return G
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().UHP().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] if (abs(real(end_1) - real(end_2)) < EPSILON) \ or CC(infinity) in [end_1, end_2]: #on same vertical line # If one of the endpoints is infinity, we replace it with a # large finite point if end_1 == CC(infinity): end_1 = (real(end_2), (imag(end_2) + 10)) end_2 = (real(end_2), imag(end_2)) elif end_2 == CC(infinity): end_2 = (real(end_1), (imag(end_1) + 10)) end_1 = (real(end_1), imag(end_1)) from sage.plot.line import line pic = line((end_1, end_2), **opts) if boundary: cent = min(bd_1, bd_2) bd_dict = {'bd_min': cent - 3, 'bd_max': cent + 3} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic else: center = (bd_1 + bd_2)/2 # Circle center radius = abs(bd_1 - bd_2)/2 theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if abs(theta1 - theta2) < EPSILON: theta2 += pi [theta1, theta2] = sorted([theta1, theta2]) from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: # We want to draw a segment of the real line. The # computations below compute the projection of the # geodesic to the real line, and then draw a little # to the left and right of the projection. shadow_1, shadow_2 = [real(k) for k in [end_1, end_2]] midpoint = (shadow_1 + shadow_2)/2 length = abs(shadow_1 - shadow_2) bd_dict = {'bd_min': midpoint - length, 'bd_max': midpoint + length} bd_pic = self._model.get_background_graphic(**bd_dict) pic = bd_pic + pic return pic
def piecewise_linear_image(A,B): # Jumps up and down going around circle, not used v = circle_drops(A,B) G = Graphics() w = [(Rational(i)/len(v), j) for i,j in enumerate(v)] for pt in w: G += line([(pt[0],pt[1]),(pt[0]+Rational(1)/len(w),pt[1])]) return G
def legend_3d(hyperplane_arrangement, hyperplane_colors, length): r""" Create plot of a 3d legend for an arrangement of planes in 3-space. The ``length`` parameter determines whether short or long labels are used in the legend. INPUT: - ``hyperplane_arrangement`` -- a hyperplane arrangement - ``hyperplane_colors`` -- list of colors - ``length`` -- either ``'short'`` or ``'long'`` OUTPUT: - A graphics object. EXAMPLES:: sage: a = hyperplane_arrangements.semiorder(3) sage: from sage.geometry.hyperplane_arrangement.plot import legend_3d sage: legend_3d(a, list(colors.values())[:6],length='long') Graphics object consisting of 6 graphics primitives sage: b = hyperplane_arrangements.semiorder(4) sage: c = b.essentialization() sage: legend_3d(c, list(colors.values())[:12], length='long') Graphics object consisting of 12 graphics primitives sage: legend_3d(c, list(colors.values())[:12], length='short') Graphics object consisting of 12 graphics primitives sage: p = legend_3d(c, list(colors.values())[:12], length='short') sage: p.set_legend_options(ncol=4) sage: type(p) <class 'sage.plot.graphics.Graphics'> """ if hyperplane_arrangement.dimension() != 3: raise ValueError('arrangements must be in 3-space') hyps = hyperplane_arrangement.hyperplanes() N = len(hyperplane_arrangement) if length == 'short': labels = [' ' + str(i) for i in range(N)] else: labels = [' ' + hyps[i]._repr_linear(include_zero=False) for i in range(N)] p = Graphics() for i in range(N): p += line([(0,0),(0,0)], color=hyperplane_colors[i], thickness=8, legend_label=labels[i], axes=False) p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, fancybox=True, font_size='x-large', ncol=2) p.legend(True) return p
def plot(self, **kwargs): """ Plot this Newton polygon. .. NOTE:: All usual rendering options (color, thickness, etc.) are available. EXAMPLES: sage: from sage.geometry.newton_polygon import NewtonPolygon sage: NP = NewtonPolygon([ (0,0), (1,1), (2,6) ]) sage: polygon = NP.plot() """ vertices = self.vertices() if len(vertices) == 0: from sage.plot.graphics import Graphics return Graphics() else: from sage.plot.line import line (xstart,ystart) = vertices[0] (xend,yend) = vertices[-1] if self.last_slope() is Infinity: return line([(xstart, ystart+1), (xstart,ystart+0.5)], linestyle="--", **kwargs) \ + line([(xstart, ystart+0.5)] + vertices + [(xend, yend+0.5)], **kwargs) \ + line([(xend, yend+0.5), (xend, yend+1)], linestyle="--", **kwargs) else: return line([(xstart, ystart+1), (xstart,ystart+0.5)], linestyle="--", **kwargs) \ + line([(xstart, ystart+0.5)] + vertices + [(xend+0.5, yend + 0.5*self.last_slope())], **kwargs) \ + line([(xend+0.5, yend + 0.5*self.last_slope()), (xend+1, yend+self.last_slope())], linestyle="--", **kwargs)
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives """ opts = dict([('axes', False), ('aspect_ratio', 1)]) opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] # Check to see if it's a line if bool(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1))**2 < EPSILON: from sage.plot.line import line pic = line([(real(bd_1),imag(bd_1)),(real(bd_2),imag(bd_2))], **opts) else: # If we are here, we know it's not a line # So we compute the center and radius of the circle center = (1/(real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) * ((imag(bd_2)-imag(bd_1)) + (real(bd_1)-real(bd_2))*I)) radius = RR(abs(bd_1 - center)) # abs is Euclidean distance # Now we calculate the angles for the parametric plot theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() if theta2 < theta1: theta1, theta2 = theta2, theta1 from sage.calculus.var import var from sage.plot.plot import parametric_plot x = var('x') mid = (theta1 + theta2)/2.0 if (radius*cos(mid) + real(center))**2 + \ (radius*sin(mid) + imag(center))**2 > 1.0: # Swap theta1 and theta2 tmp = theta1 + 2*pi theta1 = theta2 theta2 = tmp pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) else: pic = parametric_plot((radius*cos(x) + real(center), radius*sin(x) + imag(center)), (x, theta1, theta2), **opts) if boundary: bd_pic = self._model.get_background_graphic() pic = bd_pic + pic return pic
def get_background_graphic(self, **bdry_options): r""" Return a graphic object that makes the model easier to visualize. For the upper half space, the background object is the ideal boundary. EXAMPLES:: sage: hp = HyperbolicPlane().UHP().get_background_graphic() """ from sage.plot.line import line bd_min = bdry_options.get('bd_min', -5) bd_max = bdry_options.get('bd_max', 5) return line(((bd_min, 0), (bd_max, 0)), color='black')
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES: First some lines:: sage: PD = HyperbolicPlane().PD() sage: PD.get_geodesic(0, 1).show() Graphics object consisting of 2 graphics primitives sage: PD.get_geodesic(0, 0.3+0.8*I).show() Graphics object consisting of 2 graphics primitives Then some generic geodesics:: sage: PD.get_geodesic(-0.5, 0.3+0.4*I).show() Graphics object consisting of 2 graphics primitives sage: PD.get_geodesic(-1, exp(3*I*pi/7)).show(linestyle="dashed", color="red") Graphics object consisting of 2 graphics primitives sage: PD.get_geodesic(exp(2*I*pi/11), exp(1*I*pi/11)).show(thickness=6, color="orange") Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) end_1, end_2 = [CC(k.coordinates()) for k in self.endpoints()] bd_1, bd_2 = [CC(k.coordinates()) for k in self.ideal_endpoints()] # Check to see if it's a line if abs(bd_1 + bd_2) < EPSILON: pic = line([end_1, end_2], **opts) else: # If we are here, we know it's not a line # So we compute the center and radius of the circle invdet = RR.one() / (real(bd_1)*imag(bd_2) - real(bd_2)*imag(bd_1)) centerx = (imag(bd_2) - imag(bd_1)) * invdet centery = (real(bd_1) - real(bd_2)) * invdet center = centerx + I * centery radius = RR(abs(bd_1 - center)) # Now we calculate the angles for the arc theta1 = CC(end_1 - center).arg() theta2 = CC(end_2 - center).arg() theta1, theta2 = sorted([theta1, theta2]) # Make sure the sector is inside the disk if theta2 - theta1 > pi: theta1 += 2 * pi pic = arc((centerx, centery), radius, sector=(theta1, theta2), **opts) if boundary: pic += self._model.get_background_graphic() return pic
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().KM().get_geodesic((0,0), (1,0)).show() Graphics object consisting of 2 graphics primitives """ opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) pic = line([k.coordinates() for k in self.endpoints()], **opts) if boundary: pic += self._model.get_background_graphic() return pic
def plot2d(self,depth=None): # FIXME: refactor this before publishing from sage.plot.line import line from sage.plot.graphics import Graphics if self._n !=2: raise ValueError("Can only 2d plot fans.") if depth == None: depth = self._depth if not self.is_finite() and depth==infinity: raise ValueError("For infinite algebras you must specify the depth.") colors = dict([(0,'red'),(1,'green')]) G = Graphics() for i in range(2): orbit = self.ith_orbit(i,depth=depth) for j in orbit: G += line([(0,0),vector(orbit[j])],color=colors[i],thickness=0.5, zorder=2*j+1) G.set_aspect_ratio(1) G._show_axes = False return G
def plot(self, m, pointsize=100, thickness=3, axes=False): r""" Return 2d graphics object contained in the primal box [-m,m]^d. INPUT: - ``pointsize``, integer (default:``100``), - ``thickness``, integer (default:``3``), - ``axes``, bool (default:``False``), EXAMPLES:: sage: from slabbe import BondPercolationSample sage: S = BondPercolationSample(0.5,2) sage: S.plot(2) # optional long It works in 3d!!:: sage: S = BondPercolationSample(0.5,3) sage: S.plot(3, pointsize=10, thickness=1) # optional long Graphics3d Object """ s = "" s += "\\begin{tikzpicture}\n" s += "[inner sep=0pt,thick,\n" s += "reddot/.style={fill=red,draw=red,circle,minimum size=5pt}]\n" s += "\\clip %s rectangle %s;\n" % ((-m-.4,-m-.4), (m+.4,m+.4)) G = Graphics() for u in self.cluster_in_box(m+1): G += point(u, color='blue', size=pointsize) for (u,v) in self.edges_in_box(m+1): G += line((u,v), thickness=thickness, alpha=0.8) G += text("p=%.3f" % self._p, (0.5,1.03), axis_coords=True, color='black') G += circle((0,0), 0.5, color='red', thickness=thickness) if self._dimension == 2: G.axes(axes) return G
def show(self, **args): r""" Displays the pseudoline arrangement as a wiring diagram. INPUT: - ``**args`` -- any arguments to be forwarded to the ``show`` method. In particular, to tune the dimensions, use the ``figsize`` argument (example below). EXAMPLES:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolineArrangement(permutations) sage: p.show(figsize=[7,5]) TESTS:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] sage: p = PseudolineArrangement(permutations) sage: p.show() Traceback (most recent call last): ... ValueError: There has been a problem while plotting the figure... """ x = 1 from sage.plot.line import line from sage.plot.text import text lines = [[(0,self._n-1-i)] for i in range(self._n)] for i,j in self.transpositions(): iy = lines[i][-1][1] jy = lines[j][-1][1] lines[i].append((x, iy)) lines[j].append((x, jy)) if abs(iy-jy) != 1: raise ValueError( "There has been a problem while plotting the figure. It "+ "seems that the lines are not correctly ordered. Please "+ "check the pseudolines modules documentation, there is a " +"warning about that. ") lines[i].append((x+2,jy)) lines[j].append((x+2,iy)) x += 2 L = line([(1,1)]) for i, l in enumerate(lines): l.append((x+2, l[-1][1])) L += line(l) L += text(str(i), (0, l[0][1]+.3), horizontal_alignment="right") L += text(str(i), (x+2, l[-1][1]+.3), horizontal_alignment="left") return L.show(axes = False, **args)
def list_plot(cls, points, **kwargs): r""" Returns a sage figure containing a list plot. INPUT: - ``cls`` -- class on which the function is invoked. - ``points`` -- list or tuple of 2D or 3D points to be plotted. - ``joined`` -- boolean (default: False) flag triggering the production of a graph whose points are joined instead of a scatter plot. - ``alpha`` -- number (default: not used) opacity value of the points (or lines) in the produced graph. - ``size`` -- integer (default: not used) size of the points (or lines) in the produced graph. Other named arguments affecting the graphic style are forwarded to matplotlib's ``plot`` or ``scatter``. OUTPUT: figure containing a list plot. EXAMPLES: The following instructions generate and show a figure showing three points: :: >>> points = ((1, 1), (3, -1), (7, 2)) >>> from yaplf.graph import SagePlotter >>> SagePlotter.list_plot(points) The same graph can be obtained joining the single points: :: >>> SagePlotter.list_plot(points, joined = True) When ``joined`` is set to ``True``, the ``size``, ``color``, and ``alpha`` arguments affect respectively the line size, color, and opacity: :: >>> SagePlotter.list_plot(points, joined = True, size = 3, ... alpha = .2) When the first argument of ``list_plot`` is a list or tuple of three-sized list or tuples, the result is a 3D graph: :: >>> points = ((1, 3, -4), (2, 1, 2), (1, 6, 5)) >>> SagePlotter.list_plot(points) AUTHORS: - Dario Malchiodi (2010-02-22) """ try: joined = kwargs['joined'] del kwargs['joined'] except KeyError: joined = False if len(shape(points)) == 1: points = zip(range(len(points)), points) if len(points[0]) == 2: try: size = kwargs['size'] del kwargs['size'] if joined: kwargs['thickness'] = size else: kwargs['pointsize'] = size except KeyError: pass elif len(points[0]) == 3: try: alpha = kwargs['alpha'] del kwargs['alpha'] kwargs['opacity'] = alpha if joined: size = kwargs['size'] del kwargs['size'] kwargs['thickness'] = size except KeyError: pass else: raise ValueError('scatter() only available for 2D and 3D points') if joined: return line(points, **kwargs) else: return point(points, **kwargs)
def plot(self, **kwds): r""" Plot the initial triangulation associated to ``self``. INPUT: - ``radius`` - the radius of the disk; by default the length of the circle is the number of vertices - ``points_color`` - the color of the vertices; default 'black' - ``points_size`` - the size of the vertices; default 7 - ``triangulation_color`` - the color of the arcs; default 'black' - ``triangulation_thickness`` - the thickness of the arcs; default 0.5 - ``shading_color`` - the color of the shading used on neuter intervals; default 'lightgray' - ``reflections_color`` - the color of the reflection axes; default 'blue' - ``reflections_thickness`` - the thickness of the reflection axes; default 1 EXAMPLES:: sage: Y = SineGordonYsystem('A',(6,4,3)) sage: Y.plot() # long time 2s Graphics object consisting of 219 graphics primitives """ # Set up plotting options if 'radius' in kwds: radius = kwds['radius'] else: radius = ceil(self.r() / (2 * pi)) points_opts = {} if 'points_color' in kwds: points_opts['color'] = kwds['points_color'] else: points_opts['color'] = 'black' if 'points_size' in kwds: points_opts['size'] = kwds['points_size'] else: points_opts['size'] = 7 triangulation_opts = {} if 'triangulation_color' in kwds: triangulation_opts['color'] = kwds['triangulation_color'] else: triangulation_opts['color'] = 'black' if 'triangulation_thickness' in kwds: triangulation_opts['thickness'] = kwds['triangulation_thickness'] else: triangulation_opts['thickness'] = 0.5 shading_opts = {} if 'shading_color' in kwds: shading_opts['color'] = kwds['shading_color'] else: shading_opts['color'] = 'lightgray' reflections_opts = {} if 'reflections_color' in kwds: reflections_opts['color'] = kwds['reflections_color'] else: reflections_opts['color'] = 'blue' if 'reflections_thickness' in kwds: reflections_opts['thickness'] = kwds['reflections_thickness'] else: reflections_opts['thickness'] = 1 # Helper functions def triangle(x): (a, b) = sorted(x[:2]) for p in self.vertices(): if (p, a) in self.triangulation() or (a, p) in self.triangulation(): if (p, b) in self.triangulation() or (b, p) in self.triangulation(): if p < a or p > b: return sorted((a, b, p)) def plot_arc(radius, p, q, **opts): # TODO: THIS SHOULD USE THE EXISTING PLOT OF ARCS! # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p+angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts) def vertex_to_angle(v): # v==0 corresponds to pi/2 return -2 * pi * RR(v) / self.r() + 5 * pi / 2 # Begin plotting P = Graphics() # Shade neuter intervals neuter_intervals = [x for x in flatten(self.intervals()[:-1], max_level=1) if x[2] in ["NR", "NL"]] shaded_triangles = map(triangle, neuter_intervals) for (p, q, r) in shaded_triangles: points = list(plot_arc(radius, p, q)[0]) points += list(plot_arc(radius, q, r)[0]) points += list(reversed(plot_arc(radius, p, r)[0])) P += polygon2d(points, **shading_opts) # Disk boundary P += circle((0, 0), radius, **triangulation_opts) # Triangulation for (p, q) in self.triangulation(): P += plot_arc(radius, p, q, **triangulation_opts) if self.type() == 'D': s = radius / 50.0 P += polygon2d([(s, 5 * s), (s, 7 * s), (3 * s, 5 * s), (3 * s, 7 * s)], color=triangulation_opts['color']) P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)], [(2 * s, 10 * s), (s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)], [(-2 * s, 10 * s), (-s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) P += point((0, 0), zorder=len(P), **points_opts) # Vertices v_points = {x: (radius * cos(vertex_to_angle(x)), radius * sin(vertex_to_angle(x))) for x in self.vertices()} for v in v_points: P += point(v_points[v], zorder=len(P), **points_opts) # Reflection axes P += line([(0, 1.1 * radius), (0, -1.1 * radius)], zorder=len(P), **reflections_opts) axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1]) (a, b) = (1.1 * radius * cos(axis_angle), 1.1 * radius * sin(axis_angle)) P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts) # Wrap up P.set_aspect_ratio(1) P.axes(False) return P
def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, include_end_point=(True, True), end_point_offset=(0.001, 0.001), max_value=8, parameters=None, color='red', style='-', thickness=1, plot_points=75, label_axes=True, aspect_ratio='automatic'): r""" Plot the current curve (``self``) in a Cartesian graph based on the coordinates of some ambient chart. The curve is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The ambient chart's domain must overlap with the curve's codomain or with the codomain of the composite curve `\Phi\circ c`, where `c` is ``self`` and `\Phi` some manifold differential mapping (argument ``mapping`` below). INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the default chart of the codomain of the curve (or of the curve composed with `\Phi`) is used - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi` (instance of :class:`~sage.geometry.manifolds.diffmapping.DiffMapping`) providing the link between ``self`` and the ambient chart ``chart`` (cf. above); if ``None``, the ambient chart is supposed to be defined on the codomain of the curve ``self``. - ``prange`` -- (default: ``None``) range of the curve parameter for the plot; if ``None``, the entire parameter range declared during the curve construction is considered (with -Infinity replaced by ``-max_value`` and +Infinity by ``max_value``) - ``include_end_point`` -- (default: ``(True, True)``) determines whether the end points of ``prange`` are included in the plot - ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from the end points when they are not included in the plot: if ``include_end_point[0] == False``, the minimal value of the curve parameter used for the plot is ``prange[0] + end_point_offset[0]``, while if ``include_end_point[1] == False``, the maximal value is ``prange[1] - end_point_offset[1]``. - ``max_value`` -- (default: 8) numerical value substituted to +Infinity if the latter is the upper bound of the parameter range; similarly ``-max_value`` is the numerical valued substituted for -Infinity - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the coordinate expression of ``self`` - ``color`` -- (default: 'red') color of the drawn curve - ``style`` -- (default: '-') color of the drawn curve; NB: ``style`` is effective only for 2D plots - ``thickness`` -- (default: 1) thickness of the drawn curve - ``plot_points`` -- (default: 75) number of points to plot the curve - ``label_axes`` -- (default: ``True``) boolean determining whether the labels of the coordinate axes of ``chart`` shall be added to the graph; can be set to ``False`` if the graph is 3D and must be superposed with another graph. - ``aspect_ratio`` -- (default: 'automatic') aspect ratio of the plot; the default value ('automatic') applies only for 2D plots; for 3D plots, the default value is ``1`` instead. OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of ``chart``) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of ``chart``) EXAMPLES: Plot of the lemniscate of Gerono:: sage: R2 = Manifold(2, 'R^2') sage: X.<x,y> = R2.chart() sage: R.<t> = RealLine() sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') sage: c.plot() # 2D plot Graphics object consisting of 1 graphics primitive Plot for a subinterval of the curve's domain:: sage: c.plot(prange=(0,pi)) Graphics object consisting of 1 graphics primitive Plot with various options:: sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1) Graphics object consisting of 1 graphics primitive Plot via a mapping to another manifold: loxodrome of a sphere viewed in `\RR^3`:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: R3 = Manifold(3, 'R^3') sage: X3.<x,y,z> = R3.chart() sage: F = S2.diff_mapping(R3, {(XS, X3): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> R^3 on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c') sage: graph_c = c.plot(mapping=F, max_value=40, ....: plot_points=200, thickness=2, label_axes=False) # 3D plot sage: graph_S2 = XS.plot(X3, mapping=F, nb_values=11, color='black') # plot of the sphere sage: show(graph_c + graph_S2) # the loxodrome + the sphere Example of use of the argument ``parameters``: we define a curve with some symbolic parameters ``a`` and ``b``:: sage: a, b = var('a b') sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c') To make a plot, we set spectific values for ``a`` and ``b`` by means of the Python dictionary ``parameters``:: sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) Graphics object consisting of 1 graphics primitive """ from sage.rings.infinity import Infinity from sage.misc.functional import numerical_approx from sage.plot.graphics import Graphics from sage.plot.line import line from sage.geometry.manifolds.chart import Chart from sage.geometry.manifolds.utilities import set_axes_labels # # The "effective" curve to be plotted # if mapping is None: eff_curve = self else: eff_curve = mapping.restrict(self.codomain()) * self # # The chart w.r.t. which the curve is plotted # if chart is None: chart = eff_curve._codomain.default_chart() elif not isinstance(chart, Chart): raise TypeError("{} is not a chart".format(chart)) # # Coordinates of the above chart w.r.t. which the curve is plotted # if ambient_coords is None: ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc !=3: raise ValueError("The number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) ind_pc = [chart[:].index(pc) for pc in ambient_coords] # indices of plot # coordinates # # Parameter range for the plot # if prange is None: prange = (self._domain.lower_bound(), self._domain.upper_bound()) elif not isinstance(prange, (tuple, list)): raise TypeError("{} is neither a tuple nor a list".format(prange)) elif len(prange) != 2: raise ValueError("the argument prange must be a tuple/list " + "of 2 elements") tmin = prange[0] tmax = prange[1] if tmin == -Infinity: tmin = -max_value elif not include_end_point[0]: tmin = tmin + end_point_offset[0] if tmax == Infinity: tmax = max_value elif not include_end_point[1]: tmax = tmax - end_point_offset[1] tmin = numerical_approx(tmin) tmax = numerical_approx(tmax) # # The coordinate expression of the effective curve # canon_chart = self._domain.canonical_chart() transf = None for chart_pair in eff_curve._coord_expression: if chart_pair == (canon_chart, chart): transf = eff_curve._coord_expression[chart_pair] break else: # Search for a subchart for chart_pair in eff_curve._coord_expression: for schart in chart._subcharts: if chart_pair == (canon_chart, schart): transf = eff_curve._coord_expression[chart_pair] if transf is None: raise ValueError("No expression has been found for " + "{} in terms of {}".format(self, format)) # # List of points for the plot curve # plot_curve = [] dt = (tmax - tmin) / (plot_points - 1) t = tmin if parameters is None: for i in range(plot_points): x = transf(t, simplify=False) plot_curve.append( [numerical_approx(x[j]) for j in ind_pc] ) t += dt else: for i in range(plot_points): x = transf(t, simplify=False) plot_curve.append( [numerical_approx( x[j].substitute(parameters) ) for j in ind_pc] ) t += dt # # The plot # resu = Graphics() resu += line(plot_curve, color=color, linestyle=style, thickness=thickness) if n_pc==2: # 2D graphic resu.set_aspect_ratio(aspect_ratio) if label_axes: # We update the dictionary _extra_kwds (options to be passed # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$' for pc in ambient_coords] else: # 3D graphic if aspect_ratio == 'automatic': aspect_ratio = 1 resu.aspect_ratio(aspect_ratio) if label_axes: labels = [str(pc) for pc in ambient_coords] resu = set_axes_labels(resu, *labels) return resu
def plot(self, chart=None, ambient_coords=None, mapping=None, prange=None, include_end_point=(True, True), end_point_offset=(0.001, 0.001), parameters=None, color='red', style='-', label_axes=True, **kwds): r""" Plot the current curve in a Cartesian graph based on the coordinates of some ambient chart. The curve is drawn in terms of two (2D graphics) or three (3D graphics) coordinates of a given chart, called hereafter the *ambient chart*. The ambient chart's domain must overlap with the curve's codomain or with the codomain of the composite curve `\Phi\circ c`, where `c` is the current curve and `\Phi` some manifold differential map (argument ``mapping`` below). INPUT: - ``chart`` -- (default: ``None``) the ambient chart (see above); if ``None``, the default chart of the codomain of the curve (or of the curve composed with `\Phi`) is used - ``ambient_coords`` -- (default: ``None``) tuple containing the 2 or 3 coordinates of the ambient chart in terms of which the plot is performed; if ``None``, all the coordinates of the ambient chart are considered - ``mapping`` -- (default: ``None``) differentiable mapping `\Phi` (instance of :class:`~sage.manifolds.differentiable.diff_map.DiffMap`) providing the link between the curve and the ambient chart ``chart`` (cf. above); if ``None``, the ambient chart is supposed to be defined on the codomain of the curve. - ``prange`` -- (default: ``None``) range of the curve parameter for the plot; if ``None``, the entire parameter range declared during the curve construction is considered (with -Infinity replaced by ``-max_range`` and +Infinity by ``max_range``) - ``include_end_point`` -- (default: ``(True, True)``) determines whether the end points of ``prange`` are included in the plot - ``end_point_offset`` -- (default: ``(0.001, 0.001)``) offsets from the end points when they are not included in the plot: if ``include_end_point[0] == False``, the minimal value of the curve parameter used for the plot is ``prange[0] + end_point_offset[0]``, while if ``include_end_point[1] == False``, the maximal value is ``prange[1] - end_point_offset[1]``. - ``max_range`` -- (default: 8) numerical value substituted to +Infinity if the latter is the upper bound of the parameter range; similarly ``-max_range`` is the numerical valued substituted for -Infinity - ``parameters`` -- (default: ``None``) dictionary giving the numerical values of the parameters that may appear in the coordinate expression of the curve - ``color`` -- (default: 'red') color of the drawn curve - ``style`` -- (default: '-') color of the drawn curve; NB: ``style`` is effective only for 2D plots - ``thickness`` -- (default: 1) thickness of the drawn curve - ``plot_points`` -- (default: 75) number of points to plot the curve - ``label_axes`` -- (default: ``True``) boolean determining whether the labels of the coordinate axes of ``chart`` shall be added to the graph; can be set to ``False`` if the graph is 3D and must be superposed with another graph. - ``aspect_ratio`` -- (default: ``'automatic'``) aspect ratio of the plot; the default value (``'automatic'``) applies only for 2D plots; for 3D plots, the default value is ``1`` instead OUTPUT: - a graphic object, either an instance of :class:`~sage.plot.graphics.Graphics` for a 2D plot (i.e. based on 2 coordinates of ``chart``) or an instance of :class:`~sage.plot.plot3d.base.Graphics3d` for a 3D plot (i.e. based on 3 coordinates of ``chart``) EXAMPLES: Plot of the lemniscate of Gerono:: sage: R2 = Manifold(2, 'R^2') sage: X.<x,y> = R2.chart() sage: R.<t> = RealLine() sage: c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') sage: c.plot() # 2D plot Graphics object consisting of 1 graphics primitive .. PLOT:: R2 = Manifold(2, 'R^2') X = R2.chart('x y') t = RealLine().canonical_coordinate() c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') g = c.plot() sphinx_plot(g) Plot for a subinterval of the curve's domain:: sage: c.plot(prange=(0,pi)) Graphics object consisting of 1 graphics primitive .. PLOT:: R2 = Manifold(2, 'R^2') X = R2.chart('x y') t = RealLine().canonical_coordinate() c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') g = c.plot(prange=(0,pi)) sphinx_plot(g) Plot with various options:: sage: c.plot(color='green', style=':', thickness=3, aspect_ratio=1) Graphics object consisting of 1 graphics primitive .. PLOT:: R2 = Manifold(2, 'R^2') X = R2.chart('x y') t = RealLine().canonical_coordinate() c = R2.curve([sin(t), sin(2*t)/2], (t, 0, 2*pi), name='c') g = c.plot(color='green', style=':', thickness=3, aspect_ratio=1) sphinx_plot(g) Plot via a mapping to another manifold: loxodrome of a sphere viewed in `\RR^3`:: sage: S2 = Manifold(2, 'S^2') sage: U = S2.open_subset('U') sage: XS.<th,ph> = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') sage: R3 = Manifold(3, 'R^3') sage: X3.<x,y,z> = R3.chart() sage: F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), ....: sin(th)*sin(ph), cos(th)]}, name='F') sage: F.display() F: S^2 --> R^3 on U: (th, ph) |--> (x, y, z) = (cos(ph)*sin(th), sin(ph)*sin(th), cos(th)) sage: c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c') sage: graph_c = c.plot(mapping=F, max_range=40, ....: plot_points=200, thickness=2, label_axes=False) # 3D plot sage: graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black') # plot of the sphere sage: show(graph_c + graph_S2) # the loxodrome + the sphere .. PLOT:: S2 = Manifold(2, 'S^2') U = S2.open_subset('U') XS = U.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') th, ph = XS[:] R3 = Manifold(3, 'R^3') X3 = R3.chart('x y z') F = S2.diff_map(R3, {(XS, X3): [sin(th)*cos(ph), sin(th)*sin(ph), cos(th)]}, name='F') t = RealLine().canonical_coordinate() c = S2.curve([2*atan(exp(-t/10)), t], (t, -oo, +oo), name='c') graph_c = c.plot(mapping=F, max_range=40, plot_points=200, thickness=2, label_axes=False) graph_S2 = XS.plot(X3, mapping=F, number_values=11, color='black') sphinx_plot(graph_c + graph_S2) Example of use of the argument ``parameters``: we define a curve with some symbolic parameters ``a`` and ``b``:: sage: a, b = var('a b') sage: c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c') To make a plot, we set spectific values for ``a`` and ``b`` by means of the Python dictionary ``parameters``:: sage: c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) Graphics object consisting of 1 graphics primitive .. PLOT:: R2 = Manifold(2, 'R^2') X = R2.chart('x y') t = RealLine().canonical_coordinate() a, b = var('a b') c = R2.curve([a*cos(t) + b, a*sin(t)], (t, 0, 2*pi), name='c') g = c.plot(parameters={a: 2, b: -3}, aspect_ratio=1) sphinx_plot(g) """ from sage.rings.infinity import Infinity from sage.misc.functional import numerical_approx from sage.plot.graphics import Graphics from sage.plot.line import line from sage.manifolds.chart import RealChart from sage.manifolds.utilities import set_axes_labels # # Get the @options from kwds # thickness = kwds.pop('thickness') plot_points = kwds.pop('plot_points') max_range = kwds.pop('max_range') aspect_ratio = kwds.pop('aspect_ratio') # # The "effective" curve to be plotted # if mapping is None: eff_curve = self else: eff_curve = mapping.restrict(self.codomain()) * self # # The chart w.r.t. which the curve is plotted # if chart is None: chart = eff_curve._codomain.default_chart() elif not isinstance(chart, RealChart): raise TypeError("{} is not a real chart".format(chart)) # # Coordinates of the above chart w.r.t. which the curve is plotted # if ambient_coords is None: ambient_coords = chart[:] # all chart coordinates are used n_pc = len(ambient_coords) if n_pc != 2 and n_pc != 3: raise ValueError("the number of coordinates involved in the " + "plot must be either 2 or 3, not {}".format(n_pc)) # indices of plot coordinates ind_pc = [chart[:].index(pc) for pc in ambient_coords] # # Parameter range for the plot # if prange is None: prange = (self._domain.lower_bound(), self._domain.upper_bound()) elif not isinstance(prange, (tuple, list)): raise TypeError("{} is neither a tuple nor a list".format(prange)) elif len(prange) != 2: raise ValueError("the argument prange must be a tuple/list " + "of 2 elements") tmin = prange[0] tmax = prange[1] if tmin == -Infinity: tmin = -max_range elif not include_end_point[0]: tmin = tmin + end_point_offset[0] if tmax == Infinity: tmax = max_range elif not include_end_point[1]: tmax = tmax - end_point_offset[1] tmin = numerical_approx(tmin) tmax = numerical_approx(tmax) # # The coordinate expression of the effective curve # canon_chart = self._domain.canonical_chart() transf = None for chart_pair in eff_curve._coord_expression: if chart_pair == (canon_chart, chart): transf = eff_curve._coord_expression[chart_pair] break else: # Search for a subchart for chart_pair in eff_curve._coord_expression: for schart in chart._subcharts: if chart_pair == (canon_chart, schart): transf = eff_curve._coord_expression[chart_pair] if transf is None: raise ValueError("No expression has been found for " + "{} in terms of {}".format(self, chart)) # # List of points for the plot curve # plot_curve = [] dt = (tmax - tmin) / (plot_points - 1) t = tmin if parameters is None: for i in range(plot_points): x = transf(t, simplify=False) plot_curve.append([numerical_approx(x[j]) for j in ind_pc]) t += dt else: for i in range(plot_points): x = transf(t, simplify=False) plot_curve.append([ numerical_approx(x[j].substitute(parameters)) for j in ind_pc ]) t += dt # # The plot # resu = Graphics() resu += line(plot_curve, color=color, linestyle=style, thickness=thickness) if n_pc == 2: # 2D graphic resu.set_aspect_ratio(aspect_ratio) if label_axes: # We update the dictionary _extra_kwds (options to be passed # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition resu._extra_kwds['axes_labels'] = [ r'$' + latex(pc) + r'$' for pc in ambient_coords ] else: # 3D graphic if aspect_ratio == 'automatic': aspect_ratio = 1 resu.aspect_ratio(aspect_ratio) if label_axes: labels = [str(pc) for pc in ambient_coords] resu = set_axes_labels(resu, *labels) return resu
def _graphics(self, plot_curve, ambient_coords, thickness=1, aspect_ratio='automatic', color='red', style='-', label_axes=True): r""" Plot a 2D or 3D curve in a Cartesian graph with axes labeled by the ambient coordinates; it is invoked by the methods :meth:`plot` of :class:`~sage.manifolds.differentiable.curve.DifferentiableCurve`, and its subclasses (:class:`~sage.manifolds.differentiable.integrated_curve.IntegratedCurve`, :class:`~sage.manifolds.differentiable.integrated_curve.IntegratedAutoparallelCurve`, and :class:`~sage.manifolds.differentiable.integrated_curve.IntegratedGeodesic`). TESTS:: sage: M = Manifold(2, 'R^2') sage: X.<x,y> = M.chart() sage: R.<t> = RealLine() sage: c = M.curve([cos(t), sin(t)], (t, 0, 2*pi), name='c') sage: graph = c._graphics([[1,2], [3,4]], [x,y]) sage: graph._objects[0].xdata == [1,3] True sage: graph._objects[0].ydata == [2,4] True sage: graph._objects[0]._options['thickness'] == 1 True sage: graph._extra_kwds['aspect_ratio'] == 'automatic' True sage: graph._objects[0]._options['rgbcolor'] == 'red' True sage: graph._objects[0]._options['linestyle'] == '-' True sage: l = [r'$'+latex(x)+r'$', r'$'+latex(y)+r'$'] sage: graph._extra_kwds['axes_labels'] == l True """ from sage.plot.graphics import Graphics from sage.plot.line import line from sage.manifolds.utilities import set_axes_labels # # The plot # n_pc = len(ambient_coords) resu = Graphics() resu += line(plot_curve, color=color, linestyle=style, thickness=thickness) if n_pc == 2: # 2D graphic resu.set_aspect_ratio(aspect_ratio) if label_axes: # We update the dictionary _extra_kwds (options to be passed # to show()), instead of using the method # Graphics.axes_labels() since the latter is not robust w.r.t. # graph addition resu._extra_kwds['axes_labels'] = [r'$'+latex(pc)+r'$' for pc in ambient_coords] else: # 3D graphic if aspect_ratio == 'automatic': aspect_ratio = 1 resu.aspect_ratio(aspect_ratio) if label_axes: labels = [str(pc) for pc in ambient_coords] resu = set_axes_labels(resu, *labels) return resu
def legend_3d(hyperplane_arrangement, hyperplane_colors, length): r""" Create plot of a 3d legend for an arrangement of planes in 3-space. The ``length`` parameter determines whether short or long labels are used in the legend. INPUT: - ``hyperplane_arrangement`` -- a hyperplane arrangement - ``hyperplane_colors`` -- list of colors - ``length`` -- either ``'short'`` or ``'long'`` OUTPUT: - A graphics object. EXAMPLES:: sage: a = hyperplane_arrangements.semiorder(3) sage: from sage.geometry.hyperplane_arrangement.plot import legend_3d sage: legend_3d(a, list(colors.values())[:6],length='long') Graphics object consisting of 6 graphics primitives sage: b = hyperplane_arrangements.semiorder(4) sage: c = b.essentialization() sage: legend_3d(c, list(colors.values())[:12], length='long') Graphics object consisting of 12 graphics primitives sage: legend_3d(c, list(colors.values())[:12], length='short') Graphics object consisting of 12 graphics primitives sage: p = legend_3d(c, list(colors.values())[:12], length='short') sage: p.set_legend_options(ncol=4) sage: type(p) <class 'sage.plot.graphics.Graphics'> """ if hyperplane_arrangement.dimension() != 3: raise ValueError('arrangements must be in 3-space') hyps = hyperplane_arrangement.hyperplanes() N = len(hyperplane_arrangement) if length == 'short': labels = [' ' + str(i) for i in range(N)] else: labels = [ ' ' + hyps[i]._repr_linear(include_zero=False) for i in range(N) ] p = Graphics() for i in range(N): p += line([(0, 0), (0, 0)], color=hyperplane_colors[i], thickness=8, legend_label=labels[i], axes=False) p.set_legend_options(title='Hyperplanes', loc='center', labelspacing=0.4, fancybox=True, font_size='x-large', ncol=2) p.legend(True) return p
def plot_phase_trajectories(func, inits, xbound, ybound, tbound=(0, 10, 100), use_sage=False, axis=None, f_kwargs={}, odeint_kwargs={}, plt_kwargs={'color': 'blue'}): """function for plotting the phase space trajectories of ordinary differential equations (ODEs) of the form dy/dt = f(y, t), where y can be a n-dim vector (see scipy.integrate.odeint for reference). Inspired by plotdf; reference: github.com/jmoy Parameters: func - RHS of ODE; callable(t, y) inits - initial values for plotting trajectories xbound, ybound - sequences with len = 2 gives min and max values for x and y respectivly tbound - sequence with len = 3 gives min, max and step for t values to calculate the trajectories for use_sage - whether to use sage for plotting instead of matplotlib axis - matplotlib axis to draw plot in; if None, current will be used odeint_kwargs - dict containing kwargs for scipy.integrate.odeint plt_kwargs - dict containing kwargs for matplotlib.pyplot; can also be used for sage-Graphics objects Returns: list containing matplotlib-artist objects (Line2D) or one sage-Graphics object """ f = lambda x, t: func(t, x, **f_kwargs) if use_sage: from sage.plot.graphics import Graphics from sage.plot.line import line elif axis is None: axis = plt.gca() def f_neg(x, t): return -f(x, t) artists = [] if not use_sage else Graphics() t = np.linspace(*tbound) for i in inits: sol_fwd = odeint(f, i, t, **odeint_kwargs) # forward solution sol_bwd = odeint(f_neg, i, t, **odeint_kwargs) # backward solution sol = np.vstack((np.flipud(sol_bwd), sol_fwd)) # flip sol_bwd and put both together sol_x = sol[:, 0] # left column of sol sol_y = sol[:, 1] # right column of sol sol_x_masked = np.ma.masked_outside(sol_x, *xbound) # mask data to prevent sol_y_masked = np.ma.masked_outside(sol_y, *ybound) # blow-up of solution if not use_sage: artists.append(axis.plot(sol_x_masked, sol_y_masked, **plt_kwargs)) else: artists += line(zip(sol_x_masked, sol_y_masked), plt_kwargs, xmin=xbound[0], xmax=xbound[1]) if not use_sage: plt.xlim(xbound) plt.ylim(ybound) return artists
def _plot(self, geosub, color=None): r""" EXAMPLES:: sage: from EkEkstar import kFace, GeoSub sage: sub = {1:[1,2], 2:[1,3], 3:[1]} sage: geosub = GeoSub(sub,2, dual=True) sage: _ = kFace((10,21,33), (1,))._plot(geosub) # case A sage: _ = kFace((10,21,33), (1,2), dual=True)._plot(geosub) # case C sage: _ = kFace((10,21,33), (1,), dual=True)._plot(geosub) # case E :: sage: sub = {1: [1, 3, 2, 3], 2: [2, 3], 3: [3, 2, 3, 1, 3, 2, 3]} sage: geosub = GeoSub(sub, 2, dual=True) sage: _ = kFace((10,21,33), (1,2), dual=True)._plot(geosub) # case B :: sage: sub = {1:[1,2,3,3,3,3], 2:[1,3], 3:[1]} sage: geosub = GeoSub(sub,2, dual=True) sage: _ = kFace((0,0,0),(1,2), dual=True)._plot(geosub) # case A """ v = self.vector() t = self.type() if color != None: col = color else: col = self._color G = Graphics() K = geosub.field() b = K.gen() num = geosub._sigma_dict.keys() if self.is_dual(): h = list(set(num) - set(t)) B = b vec = geosub.dominant_left_eigenvector() emb = geosub.contracting_eigenvalues_indices() else: h = list(t) B = b**(-1) # TODO: this seems useless (why?) vec = -geosub.dominant_left_eigenvector() emb = geosub.dilating_eigenvalues_indices() el = v * vec iter = 0 conjugates = geosub.complex_embeddings() if len(h) == 1: if conjugates[emb[0]].is_real() == True: bp = zero_vector(CC, len(emb)) for i in range(len(emb)): bp[i] = K(el).complex_embeddings()[emb[i]] bp1 = zero_vector(CC, len(emb)) for i in range(len(emb)): bp1[i] = K( (el + vec[h[0] - 1])).complex_embeddings()[emb[i]] if len(emb) == 1: return line([bp[0], bp1[0]], color=col, thickness=3) else: return line([bp, bp1], color=col, thickness=3) else: bp = K(el).complex_embeddings()[emb[0]] bp1 = K((el + vec[h[0] - 1])).complex_embeddings()[emb[0]] return line([bp, bp1], color=col, thickness=3) elif len(h) == 2: if conjugates[emb[0]].is_real() == True: bp = (K(el).complex_embeddings()[emb[0]], K(el).complex_embeddings()[emb[1]]) bp1 = (K(el + vec[h[0] - 1]).complex_embeddings()[emb[0]], K(el + vec[h[0] - 1]).complex_embeddings()[emb[1]]) bp2 = (K(el + vec[h[0] - 1] + vec[h[1] - 1]).complex_embeddings()[emb[0]], K(el + vec[h[0] - 1] + vec[h[1] - 1]).complex_embeddings()[emb[1]]) bp3 = (K(el + vec[h[1] - 1]).complex_embeddings()[emb[0]], K(el + vec[h[1] - 1]).complex_embeddings()[emb[1]]) return polygon2d([bp, bp1, bp2, bp3], color=col, thickness=.1, alpha=0.8) else: bp = K(el).complex_embeddings()[emb[0]] bp1 = K(el + vec[h[0] - 1]).complex_embeddings()[emb[0]] bp2 = K(el + vec[h[0] - 1] + vec[h[1] - 1]).complex_embeddings()[emb[0]] bp3 = K(el + vec[h[1] - 1]).complex_embeddings()[emb[0]] return polygon2d([[bp[0], bp[1]], [bp1[0], bp1[1]], [bp2[0], bp2[1]], [bp3[0], bp3[1]]], color=col, thickness=.1, alpha=0.8) else: raise NotImplementedError( "Plotting is implemented only for patches in two or three dimensions." ) return G
def plot_cluster_fan_stereographically(self, northsign=1, north=None, right=None, colors=None, d_vectors=False): from sage.plot.graphics import Graphics from sage.plot.point import point from sage.misc.flatten import flatten from sage.plot.line import line from sage.misc.functional import norm if self.rk != 3: raise ValueError("Can only stereographically project fans in 3d.") if not self.is_finite() and self._depth == infinity: raise ValueError( "For infinite algebras you must specify the depth.") if north == None: if self.is_affine(): north = vector(self.delta()) else: north = vector((-1, -1, -1)) if right == None: if self.is_affine(): right = vector(self.gamma()) else: right = vector((1, 0, 0)) if colors == None: colors = dict([(0, 'red'), (1, 'green'), (2, 'blue'), (3, 'cyan'), (4, 'yellow')]) G = Graphics() roots = list(self.g_vectors()) compatible = [] while roots: x = roots.pop() if x in self.initial_cluster() and d_vectors: x1 = -self.simple_roots()[list( self.initial_cluster()).index(x)] else: x1 = x for y in roots: if self.compatibility_degree(x, y) == 0: if y in self.initial_cluster() and d_vectors: y1 = -self.simple_roots()[list( self.initial_cluster()).index(y)] else: y1 = y compatible.append((x1, y1)) for (u, v) in compatible: G += _stereo_arc(vector(u), vector(v), vector(u + v), north=northsign * north, right=right, thickness=0.5, color='black') for i in range(3): orbit = self.ith_orbit(i) if d_vectors: orbit[0] = -self.simple_roots()[list( self.initial_cluster()).index(orbit[0])] for j in orbit: G += point(_stereo_coordinates(vector(orbit[j]), north=northsign * north, right=right), color=colors[i], zorder=len(G)) if self.is_affine(): tube_vectors = map(vector, flatten(self.affine_tubes())) for v in tube_vectors: G += point(_stereo_coordinates(v, north=northsign * north, right=right), color=colors[3], zorder=len(G)) if north != vector(self.delta()): G += _stereo_arc(tube_vectors[0], tube_vectors[1], vector(self.delta()), north=northsign * north, right=right, thickness=2, color=colors[4], zorder=0) else: # FIXME: refactor this before publishing tube_projections = [ _stereo_coordinates(v, north=northsign * north, right=right) for v in tube_vectors ] t = min( (G.get_minmax_data()['xmax'], G.get_minmax_data()['ymax'])) G += line([ tube_projections[0], tube_projections[0] + t * (_normalize(tube_projections[0] - tube_projections[1])) ], thickness=2, color=colors[4], zorder=0) G += line([ tube_projections[1], tube_projections[1] + t * (_normalize(tube_projections[1] - tube_projections[0])) ], thickness=2, color=colors[4], zorder=0) G.set_aspect_ratio(1) G._show_axes = False return G
def plot(self): r""" Return a graphical object of the Fully Packed Loop EXAMPLES: Here is the fully packed loop for .. MATH:: \begin{pmatrix} 0&1&1 \\ 1&-1&1 \\ 0&1&0 \end{pmatrix}: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) Here is how Sage represents this:: sage: A = AlternatingSignMatrix([[0, 1, 0], [1, -1, 1], [0, 1, 0]]) sage: fpl = FullyPackedLoop(A) sage: print(fpl.plot().description()) Line defined by 2 points: [(-1.0, 1.0), (0.0, 1.0)] Line defined by 2 points: [(0.0, 0.0), (0.0, -1.0)] Line defined by 2 points: [(0.0, 0.0), (1.0, 0.0)] Line defined by 2 points: [(0.0, 2.0), (0.0, 3.0)] Line defined by 2 points: [(0.0, 2.0), (0.0, 3.0)] Line defined by 2 points: [(0.0, 2.0), (1.0, 2.0)] Line defined by 2 points: [(1.0, 1.0), (0.0, 1.0)] Line defined by 2 points: [(1.0, 1.0), (2.0, 1.0)] Line defined by 2 points: [(2.0, 0.0), (1.0, 0.0)] Line defined by 2 points: [(2.0, 0.0), (2.0, -1.0)] Line defined by 2 points: [(2.0, 2.0), (1.0, 2.0)] Line defined by 2 points: [(2.0, 2.0), (2.0, 3.0)] Line defined by 2 points: [(2.0, 2.0), (2.0, 3.0)] Line defined by 2 points: [(3.0, 1.0), (2.0, 1.0)] Line defined by 2 points: [(3.0, 1.0), (2.0, 1.0)] Here are the other 3 by 3 Alternating Sign Matrices and their corresponding fully packed loops: .. MATH:: A = \begin{pmatrix} 1&0&0 \\ 0&1&0 \\ 0&0&1 \\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) .. MATH:: A = \begin{pmatrix} 1&0&0 \\ 0&0&1 \\ 0&1&0 \\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[1, 0, 0], [0, 0, 1], [0, 1, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) .. MATH:: A = \begin{pmatrix} 0&1&0\\ 1&0&0\\ 0&0&1\\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) .. MATH:: A = \begin{pmatrix} 0&1&0\\ 0&0&1\\ 1&0&0\\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) .. MATH:: A = \begin{pmatrix} 0&0&1\\ 1&0&0\\ 0&1&0\\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[0, 0, 1], [1, 0, 0], [0, 1, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) .. MATH:: A = \begin{pmatrix} 0&0&1\\ 0&1&0\\ 1&0&0\\ \end{pmatrix} gives: .. PLOT:: :width: 200 px A = AlternatingSignMatrix([[0, 0, 1], [0, 1, 0], [1, 0, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) EXAMPLES:: sage: A = AlternatingSignMatrix([[0, 1, 0, 0], [1, -1, 0, 1], \ [0, 1, 0, 0],[0, 0, 1, 0]]) sage: fpl = FullyPackedLoop(A) sage: print(fpl.plot().description()) Line defined by 2 points: [(-1.0, 0.0), (0.0, 0.0)] Line defined by 2 points: [(-1.0, 2.0), (0.0, 2.0)] Line defined by 2 points: [(0.0, 1.0), (0.0, 0.0)] Line defined by 2 points: [(0.0, 1.0), (1.0, 1.0)] Line defined by 2 points: [(0.0, 3.0), (0.0, 4.0)] Line defined by 2 points: [(0.0, 3.0), (0.0, 4.0)] Line defined by 2 points: [(0.0, 3.0), (1.0, 3.0)] Line defined by 2 points: [(1.0, 0.0), (1.0, -1.0)] Line defined by 2 points: [(1.0, 0.0), (2.0, 0.0)] Line defined by 2 points: [(1.0, 2.0), (0.0, 2.0)] Line defined by 2 points: [(1.0, 2.0), (2.0, 2.0)] Line defined by 2 points: [(2.0, 1.0), (1.0, 1.0)] Line defined by 2 points: [(2.0, 1.0), (2.0, 2.0)] Line defined by 2 points: [(2.0, 3.0), (1.0, 3.0)] Line defined by 2 points: [(2.0, 3.0), (2.0, 4.0)] Line defined by 2 points: [(2.0, 3.0), (2.0, 4.0)] Line defined by 2 points: [(3.0, 0.0), (2.0, 0.0)] Line defined by 2 points: [(3.0, 0.0), (3.0, -1.0)] Line defined by 2 points: [(3.0, 2.0), (3.0, 1.0)] Line defined by 2 points: [(3.0, 2.0), (3.0, 3.0)] Line defined by 2 points: [(4.0, 1.0), (3.0, 1.0)] Line defined by 2 points: [(4.0, 1.0), (3.0, 1.0)] Line defined by 2 points: [(4.0, 3.0), (3.0, 3.0)] Line defined by 2 points: [(4.0, 3.0), (3.0, 3.0)] Here is the plot: .. PLOT:: :width: 300 px A = AlternatingSignMatrix([[0, 1, 0, 0], [1, -1, 0, 1], [0, 1, 0, 0],[0, 0, 1, 0]]) fpl = FullyPackedLoop(A) p = fpl.plot() sphinx_plot(p) """ G = Graphics() n=len(self._six_vertex_model)-1 for j,row in enumerate(reversed(self._six_vertex_model)): for i,entry in enumerate(row): if i == 0 and (i+j+n+1) % 2 ==0: G+= line([(i-1,j),(i,j)]) if i == n and (i+j+n+1) % 2 ==0: G+= line([(i+1,j),(i,j)]) if j == 0 and (i+j+n) % 2 ==0: G+= line([(i,j),(i,j-1)]) if j == n and (i+j+n) % 2 ==0: G+= line([(i,j),(i,j+1)]) if entry == 0: # LR if (i+j+n) % 2==0: G += line([(i,j), (i+1,j)]) else: G += line([(i,j),(i,j+1)]) elif entry == 1: # LU if (i+j+n) % 2 ==0: G += line([(i,j), (i,j+1)]) else: G += line([(i+1,j), (i,j)]) elif entry == 2: # LD if (i+j+n) % 2 == 0: pass else: G += line([(i,j+1), (i,j)]) G += line([(i+1,j), (i,j)]) elif entry == 3: # UD if (i+j+n) % 2 == 0: G += line([(i,j), (i,j+1)]) else: G += line([(i+1,j), (i,j)]) elif entry == 4: # UR if (i+j+n) % 2 ==0: G += line([(i,j), (i,j+1)]) G += line([(i,j), (i+1,j)]) else: pass elif entry == 5: # RD if (i+j+n) % 2 ==0: G += line([(i,j), (i+1,j)]) else: G += line([(i,j+1), (i,j)]) G.axes(False) return G
def plot(self, **kwds): r""" Plot the initial triangulation associated to ``self``. INPUT: - ``radius`` - the radius of the disk; by default the length of the circle is the number of vertices - ``points_color`` - the color of the vertices; default 'black' - ``points_size`` - the size of the vertices; default 7 - ``triangulation_color`` - the color of the arcs; default 'black' - ``triangulation_thickness`` - the thickness of the arcs; default 0.5 - ``shading_color`` - the color of the shading used on neuter intervals; default 'lightgray' - ``reflections_color`` - the color of the reflection axes; default 'blue' - ``reflections_thickness`` - the thickness of the reflection axes; default 1 EXAMPLES:: sage: Y = SineGordonYsystem('A',(6,4,3)); sage: Y.plot() # not tested """ # Set up plotting options if 'radius' in kwds: radius = kwds['radius'] else: radius = ceil(self.r() / (2 * pi)) points_opts = {} if 'points_color' in kwds: points_opts['color'] = kwds['points_color'] else: points_opts['color'] = 'black' if 'points_size' in kwds: points_opts['size'] = kwds['points_size'] else: points_opts['size'] = 7 triangulation_opts = {} if 'triangulation_color' in kwds: triangulation_opts['color'] = kwds['triangulation_color'] else: triangulation_opts['color'] = 'black' if 'triangulation_thickness' in kwds: triangulation_opts['thickness'] = kwds['triangulation_thickness'] else: triangulation_opts['thickness'] = 0.5 shading_opts = {} if 'shading_color' in kwds: shading_opts['color'] = kwds['shading_color'] else: shading_opts['color'] = 'lightgray' reflections_opts = {} if 'reflections_color' in kwds: reflections_opts['color'] = kwds['reflections_color'] else: reflections_opts['color'] = 'blue' if 'reflections_thickness' in kwds: reflections_opts['thickness'] = kwds['reflections_thickness'] else: reflections_opts['thickness'] = 1 # Helper functions def triangle(x): (a, b) = sorted(x[:2]) for p in self.vertices(): if (p, a) in self.triangulation() or (a, p) in self.triangulation(): if (p, b) in self.triangulation() or (b, p) in self.triangulation(): if p < a or p > b: return sorted((a, b, p)) def plot_arc(radius, p, q, **opts): # plot the arc from p to q differently depending on the type of self p = ZZ(p) q = ZZ(q) t = var('t') if p - q in [1, -1]: def f(t): return (radius * cos(t), radius * sin(t)) (p, q) = sorted([p, q]) angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) return parametric_plot(f(t), (t, angle_q, angle_p), **opts) if self.type() == 'A': angle_p = vertex_to_angle(p) angle_q = vertex_to_angle(q) if angle_p < angle_q: angle_p += 2 * pi internal_angle = angle_p - angle_q if internal_angle > pi: (angle_p, angle_q) = (angle_q + 2 * pi, angle_p) internal_angle = angle_p - angle_q angle_center = (angle_p+angle_q) / 2 hypotenuse = radius / cos(internal_angle / 2) radius_arc = hypotenuse * sin(internal_angle / 2) center = (hypotenuse * cos(angle_center), hypotenuse * sin(angle_center)) center_angle_p = angle_p + pi / 2 center_angle_q = angle_q + 3 * pi / 2 def f(t): return (radius_arc * cos(t) + center[0], radius_arc * sin(t) + center[1]) return parametric_plot(f(t), (t, center_angle_p, center_angle_q), **opts) elif self.type() == 'D': if p >= q: q += self.r() px = -2 * pi * p / self.r() + pi / 2 qx = -2 * pi * q / self.r() + pi / 2 arc_radius = (px - qx) / 2 arc_center = qx + arc_radius def f(t): return exp(I * ((cos(t) + I * sin(t)) * arc_radius + arc_center)) * radius return parametric_plot((real_part(f(t)), imag_part(f(t))), (t, 0, pi), **opts) def vertex_to_angle(v): # v==0 corresponds to pi/2 return -2 * pi * RR(v) / self.r() + 5 * pi / 2 # Begin plotting P = Graphics() # Shade neuter intervals neuter_intervals = [x for x in flatten(self.intervals()[:-1], max_level=1) if x[2] in ["NR", "NL"]] shaded_triangles = map(triangle, neuter_intervals) for (p, q, r) in shaded_triangles: points = list(plot_arc(radius, p, q)[0]) points += list(plot_arc(radius, q, r)[0]) points += list(reversed(plot_arc(radius, p, r)[0])) P += polygon2d(points, **shading_opts) # Disk boundary P += circle((0, 0), radius, **triangulation_opts) # Triangulation for (p, q) in self.triangulation(): P += plot_arc(radius, p, q, **triangulation_opts) if self.type() == 'D': s = radius / 50.0 P += polygon2d([(s, 5 * s), (s, 7 * s), (3 * s, 5 * s), (3 * s, 7 * s)], color=triangulation_opts['color']) P += bezier_path([[(0, 0), (2 * s, 1 * s), (2 * s, 6 * s)], [(2 * s, 10 * s), (s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) P += bezier_path([[(0, 0), (-2 * s, 1 * s), (-2 * s, 6 * s)], [(-2 * s, 10 * s), (-s, 20 * s)], [(0, 30 * s), (0, radius)]], **triangulation_opts) P += point((0, 0), zorder=len(P), **points_opts) # Vertices v_points = {x: (radius * cos(vertex_to_angle(x)), radius * sin(vertex_to_angle(x))) for x in self.vertices()} for v in v_points: P += point(v_points[v], zorder=len(P), **points_opts) # Reflection axes P += line([(0, 1.1 * radius), (0, -1.1 * radius)], zorder=len(P), **reflections_opts) axis_angle = vertex_to_angle(-0.5 * (self.rk() + (1, 1))[1]) (a, b) = (1.1 * radius * cos(axis_angle), 1.1 * radius * sin(axis_angle)) P += line([(a, b), (-a, -b)], zorder=len(P), **reflections_opts) # Wrap up P.set_aspect_ratio(1) P.axes(False) return P
def show(self, **args): r""" Displays the pseudoline arrangement as a wiring diagram. INPUT: - ``**args`` -- any arguments to be forwarded to the ``show`` method. In particular, to tune the dimensions, use the ``figsize`` argument (example below). EXAMPLES:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 1, 0], [2, 1, 0]] sage: p = PseudolineArrangement(permutations) sage: p.show(figsize=[7,5]) TESTS:: sage: from sage.geometry.pseudolines import PseudolineArrangement sage: permutations = [[3, 2, 1], [3, 2, 0], [3, 0, 1], [2, 0, 1]] sage: p = PseudolineArrangement(permutations) sage: p.show() Traceback (most recent call last): ... ValueError: There has been a problem while plotting the figure... """ x = 1 from sage.plot.line import line from sage.plot.text import text lines = [[(0, self._n - 1 - i)] for i in range(self._n)] for i, j in self.transpositions(): iy = lines[i][-1][1] jy = lines[j][-1][1] lines[i].append((x, iy)) lines[j].append((x, jy)) if abs(iy - jy) != 1: raise ValueError( "There has been a problem while plotting the figure. It " + "seems that the lines are not correctly ordered. Please " + "check the pseudolines modules documentation, there is a " + "warning about that. ") lines[i].append((x + 2, jy)) lines[j].append((x + 2, iy)) x += 2 L = line([(1, 1)]) for i, l in enumerate(lines): l.append((x + 2, l[-1][1])) L += line(l) L += text(str(i), (0, l[0][1] + .3), horizontal_alignment="right") L += text(str(i), (x + 2, l[-1][1] + .3), horizontal_alignment="left") return L.show(axes=False, **args)
def plot_paths_2d(self, start_sys, end_sys, input_ring, c_skew=.001, endpoints=True, saved_start=None, rand_colors=False): """ This returns a graphics object of solution paths in the complex plane. INPUT: - start_sys -- a square polynomial system, given as a list of polynomials - end_sys -- same type as start_sys - input_ring -- for coercion of the variables into the desired ring. - c_skew -- optional. the imaginary part of homotopy multiplier; nonzero values are often necessary to avoid intermediate path collisions - endpoints -- optional. Whether to draw in the ends of paths as points. - saved_start -- optional. A phc output file. If not given, start system solutions are computed via the phc.blackbox function. OUTPUT: - lines and points of solution paths EXAMPLES:: sage: from sage.interfaces.phc import * sage: from sage.structure.sage_object import SageObject sage: R2.<x,y> = PolynomialRing(QQ,2) sage: start_sys = [x^5-y^2,y^5-1] sage: sol = phc.blackbox(start_sys, R2) # optional -- phc sage: start_save = sol.save_as_start() # optional -- phc sage: end_sys = [x^5-25,y^5-x^2] # optional -- phc sage: testing = phc.plot_paths_2d(start_sys, end_sys, R2) # optional -- phc sage: type(testing) # optional -- phc (normally use plot here) <class 'sage.plot.graphics.Graphics'> """ paths = phc.path_track(start_sys, end_sys, input_ring, c_skew=c_skew, saved_start=saved_start) path_lines = [] sol_pts = [] if rand_colors: r_color = {} for a_var in input_ring.gens(): var_name = str(a_var) r_color[var_name] = (random(), random(), random()) for a_sol in paths: for a_var in input_ring.gens(): var_name = str(a_var) temp_line = [] for data in a_sol: temp_line.append( [data[var_name].real(), data[var_name].imag()]) if rand_colors: path_lines.append( line(temp_line, rgbcolor=r_color[var_name])) else: path_lines.append(line(temp_line)) if endpoints: sol_pts = [] for a_sol in paths: for a_var in input_ring.gens(): var_name = str(a_var) sol_pts.append( point([ a_sol[0][var_name].real(), a_sol[0][var_name].imag() ])) sol_pts.append( point([ a_sol[-1][var_name].real(), a_sol[-1][var_name].imag() ])) return sum(sol_pts) + sum(path_lines) else: return sum(path_lines)
def plot(self, size=[[0],[0]], projection='usual', simple_roots=True, fundamental_weights=True, alcovewalks=[]): r""" Return a graphics object built from a space of weight(space/lattice). There is a different technic to plot if the Cartan type is affine or not. The graphics returned is a Graphics object. This function is experimental, and is subject to short term evolutions. EXAMPLES:: By default, the plot returned has no axes and the ratio between axes is 1. sage: G = RootSystem(['C',2]).weight_lattice().plot() sage: G.axes(True) sage: G.set_aspect_ratio(2) For a non affine Cartan type, the plot method work for type with 2 generators, it will draw the hyperlane(line for this dimension) accrow the fundamentals weights. sage: G = RootSystem(['A',2]).weight_lattice().plot() sage: G = RootSystem(['B',2]).weight_lattice().plot() sage: G = RootSystem(['G',2]).weight_lattice().plot() The plot returned has a size of one fundamental polygon by default. We can ask plot to give a bigger plot by using the argument size sage: G = RootSystem(['G',2,1]).weight_space().plot(size = [[0..1],[-1..1]]) sage: G = RootSystem(['A',2,1]).weight_space().plot(size = [[-1..1],[-1..1]]) A very important argument is the projection which will draw the plot. There are some usual projections is this method. If you want to draw in the plane a very special Cartan type, Sage will ask you to specify the projection. The projection is a matrix over a ring. In practice, calcul over float is a good way to draw. sage: L = RootSystem(['A',2,1]).weight_space() sage: G = L.plot(projection=matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]])) sage: G = RootSystem(['C',2,1]).weight_space().plot() By default, the plot method draw the simple roots, this can be disabled by setting the argument simple_roots=False sage: G = RootSystem(['A',2]).weight_space().plot(simple_roots=False) By default, the plot method draw the fundamental weights,this can be disabled by setting the argument fundamental_weights=False sage: G = RootSystem(['A',2]).weight_space().plot(fundamental_weights=False, simple_roots=False) There is in a plot an argument to draw alcoves walks. The good way to do this is to use the crystals theory. the plot method contains only the drawing part... sage: L = RootSystem(['A',2,1]).weight_space() sage: G = L.plot(size=[[-1..1],[-1..1]],alcovewalks=[[0,2,0,1,2,1,2,0,2,1]]) """ from sage.plot.all import Graphics from sage.plot.line import line from cartan_type import CartanType from sage.matrix.constructor import matrix from sage.rings.all import QQ, RR from sage.plot.arrow import arrow from sage.plot.point import point # We begin with an empty plot G G = Graphics() ct = self.cartan_type() n = ct.n # Define a set of colors # TODO : Colors in option ? colors=[(0,1,0),(1,0,0),(0,0,1),(1,1,0),(0,1,1),(1,0,1)] # plot the affine types: if ct.is_affine(): # Check the projection # TODO : try to have usual_projection for main plotable types if projection == 'usual': if ct == CartanType(['A',2,1]): projection = matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]]) elif ct == CartanType(['C',2,1]): projection = matrix(QQ, [[0,1,1],[0,0,1]]) elif ct == CartanType(['G',2,1]): projection = matrix(RR, [[0,0.5,0],[0,0.866,1.732]]) else: raise 'There is no usual projection for this Cartan type, you have to give one in argument' assert(n + 1 == projection.ncols()) assert(2 == projection.nrows()) # Check the size is correct with the lattice assert(len(size) == n) # Select the center of the translated fundamental polygon to plot translation_factors = ct.translation_factors() simple_roots = self.simple_roots() translation_vectors = [translation_factors[i]*simple_roots[i] for i in ct.classical().index_set()] initial = [[]] for i in range(n): prod_list = [] for elem in size[i]: for partial_list in initial: prod_list.append( [elem]+partial_list ); initial = prod_list; part_lattice = [] for combinaison in prod_list: elem_lattice = self.zero() for i in range(n): elem_lattice = elem_lattice + combinaison[i]*translation_vectors[i] part_lattice.append(elem_lattice) # Get the vertices of the fundamental alcove fundamental_weights = self.fundamental_weights() vertices = map(lambda x: (1/x.level())*x, fundamental_weights.list()) # Recup the group which act on the fundamental polygon classical = self.weyl_group().classical() for center in part_lattice: for w in classical: # for each center of polygon and each element of classical # parabolic subgroup, we have to draw an alcove. #first, iterate over pairs of fundamental weights, drawing lines border of polygons: for i in range(1,n+1): for j in range(i+1,n+1): p1=projection*((w.action(vertices[i])).to_vector() + center.to_vector()) p2=projection*((w.action(vertices[j])).to_vector() + center.to_vector()) G+=line([p1,p2],rgbcolor=(0,0,0),thickness=2) #next, get all lines from point to a fundamental weight, that separe different #chanber in a same polygon (important: associate a color with a fundamental weight) pcenter = projection*(center.to_vector()) for i in range(1,n+1): p3=projection*((w.action(vertices[i])).to_vector() + center.to_vector()) G+=line([p3,pcenter], rgbcolor=colors[n-i+1]) #Draw alcovewalks #FIXME : The good way to draw this is to use the alcoves walks works made in Cristals #The code here just draw like example and import the good things. rho = (1/self.rho().level())*self.rho() W = self.weyl_group() for walk in alcovewalks: target = W.from_reduced_word(walk).action(rho) for i in range(len(walk)): walk.pop() origin = W.from_reduced_word(walk).action(rho) G+=arrow(projection*(origin.to_vector()),projection*(target.to_vector()), rgbcolor=(0.6,0,0.6), width=1, arrowsize=5) target = origin else: # non affine plot # Check the projection # TODO : try to have usual_projection for main plotable types if projection == 'usual': if ct == CartanType(['A',2]): projection = matrix(RR, [[0.5,-0.5],[0.866,0.866]]) elif ct == CartanType(['B',2]): projection = matrix(QQ, [[1,0],[1,1]]) elif ct == CartanType(['C',2]): projection = matrix(QQ, [[1,1],[0,1]]) elif ct == CartanType(['G',2]): projection = matrix(RR, [[0.5,0],[0.866,1.732]]) else: raise 'There is no usual projection for this Cartan type, you have to give one in argument' # Get the fundamental weights fundamental_weights = self.fundamental_weights() WeylGroup = self.weyl_group() #Draw not the alcove but the cones delimited by the hyperplanes #The size of the line depend of the fundamental weights. pcenter = projection*(self.zero().to_vector()) for w in WeylGroup: for i in range(1,n+1): p3=3*projection*((w.action(fundamental_weights[i])).to_vector()) G+=line([p3,pcenter], rgbcolor=colors[n-i+1]) #Draw the simple roots if simple_roots: SimpleRoots = self.simple_roots() if ct.is_affine(): G+=arrow((0,0), projection*(SimpleRoots[0].to_vector()), rgbcolor=(0,0,0)) for j in range(1,n+1): G+=arrow((0,0),projection*(SimpleRoots[j].to_vector()), rgbcolor=colors[j]) #Draw the fundamental weights if fundamental_weights: FundWeight = self.fundamental_weights() for j in range(1,n+1): G+=point(projection*(FundWeight[j].to_vector()), rgbcolor=colors[j], pointsize=60) G.set_aspect_ratio(1) G.axes(False) return G
def plot(self, size=[[0], [0]], projection='usual', simple_roots=True, fundamental_weights=True, alcovewalks=[]): r""" Return a graphics object built from a space of weight(space/lattice). There is a different technic to plot if the Cartan type is affine or not. The graphics returned is a Graphics object. This function is experimental, and is subject to short term evolutions. EXAMPLES:: By default, the plot returned has no axes and the ratio between axes is 1. sage: G = RootSystem(['C',2]).weight_lattice().plot() sage: G.axes(True) sage: G.set_aspect_ratio(2) For a non affine Cartan type, the plot method work for type with 2 generators, it will draw the hyperlane(line for this dimension) accrow the fundamentals weights. sage: G = RootSystem(['A',2]).weight_lattice().plot() sage: G = RootSystem(['B',2]).weight_lattice().plot() sage: G = RootSystem(['G',2]).weight_lattice().plot() The plot returned has a size of one fundamental polygon by default. We can ask plot to give a bigger plot by using the argument size sage: G = RootSystem(['G',2,1]).weight_space().plot(size = [[0..1],[-1..1]]) sage: G = RootSystem(['A',2,1]).weight_space().plot(size = [[-1..1],[-1..1]]) A very important argument is the projection which will draw the plot. There are some usual projections is this method. If you want to draw in the plane a very special Cartan type, Sage will ask you to specify the projection. The projection is a matrix over a ring. In practice, calcul over float is a good way to draw. sage: L = RootSystem(['A',2,1]).weight_space() sage: G = L.plot(projection=matrix(RR, [[0,0.5,-0.5],[0,0.866,0.866]])) sage: G = RootSystem(['C',2,1]).weight_space().plot() By default, the plot method draw the simple roots, this can be disabled by setting the argument simple_roots=False sage: G = RootSystem(['A',2]).weight_space().plot(simple_roots=False) By default, the plot method draw the fundamental weights,this can be disabled by setting the argument fundamental_weights=False sage: G = RootSystem(['A',2]).weight_space().plot(fundamental_weights=False, simple_roots=False) There is in a plot an argument to draw alcoves walks. The good way to do this is to use the crystals theory. the plot method contains only the drawing part... sage: L = RootSystem(['A',2,1]).weight_space() sage: G = L.plot(size=[[-1..1],[-1..1]],alcovewalks=[[0,2,0,1,2,1,2,0,2,1]]) """ from sage.plot.all import Graphics from sage.plot.line import line from cartan_type import CartanType from sage.matrix.constructor import matrix from sage.rings.all import QQ, RR from sage.plot.arrow import arrow from sage.plot.point import point # We begin with an empty plot G G = Graphics() ct = self.cartan_type() n = ct.n # Define a set of colors # TODO : Colors in option ? colors = [(0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0), (0, 1, 1), (1, 0, 1)] # plot the affine types: if ct.is_affine(): # Check the projection # TODO : try to have usual_projection for main plotable types if projection == 'usual': if ct == CartanType(['A', 2, 1]): projection = matrix( RR, [[0, 0.5, -0.5], [0, 0.866, 0.866]]) elif ct == CartanType(['C', 2, 1]): projection = matrix(QQ, [[0, 1, 1], [0, 0, 1]]) elif ct == CartanType(['G', 2, 1]): projection = matrix(RR, [[0, 0.5, 0], [0, 0.866, 1.732]]) else: raise 'There is no usual projection for this Cartan type, you have to give one in argument' assert (n + 1 == projection.ncols()) assert (2 == projection.nrows()) # Check the size is correct with the lattice assert (len(size) == n) # Select the center of the translated fundamental polygon to plot translation_factors = ct.translation_factors() simple_roots = self.simple_roots() translation_vectors = [ translation_factors[i] * simple_roots[i] for i in ct.classical().index_set() ] initial = [[]] for i in range(n): prod_list = [] for elem in size[i]: for partial_list in initial: prod_list.append([elem] + partial_list) initial = prod_list part_lattice = [] for combinaison in prod_list: elem_lattice = self.zero() for i in range(n): elem_lattice = elem_lattice + combinaison[ i] * translation_vectors[i] part_lattice.append(elem_lattice) # Get the vertices of the fundamental alcove fundamental_weights = self.fundamental_weights() vertices = map(lambda x: (1 / x.level()) * x, fundamental_weights.list()) # Recup the group which act on the fundamental polygon classical = self.weyl_group().classical() for center in part_lattice: for w in classical: # for each center of polygon and each element of classical # parabolic subgroup, we have to draw an alcove. #first, iterate over pairs of fundamental weights, drawing lines border of polygons: for i in range(1, n + 1): for j in range(i + 1, n + 1): p1 = projection * ( (w.action(vertices[i])).to_vector() + center.to_vector()) p2 = projection * ( (w.action(vertices[j])).to_vector() + center.to_vector()) G += line([p1, p2], rgbcolor=(0, 0, 0), thickness=2) #next, get all lines from point to a fundamental weight, that separe different #chanber in a same polygon (important: associate a color with a fundamental weight) pcenter = projection * (center.to_vector()) for i in range(1, n + 1): p3 = projection * ( (w.action(vertices[i])).to_vector() + center.to_vector()) G += line([p3, pcenter], rgbcolor=colors[n - i + 1]) #Draw alcovewalks #FIXME : The good way to draw this is to use the alcoves walks works made in Cristals #The code here just draw like example and import the good things. rho = (1 / self.rho().level()) * self.rho() W = self.weyl_group() for walk in alcovewalks: target = W.from_reduced_word(walk).action(rho) for i in range(len(walk)): walk.pop() origin = W.from_reduced_word(walk).action(rho) G += arrow(projection * (origin.to_vector()), projection * (target.to_vector()), rgbcolor=(0.6, 0, 0.6), width=1, arrowsize=5) target = origin else: # non affine plot # Check the projection # TODO : try to have usual_projection for main plotable types if projection == 'usual': if ct == CartanType(['A', 2]): projection = matrix(RR, [[0.5, -0.5], [0.866, 0.866]]) elif ct == CartanType(['B', 2]): projection = matrix(QQ, [[1, 0], [1, 1]]) elif ct == CartanType(['C', 2]): projection = matrix(QQ, [[1, 1], [0, 1]]) elif ct == CartanType(['G', 2]): projection = matrix(RR, [[0.5, 0], [0.866, 1.732]]) else: raise 'There is no usual projection for this Cartan type, you have to give one in argument' # Get the fundamental weights fundamental_weights = self.fundamental_weights() WeylGroup = self.weyl_group() #Draw not the alcove but the cones delimited by the hyperplanes #The size of the line depend of the fundamental weights. pcenter = projection * (self.zero().to_vector()) for w in WeylGroup: for i in range(1, n + 1): p3 = 3 * projection * ( (w.action(fundamental_weights[i])).to_vector()) G += line([p3, pcenter], rgbcolor=colors[n - i + 1]) #Draw the simple roots if simple_roots: SimpleRoots = self.simple_roots() if ct.is_affine(): G += arrow((0, 0), projection * (SimpleRoots[0].to_vector()), rgbcolor=(0, 0, 0)) for j in range(1, n + 1): G += arrow((0, 0), projection * (SimpleRoots[j].to_vector()), rgbcolor=colors[j]) #Draw the fundamental weights if fundamental_weights: FundWeight = self.fundamental_weights() for j in range(1, n + 1): G += point(projection * (FundWeight[j].to_vector()), rgbcolor=colors[j], pointsize=60) G.set_aspect_ratio(1) G.axes(False) return G