I'm using this bit of code from a deap symbolic regression example problem and the graph displays fine but I want the nodes to expand as rounded rectangles to fit the text automatically. (I don't want to just specify the node size through trial and error). How would I do that?
# show tree
import matplotlib.pyplot as plt
import networkx
nodes, edges, labels = gp.graph(bests[0])
graph = networkx.Graph()
graph.add_nodes_from(nodes)
graph.add_edges_from(edges)
pos = networkx.graphviz_layout(graph, prog="dot")
plt.figure(figsize=(7,7))
networkx.draw_networkx_nodes(graph, pos, node_size=900, node_color="w")
networkx.draw_networkx_edges(graph, pos)
networkx.draw_networkx_labels(graph, pos, labels)
plt.axis("off")
plt.show()
Node Size. Altering node size globally is, again, quite simple via a keyword argument in the . draw() method — just specify node_size!
For NetworkX, a graph with more than 100K nodes may be too large. I'll demonstrate that it can handle a network with 187K nodes in this post, but the centrality calculations were prolonged. Luckily, there are some other packages available to help us with even larger graphs.
The draw() function of networkx library is used to draw the graph G with matplotlib. You can make customization to the nodes by passing these parameters to the function: node_size, node_color, node_shape, alpha, linewidths.
The argument node_size accepts both scalar and vector values. While scalar makes all nodes of equal sizes, vector helps you to specify individual values in a list to be used for each node. If your node ids are strings then the following strategy works quite well.
Just change the size argument to a list in networkx.draw_networkx_nodes
based on the length of each node id. Choose the_base_size
appropriately.
networkx.draw_networkx_nodes(graph, pos,
node_size=[len(v) * the_base_size for v in graph.nodes()],
node_color="w")
You can adapt this to the case where you can handles labels too.
***However, I am not sure if one-to-one correspondence will be preserved while it chooses the node sizes from the list based on label sizes. Do share your results. I have personally used it for string node ids and it works well.
There isn't a simple way to do that with matplotlib and networkx (of course it is possible with enough code).
Graphviz does a really excellent job with labels and it is easy to write dot format files from networkx to process with Graphviz.
Also take a look at https://github.com/chebee7i/nxpd which might do exactly what you need.
I liked @mathfux's solution because it positions the arrows correctly in directed graphs. But it needs some tweaks to solve that correspondence problem mentioned (lists of positions and colours are in layout order, not node order); also to handle zero-based indexing for lists. I also found the sizes work by a square law, rather than linearly. Here's an improved version with colours, using Kamada Kwai rather than Spring so the layout doesn't change each time.
import pandas as pd
import matplotlib.pyplot as plt
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([(0,1), (1, 1), (1, 7), (2, 1), (2, 2), (2, 3),
(2, 6), (3, 5), (4, 3), (5, 4), (5, 8),
(5, 9), (6, 4), (7, 2), (7, 6), (8, 7)])
labelList="zero one twotwotwo three four five six seven eighteighteight nine".split(' ')
positions=nx.kamada_kawai_layout(G)
plt.figure(figsize =(9, 9))
nx.draw_networkx(G,
node_color =['C{}'.format(i) for i in positions],
pos=positions,
labels={idx: val for idx, val in enumerate(labelList)},
node_size=[len(labelList[i])**2 * 60 for i in positions]
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With