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_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 plot_line(self): from sage.plot.line import line2d from sage.plot.point import point p = line2d([[0,0],[1,0]]) for a in self._alpha: p += point([a,0], color='blue', size=100) for b in self._beta: p += point([b,0], color='red', size=100) p.show(axes=False, xmin=0, xmax=1, ymin=-.1, ymax=.1)
def plot_line(self): from sage.plot.line import line2d from sage.plot.point import point p = line2d([[0, 0], [1, 0]]) for a in self._alpha: p += point([a, 0], color='blue', size=100) for b in self._beta: p += point([b, 0], color='red', size=100) p.show(axes=False, xmin=0, xmax=1, ymin=-.1, ymax=.1)
def plot3d(self, depth=None): # FIXME: refactor this before publishing from sage.plot.graphics import Graphics from sage.plot.point import point from sage.misc.flatten import flatten from sage.plot.plot3d.shapes2 import sphere if self._n != 3: raise ValueError("Can only 3d 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'), (2, 'blue'), (3, 'cyan')]) G = Graphics() roots = self.d_vectors(depth=depth) 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 += _arc3d((_normalize(vector(u)), _normalize(vector(v))), thickness=0.5, color='black') for i in range(3): orbit = self.ith_orbit(i, depth=depth) for j in orbit: G += point(_normalize(vector(orbit[j])), color=colors[i], size=10, zorder=len(G.all)) if self.is_affine(): tube_vectors = map(vector, flatten(self.affine_tubes())) tube_vectors = map(_normalize, tube_vectors) for v in tube_vectors: G += point(v, color=colors[3], size=10, zorder=len(G.all)) G += _arc3d((tube_vectors[0], tube_vectors[1]), thickness=5, color='gray', zorder=0) G += sphere((0, 0, 0), opacity=0.1, zorder=0) G._extra_kwds['frame'] = False G._extra_kwds['aspect_ratio'] = 1 return G
def plot_fan_stereographically(rays, walls, northsign=1, north=vector((-1,-1,-1)), right=vector((1,0,0)), colors=None, thickness=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 colors == None: colors = dict([('walls','black'),('rays','red')]) if thickness == None: thickness = dict([('walls',0.5),('rays',20)]) G = Graphics() for (u,v) in walls: G += _stereo_arc(vector(u),vector(v),vector(u+v),north=northsign*north,right=right,color=colors['walls'],thickness=thickness['walls'],zorder=len(G)) for v in rays: G += point(_stereo_coordinates(vector(v),north=northsign*north,right=right),color=colors['rays'],zorder=len(G),size=thickness['rays']) G.set_aspect_ratio(1) G._show_axes = False return G
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 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 plot(self): from sage.functions.trig import sin, cos from sage.plot.circle import circle from sage.plot.point import point from sage.plot.text import text p = circle((0,0),1) for i in range(self._dimension): a = self._alpha[i] p += point([cos(2*pi*a),sin(2*pi*a)], color='blue', size=100) p += text(r"$\alpha_%i$"%(self._i_alpha[i]+1), [1.2*cos(2*pi*a),1.2*sin(2*pi*a)],fontsize=40) for i in range(self._dimension): b = self._beta[i] p += point([cos(2*pi*b),sin(2*pi*b)], color='red', size=100) p += text(r"$\beta_%i$"%(self._i_beta[i]+1), [1.2*cos(2*pi*b),1.2*sin(2*pi*b)],fontsize=40) p.show(axes=False, xmin=-1, xmax=1, ymin=-1, ymax=1)
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_point(0).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().KM().get_point((0,0)).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().HM().get_point((0,0,1)).show() Graphics3d Object """ p = self.coordinates() if p == infinity: raise NotImplementedError("can't draw the point infinity") opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) from sage.plot.point import point from sage.misc.functional import numerical_approx if self._bdry: # It is a boundary point p = numerical_approx(p) pic = point((p, 0), **opts) if boundary: bd_pic = self._model.get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: # It is an interior point if p in RR: p = CC(p) elif hasattr(p, 'items') or hasattr(p, '__iter__'): p = [numerical_approx(k) for k in p] else: p = numerical_approx(p) pic = point(p, **opts) if boundary: bd_pic = self.parent().get_background_graphic() pic = bd_pic + pic return pic
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_point(0).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().KM().get_point((0,0)).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().HM().get_point((0,0,1)).show() Graphics3d Object """ p = self.coordinates() if p == infinity: raise NotImplementedError("can't draw the point infinity") opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) from sage.plot.point import point from sage.misc.functional import numerical_approx if self._bdry: # It is a boundary point p = numerical_approx(p) pic = point((p, 0), **opts) if boundary: bd_pic = self._model.get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: # It is an interior point if p in RR: p = CC(p) elif hasattr(p, 'iteritems') or hasattr(p, '__iter__'): p = [numerical_approx(k) for k in p] else: p = numerical_approx(p) pic = point(p, **opts) if boundary: bd_pic = self.parent().get_background_graphic() pic = bd_pic + pic return pic
def plot_profile(self): from sage.plot.line import line2d from sage.plot.point import point from sage.plot.text import text p_color, p_number, p_ev = self.profile() d = len(p_color) color = lambda i: 'blue' if p_color[i] else 'red' p = lambda i: [0,0] if i == -1 else [i+1,p_number[i]] plt = point([0,0],marker='x',size=100) for i in range(d): plt += line2d([p(i-1),p(i)],alpha=.5) plt += point(p(i), color=color(i), size=100) if p_color[i]: [x,y] = p(i) plt += text(r"$\alpha_%i$"%(self._i_alpha[p_ev[i]]+1), [x,y+.2], fontsize = 40) else: [x,y] = p(i) plt += text(r"$\beta_%i$"%(self._i_beta[p_ev[i]]+1), [x,y+.2], fontsize = 40) plt.show(axes=False, ymin=0, xmin=0, xmax=d)
def plot3d(self,depth=None): # FIXME: refactor this before publishing from sage.plot.graphics import Graphics from sage.plot.point import point from sage.misc.flatten import flatten from sage.plot.plot3d.shapes2 import sphere if self._n !=3: raise ValueError("Can only 3d 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'),(2,'blue'),(3,'cyan')]) G = Graphics() roots = self.d_vectors(depth=depth) 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 += _arc3d((_normalize(vector(u)),_normalize(vector(v))),thickness=0.5,color='black') for i in range(3): orbit = self.ith_orbit(i,depth=depth) for j in orbit: G += point(_normalize(vector(orbit[j])),color=colors[i],size=10,zorder=len(G.all)) if self.is_affine(): tube_vectors=map(vector,flatten(self.affine_tubes())) tube_vectors=map(_normalize,tube_vectors) for v in tube_vectors: G += point(v,color=colors[3],size=10,zorder=len(G.all)) G += _arc3d((tube_vectors[0],tube_vectors[1]),thickness=5,color='gray',zorder=0) G += sphere((0,0,0),opacity=0.1,zorder=0) G._extra_kwds['frame']=False G._extra_kwds['aspect_ratio']=1 return G
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().UHP().get_point(I).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().UHP().get_point(0).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().UHP().get_point(infinity).show() Traceback (most recent call last): ... NotImplementedError: can't draw the point infinity """ p = self.coordinates() if p == infinity: raise NotImplementedError("can't draw the point infinity") opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) from sage.misc.functional import numerical_approx p = numerical_approx(p + 0 * I) from sage.plot.point import point if self._bdry: pic = point((p, 0), **opts) if boundary: bd_pic = self.parent().get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: pic = point(p, **opts) if boundary: cent = real(p) bd_pic = self.parent().get_background_graphic(bd_min=cent - 1, bd_max=cent + 1) pic = bd_pic + pic return pic
def plot_profile(self): from sage.plot.line import line2d from sage.plot.point import point from sage.plot.text import text p_color, p_number, p_ev = self.profile() d = len(p_color) color = lambda i: 'blue' if p_color[i] else 'red' p = lambda i: [0, 0] if i == -1 else [i + 1, p_number[i]] plt = point([0, 0], marker='x', size=100) for i in range(d): plt += line2d([p(i - 1), p(i)], alpha=.5) plt += point(p(i), color=color(i), size=100) if p_color[i]: [x, y] = p(i) plt += text(r"$\alpha_%i$" % (self._i_alpha[p_ev[i]] + 1), [x, y + .2], fontsize=40) else: [x, y] = p(i) plt += text(r"$\beta_%i$" % (self._i_beta[p_ev[i]] + 1), [x, y + .2], fontsize=40) plt.show(axes=False, ymin=0, xmin=0, xmax=d)
def plot(self): from sage.functions.trig import sin, cos from sage.plot.circle import circle from sage.plot.point import point from sage.plot.text import text p = circle((0, 0), 1) for i in range(self._dimension): a = self._alpha[i] p += point([cos(2 * pi * a), sin(2 * pi * a)], color='blue', size=100) p += text(r"$\alpha_%i$" % (self._i_alpha[i] + 1), [1.2 * cos(2 * pi * a), 1.2 * sin(2 * pi * a)], fontsize=40) for i in range(self._dimension): b = self._beta[i] p += point([cos(2 * pi * b), sin(2 * pi * b)], color='red', size=100) p += text(r"$\beta_%i$" % (self._i_beta[i] + 1), [1.2 * cos(2 * pi * b), 1.2 * sin(2 * pi * b)], fontsize=40) p.show(axes=False, xmin=-1, xmax=1, ymin=-1, ymax=1)
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 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 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_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_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic(): raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [ 0, 1, 2 ]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d / x, 0), size=pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d / x, label_offset), color=label_color, fontsize=label_fontsize) p += text('', (d / x, label_offset + 0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() t = SR.var('t') if ranges_set: if isinstance(ranges, (list, tuple)): t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt + t * w[0], (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label, (pnt[0] + b0, pnt[1] + b1), color=label_color, fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() s, t = SR.var('s t') if ranges_set: if isinstance(ranges, (list, tuple)): s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt + s * w[0] + t * w[1], (s, s0, s1), (t, t0, t1), **kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label, (pnt[0] + b0, pnt[1] + b1, pnt[2] + b2), color=label_color, fontsize=label_fontsize) p += label return p
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_hyperplane(hyperplane, **kwds): r""" Return the plot of a single hyperplane. INPUT: - ``**kwds`` -- plot options: see below OUTPUT: A graphics object of the plot. .. RUBRIC:: Plot Options Beside the usual plot options (enter ``plot?``), the plot command for hyperplanes includes the following: - ``hyperplane_label`` -- Boolean value or string (default: ``True``). If ``True``, the hyperplane is labeled with its equation, if a string, it is labeled by that string, otherwise it is not labeled. - ``label_color`` -- (Default: ``'black'``) Color for hyperplane_label. - ``label_fontsize`` -- Size for ``hyperplane_label`` font (default: 14) (does not work in 3d, yet). - ``label_offset`` -- (Default: 0-dim: 0.1, 1-dim: (0,1), 2-dim: (0,0,0.2)) Amount by which label is offset from ``hyperplane.point()``. - ``point_size`` -- (Default: 50) Size of points in a zero-dimensional arrangement or of an arrangement over a finite field. - ``ranges`` -- Range for the parameters for the parametric plot of the hyperplane. If a single positive number ``r`` is given for the value of ``ranges``, then the ranges for all parameters are set to `[-r, r]`. Otherwise, for a line in the plane, ``ranges`` has the form ``[a, b]`` (default: [-3,3]), and for a plane in 3-space, the ``ranges`` has the form ``[[a, b], [c, d]]`` (default: [[-3,3],[-3,3]]). (The ranges are centered around ``hyperplane.point()``.) EXAMPLES:: sage: H1.<x> = HyperplaneArrangements(QQ) sage: a = 3*x + 4 sage: a.plot() # indirect doctest Graphics object consisting of 3 graphics primitives sage: a.plot(point_size=100,hyperplane_label='hello') Graphics object consisting of 3 graphics primitives sage: H2.<x,y> = HyperplaneArrangements(QQ) sage: b = 3*x + 4*y + 5 sage: b.plot() Graphics object consisting of 2 graphics primitives sage: b.plot(ranges=(1,5),label_offset=(2,-1)) Graphics object consisting of 2 graphics primitives sage: opts = {'hyperplane_label':True, 'label_color':'green', ....: 'label_fontsize':24, 'label_offset':(0,1.5)} sage: b.plot(**opts) Graphics object consisting of 2 graphics primitives sage: H3.<x,y,z> = HyperplaneArrangements(QQ) sage: c = 2*x + 3*y + 4*z + 5 sage: c.plot() Graphics3d Object sage: c.plot(label_offset=(1,0,1), color='green', label_color='red', frame=False) Graphics3d Object sage: d = -3*x + 2*y + 2*z + 3 sage: d.plot(opacity=0.8) Graphics3d Object sage: e = 4*x + 2*z + 3 sage: e.plot(ranges=[[-1,1],[0,8]], label_offset=(2,2,1), aspect_ratio=1) Graphics3d Object """ if hyperplane.base_ring().characteristic() != 0: raise NotImplementedError('base field must have characteristic zero') elif hyperplane.dimension() not in [0, 1, 2]: # dimension of hyperplane, not ambient space raise ValueError('can only plot hyperplanes in dimensions 1, 2, 3') # handle extra keywords if 'hyperplane_label' in kwds: hyp_label = kwds.pop('hyperplane_label') if not hyp_label: has_hyp_label = False else: has_hyp_label = True else: # default hyp_label = True has_hyp_label = True if has_hyp_label: if hyp_label: # then label hyperplane with its equation if hyperplane.dimension() == 2: # jmol does not like latex label = hyperplane._repr_linear(include_zero=False) else: label = hyperplane._latex_() else: label = hyp_label # a string if 'label_color' in kwds: label_color = kwds.pop('label_color') else: label_color = 'black' if 'label_fontsize' in kwds: label_fontsize = kwds.pop('label_fontsize') else: label_fontsize = 14 if 'label_offset' in kwds: has_offset = True label_offset = kwds.pop('label_offset') else: has_offset = False # give default values below if 'point_size' in kwds: pt_size = kwds.pop('point_size') else: pt_size = 50 if 'ranges' in kwds: ranges_set = True ranges = kwds.pop('ranges') else: ranges_set = False # give default values below # the extra keywords have now been handled # now create the plot if hyperplane.dimension() == 0: # a point on a line x, = hyperplane.A() d = hyperplane.b() p = point((d/x,0), size = pt_size, **kwds) if has_hyp_label: if not has_offset: label_offset = 0.1 p += text(label, (d/x,label_offset), color=label_color,fontsize=label_fontsize) p += text('',(d/x,label_offset+0.4)) # add space at top if 'ymax' not in kwds: kwds['ymax'] = 0.5 elif hyperplane.dimension() == 1: # a line in the plane pnt = hyperplane.point() w = hyperplane.linear_part().matrix() x, y = hyperplane.A() d = hyperplane.b() t = SR.var('t') if ranges_set: if type(ranges) in [list,tuple]: t0, t1 = ranges else: # ranges should be a single positive number t0, t1 = -ranges, ranges else: # default t0, t1 = -3, 3 p = parametric_plot(pnt+t*w[0], (t,t0,t1), **kwds) if has_hyp_label: if has_offset: b0, b1 = label_offset else: b0, b1 = 0, 0.2 label = text(label,(pnt[0]+b0,pnt[1]+b1), color=label_color,fontsize=label_fontsize) p += label elif hyperplane.dimension() == 2: # a plane in 3-space pnt = hyperplane.point() w = hyperplane.linear_part().matrix() a, b, c = hyperplane.A() d = hyperplane.b() s,t = SR.var('s t') if ranges_set: if type(ranges) in [list,tuple]: s0, s1 = ranges[0] t0, t1 = ranges[1] else: # ranges should be a single positive integers s0, s1 = -ranges, ranges t0, t1 = -ranges, ranges else: # default s0, s1 = -3, 3 t0, t1 = -3, 3 p = parametric_plot3d(pnt+s*w[0]+t*w[1],(s,s0,s1),(t,t0,t1),**kwds) if has_hyp_label: if has_offset: b0, b1, b2 = label_offset else: b0, b1, b2 = 0, 0, 0 label = text3d(label,(pnt[0]+b0,pnt[1]+b1,pnt[2]+b2), color=label_color,fontsize=label_fontsize) p += label return p
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
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 example_plot(cls, sample, **kwargs): r""" Returns a sage figure containing a colored scatter plot of the labeled sample passed as argument. Each pattern is represented through a bullet, colored according to the corresponding label. The function forwards to ``scatter`` named parameters with the exception of ``color_function``. ``plotter.example_plot(sample, ...)`` INPUT: - ``sample`` -- a sequence of ``Example`` objects. The following optional inputs can be specified through named arguments: - ``color_function`` -- function (default: function associating the color ``'black'`` whenever an example label is ``1``, ``'gray'`` otherwise); function having as input a generic ``Example`` object and as value the corresponding colour. - ``size_function`` -- function (default: function associating the value ``20`` independently of its argument); function having as input a generic ``Example`` object and as value the corresponding bullet size, expressed in pts^2. - ``alpha_function``-- function (default: function associating the value 1 independently of its argument, which means no transparency) function having as input a generic ``Example``object and as value the corresponding opacity. OUTPUT: figure -- a graph containing the example plot. EXAMPLES: Simple plot of the XOR binary function: :: >>> from yaplf.data import LabeledExample >>> xor_sample = (LabeledExample((0., 0.), 0.), ... LabeledExample((1., 0.), 1.), LabeledExample((0., 1.), 1.), ... LabeledExample((1., 1.), 0.)) >>> from yaplf.graph import SagePlotter >>> SagePlotter.example_plot(xor_sample) The same graph using a more sophisticated style, assigning green opaque bullets to examples having label set to ``1`` and yellow transparent bullets to the remaining examples, the bullet size being chosen according to its relative position w.r.t. `(\frac{1}{2}, \frac{1}{2})`: :: >>> cf = lambda x: ('green' if x.label == 1 else 'yellow') >>> sf = lambda x: (90 if x.pattern < (.5, .5) else 20) >>> af = lambda x: (.4 if x.label == 1 else .8) >>> SagePlotter.example_plot(xor_sample, color_function = cf, \ ... size_function = sf, alpha_function = af) A 3D sample plot: :: >>> patterns = ((0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), \ ... (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)) >>> parity = lambda x: sum(x) % 2 >>> parity_sample = [LabeledExample(e, parity(e)) \ ... for e in patterns] >>> sf = lambda x: (20 if x.pattern[1] == 1 else 40) >>> af = lambda x: (.2 if x.pattern[0] == 1 else 1) >>> SagePlotter.example_plot(parity_sample, color_function = cf, \ ... alpha_function = af, size_function = sf) AUTHORS: - Dario Malchiodi (2010-02-22) """ if len(sample[0].pattern) == 2: size_name = 'pointsize' alpha_name = 'alpha' elif len(sample[0].pattern) == 3: size_name = 'size' alpha_name = 'opacity' else: raise ValueError( 'data plots only generated for 2D and 3D patterns.') try: color_function = kwargs['color_function'] del kwargs['color_function'] except KeyError: color_function = lambda e: ('black' if e.label == 1 else 'gray') try: size_function = kwargs['size_function'] del kwargs['size_function'] except KeyError: size_function = lambda e: 20 try: alpha_function = kwargs['alpha_function'] del kwargs['alpha_function'] except KeyError: alpha_function = lambda e: 1 def style_function(example): """Style function to be applied to points in scatter plot""" style = {size_name: size_function(example), alpha_name: alpha_function(example), 'color': color_function(example)} return style points = [] for elem in sample: kwargs.update(style_function(elem)) points.append(point(elem.pattern, **kwargs)) return sum(points)