10000 Long node names break nx_pydot.pydot_layout (and possibly others) · Issue #7648 · networkx/networkx · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Long node names break nx_pydot.pydot_layout (and possibly others) #7648

New issue
Open
dougthor42 opened this issue Sep 23, 2024 · 3 comments · May be fixed by #8079
Open

Long node names break nx_pydot.pydot_layout (and possibly others) #7648

dougthor42 opened this issue Sep 23, 2024 · 3 comments · May be fixed by #8079
Labels
Pydot Items related to pydot dependency

Comments

@dougthor42
Copy link

Really long node names get split into multiple lines when creating the dot representation via create_dot():

(Pdb) print(D_bytes.decode())
strict graph {
        graph [bb="0,0,1266.1,197.74"];
        node [label="\N"];
        "A\nbig test"   [height=0.74639,
                pos="54,170.87",
                width=1.0999];
        B       [height=0.5,
                pos="27,90",
                width=0.75];
        "A\nbig test" -- B      [pos="45.308,144.48 41.177,132.41 36.354,118.33 32.696,107.64"];
        C       [height=0.5,
                pos="54,18",
                width=0.75];
        "A\nbig test" -- C      [pos="58.602,144.07 60.356,133.01 62.138,119.91 63,108 64.155,92.042 64.344,87.943 63,72 61.981,59.91 59.676,46.431 57.654,36.092"];
        B -- C  [pos="33.399,72.411 37.64,61.414 43.189,47.027 47.46,35.956"];
        "=10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =\
10chars= "      [height=0.5,
                pos="689,170.87",
                width=16.032];
        D       [height=0.5,
                pos="689,90",
                width=0.75];
        "=10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =\
10chars= " -- D [pos="689,152.76 689,139.53 689,121.3 689,108.08"];
}

This causes the pydot_layout function call to be unable to find node names.

        for n in G.nodes():
            str_n = str(n)
            node = Q.get_node(pydot.quote_id_if_necessary(str_n))
    
            if isinstance(node, list):
                if len(node) == 0:  # added to highlight this Issue
>                   raise ValueError(f"Failed to find node named {str_n=}")
E                   ValueError: Failed to find node named str_n='=10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= =10chars= '

Current Behavior

nx_pydot.pydot_layout raises IndexError:

        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]
E               IndexError: list index out of range

networkx/drawing/nx_pydot.py:348: IndexError

node is a list but it is empty: node == []. It's empty because the node = Q.get_node(pydot.quote_id_if_necessary(str_n)) line fails to find a node named str_n.

Expected Behavior

nx_pydot.pydot_layout should work even when node names are very long.

Steps to Reproduce

Edit this test case and run the test:

diff --git a/networkx/drawing/tests/test_pydot.py b/networkx/drawing/tests/test_pydot.py
index acf93d77..8a871910 100644
--- a/networkx/drawing/tests/test_pydot.py
+++ b/networkx/drawing/tests/test_pydot.py
@@ -98,7 +98,15 @@ def test_pydot_issue_7581(tmp_path):
     which caused #7581.
     """
     G = nx.Graph()
-    G.add_edges_from([("A\nbig test", "B"), ("A\nbig test", "C"), ("B", "C")])
+    G.add_edges_from(
+        [
+            ("A\nbig test", "B"),
+            ("A\nbig test", "C"),
+            ("B", "C"),
+            # Lines longer than ~130 chars get split
+            ("=10chars= "*14, "D"),
+        ]
+    )
 
     graph_layout = nx.nx_pydot.pydot_layout(G, prog="dot")
     assert isinstance(graph_layout, dict)

You'll see that an IndexError is raised.

Add some error handling to see the exact ValueError I displayed above:

diff --git a/networkx/drawing/nx_pydot.py b/networkx/drawing/nx_pydot.py
index 7df0c111..946498d7 100644
--- a/networkx/drawing/nx_pydot.py
+++ b/networkx/drawing/nx_pydot.py
@@ -344,6 +344,8 @@ def pydot_layout(G, prog="neato", root=None):
         node = Q.get_node(pydot.quote_id_if_necessary(str_n))
 
         if isinstance(node, list):
+            if len(node) == 0:
+                raise ValueError(f"Failed to find node named {str_n=}")
             node = node[0]
         pos = node.get_pos()[1:-1]  # strip leading and trailing double quotes
         if pos is not None:

Environment

Python version: 3.11.9
NetworkX version: main @ 0aaa392 (2024-09-20 13:47:12 -0700)
Pydot version: 3.0.1

Additional context

I haven't investigated where in pydot the newlines are being added, or if that's a "feature" of graphviz itself.

@AKASHYADAVO
Copy link

There's a problem with the nx_pydot.pydot_layout function in NetworkX when you try to use it with really long node names. It can cause errors because it doesn't handle these long names correctly.

To fix this, we need to update the code to be smarter about how it deals with empty nodes and raise a clear error message if it can't find the nodes you're looking for. This will stop the errors from happening when you have long node labels.

We might need to do some more testing to make sure this fix works with other parts of the code that have to do with layout

AKASHYADAVO added a commit to AKASHYADAVO/networkx that referenced this issue Oct 14, 2024
…bly others) networkx#7648

There was a problem with the nx_pydot.pydot_layout function in NetworkX when you had really long node names. It would mess up the layout and cause errors.

We fixed this by making the code smarter. Now it checks if the node exists before trying to find its position, and it gives you a clear error message if it can't find it or if there's a problem with the position information.

This makes the layout function more reliable, so it won't crash anymore even if you have long or weird node names.
@rossbar rossbar added the Pydot Items related to pydot dependency label Oct 28, 2024
@BastianKusserow
Copy link

Is there any movement on this? Would be nice to find a fix for it soonish :)

@dschult
Copy link
Member
dschult commented May 27, 2025

Is this a problem with pydot or with network or with graphviz?
Do the long names work with the pygraphviz interface functions?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Pydot Items related to pydot dependency
5 participants
0