def __init__(self, v, t, dual=False, color=None): r""" EXAMPLES:: sage: from EkEkstar import kFace sage: F = kFace((0,0,0),(1,2)) sage: F [(0, 0, 0), (1, 2)] """ self._vector = (ZZ**len(v))(v) self._vector.set_immutable() self._dual = dual if t in ZZ: self._type = (t, ) else: self._type = t if not all((tt in ZZ and 1 <= tt <= len(v)) for tt in self._type): raise ValueError( 'The type must be a tuple of integers between 1 and {}'.format( len(v))) if color is not None: self._color = Color(color) else: sorted_types = list( combinations(range(1, len(v) + 1), len(self._type))) Col = rainbow(len(sorted_types)) D = dict(zip(sorted_types, Col)) self._color = Color(D.get(self.sorted_type(), 'black'))
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 plotclusters(clusters, centroids): k = len(clusters) colors = rainbow(k) plot = sum([ list_plot(clusters[i], color=colors[i], size=20, aspect_ratio=1) for i in range(k) ]) return plot + list_plot(centroids, color='black', size=50)
def plot3d(self, color='rainbow'): """ Plots the braid in 3d. The following option is available: - ``color`` -- (default: ``'rainbow'``) the color of the strands. Possible values are: * ``'rainbow'``, uses :meth:`~sage.plot.colors.rainbow` according to the number of strands. * a valid color name for :meth:`~sage.plot.plot3d.bezier3d`. Used for all strands. * a list or a tuple of colors for each individual strand. EXAMPLES:: sage: B = BraidGroup(4, 's') sage: b = B([1, 2, 3, 1, 2, 1]) sage: b.plot3d() sage: b.plot3d(color="red") sage: b.plot3d(color=["red", "blue", "red", "blue"]) """ from sage.plot.plot3d.shapes2 import bezier3d from sage.plot.colors import rainbow b = [] n = self.strands() if isinstance(color, (list, tuple)): if len(color) != n: raise TypeError("color (=%s) must contain exactly %d colors" % (color, n)) col = list(color) elif color == "rainbow": col = rainbow(n) else: col = [color]*n braid = self.Tietze() for i, m in enumerate(braid): for j in range(n): if m==j+1: b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (0.25, j, i+0.25), (0.25, j+0.5, i+0.5)], [(0.25, j+1, i+0.75), (0, j+1, i+0.75), (0, j+1, i+1)]], color=col[j])) elif -m==j+1: b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (-0.25, j, i+0.25), (-0.25, j+0.5, i+0.5)], [(-0.25, j+1, i+0.75), (0, j+1, i+0.75), (0, j+1, i+1)]], color=col[j])) elif m==j: b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (-0.25, j, i+0.25), (-0.25, j-0.5, i+0.5)], [(-0.25, j-1, i+0.75), (0, j-1, i+0.75), (0, j-1, i+1)]], color=col[j])) col[j], col[j-1] = col[j-1], col[j] elif -m==j: b.append(bezier3d([[(0, j, i), (0, j, i+0.25), (0.25, j, i+0.25), (0.25, j-0.5, i+0.5)], [(0.25, j-1, i+0.75), (0, j-1, i+0.75), (0, j-1, i+1)]], color=col[j])) col[j], col[j-1] = col[j-1], col[j] else: b.append(bezier3d([[(0, j, i), (0, j, i+1)]], color=col[j])) return sum(b)
def __init__(self, E, ls, special=False): self._ls = ls j = E.j_invariant() self.field = E.base_field() self._graph = Graph(multiedges=True, loops=True) self._special = False self._graph.add_vertex(j) queue = [j] R = rainbow(len(ls) + 1) self._rainbow = R self._edge_colors = {R[i]: [] for i in range(len(ls))} while queue: color = 0 s = queue.pop(0) if s == 0 or s == 1728: self._special = True for l in ls: neighb = isogenous_curves(s, l) for i in neighb: if not self._graph.has_vertex(i[0]): queue.append(i[0]) self._graph.add_vertex(i[0]) if not ((s, i[0], l) in self._edge_colors[R[color]] or (i[0], s, l) in self._edge_colors[R[color]]): for _ in range(i[1]): self._graph.add_edge((s, i[0], l)) self._edge_colors[R[color]].append((s, i[0], l)) color += 1 if self._special and special: print("Curve with j_invariant 0 or 1728 found, may malfunction.")
def plot(self, color='rainbow', orientation='bottom-top', gap=0.05, aspect_ratio=1, axes=False, **kwds): """ Plot the braid The following options are available: - ``color`` -- (default: ``'rainbow'``) the color of the strands. Possible values are: * ``'rainbow'``, uses :meth:`~sage.plot.colors.rainbow` according to the number of strands. * a valid color name for :meth:`~sage.plot.bezier_path` and :meth:`~sage.plot.line`. Used for all strands. * a list or a tuple of colors for each individual strand. - ``orientation`` -- (default: ``'bottom-top'``) determines how the braid is printed. The possible values are: * ``'bottom-top'``, the braid is printed from bottom to top * ``'top-bottom'``, the braid is printed from top to bottom * ``'left-right'``, the braid is printed from left to right - ``gap`` -- floating point number (default: 0.05). determines the size of the gap left when a strand goes under another. - ``aspect_ratio`` -- floating point number (default: ``1``). The aspect ratio. - ``**kwds`` -- other keyword options that are passed to :meth:`~sage.plot.bezier_path` and :meth:`~sage.plot.line`. EXAMPLES:: sage: B = BraidGroup(4, 's') sage: b = B([1, 2, 3, 1, 2, 1]) sage: b.plot() sage: b.plot(color=["red", "blue", "red", "blue"]) sage: B.<s,t> = BraidGroup(3) sage: b = t^-1*s^2 sage: b.plot(orientation="left-right", color="red") """ from sage.plot.bezier_path import bezier_path from sage.plot.plot import Graphics, line from sage.plot.colors import rainbow if orientation=='top-bottom': orx = 0 ory = -1 nx = 1 ny = 0 elif orientation=='left-right': orx = 1 ory = 0 nx = 0 ny = -1 elif orientation=='bottom-top': orx = 0 ory = 1 nx = 1 ny = 0 else: raise ValueError('unknown value for "orientation"') n = self.strands() if isinstance(color, (list, tuple)): if len(color) != n: raise TypeError("color (=%s) must contain exactly %d colors" % (color, n)) col = list(color) elif color == "rainbow": col = rainbow(n) else: col = [color]*n braid = self.Tietze() a = Graphics() op = gap for i, m in enumerate(braid): for j in range(n): if m==j+1: a += bezier_path([[(j*nx+i*orx, i*ory+j*ny), (j*nx+orx*(i+0.25), j*ny+ory*(i+0.25)), (nx*(j+0.5)+orx*(i+0.5), ny*(j+0.5)+ory*(i+0.5))], [(nx*(j+1)+orx*(i+0.75), ny*(j+1)+ory*(i+0.75)), (nx*(j+1)+orx*(i+1), ny*(j+1)+ory*(i+1))]], color=col[j], **kwds) elif m==j: a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), (nx*(j-0.5+4*op)+orx*(i+0.5-2*op), ny*(j-0.5+4*op)+ory*(i+0.5-2*op)), (nx*(j-0.5+2*op)+orx*(i+0.5-op), ny*(j-0.5+2*op)+ory*(i+0.5-op))]], color=col[j], **kwds) a += bezier_path([[(nx*(j-0.5-2*op)+orx*(i+0.5+op), ny*(j-0.5-2*op)+ory*(i+0.5+op)), (nx*(j-0.5-4*op)+orx*(i+0.5+2*op), ny*(j-0.5-4*op)+ory*(i+0.5+2*op)), (nx*(j-1)+orx*(i+0.75), ny*(j-1)+ory*(i+0.75)), (nx*(j-1)+orx*(i+1), ny*(j-1)+ory*(i+1))]], color=col[j], **kwds) col[j], col[j-1] = col[j-1], col[j] elif -m==j+1: a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), (nx*(j+0.5-4*op)+orx*(i+0.5-2*op), ny*(j+0.5-4*op)+ory*(i+0.5-2*op)), (nx*(j+0.5-2*op)+orx*(i+0.5-op), ny*(j+0.5-2*op)+ory*(i+0.5-op))]], color=col[j], **kwds) a += bezier_path([[(nx*(j+0.5+2*op)+orx*(i+0.5+op), ny*(j+0.5+2*op)+ory*(i+0.5+op)), (nx*(j+0.5+4*op)+orx*(i+0.5+2*op), ny*(j+0.5+4*op)+ory*(i+0.5+2*op)), (nx*(j+1)+orx*(i+0.75), ny*(j+1)+ory*(i+0.75)), (nx*(j+1)+orx*(i+1), ny*(j+1)+ory*(i+1))]], color=col[j], **kwds) elif -m==j: a += bezier_path([[(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+0.25), ny*j+ory*(i+0.25)), (nx*(j-0.5)+orx*(i+0.5), ny*(j-0.5)+ory*(i+0.5))], [(nx*(j-1)+orx*(i+0.75), ny*(j-1)+ory*(i+0.75)), (nx*(j-1)+orx*(i+1), ny*(j-1)+ory*(i+1))]], color=col[j], **kwds) col[j], col[j-1] = col[j-1], col[j] else: a += line([(nx*j+orx*i, ny*j+ory*i), (nx*j+orx*(i+1), ny*j+ory*(i+1))], color=col[j], **kwds) a.set_aspect_ratio(aspect_ratio) a.axes(axes) return a
def plot_two_intervals(self, position=(0,0), vertical_alignment='center', horizontal_alignment='left', interval_height=0.1, labels_height=0.05, fontsize=14, labels=True, colors=None): r""" Returns a picture of the interval exchange transformation. INPUT: - ``position`` - a 2-uple of the position - ``horizontal_alignment`` - left (defaut), center or right - ``labels`` - boolean (defaut: True) - ``fontsize`` - the size of the label OUTPUT: 2d plot -- a plot of the two intervals (domain and range) EXAMPLES:: sage: t = iet.IntervalExchangeTransformation(('a b','b a'),[1,1]) sage: t.plot_two_intervals() """ from sage.plot.all import Graphics from sage.plot.plot import line2d from sage.plot.plot import text from sage.plot.colors import rainbow G = Graphics() lengths = map(float,self._lengths) total_length = sum(lengths) if colors is None: colors = rainbow(len(self._permutation), 'rgbtuple') if horizontal_alignment == 'left': s = position[0] elif horizontal_alignment == 'center': s = position[0] - total_length / 2 elif horizontal_alignment == 'right': s = position[0] - total_length else: raise ValueError("horizontal_alignement must be left, center or right") top_height = position[1] + interval_height for i in self._permutation._intervals[0]: G += line2d([(s,top_height), (s+lengths[i],top_height)], rgbcolor=colors[i]) if labels: G += text(str(self._permutation._alphabet.unrank(i)), (s+float(lengths[i])/2, top_height+labels_height), horizontal_alignment='center', rgbcolor=colors[i], fontsize=fontsize) s += lengths[i] if horizontal_alignment == 'left': s = position[0] elif horizontal_alignment == 'center': s = position[0] - total_length / 2 elif horizontal_alignment == 'right': s = position[0] - total_length else: raise ValueError("horizontal_alignement must be left, center or right") bottom_height = position[1] - interval_height for i in self._permutation._intervals[1]: G += line2d([(s,bottom_height), (s+lengths[i],bottom_height)], rgbcolor=colors[i]) if labels: G += text(str(self._permutation._alphabet.unrank(i)), (s+float(lengths[i])/2, bottom_height-labels_height), horizontal_alignment='center', rgbcolor=colors[i], fontsize=fontsize) s += lengths[i] return G
def gen_html_code(G, vertex_labels=False, edge_labels=False, vertex_partition=[], edge_partition=[], force_spring_layout=False, charge=-120, link_distance=30, link_strength=2, gravity=.04, vertex_size=7, edge_thickness=4): r""" Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_. This function returns the name of the .html file. If you want to visualize the actual graph use :meth:`~sage.graphs.generic_graph.GenericGraph.show`. INPUT: - ``G`` -- the graph - ``vertex_labels`` (boolean) -- Whether to display vertex labels (set to ``False`` by default). - ``edge_labels`` (boolean) -- Whether to display edge labels (set to ``False`` by default). - ``vertex_partition`` -- a list of lists representing a partition of the vertex set. Vertices are then colored in the graph according to the partition. Set to ``[]`` by default. - ``edge_partition`` -- same as ``vertex_partition``, with edges instead. Set to ``[]`` by default. - ``force_spring_layout`` -- whether to take sage's position into account if there is one (see :meth:`~sage.graphs.generic_graph.GenericGraph.` and :meth:`~sage.graphs.generic_graph.GenericGraph.`), or to compute a spring layout. Set to ``False`` by default. - ``vertex_size`` -- The size of a vertex' circle. Set to `7` by default. - ``edge_thickness`` -- Thickness of an edge. Set to ``4`` by default. - ``charge`` -- the vertices' charge. Defines how they repulse each other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``-120`` by default. - ``link_distance`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``30`` by default. - ``link_strength`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``2`` by default. - ``gravity`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``0.04`` by default. EXAMPLES:: sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage: g = graphs.PetersenGraph() sage: g.show(method = "js", vertex_partition=g.coloring()) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage: g = digraphs.DeBruijn(2,2) sage: g.allow_multiple_edges(True) sage: g.add_edge("10","10","a") sage: g.add_edge("10","10","b") sage: g.add_edge("10","10","c") sage: g.add_edge("10","10","d") sage: g.add_edge("01","11","1") sage: g.show(method="js", vertex_labels=True,edge_labels=True, ....: link_distance=200,gravity=.05,charge=-500, ....: edge_partition=[[("11","12","2"),("21","21","a")]], ....: edge_thickness=4) # optional -- internet TESTS:: sage: from sage.graphs.graph_plot_js import gen_html_code sage: filename = gen_html_code(graphs.PetersenGraph()) """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G.vertices())} # Vertex colors color = {i: len(vertex_partition) for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list nodes = [] for v in G.vertices(): nodes.append({"name": str(v), "group": str(color[v_to_id[v]])}) # Edge colors. edge_color_default = "#aaa" color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e+(None,) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edges(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0)+1 curve = seen[u, v]*10+10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0)+1 curve = seen[u, v]*15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1)*(seen[u, v]//2)*15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1)*(seen[u, v]//2)*15 # Adding the edge to the list edges.append({"source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else ""}) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible Gpos = G.get_pos() pos = [] if Gpos is not None and force_spring_layout is False: charge = 0 link_strength = 0 gravity = 0 for v in G.vertices(): x, y = Gpos[v] pos.append([x, -y]) # Encodes the data as a JSON string from json import JSONEncoder string = JSONEncoder().encode({"nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness)}) from sage.env import SAGE_EXTCODE js_code_file = open(SAGE_EXTCODE+"/graphs/graph_plot_js.html", 'r') js_code = js_code_file.read().replace("// HEREEEEEEEEEEE", string) js_code_file.close() # Writes the temporary .html file filename = tmp_filename(ext='.html') f = open(filename, 'w') f.write(js_code) f.close() return filename
from sage.plot.colors import rainbow C = graphs.CubeGraph(5) R = rainbow(5) edge_colors = {} for i in range(5): edge_colors[R[i]] = [] for u, v, l in C.edges(): for i in range(5): if u[i] != v[i]: edge_colors[R[i]].append((u, v, l)) sphinx_plot( C.graphplot(vertex_labels=False, vertex_size=0, edge_colors=edge_colors))
def plot_two_intervals(self, position=(0,0), vertical_alignment='center', horizontal_alignment='left', interval_height=0.1, labels_height=0.05, fontsize=14, labels=True, colors=None): r""" Returns a picture of the interval exchange transformation. INPUT: - ``position`` - a 2-uple of the position - ``horizontal_alignment`` - left (default), center or right - ``labels`` - boolean (default: True) - ``fontsize`` - the size of the label OUTPUT: 2d plot -- a plot of the two intervals (domain and range) EXAMPLES:: sage: t = iet.IntervalExchangeTransformation(('a b','b a'),[1,1]) sage: t.plot_two_intervals() Graphics object consisting of 8 graphics primitives """ from sage.plot.all import Graphics from sage.plot.plot import line2d from sage.plot.plot import text from sage.plot.colors import rainbow G = Graphics() lengths = [float(_) for _ in self._lengths] total_length = sum(lengths) if colors is None: colors = rainbow(len(self._permutation), 'rgbtuple') if horizontal_alignment == 'left': s = position[0] elif horizontal_alignment == 'center': s = position[0] - total_length / 2 elif horizontal_alignment == 'right': s = position[0] - total_length else: raise ValueError("horizontal_alignement must be left, center or right") top_height = position[1] + interval_height for i in self._permutation._intervals[0]: G += line2d([(s,top_height), (s+lengths[i],top_height)], rgbcolor=colors[i]) if labels: G += text(str(self._permutation._alphabet.unrank(i)), (s+float(lengths[i])/2, top_height+labels_height), horizontal_alignment='center', rgbcolor=colors[i], fontsize=fontsize) s += lengths[i] if horizontal_alignment == 'left': s = position[0] elif horizontal_alignment == 'center': s = position[0] - total_length / 2 elif horizontal_alignment == 'right': s = position[0] - total_length else: raise ValueError("horizontal_alignement must be left, center or right") bottom_height = position[1] - interval_height for i in self._permutation._intervals[1]: G += line2d([(s,bottom_height), (s+lengths[i],bottom_height)], rgbcolor=colors[i]) if labels: G += text(str(self._permutation._alphabet.unrank(i)), (s+float(lengths[i])/2, bottom_height-labels_height), horizontal_alignment='center', rgbcolor=colors[i], fontsize=fontsize) s += lengths[i] return G
def set_vertices(self, **vertex_options): """ Sets the vertex plotting parameters for this GraphPlot. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'), ... (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')]) sage: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_vertices(talk=True) sage: GP.plot() sage: GP.set_vertices(vertex_colors='pink', vertex_shape='^') sage: GP.plot() """ # Handle base vertex options voptions = {} for arg in vertex_options: self._options[arg] = vertex_options[arg] # First set defaults for styles vertex_colors = None if self._options['talk']: voptions['markersize'] = 500 if self._options['partition'] is None: vertex_colors = '#ffffff' else: voptions['markersize'] = self._options['vertex_size'] if 'vertex_colors' not in self._options: if self._options['partition'] is not None: from sage.plot.colors import rainbow, rgbcolor partition = self._options['partition'] l = len(partition) R = rainbow(l) vertex_colors = {} for i in range(l): vertex_colors[R[i]] = partition[i] elif len(self._graph._boundary) != 0: vertex_colors = {} bdy_verts = [] int_verts = [] for v in self._graph.vertex_iterator(): if v in self._graph._boundary: bdy_verts.append(v) else: int_verts.append(v) vertex_colors['#fec7b8'] = int_verts vertex_colors['#b3e8ff'] = bdy_verts elif not vertex_colors: vertex_colors = '#fec7b8' else: vertex_colors = self._options['vertex_colors'] if 'vertex_shape' in self._options: voptions['marker'] = self._options['vertex_shape'] if self._graph.is_directed(): self._vertex_radius = sqrt(voptions['markersize'] / pi) self._arrowshorten = 2 * self._vertex_radius if self._arcdigraph: self._vertex_radius = sqrt(voptions['markersize'] / (20500 * pi)) voptions['zorder'] = 7 if not isinstance(vertex_colors, dict): voptions['facecolor'] = vertex_colors if self._arcdigraph: self._plot_components['vertices'] = [ circle(center, self._vertex_radius, fill=True, facecolor=vertex_colors, clip=False) for center in self._pos.values() ] else: self._plot_components['vertices'] = scatter_plot( self._pos.values(), clip=False, **voptions) else: # Color list must be ordered: pos = [] colors = [] for i in vertex_colors: pos += [self._pos[j] for j in vertex_colors[i]] colors += [i] * len(vertex_colors[i]) # If all the vertices have not been assigned a color if len(self._pos) != len(pos): from sage.plot.colors import rainbow, rgbcolor vertex_colors_rgb = [rgbcolor(c) for c in vertex_colors] for c in rainbow(len(vertex_colors) + 1): if rgbcolor(c) not in vertex_colors_rgb: break leftovers = [j for j in self._pos.values() if j not in pos] pos += leftovers colors += [c] * len(leftovers) if self._arcdigraph: self._plot_components['vertices'] = [ circle(pos[i], self._vertex_radius, fill=True, facecolor=colors[i], clip=False) for i in range(len(pos)) ] else: self._plot_components['vertices'] = scatter_plot( pos, facecolor=colors, clip=False, **voptions) if self._options['vertex_labels']: self._plot_components['vertex_labels'] = [] # TODO: allow text options for v in self._nodelist: self._plot_components['vertex_labels'].append( text(str(v), self._pos[v], rgbcolor=(0, 0, 0), zorder=8))
def graph_to_d3_jsonable(G, vertex_labels=True, edge_labels=False, vertex_partition=[], edge_partition=[], force_spring_layout=False, charge=-120, link_distance=50, link_strength=1, gravity=.04, vertex_size=7, edge_thickness=2, width=None, height=None, **ignored): r""" Display a graph in CoCalc using the D3 visualization library. INPUT: - ``G`` -- the graph - ``vertex_labels`` (boolean) -- Whether to display vertex labels (set to ``True`` by default). - ``edge_labels`` (boolean) -- Whether to display edge labels (set to ``False`` by default). - ``vertex_partition`` -- a list of lists representing a partition of the vertex set. Vertices are then colored in the graph according to the partition. Set to ``[]`` by default. - ``edge_partition`` -- same as ``vertex_partition``, with edges instead. Set to ``[]`` by default. - ``force_spring_layout`` -- whether to take sage's position into account if there is one (see :meth:`~sage.graphs.generic_graph.GenericGraph.` and :meth:`~sage.graphs.generic_graph.GenericGraph.`), or to compute a spring layout. Set to ``False`` by default. - ``vertex_size`` -- The size of a vertex' circle. Set to `7` by default. - ``edge_thickness`` -- Thickness of an edge. Set to ``2`` by default. - ``charge`` -- the vertices' charge. Defines how they repulse each other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``-120`` by default. - ``link_distance`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``30`` by default. - ``link_strength`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``1.5`` by default. - ``gravity`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``0.04`` by default. EXAMPLES:: show(graphs.RandomTree(50), d3=True) show(graphs.PetersenGraph(), d3=True, vertex_partition=g.coloring()) show(graphs.DodecahedralGraph(), d3=True, force_spring_layout=True) show(graphs.DodecahedralGraph(), d3=True) g = digraphs.DeBruijn(2,2) g.allow_multiple_edges(True) g.add_edge("10","10","a") g.add_edge("10","10","b") g.add_edge("10","10","c") g.add_edge("10","10","d") g.add_edge("01","11","1") show(g, d3=True, vertex_labels=True,edge_labels=True, link_distance=200,gravity=.05,charge=-500, edge_partition=[[("11","12","2"),("21","21","a")]], edge_thickness=4) """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G.vertices())} # Vertex colors color = {i: len(vertex_partition) for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list nodes = [] for v in G.vertices(): nodes.append({"name": str(v), "group": str(color[v_to_id[v]])}) # Edge colors. edge_color_default = "#aaa" from sage.plot.colors import rainbow color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e + (None, ) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edges(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 10 + 10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list edges.append({ "source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else "" }) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible Gpos = G.get_pos() pos = [] if Gpos is not None and force_spring_layout is False: charge = 0 link_strength = 0 gravity = 0 for v in G.vertices(): x, y = Gpos[v] pos.append([json_float(x), json_float(-y)]) return { "nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness), "width": json_float(width), "height": json_float(height) }
def gen_html_code(G, vertex_labels=True, edge_labels=False, vertex_partition=[], vertex_colors=None, edge_partition=[], force_spring_layout=False, charge=-120, link_distance=30, link_strength=2, gravity=.04, vertex_size=7, edge_thickness=4): r""" Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_. This function returns the name of the .html file. If you want to visualize the actual graph use :meth:`~sage.graphs.generic_graph.GenericGraph.show`. INPUT: - ``G`` -- the graph - ``vertex_labels`` -- boolean (default: ``False``); whether to display vertex labels - ``edge_labels`` -- boolean (default: ``False``); whether to display edge labels - ``vertex_partition`` -- list (default: ``[]``); a list of lists representing a partition of the vertex set. Vertices are then colored in the graph according to the partition - ``vertex_colors`` -- dict (default: ``None``); a dictionary representing a partition of the vertex set. Keys are colors (ignored) and values are lists of vertices. Vertices are then colored in the graph according to the partition - ``edge_partition`` -- list (default: ``[]``); same as ``vertex_partition``, with edges instead - ``force_spring_layout`` -- boolean (default: ``False``); whether to take previously computed position of nodes into account if there is one, or to compute a spring layout - ``vertex_size`` -- integer (default: ``7``); the size of a vertex' circle - ``edge_thickness`` -- integer (default: ``4``); thickness of an edge - ``charge`` -- integer (default: ``-120``); the vertices' charge. Defines how they repulse each other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``link_distance`` -- integer (default: ``30``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``link_strength`` -- integer (default: ``2``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``gravity`` -- float (default: ``0.04``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information .. WARNING:: Since the d3js package is not standard yet, the javascript is fetched from d3js.org website by the browser. If you want to avoid that (e.g. to protect your privacy or by lack of internet connection), you can install the d3js package for offline use by running ``sage -i d3js`` from the command line. EXAMPLES:: sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage: g = graphs.PetersenGraph() sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage: g = digraphs.DeBruijn(2, 2) sage: g.allow_multiple_edges(True) sage: g.add_edge("10", "10", "a") sage: g.add_edge("10", "10", "b") sage: g.add_edge("10", "10", "c") sage: g.add_edge("10", "10", "d") sage: g.add_edge("01", "11", "1") sage: g.show(method="js", vertex_labels=True,edge_labels=True, ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], ....: edge_thickness=4) # optional -- internet TESTS:: sage: from sage.graphs.graph_plot_js import gen_html_code sage: filename = gen_html_code(graphs.PetersenGraph()) :trac:`17370`:: sage: filename = gen_html_code(graphs.CompleteBipartiteGraph(4, 5)) In the generated html code, the source (resp. target) of a link is the index of the node in the list defining the names of the nodes. We check that the order is correct (:trac:`27460`):: sage: filename = gen_html_code(DiGraph({1: [10]})) sage: with open(filename, 'r') as f: ....: data = f.read() sage: nodes = data.partition('"nodes":')[2]; nodes ...[{..."name": "10"...}, {..."name": "1"...}]... sage: links = data.partition('"links":')[2] sage: '"source": 1' in links and '"target": 0' in links True """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G)} # Vertex colors if vertex_colors is not None: vertex_partition = list(vertex_colors.values()) len_vertex_partition = len(vertex_partition) color = {i: len_vertex_partition for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list # Data for vertex v must be at position v_to_id[v] in list nodes nodes = [{"name": str(v), "group": str(color[v_to_id[v]])} for v in G] # Edge colors. edge_color_default = "#aaa" color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e+(None,) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edge_iterator(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 10 + 10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list # The source (resp. target) is the index of u (resp. v) in list nodes edges.append({"source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else ""}) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible Gpos = G.get_pos() pos = [] if Gpos is not None and force_spring_layout is False: charge = 0 link_strength = 0 gravity = 0 for v in G: x, y = Gpos[v] pos.append([float(x), float(-y)]) # Encodes the data as a JSON string from json import JSONEncoder string = JSONEncoder().encode({"nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness)}) from sage.env import SAGE_EXTCODE, SAGE_SHARE js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r') js_code = js_code_file.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE", string) js_code_file.close() # Add d3.js script depending on whether d3js package is installed. d3js_filepath = os.path.join(SAGE_SHARE, 'd3js', 'd3.min.js') if os.path.exists(d3js_filepath): with open(d3js_filepath, 'r') as d3js_code_file: d3js_script = '<script>' + d3js_code_file.read() + '</script>' else: d3js_script = '<script src="http://d3js.org/d3.v3.min.js"></script>' js_code = js_code.replace('// D3JS_SCRIPT_HEREEEEEEEEEEE', d3js_script) # Writes the temporary .html file filename = tmp_filename(ext='.html') f = open(filename, 'w') f.write(js_code) f.close() return filename
def graph_to_JSON(G, vertex_partition=[], vertex_colors=None, edge_partition=[], layout=None, charge=-120, link_distance=100, link_strength=2, gravity=.04, vertex_size=12, edge_thickness=4): directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G)} # Vertex colors if vertex_colors is not None: vertex_partition = list(vertex_colors.values()) len_vertex_partition = len(vertex_partition) color = {i: len_vertex_partition for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list # Data for vertex v must be at position v_to_id[v] in list nodes nodes = [{"name": str(v), "group": str(color[v_to_id[v]])} for v in G] # Edge colors. edge_color_default = "#aaa" color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e + (None, ) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edge_iterator(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 10 + 10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list # The source (resp. target) is the index of u (resp. v) in list nodes edges.append({ "source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) }) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible if layout is not None: Gpos = G.graphplot(layout=layout)._pos else: Gpos = G.get_pos() pos = [] if Gpos is not None: charge = 0 link_strength = 0 gravity = 0 for v in G: x, y = Gpos[v] pos.append([float(x), float(-y)]) # Encodes the data as a JSON string from json import JSONEncoder string = JSONEncoder().encode({ "nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness) }) return string
def gen_html_code(G, vertex_labels=False, edge_labels=False, vertex_partition=[], edge_partition=[], force_spring_layout=False, charge=-120, link_distance=30, link_strength=2, gravity=.04, vertex_size=7, edge_thickness=4): r""" Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_. This function returns the name of the .html file. If you want to visualize the actual graph use :meth:`~sage.graphs.generic_graph.GenericGraph.show`. INPUT: - ``G`` -- the graph - ``vertex_labels`` (boolean) -- Whether to display vertex labels (set to ``False`` by default). - ``edge_labels`` (boolean) -- Whether to display edge labels (set to ``False`` by default). - ``vertex_partition`` -- a list of lists representing a partition of the vertex set. Vertices are then colored in the graph according to the partition. Set to ``[]`` by default. - ``edge_partition`` -- same as ``vertex_partition``, with edges instead. Set to ``[]`` by default. - ``force_spring_layout`` -- whether to take sage's position into account if there is one (see :meth:`~sage.graphs.generic_graph.GenericGraph.` and :meth:`~sage.graphs.generic_graph.GenericGraph.`), or to compute a spring layout. Set to ``False`` by default. - ``vertex_size`` -- The size of a vertex' circle. Set to `7` by default. - ``edge_thickness`` -- Thickness of an edge. Set to ``4`` by default. - ``charge`` -- the vertices' charge. Defines how they repulse each other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``-120`` by default. - ``link_distance`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``30`` by default. - ``link_strength`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``2`` by default. - ``gravity`` -- See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information. Set to ``0.04`` by default. EXAMPLES:: sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage: g = graphs.PetersenGraph() sage: g.show(method = "js", vertex_partition=g.coloring()) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage: g = digraphs.DeBruijn(2,2) sage: g.allow_multiple_edges(True) sage: g.add_edge("10","10","a") sage: g.add_edge("10","10","b") sage: g.add_edge("10","10","c") sage: g.add_edge("10","10","d") sage: g.add_edge("01","11","1") sage: g.show(method="js", vertex_labels=True,edge_labels=True, ....: link_distance=200,gravity=.05,charge=-500, ....: edge_partition=[[("11","12","2"),("21","21","a")]], ....: edge_thickness=4) # optional -- internet TESTS:: sage: from sage.graphs.graph_plot_js import gen_html_code sage: filename = gen_html_code(graphs.PetersenGraph()) """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G.vertices())} # Vertex colors color = {i: len(vertex_partition) for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list nodes = [] for v in G.vertices(): nodes.append({"name": str(v), "group": str(color[v_to_id[v]])}) # Edge colors. edge_color_default = "#aaa" color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e + (None, ) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edges(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 10 + 10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list edges.append({ "source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else "" }) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible Gpos = G.get_pos() pos = [] if Gpos is not None and force_spring_layout is False: charge = 0 link_strength = 0 gravity = 0 for v in G.vertices(): x, y = Gpos[v] pos.append([x, -y]) # Encodes the data as a JSON string from json import JSONEncoder string = JSONEncoder().encode({ "nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness) }) from sage.env import SAGE_EXTCODE js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r') js_code = js_code_file.read().replace("// HEREEEEEEEEEEE", string) js_code_file.close() # Writes the temporary .html file filename = tmp_filename(ext='.html') f = open(filename, 'w') f.write(js_code) f.close() return filename
def plot3d_adaptive(f, x_range, y_range, color="automatic", grad_f=None, max_bend=.5, max_depth=5, initial_depth=4, num_colors=128, **kwds): r""" Adaptive 3d plotting of a function of two variables. This is used internally by the plot3d command when the option ``adaptive=True`` is given. INPUT: - ``f`` - a symbolic function or a Python function of 3 variables. - ``x_range`` - x range of values: 2-tuple (xmin, xmax) or 3-tuple (x,xmin,xmax) - ``y_range`` - y range of values: 2-tuple (ymin, ymax) or 3-tuple (y,ymin,ymax) - ``grad_f`` - gradient of f as a Python function - ``color`` - "automatic" - a rainbow of num_colors colors - ``num_colors`` - (default: 128) number of colors to use with default color - ``max_bend`` - (default: 0.5) - ``max_depth`` - (default: 5) - ``initial_depth`` - (default: 4) - ``**kwds`` - standard graphics parameters EXAMPLES: We plot `\sin(xy)`:: sage: from sage.plot.plot3d.plot3d import plot3d_adaptive sage: x,y=var('x,y'); plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5) Graphics3d Object .. PLOT:: from sage.plot.plot3d.plot3d import plot3d_adaptive x,y=var('x,y') sphinx_plot(plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5)) """ if initial_depth >= max_depth: max_depth = initial_depth from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid(f, [x_range, y_range], plot_points=2) xmin, xmax = ranges[0][:2] ymin, ymax = ranges[1][:2] opacity = kwds.get('opacity', 1) if color == "automatic": texture = rainbow(num_colors, 'rgbtuple') else: if isinstance(color, list): texture = color else: kwds['color'] = color texture = Texture(kwds) factory = TrivialTriangleFactory() plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g=grad_f, min_depth=initial_depth, max_depth=max_depth, max_bend=max_bend, num_colors=None) P = IndexFaceSet(plot._objects) if isinstance(texture, (list, tuple)): if len(texture) == 2: # do a grid coloring xticks = (xmax - xmin) / 2**initial_depth yticks = (ymax - ymin) / 2**initial_depth parts = P.partition(lambda x, y, z: (int( (x - xmin) / xticks) + int((y - ymin) / yticks)) % 2) else: # do a topo coloring bounds = P.bounding_box() min_z = bounds[0][2] max_z = bounds[1][2] if max_z == min_z: span = 0 else: span = (len(texture) - 1) / (max_z - min_z ) # max to avoid dividing by 0 parts = P.partition(lambda x, y, z: int((z - min_z) * span)) all = [] for k, G in iteritems(parts): G.set_texture(texture[k], opacity=opacity) all.append(G) P = Graphics3dGroup(all) else: P.set_texture(texture) P.frame_aspect_ratio([1.0, 1.0, 0.5]) P._set_extra_kwds(kwds) return P
], x, y, solution_dict=True) return (n(sol[0][x]), n(sol[0][y])) def distance(p1, p2): return n(sqrt((p2[0] - p1[0])**2 + (p2[1] - p1[1])**2)) if __name__ == "__main__": disp = circle((0, 0), 1) #angles = [[1./3, 2./3], [1./7, 2./7], [3./7, 4./7], [11./31, 12./31]] global angles colors = rainbow(len(angles)) for i, pair in enumerate(angles): # Get points associated with angles p1 = get_point_from_angle(pair[0]) p2 = get_point_from_angle(pair[1]) #disp += text("%s" % pair[0], p1, fontsize = 'xx-small') # Get arc between points center = get_center(p1, p2) radius = distance(center, p1) disp += arc(center, radius, rgbcolor=colors[i], thickness=0.8) #disp += bezier_path([[p1, (0,0), p2]], thickness = 0.5, rgbcolor = colors[i]) disp.axes(False) disp.show(dpi=1000, title="External Angles in the Mandlebrot Set",
def set_vertices(self, **vertex_options): """ Sets the vertex plotting parameters for this GraphPlot. This function is called by the constructor but can also be called to make updates to the vertex options of an existing GraphPlot object. Note that the changes are cumulative. EXAMPLES:: sage: g = Graph({}, loops=True, multiedges=True, sparse=True) sage: g.add_edges([(0,0,'a'),(0,0,'b'),(0,1,'c'),(0,1,'d'), ... (0,1,'e'),(0,1,'f'),(0,1,'f'),(2,1,'g'),(2,2,'h')]) sage: GP = g.graphplot(vertex_size=100, edge_labels=True, color_by_label=True, edge_style='dashed') sage: GP.set_vertices(talk=True) sage: GP.plot() sage: GP.set_vertices(vertex_colors='pink', vertex_shape='^') sage: GP.plot() """ # Handle base vertex options voptions = {} for arg in vertex_options: self._options[arg] = vertex_options[arg] # First set defaults for styles vertex_colors = None if self._options['talk']: voptions['markersize'] = 500 if self._options['partition'] is None: vertex_colors = '#ffffff' else: voptions['markersize'] = self._options['vertex_size'] if 'vertex_colors' not in self._options or self._options['vertex_colors'] is None: if self._options['partition'] is not None: from sage.plot.colors import rainbow,rgbcolor partition = self._options['partition'] l = len(partition) R = rainbow(l) vertex_colors = {} for i in range(l): vertex_colors[R[i]] = partition[i] elif len(self._graph._boundary) != 0: vertex_colors = {} bdy_verts = [] int_verts = [] for v in self._graph.vertex_iterator(): if v in self._graph._boundary: bdy_verts.append(v) else: int_verts.append(v) vertex_colors['#fec7b8'] = int_verts vertex_colors['#b3e8ff'] = bdy_verts elif not vertex_colors: vertex_colors='#fec7b8' else: vertex_colors = self._options['vertex_colors'] if 'vertex_shape' in self._options: voptions['marker'] = self._options['vertex_shape'] if self._graph.is_directed(): self._vertex_radius = sqrt(voptions['markersize']/pi) self._arrowshorten = 2*self._vertex_radius if self._arcdigraph: self._vertex_radius = sqrt(voptions['markersize']/(20500*pi)) voptions['zorder'] = 7 if not isinstance(vertex_colors, dict): voptions['facecolor'] = vertex_colors if self._arcdigraph: self._plot_components['vertices'] = [circle(center, self._vertex_radius, fill=True, facecolor=vertex_colors, clip=False) for center in self._pos.values()] else: self._plot_components['vertices'] = scatter_plot( self._pos.values(), clip=False, **voptions) else: # Color list must be ordered: pos = [] colors = [] for i in vertex_colors: pos += [self._pos[j] for j in vertex_colors[i]] colors += [i]*len(vertex_colors[i]) # If all the vertices have not been assigned a color if len(self._pos)!=len(pos): from sage.plot.colors import rainbow,rgbcolor vertex_colors_rgb=[rgbcolor(c) for c in vertex_colors] for c in rainbow(len(vertex_colors)+1): if rgbcolor(c) not in vertex_colors_rgb: break leftovers=[j for j in self._pos.values() if j not in pos] pos+=leftovers colors+=[c]*len(leftovers) if self._arcdigraph: self._plot_components['vertices'] = [circle(pos[i], self._vertex_radius, fill=True, facecolor=colors[i], clip=False) for i in range(len(pos))] else: self._plot_components['vertices'] = scatter_plot(pos, facecolor=colors, clip=False, **voptions) if self._options['vertex_labels']: self._plot_components['vertex_labels'] = [] # TODO: allow text options for v in self._nodelist: self._plot_components['vertex_labels'].append(text(str(v), self._pos[v], rgbcolor=(0,0,0), zorder=8))
def plot3d_adaptive(f, x_range, y_range, color="automatic", grad_f=None, max_bend=.5, max_depth=5, initial_depth=4, num_colors=128, **kwds): r""" Adaptive 3d plotting of a function of two variables. This is used internally by the plot3d command when the option ``adaptive=True`` is given. INPUT: - ``f`` - a symbolic function or a Python function of 3 variables. - ``x_range`` - x range of values: 2-tuple (xmin, xmax) or 3-tuple (x,xmin,xmax) - ``y_range`` - y range of values: 2-tuple (ymin, ymax) or 3-tuple (y,ymin,ymax) - ``grad_f`` - gradient of f as a Python function - ``color`` - "automatic" - a rainbow of num_colors colors - ``num_colors`` - (default: 128) number of colors to use with default color - ``max_bend`` - (default: 0.5) - ``max_depth`` - (default: 5) - ``initial_depth`` - (default: 4) - ``**kwds`` - standard graphics parameters EXAMPLES: We plot `\sin(xy)`:: sage: from sage.plot.plot3d.plot3d import plot3d_adaptive sage: x,y=var('x,y'); plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5) Graphics3d Object .. PLOT:: from sage.plot.plot3d.plot3d import plot3d_adaptive x,y=var('x,y') sphinx_plot(plot3d_adaptive(sin(x*y), (x,-pi,pi), (y,-pi,pi), initial_depth=5)) """ if initial_depth >= max_depth: max_depth = initial_depth from sage.plot.misc import setup_for_eval_on_grid g, ranges = setup_for_eval_on_grid(f, [x_range,y_range], plot_points=2) xmin,xmax = ranges[0][:2] ymin,ymax = ranges[1][:2] opacity = kwds.get('opacity',1) if color == "automatic": texture = rainbow(num_colors, 'rgbtuple') else: if isinstance(color, list): texture = color else: kwds['color'] = color texture = Texture(kwds) factory = TrivialTriangleFactory() plot = TrianglePlot(factory, g, (xmin, xmax), (ymin, ymax), g = grad_f, min_depth=initial_depth, max_depth=max_depth, max_bend=max_bend, num_colors = None) P = IndexFaceSet(plot._objects) if isinstance(texture, (list, tuple)): if len(texture) == 2: # do a grid coloring xticks = (xmax - xmin)/2**initial_depth yticks = (ymax - ymin)/2**initial_depth parts = P.partition(lambda x,y,z: (int((x-xmin)/xticks) + int((y-ymin)/yticks)) % 2) else: # do a topo coloring bounds = P.bounding_box() min_z = bounds[0][2] max_z = bounds[1][2] if max_z == min_z: span = 0 else: span = (len(texture)-1) / (max_z - min_z) # max to avoid dividing by 0 parts = P.partition(lambda x,y,z: int((z-min_z)*span)) all = [] for k, G in parts.iteritems(): G.set_texture(texture[k], opacity=opacity) all.append(G) P = Graphics3dGroup(all) else: P.set_texture(texture) P.frame_aspect_ratio([1.0,1.0,0.5]) P._set_extra_kwds(kwds) return P
def gen_html_code(G, vertex_labels=True, edge_labels=False, vertex_partition=[], vertex_colors=None, edge_partition=[], force_spring_layout=False, charge=-120, link_distance=30, link_strength=2, gravity=.04, vertex_size=7, edge_thickness=4): r""" Creates a .html file showing the graph using `d3.js <http://d3js.org/>`_. This function returns the name of the .html file. If you want to visualize the actual graph use :meth:`~sage.graphs.generic_graph.GenericGraph.show`. INPUT: - ``G`` -- the graph - ``vertex_labels`` -- boolean (default: ``False``); whether to display vertex labels - ``edge_labels`` -- boolean (default: ``False``); whether to display edge labels - ``vertex_partition`` -- list (default: ``[]``); a list of lists representing a partition of the vertex set. Vertices are then colored in the graph according to the partition - ``vertex_colors`` -- dict (default: ``None``); a dictionary representing a partition of the vertex set. Keys are colors (ignored) and values are lists of vertices. Vertices are then colored in the graph according to the partition - ``edge_partition`` -- list (default: ``[]``); same as ``vertex_partition``, with edges instead - ``force_spring_layout`` -- boolean (default: ``False``); whether to take previously computed position of nodes into account if there is one, or to compute a spring layout - ``vertex_size`` -- integer (default: ``7``); the size of a vertex' circle - ``edge_thickness`` -- integer (default: ``4``); thickness of an edge - ``charge`` -- integer (default: ``-120``); the vertices' charge. Defines how they repulse each other. See `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``link_distance`` -- integer (default: ``30``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``link_strength`` -- integer (default: ``2``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information - ``gravity`` -- float (default: ``0.04``); see `<https://github.com/mbostock/d3/wiki/Force-Layout>`_ for more information .. WARNING:: Since the d3js package is not standard yet, the javascript is fetched from d3js.org website by the browser. If you want to avoid that (e.g. to protect your privacy or by lack of internet connection), you can install the d3js package for offline use by running ``sage -i d3js`` from the command line. EXAMPLES:: sage: graphs.RandomTree(50).show(method="js") # optional -- internet sage: g = graphs.PetersenGraph() sage: g.show(method="js", vertex_partition=g.coloring()) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js", force_spring_layout=True) # optional -- internet sage: graphs.DodecahedralGraph().show(method="js") # optional -- internet sage: g = digraphs.DeBruijn(2, 2) sage: g.allow_multiple_edges(True) sage: g.add_edge("10", "10", "a") sage: g.add_edge("10", "10", "b") sage: g.add_edge("10", "10", "c") sage: g.add_edge("10", "10", "d") sage: g.add_edge("01", "11", "1") sage: g.show(method="js", vertex_labels=True,edge_labels=True, ....: link_distance=200, gravity=.05, charge=-500, ....: edge_partition=[[("11", "12", "2"), ("21", "21", "a")]], ....: edge_thickness=4) # optional -- internet TESTS:: sage: from sage.graphs.graph_plot_js import gen_html_code sage: filename = gen_html_code(graphs.PetersenGraph()) :trac:`17370`:: sage: filename = gen_html_code(graphs.CompleteBipartiteGraph(4, 5)) """ directed = G.is_directed() multiple_edges = G.has_multiple_edges() # Associated an integer to each vertex v_to_id = {v: i for i, v in enumerate(G)} # Vertex colors if vertex_colors is not None: vertex_partition = list(vertex_colors.values()) len_vertex_partition = len(vertex_partition) color = {i: len_vertex_partition for i in range(G.order())} for i, l in enumerate(vertex_partition): for v in l: color[v_to_id[v]] = i # Vertex list nodes = [] for v in G.vertices(): nodes.append({"name": str(v), "group": str(color[v_to_id[v]])}) # Edge colors. edge_color_default = "#aaa" color_list = rainbow(len(edge_partition)) edge_color = {} for i, l in enumerate(edge_partition): for e in l: u, v, label = e if len(e) == 3 else e+(None,) edge_color[u, v, label] = color_list[i] if not directed: edge_color[v, u, label] = color_list[i] # Edge list edges = [] seen = {} # How many times has this edge been seen ? for u, v, l in G.edge_iterator(): # Edge color color = edge_color.get((u, v, l), edge_color_default) # Computes the curve of the edge curve = 0 # Loop ? if u == v: seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 10 + 10 # For directed graphs, one also has to take into accounts # edges in the opposite direction elif directed: if G.has_edge(v, u): seen[u, v] = seen.get((u, v), 0) + 1 curve = seen[u, v] * 15 else: if multiple_edges and len(G.edge_label(u, v)) != 1: # Multiple edges. The first one has curve 15, then # -15, then 30, then -30, ... seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 elif not directed and multiple_edges: # Same formula as above for multiple edges if len(G.edge_label(u, v)) != 1: seen[u, v] = seen.get((u, v), 0) + 1 curve = (1 if seen[u, v] % 2 else -1) * (seen[u, v] // 2) * 15 # Adding the edge to the list edges.append({"source": v_to_id[u], "target": v_to_id[v], "strength": 0, "color": color, "curve": curve, "name": str(l) if edge_labels else ""}) loops = [e for e in edges if e["source"] == e["target"]] edges = [e for e in edges if e["source"] != e["target"]] # Defines the vertices' layout if possible Gpos = G.get_pos() pos = [] if Gpos is not None and force_spring_layout is False: charge = 0 link_strength = 0 gravity = 0 for v in G: x, y = Gpos[v] pos.append([float(x), float(-y)]) # Encodes the data as a JSON string from json import JSONEncoder string = JSONEncoder().encode({"nodes": nodes, "links": edges, "loops": loops, "pos": pos, "directed": G.is_directed(), "charge": int(charge), "link_distance": int(link_distance), "link_strength": int(link_strength), "gravity": float(gravity), "vertex_labels": bool(vertex_labels), "edge_labels": bool(edge_labels), "vertex_size": int(vertex_size), "edge_thickness": int(edge_thickness)}) from sage.env import SAGE_EXTCODE, SAGE_SHARE js_code_file = open(SAGE_EXTCODE + "/graphs/graph_plot_js.html", 'r') js_code = js_code_file.read().replace("// GRAPH_DATA_HEREEEEEEEEEEE", string) js_code_file.close() # Add d3.js script depending on whether d3js package is installed. d3js_filepath = os.path.join(SAGE_SHARE, 'd3js', 'd3.min.js') if os.path.exists(d3js_filepath): with open(d3js_filepath, 'r') as d3js_code_file: d3js_script = '<script>' + d3js_code_file.read() + '</script>' else: d3js_script = '<script src="http://d3js.org/d3.v3.min.js"></script>' js_code = js_code.replace('// D3JS_SCRIPT_HEREEEEEEEEEEE', d3js_script) # Writes the temporary .html file filename = tmp_filename(ext='.html') f = open(filename, 'w') f.write(js_code) f.close() return filename
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