aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py352
1 files changed, 352 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py b/.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py
new file mode 100644
index 00000000..7df0c111
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/drawing/nx_pydot.py
@@ -0,0 +1,352 @@
+"""
+*****
+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.
+
+Examples
+--------
+>>> G = nx.complete_graph(5)
+>>> PG = nx.nx_pydot.to_pydot(G)
+>>> H = nx.nx_pydot.from_pydot(PG)
+
+See Also
+--------
+ - pydot: https://github.com/erocarrera/pydot
+ - Graphviz: https://www.graphviz.org
+ - DOT Language: http://www.graphviz.org/doc/info/lang.html
+"""
+
+from locale import getpreferredencoding
+
+import networkx as nx
+from networkx.utils import open_file
+
+__all__ = [
+ "write_dot",
+ "read_dot",
+ "graphviz_layout",
+ "pydot_layout",
+ "to_pydot",
+ "from_pydot",
+]
+
+
+@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")
+@nx._dispatchable(name="pydot_read_dot", graphs=None, returns_graph=True)
+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(nx.nx_pydot.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])
+
+
+@nx._dispatchable(graphs=None, returns_graph=True)
+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, str):
+ s.append(u.strip('"'))
+ else:
+ for unodes in u["nodes"]:
+ s.append(unodes.strip('"'))
+
+ if isinstance(v, str):
+ 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(
+ f'"{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 = {str(k): str(v) for k, v in nodedata.items()}
+ n = str(n)
+ p = pydot.Node(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 = {str(k): str(v) for k, v in edgedata.items() if k != "key"}
+ u, v = str(u), str(v)
+ edge = pydot.Edge(u, v, key=str(key), **str_edgedata)
+ P.add_edge(edge)
+
+ else:
+ for u, v, edgedata in N.edges(data=True):
+ str_edgedata = {str(k): str(v) for k, v in edgedata.items()}
+ u, v = str(u), str(v)
+ edge = pydot.Edge(u, 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(H, 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", 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 = str(D_bytes, encoding=getpreferredencoding())
+
+ if D == "": # no data returned
+ print(f"Graphviz layout with {prog} failed")
+ print()
+ print("To debug what happened try:")
+ print("P = nx.nx_pydot.to_pydot(G)")
+ print('P.write_dot("file.dot")')
+ print(f"And then run {prog} on file.dot")
+ 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():
+ str_n = str(n)
+ node = Q.get_node(pydot.quote_id_if_necessary(str_n))
+
+ 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