最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How to add spacing between nodes in networkx - Stack Overflow

programmeradmin7浏览0评论

I'm trying to make a graph to visualize parts in a product and their type of connection inbetween.

The labels between the nodes are important, not the labels on the nodes themselves. Sometimes the connection lines are not long enough to fit their label or are intersecting.

I have seen another SO question but that one is about the labels ON the nodes.

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()

# add nodes
nodes = set(df["part_a"]).union(set(df["part_b"]))
G.add_nodes_from(nodes)

# add edges
for _, row in df.iterrows():
    G.add_edge(row["part_a"], row["part_b"], type=row["type_of_connection"], force=row["force"], tool=row["tool"])

# set positions
pos = nx.spring_layout(G, k=0.1, scale=2)

# draw
plt.figure(figsize=(10, 6))
nx.draw(G, pos, with_labels=True, node_size=700, node_color="lightblue", edge_color="gray", alpha=0.8)

# tryin to reduce overlap
edge_labels = {(row["part_a"], row["part_b"]): row["type_of_connection"] for _, row in df.iterrows()}
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=9, label_pos=0.3)

plt.title(f"Node Graph of Part {df_product['id'].values[0]}: {df_product['brand'].values[0]} {df_product['model'].values[0]}")
plt.show()

However in the following picture you can see that sometimes the connection lines are too short to fit the label, or connection lines are intersecting. What can I do? Tried messing with k value or scale but it does not seem to help

I'm trying to make a graph to visualize parts in a product and their type of connection inbetween.

The labels between the nodes are important, not the labels on the nodes themselves. Sometimes the connection lines are not long enough to fit their label or are intersecting.

I have seen another SO question but that one is about the labels ON the nodes.

import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt

G = nx.Graph()

# add nodes
nodes = set(df["part_a"]).union(set(df["part_b"]))
G.add_nodes_from(nodes)

# add edges
for _, row in df.iterrows():
    G.add_edge(row["part_a"], row["part_b"], type=row["type_of_connection"], force=row["force"], tool=row["tool"])

# set positions
pos = nx.spring_layout(G, k=0.1, scale=2)

# draw
plt.figure(figsize=(10, 6))
nx.draw(G, pos, with_labels=True, node_size=700, node_color="lightblue", edge_color="gray", alpha=0.8)

# tryin to reduce overlap
edge_labels = {(row["part_a"], row["part_b"]): row["type_of_connection"] for _, row in df.iterrows()}
nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=9, label_pos=0.3)

plt.title(f"Node Graph of Part {df_product['id'].values[0]}: {df_product['brand'].values[0]} {df_product['model'].values[0]}")
plt.show()

However in the following picture you can see that sometimes the connection lines are too short to fit the label, or connection lines are intersecting. What can I do? Tried messing with k value or scale but it does not seem to help

Share Improve this question edited Mar 13 at 11:01 kucb asked Mar 13 at 10:41 kucbkucb 375 bronze badges 1
  • @BenGrossman thanks a lot; this I can continue with – kucb Commented Mar 17 at 8:25
Add a comment  | 

1 Answer 1

Reset to default 1

Unfortunately, networkx doesn't have a graph layout function (that I know of) that allows you to place constraints on the length of connections. Also, spring_layout (which is what you have opted for and the networkx default) tends to behave poorly for disconnected graphs; the connected components will be slowly pushed apart if the algorithm is allowed to go on for too many iterations.

The approach that I think works best here is to plot the two connected components in separate subplots. I also found it useful to move the label position back into the center of the edge.

Here's some code that does this

df = pd.DataFrame({
    "part_a": [1, 2, 2, 4, 2, 2,  9,  9,  6, 7, 8,  8,  8,  8, 10], 
    "part_b": [2, 3, 5, 5, 9, 10, 11, 14, 7, 8, 13, 12, 15, 16, 9],
    "type_of_connection": ["snap-fit", 
                           "snap-fit",
                            "screw", 
                            "screw", 
                            "snap-fit", 
                            "screw", 
                            "clip", 
                            "snap-fit",
                            "screw",
                            "screw", 
                            "screw", 
                            "snap-fit",
                            "screw", 
                            "other",
                            "screw"]})

G = nx.Graph()

# add nodes
nodes = set(df["part_a"]).union(set(df["part_b"]))
G.add_nodes_from(nodes)

# add edges
for _, row in df.iterrows():
    G.add_edge(row["part_a"], row["part_b"], type=row["type_of_connection"])

components = list(nx.connected_components(G))
n = len(components)

all_edge_labels = {(row["part_a"], row["part_b"]): row["type_of_connection"] for _, row in df.iterrows()}

# draw
plt.figure(figsize=(10, 6))
for i, component in enumerate(components, 1):
    H = nx.induced_subgraph(G, component)
    pos = nx.spring_layout(H, k=0.1, scale=2)
    edge_labels = {(a, b): conn_type for (a,b), conn_type in all_edge_labels.items() if a in component}
    plt.subplot(1, n, i)
    nx.draw(H, pos, with_labels=True, node_size=700, node_color="lightblue", edge_color="gray", alpha=0.8)
    nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=9, label_pos=0.5)

plt.show()

This isn't guaranteed to completely remove node on edge-label overlap, but I found that after 1-3 tries I seem to end up with a "lucky" layout with the overlap removed. Here's an example

For some alternative strategies, you could use the same method but reduce the iterations parameter of nx.spring_layout (somewhere between 5 to 10 seems to work well here; the default is 50) and you could try a completely different layout function (nx.planar_layout seems to do surprisingly well here, but I don't think you can guarantee its performance for more complicated graphs).

发布评论

评论列表(0)

  1. 暂无评论