def plot(self, polygon_label=True): r""" Returns a plot of the GraphicalPolygon. EXAMPLES:: sage: from flatsurf import * sage: s = similarity_surfaces.example() sage: from flatsurf.graphical.surface import GraphicalSurface sage: gs = GraphicalSurface(s) sage: gs.graphical_polygon(0).set_fill_color("red") sage: gs.graphical_polygon(0).plot() Graphics object consisting of 5 graphics primitives """ from sage.plot.point import point2d from sage.plot.polygon import polygon2d from sage.plot.graphics import Graphics from sage.plot.text import text p = polygon2d(self._v, **self.polygon_options()) if self._label is not None and polygon_label: p += text(str(self._label), sum(self._v) / len(self._v), **self.polygon_label_options()) if self._edge_labels: opt = self.edge_label_options() n = self.base_polygon().num_edges() for i in range(n): lab = str(i) if self._edge_labels is True else self._edge_labels[i] if lab: e = self._v[(i + 1) % n] - self._v[i] no = V((-e[1], e[0])) p += text(lab, self._v[i] + 0.3 * e + 0.05 * no, **self.edge_label_options()) return p
def _new_plot(self, M, color=None): r""" INPUT: - ``M`` -- projection matrix - ``color`` -- string or None 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: M = geosub.projection() sage: _ = kFace((10,21,33), (1,2), dual=True)._new_plot(M) # case C """ if color is None: color = self._color L = self.new_proj(M) if self.face_dimension() == 1: return line(L, color=color, thickness=3) elif self.face_dimension() == 2: return polygon2d(L, color=color, thickness=.1, alpha=.8) else: raise NotImplementedError( "Plotting is implemented only for patches in two or three dimensions." )
def plot(self): """ Plot the lattice polygon. OUTPUT: A graphics object. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0), (0,1), (0,0), (2,2)) sage: P.plot() Graphics object consisting of 6 graphics primitives sage: LatticePolytope_PPL([0], [1]).plot() Graphics object consisting of 3 graphics primitives sage: LatticePolytope_PPL([0]).plot() Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d from sage.plot.polygon import polygon2d vertices = self.ordered_vertices() points = self.integral_points() if self.space_dimension() == 1: vertices = [vector(ZZ, (v[0], 0)) for v in vertices] points = [vector(ZZ, (p[0], 0)) for p in points] point_plot = sum( point2d(p, pointsize=100, color='red') for p in points) polygon_plot = polygon2d(vertices, alpha=0.2, color='green', zorder=-1, thickness=2) return polygon_plot + point_plot
def plot(self): """ Plot the lattice polygon. OUTPUT: A graphics object. EXAMPLES:: sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL sage: P = LatticePolytope_PPL((1,0), (0,1), (0,0), (2,2)) sage: P.plot() Graphics object consisting of 6 graphics primitives sage: LatticePolytope_PPL([0], [1]).plot() Graphics object consisting of 3 graphics primitives sage: LatticePolytope_PPL([0]).plot() Graphics object consisting of 2 graphics primitives """ from sage.plot.point import point2d from sage.plot.polygon import polygon2d vertices = self.ordered_vertices() points = self.integral_points() if self.space_dimension() == 1: vertices = [vector(ZZ, (v[0], 0)) for v in vertices] points = [vector(ZZ, (p[0], 0)) for p in points] point_plot = sum(point2d(p, pointsize=100, color='red') for p in points) polygon_plot = polygon2d(vertices, alpha=0.2, color='green', zorder=-1, thickness=2) return polygon_plot + point_plot
def plot(self, **options): r""" Plot this cylinder in coordinates used by a graphical surface. This plots this cylinder as a union of subpolygons. Only the intersections with polygons visible in the graphical surface are shown. Parameters other than `graphical_surface` are passed to `polygon2d` which is called to render the polygons. Parameters ---------- graphical_surface : a GraphicalSurface If not provided or `None`, the plot method uses the default graphical surface for the surface. """ if "graphical_surface" in options and options["graphical_surface"] is not None: gs = options["graphical_surface"] assert gs.get_surface() == self._s, "Graphical surface for the wrong surface." del options["graphical_surface"] else: gs = self._s.graphical_surface() plt = Graphics() for l,p in self.polygons(): if gs.is_visible(l): gp = gs.graphical_polygon(l) t = gp.transformation() pp = t(p) poly = polygon2d(pp.vertices(), **options) plt += poly.plot() return plt
def plot(self, **options): r""" Plot this cylinder in coordinates used by a graphical surface. This plots this cylinder as a union of subpolygons. Only the intersections with polygons visible in the graphical surface are shown. Parameters other than `graphical_surface` are passed to `polygon2d` which is called to render the polygons. Parameters ---------- graphical_surface : a GraphicalSurface If not provided or `None`, the plot method uses the default graphical surface for the surface. """ if "graphical_surface" in options and options[ "graphical_surface"] is not None: gs = options["graphical_surface"] assert gs.get_surface( ) == self._s, "Graphical surface for the wrong surface." del options["graphical_surface"] else: gs = self._s.graphical_surface() plt = Graphics() for l, p in self.polygons(): if gs.is_visible(l): gp = gs.graphical_polygon(l) t = gp.transformation() pp = t(p) poly = polygon2d(pp.vertices(), **options) plt += poly.plot() return plt
def plot_towers(self, iterations, position=(0,0), colors=None): """ Plot the towers of this interval exchange obtained from Rauzy induction. INPUT: - ``nb_iterations`` -- the number of steps of Rauzy induction - ``colors`` -- (optional) colors for the towers EXAMPLES:: sage: from surface_dynamics.all import * sage: p = iet.Permutation('A B', 'B A') sage: T = iet.IntervalExchangeTransformation(p, [0.41510826, 0.58489174]) sage: T.plot_towers(iterations=5) Graphics object consisting of 65 graphics primitives """ px,py = map(float, position) T,_,towers = self.rauzy_move(iterations=iterations,data=True) pi = T.permutation() A = pi.alphabet() lengths = map(float, T.lengths()) if colors is None: from sage.plot.colors import rainbow colors = {a:z for a,z in zip(A, rainbow(len(A)))} from sage.plot.graphics import Graphics from sage.plot.line import line2d from sage.plot.polygon import polygon2d from sage.plot.text import text G = Graphics() x = px for letter in pi[0]: y = x + lengths[A.rank(letter)] tower = towers.image(letter) h = tower.length() G += line2d([(x,py),(x,py+h)], color='black') G += line2d([(y,py),(y,py+h)], color='black') for i,a in enumerate(tower): G += line2d([(x,py+i),(y,py+i)], color='black') G += polygon2d([(x,py+i),(y,py+i),(y,py+i+1),(x,py+i+1)], color=colors[a], alpha=0.4) G += text(a, ((x+y)/2, py+i+.5), color='darkgray') G += line2d([(x,py+h),(y,py+h)], color='black', linestyle='dashed') G += text(letter, ((x+y)/2, py+h+.5), color='black', fontsize='large') x = y x = px G += line2d([(px,py-.5),(px+sum(lengths),py-.5)], color='black') for letter in pi[1]: y = x + lengths[A.rank(letter)] G += line2d([(x,py-.7),(x,py-.3)], color='black') G += text(letter, ((x+y)/2, py-.5), color='black', fontsize='large') x = y G += line2d([(x,py-.7),(x,py-.3)], color='black') return G
def plot_polygon(self, **options): r""" Returns only the filled polygon. Options are processed as in sage.plot.polygon.polygon2d except that by default axes=False. """ if not "axes" in options: options["axes"] = False return polygon2d(self._v, **options)
def plot(self, translation=None): r""" Plot the polygon with the origin at ``translation``. """ from sage.plot.point import point2d from sage.plot.line import line2d from sage.plot.polygon import polygon2d from sage.modules.free_module import VectorSpace V = VectorSpace(RR,2) P = self.vertices(translation) return point2d(P, color='red') + line2d(P + (P[0],), color='orange') + polygon2d(P, alpha=0.3)
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, **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 _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_towers(self, iterations, position=(0, 0), colors=None): """ Plot the towers of this interval exchange obtained from Rauzy induction. INPUT: - ``nb_iterations`` -- the number of steps of Rauzy induction - ``colors`` -- (optional) colors for the towers EXAMPLES:: sage: from surface_dynamics.all import * sage: p = iet.Permutation('A B', 'B A') sage: T = iet.IntervalExchangeTransformation(p, [0.41510826, 0.58489174]) sage: T.plot_towers(iterations=5) # not tested (problem with matplotlib font cache) Graphics object consisting of 65 graphics primitives """ px, py = map(float, position) T, _, towers = self.rauzy_move(iterations=iterations, data=True) pi = T.permutation() A = pi.alphabet() lengths = map(float, T.lengths()) if colors is None: from sage.plot.colors import rainbow colors = {a: z for a, z in zip(A, rainbow(len(A)))} from sage.plot.graphics import Graphics from sage.plot.line import line2d from sage.plot.polygon import polygon2d from sage.plot.text import text G = Graphics() x = px for letter in pi[0]: y = x + lengths[A.rank(letter)] tower = towers.image(letter) h = tower.length() G += line2d([(x, py), (x, py + h)], color='black') G += line2d([(y, py), (y, py + h)], color='black') for i, a in enumerate(tower): G += line2d([(x, py + i), (y, py + i)], color='black') G += polygon2d([(x, py + i), (y, py + i), (y, py + i + 1), (x, py + i + 1)], color=colors[a], alpha=0.4) G += text(a, ((x + y) / 2, py + i + .5), color='darkgray') G += line2d([(x, py + h), (y, py + h)], color='black', linestyle='dashed') G += text(letter, ((x + y) / 2, py + h + .5), color='black', fontsize='large') x = y x = px G += line2d([(px, py - .5), (px + sum(lengths), py - .5)], color='black') for letter in pi[1]: y = x + lengths[A.rank(letter)] G += line2d([(x, py - .7), (x, py - .3)], color='black') G += text(letter, ((x + y) / 2, py - .5), color='black', fontsize='large') x = y G += line2d([(x, py - .7), (x, py - .3)], color='black') return G