Mercurial > repos > guerler > springsuite
diff planemo/lib/python3.7/site-packages/networkx/drawing/nx_pydot.py @ 1:56ad4e20f292 draft
"planemo upload commit 6eee67778febed82ddd413c3ca40b3183a3898f1"
author | guerler |
---|---|
date | Fri, 31 Jul 2020 00:32:28 -0400 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/planemo/lib/python3.7/site-packages/networkx/drawing/nx_pydot.py Fri Jul 31 00:32:28 2020 -0400 @@ -0,0 +1,354 @@ +""" +***** +Pydot +***** + +Import and export NetworkX graphs in Graphviz dot format using pydot. + +Either this module or nx_agraph can be used to interface with graphviz. + +See Also +-------- +pydot: https://github.com/erocarrera/pydot +Graphviz: https://www.graphviz.org +DOT Language: http://www.graphviz.org/doc/info/lang.html +""" +# Author: Aric Hagberg (aric.hagberg@gmail.com) + +# Copyright (C) 2004-2019 by +# Aric Hagberg <hagberg@lanl.gov> +# Dan Schult <dschult@colgate.edu> +# Pieter Swart <swart@lanl.gov> +# Cecil Curry <leycec@gmail.com> +# All rights reserved. +# BSD license. +from locale import getpreferredencoding +from networkx.utils import open_file, make_str +import networkx as nx + +__all__ = ['write_dot', 'read_dot', 'graphviz_layout', 'pydot_layout', + 'to_pydot', 'from_pydot'] + +# 2.x/3.x compatibility +try: + basestring +except NameError: + basestring = str + unicode = str + + +@open_file(1, mode='w') +def write_dot(G, path): + """Write NetworkX graph G to Graphviz dot format on path. + + Path can be a string or a file handle. + """ + P = to_pydot(G) + path.write(P.to_string()) + return + + +@open_file(0, mode='r') +def read_dot(path): + """Returns a NetworkX :class:`MultiGraph` or :class:`MultiDiGraph` from the + dot file with the passed path. + + If this file contains multiple graphs, only the first such graph is + returned. All graphs _except_ the first are silently ignored. + + Parameters + ---------- + path : str or file + Filename or file handle. + + Returns + ------- + G : MultiGraph or MultiDiGraph + A :class:`MultiGraph` or :class:`MultiDiGraph`. + + Notes + ----- + Use `G = nx.Graph(read_dot(path))` to return a :class:`Graph` instead of a + :class:`MultiGraph`. + """ + import pydot + data = path.read() + + # List of one or more "pydot.Dot" instances deserialized from this file. + P_list = pydot.graph_from_dot_data(data) + + # Convert only the first such instance into a NetworkX graph. + return from_pydot(P_list[0]) + + +def from_pydot(P): + """Returns a NetworkX graph from a Pydot graph. + + Parameters + ---------- + P : Pydot graph + A graph created with Pydot + + Returns + ------- + G : NetworkX multigraph + A MultiGraph or MultiDiGraph. + + Examples + -------- + >>> K5 = nx.complete_graph(5) + >>> A = nx.nx_pydot.to_pydot(K5) + >>> G = nx.nx_pydot.from_pydot(A) # return MultiGraph + + # make a Graph instead of MultiGraph + >>> G = nx.Graph(nx.nx_pydot.from_pydot(A)) + + """ + if P.get_strict(None): # pydot bug: get_strict() shouldn't take argument + multiedges = False + else: + multiedges = True + + if P.get_type() == 'graph': # undirected + if multiedges: + N = nx.MultiGraph() + else: + N = nx.Graph() + else: + if multiedges: + N = nx.MultiDiGraph() + else: + N = nx.DiGraph() + + # assign defaults + name = P.get_name().strip('"') + if name != '': + N.name = name + + # add nodes, attributes to N.node_attr + for p in P.get_node_list(): + n = p.get_name().strip('"') + if n in ('node', 'graph', 'edge'): + continue + N.add_node(n, **p.get_attributes()) + + # add edges + for e in P.get_edge_list(): + u = e.get_source() + v = e.get_destination() + attr = e.get_attributes() + s = [] + d = [] + + if isinstance(u, basestring): + s.append(u.strip('"')) + else: + for unodes in u['nodes']: + s.append(unodes.strip('"')) + + if isinstance(v, basestring): + d.append(v.strip('"')) + else: + for vnodes in v['nodes']: + d.append(vnodes.strip('"')) + + for source_node in s: + for destination_node in d: + N.add_edge(source_node, destination_node, **attr) + + # add default attributes for graph, nodes, edges + pattr = P.get_attributes() + if pattr: + N.graph['graph'] = pattr + try: + N.graph['node'] = P.get_node_defaults()[0] + except (IndexError, TypeError): + pass # N.graph['node']={} + try: + N.graph['edge'] = P.get_edge_defaults()[0] + except (IndexError, TypeError): + pass # N.graph['edge']={} + return N + + +def to_pydot(N): + """Returns a pydot graph from a NetworkX graph N. + + Parameters + ---------- + N : NetworkX graph + A graph created with NetworkX + + Examples + -------- + >>> K5 = nx.complete_graph(5) + >>> P = nx.nx_pydot.to_pydot(K5) + + Notes + ----- + + """ + import pydot + + # set Graphviz graph type + if N.is_directed(): + graph_type = 'digraph' + else: + graph_type = 'graph' + strict = nx.number_of_selfloops(N) == 0 and not N.is_multigraph() + + name = N.name + graph_defaults = N.graph.get('graph', {}) + if name == '': + P = pydot.Dot('', graph_type=graph_type, strict=strict, + **graph_defaults) + else: + P = pydot.Dot('"%s"' % name, graph_type=graph_type, strict=strict, + **graph_defaults) + try: + P.set_node_defaults(**N.graph['node']) + except KeyError: + pass + try: + P.set_edge_defaults(**N.graph['edge']) + except KeyError: + pass + + for n, nodedata in N.nodes(data=True): + str_nodedata = dict((k, make_str(v)) for k, v in nodedata.items()) + p = pydot.Node(make_str(n), **str_nodedata) + P.add_node(p) + + if N.is_multigraph(): + for u, v, key, edgedata in N.edges(data=True, keys=True): + str_edgedata = dict((k, make_str(v)) for k, v in edgedata.items() + if k != 'key') + edge = pydot.Edge(make_str(u), make_str(v), + key=make_str(key), **str_edgedata) + P.add_edge(edge) + + else: + for u, v, edgedata in N.edges(data=True): + str_edgedata = dict((k, make_str(v)) for k, v in edgedata.items()) + edge = pydot.Edge(make_str(u), make_str(v), **str_edgedata) + P.add_edge(edge) + return P + + +def graphviz_layout(G, prog='neato', root=None): + """Create node positions using Pydot and Graphviz. + + Returns a dictionary of positions keyed by node. + + Parameters + ---------- + G : NetworkX Graph + The graph for which the layout is computed. + prog : string (default: 'neato') + The name of the GraphViz program to use for layout. + Options depend on GraphViz version but may include: + 'dot', 'twopi', 'fdp', 'sfdp', 'circo' + root : Node from G or None (default: None) + The node of G from which to start some layout algorithms. + + Returns + ------- + Dictionary of (x, y) positions keyed by node. + + Examples + -------- + >>> G = nx.complete_graph(4) + >>> pos = nx.nx_pydot.graphviz_layout(G) + >>> pos = nx.nx_pydot.graphviz_layout(G, prog='dot') + + Notes + ----- + This is a wrapper for pydot_layout. + """ + return pydot_layout(G=G, prog=prog, root=root) + + +def pydot_layout(G, prog='neato', root=None): + """Create node positions using :mod:`pydot` and Graphviz. + + Parameters + -------- + G : Graph + NetworkX graph to be laid out. + prog : string (default: 'neato') + Name of the GraphViz command to use for layout. + Options depend on GraphViz version but may include: + 'dot', 'twopi', 'fdp', 'sfdp', 'circo' + root : Node from G or None (default: None) + The node of G from which to start some layout algorithms. + + Returns + -------- + dict + Dictionary of positions keyed by node. + + Examples + -------- + >>> G = nx.complete_graph(4) + >>> pos = nx.nx_pydot.pydot_layout(G) + >>> pos = nx.nx_pydot.pydot_layout(G, prog='dot') + + Notes + ----- + If you use complex node objects, they may have the same string + representation and GraphViz could treat them as the same node. + The layout may assign both nodes a single location. See Issue #1568 + If this occurs in your case, consider relabeling the nodes just + for the layout computation using something similar to: + + H = nx.convert_node_labels_to_integers(G, label_attribute='node_label') + H_layout = nx.nx_pydot.pydot_layout(G, prog='dot') + G_layout = {H.nodes[n]['node_label']: p for n, p in H_layout.items()} + + """ + import pydot + P = to_pydot(G) + if root is not None: + P.set("root", make_str(root)) + + # List of low-level bytes comprising a string in the dot language converted + # from the passed graph with the passed external GraphViz command. + D_bytes = P.create_dot(prog=prog) + + # Unique string decoded from these bytes with the preferred locale encoding + D = unicode(D_bytes, encoding=getpreferredencoding()) + + if D == "": # no data returned + print("Graphviz layout with %s failed" % (prog)) + print() + print("To debug what happened try:") + print("P = nx.nx_pydot.to_pydot(G)") + print("P.write_dot(\"file.dot\")") + print("And then run %s on file.dot" % (prog)) + return + + # List of one or more "pydot.Dot" instances deserialized from this string. + Q_list = pydot.graph_from_dot_data(D) + assert len(Q_list) == 1 + + # The first and only such instance, as guaranteed by the above assertion. + Q = Q_list[0] + + node_pos = {} + for n in G.nodes(): + pydot_node = pydot.Node(make_str(n)).get_name() + node = Q.get_node(pydot_node) + + if isinstance(node, list): + node = node[0] + pos = node.get_pos()[1:-1] # strip leading and trailing double quotes + if pos is not None: + xx, yy = pos.split(",") + node_pos[n] = (float(xx), float(yy)) + return node_pos + + +# fixture for pytest +def setup_module(module): + import pytest + pytdot = pytest.importorskip('pytdot')