I am trying to visualize a bipartite graph that has about 300,000 nodes total. I'm using my helper function below.
def plot_network(G):
pos = nx.spring_layout(G)
plt.figure(figsize=(10,10))
nx.draw_networkx(G, pos, iterations=20, node_grouping='bipartite',
with_labels=False, node_size = 5)
plot_network(G)
When I try to visualize the Graph in its entirety, the following errors pops up in the IPython cell and the process just hangs there forever:
C:\Users\user\AppData\Roaming\Python\Python36\site-packages\networkx\drawing\layout.py:499: RuntimeWarning:
invalid value encountered in sqrt
I tried visualizing smaller graphs by taking random samples of my data and it has worked...until the samples go above 9000 nodes.
I am not sure how to interpret the error I'm getting, but it seems graph size is a factor. So, is there a limitation on the size of graphs I can visualize in Networkx? Is there anyway I can get around this?
It seems Networkx just couldn't allocate enough space for all the nodes, try increase the figsize or shrink node_size first. If neither of those works, try upgrade the networkx package with pip install networkx --upgrade since it seems like you're not using the latest version of networkx.
In addition to Bubble Bubble's answer suggestions, try using a simpler layout algorithm. Originally I was hitting this error using spring_layout, but I found circular works.
fig, axs = plt.subplots(1,1, figsize=(25,25))
# Define node positions using layout algo
# pos = nx.spring_layout(G, center=(1,1), k=40, iterations=5) # returns error
pos = nx.circular_layout(G)
# draw
nx.draw(G,axis=axs, pos=pos, node_size=1)
Related
I would like to obtain something similar to this:
using the python library networkx. I can generate a similar directed graph using the following code:
import matplotlib.pyplot as plt
import networkx as nx
G = nx.DiGraph()
G.add_edge('1','2')
G.add_edge('1','3')
G.add_edge('3','2')
G.add_edge('3','4')
G.add_edge('4','3')
nx.draw(G, node_color='w', edgecolors='k', width=2.0, with_labels=True)
plt.show()
which produces:
However, the arrows between the nodes 3 and 4 are superimposed, and it just looks as a single arrow with two heads. Would it be possible to separate them slightly, in order to make more evident the fact that there are two edges over there and not just one? (I know that it can be done using pygraphviz, but I am trying to do it using matplotlib).
I forked the networkx drawing utilities some time ago to work around this and several other issues I have had. The package is called netgraph, and supports drawing of networkx and igraph graph structures (as well as simple edge lists).
It uses matplotlib under the hood, and exposes the created artists so that it easy to manipulate them further even if there is not in-built functionality to do so.
#!/usr/bin/env python
"""
https://stackoverflow.com/questions/61412323/separate-edge-arrows-in-python-networkx-directed-graph
"""
import matplotlib.pyplot as plt
import networkx as nx
import netgraph
G = nx.DiGraph()
G.add_edge('1','2')
G.add_edge('1','3')
G.add_edge('3','2')
G.add_edge('3','4')
G.add_edge('4','3')
netgraph.draw(G, node_color='w', edge_color='k', edge_width=2.0, node_labels={str(ii) : str(ii) for ii in range(1,5)})
plt.show()
You'll need a MultiDiGraph for multiple edges between two nodes:
G = nx.MultiDiGraph()
G.add_edge('1','2')
G.add_edge('1','3')
G.add_edge('3','2')
G.add_edge('3','4')
G.add_edge('4','3')
To visualise the network you could use Graphviz which does display parallel edges. You could write the graph in dot and display the graph with graphviz.Source:
from networkx.drawing import nx_pydot
from graphviz import Source
nx_pydot.write_dot(G, 'multig.dot')
Source.from_file('multig.dot')
I want to draw two graphs are almost same, the only difference is that the second one will have some edges grayed out. And I want nodes in the second graph stay exactly where they are in the first graph.
You need to define the optional pos argument.
In your case using circular layout pos = nx.circular_layout(G). Then you call the plotting commands like nx.draw(G, pos, other_arguments...).
I try to make the simplest graph in networkx:
import networkx as nx
G = nx.Graph()
G.add_edge('x','y')
and that draw it:
nx.draw_networkx(G)
I have something like this:
which is absolutely wrong, because I created a graph with only two nodes and one edge between it.
I am able to reproduce a figure that is almost identical to this, but to do so I do the following:
G=nx.Graph()
G.add_node('y')
nx.draw_networkx(G)
G.add_edge('x','y')
nx.draw_networkx(G)
The first draw command results in 'y' being at (0,0). The second draw command generates new coordinates for the nodes, but it does not remove the first drawing of node 'y'.
I believe this is probably what you actually did. The code you've provided will behave as you expected it to.
I'm trying to produce an animation of a networkx graph changing over time. I'm using the networkx_draw utilities to create matplotlib figures of the graph, and matplotlib's ArtistAnimation module to create an animation from the artists networkx produces. I've made a minimum reproduction of what I'm doing here:
import numpy as np
import networkx as nx
import matplotlib.animation as animation
import matplotlib.pyplot as plt
# Instantiate the graph model
G = nx.Graph()
G.add_edge(1, 2)
# Keep track of highest node ID
G.maxNode = 2
fig = plt.figure()
nx.draw(G)
ims = []
for timeStep in xrange(10):
G.add_edge(G.maxNode,G.maxNode+1)
G.maxNode += 1
pos = nx.drawing.spring_layout(G)
nodes = nx.drawing.draw_networkx_nodes(G, pos)
lines = nx.drawing.draw_networkx_edges(G, pos)
ims.append((nodes,lines,))
plt.pause(.2)
plt.cla()
im_ani = animation.ArtistAnimation(fig, ims, interval=200, repeat_delay=3000,blit=True)
im_ani.save('im.mp4', metadata={'artist':'Guido'})
The process works fine while displaying the figures live, it produces exactly the animation I want. And it even produces a looping animation in a figure at the end of the script, again what I want, which would suggest that the animation process worked. However when I open the "im.mp4" file saved to disk, it is a blank white image which runs for the expected period of time, never showing any of the graph images which were showed live.
I'm using networkx version 1.11, and matplotlib version 2.0. I'm using ffmpeg for the animation, and am running on a Mac, OSX 10.12.3.
What am I doing incorrectly?
The short answer: If you don't want to have an empty animation, do not clear the axes! I.e. remove the line plt.cla(). You should then also remove the initial nx.draw(G), because this is not added to the ims array and would otherwise stick around in every frame of the animation.
The reasons and a longer explanation can be found in this question,
Matplotlib video creation, where a similar case is tackled.
The drawback is of course that when removing the plt.cla() you'll end up with a crowded animation on screen; so you need to decide whether to plot on screen or whether to save beforehands.
I encountered a problem when trying to plot a graph with many nodes using NetworkX and graphviz_layout. More specifically, the arguments that pass into nx.graphviz_layout do not help at all. Attached is the code I use:
G=some_graph()
import matplotlib.pyplot as plt
plt.figure(figsize=(32,32))
# use graphviz to find radial layout
pos=nx.graphviz_layout(G,prog="dot",
root=1000,
args='-splines=true -nodesep=0.6 -overlap=scalexy'
)
nx.draw(G,pos,
with_labels=True,
alpha=0.5,
node_size=600,
font_size=10
)
plt.savefig("imagenet_layout.png")
No matter how I change "args" in nx.graphviz_layout, the output image would be the same, and all nodes overlap with each other. Could anybody help me with this? Thanks!
For me it seems that in order to give args to the prog you need to use the format '-G' +'argsname=x'. I noticed in the example they give the docs the arg epsilon asG.draw(‘test.ps’,prog=’twopi’,args=’-Gepsilon=1’). So I tried out that pattern as shown below. I just added G in front of the arguments. Now, these arguments vary quite a bit depending on what prog you use, so you definitely want to use 'dot' for what you want to accomplish. You can see all the possible arguments and how they work with each prog here. For my porpoises, I needed to have the nodesep=0.01.
G=some_graph()
import matplotlib.pyplot as plt
plt.figure(figsize=(32,32))
# use graphviz to find radial layout
pos=nx.graphviz_layout(G,prog="dot",
root=1000,
args='-Gsplines=true -Gnodesep=0.6 -Goverlap=scalexy'
)
nx.draw(G,pos,
with_labels=True,
alpha=0.5,
node_size=600,
font_size=10
)
plt.savefig("imagenet_layout.png")
Here is a comparison of my graph with and without the args, with code. First without the args.
A = nx.nx_agraph.to_agraph(G) # convert to a graphviz graph
A.layout(prog='neato') # neato layout
#A.draw('test3.pdf')
A.draw('test3.png' )
With args
A = nx.nx_agraph.to_agraph(G) # convert to a graphviz graph
A.layout(prog='dot') # neato layout
#A.draw('test3.pdf')
A.draw('test3.png',args='-Gnodesep=0.01 -Gfont_size=1', prog='dot' )
SO you can see that the images are different once I got the args to work.
My reading of the documentation for pygraphviz suggests that overlap does not work with dot.
For nodesep :
In dot, this specifies the minimum space between two adjacent nodes in the same rank, in inches.
It's not clear if the overlaps you are observing are between nodes in the same rank or between the ranks. If it is just between ranks, you may want to modify ranksep.
I do see that you are setting the positions, and then later you set the nodesize, and you are making node_size quite a bit larger than the default (600 vs 300). Since it does not know what node_size you are going to use when it finds pos, using a large enough node_size will cause overlap.
So I would recommend setting node_size to be the default, and if overlap remains, setting node_size to be smaller. If you're having issues with the between or within rank separations being out of proportion, then play with ranksep and nodesep.
About “overlap”,do you mean there are nodes drawed last time in current output? If so, add "plt.clf()"after"plt.savefig(****)"!
About the node_size, the default is 300, but the unit is not given in the document. I am using networkx these days too, can you tell me the unit if you know that?