Example #1
0
    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'))
Example #2
0
    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
Example #3
0
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)
Example #4
0
    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)
Example #5
0
    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.")
Example #6
0
    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
Example #7
0
File: iet.py Project: CETHop/sage
    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
Example #8
0
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
Example #9
0
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))
Example #10
0
    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
Example #11
0
    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))
Example #12
0
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)
    }
Example #13
0
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
Example #15
0
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
Example #16
0
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)
    }
Example #17
0
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
Example #18
0
    ],
                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",
Example #19
0
    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))
Example #20
0
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
Example #21
0
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
Example #22
0
    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