I am having trouble with large graph visualization in python and networkx. The graph is wish to visualize is directed, and has an edge and vertex set size of 215,000 From the documenation (which is linked at the top page) it is clear that networkx supports plotting with matplotlib and GraphViz. In matplotlib and networkx the drawing is done as follows:
import
networkx as nx
import matplotlib.pyplot as plt
#Let g be a graph that I created
nx.draw(g)
I get a memory error after nx.draw(g), afterwards you would normally do plt.show() or plt.[some_function] to save the file in a format for efficient and so forth.
Next I tried GraphViz. From the wikipedia page the dot format is used for directed graphs and I created a dot file:
nx.write_dot(g, "g.dot")
This worked well and I had a dot file in my current directory that is 12 megabytes. Next I ran the dot program (part of graphviz to create a postscript file):
dot -Tps g.dot -o g.ps
This slows down my computer, runs for a few minutes and then display Killed in the terminal. So it never could execute... While reading the documentation for graphviz it seems that only undirected graphs were supported for large graph visualization.
Question:
With these two unsuccessful attempts can anyone show me how to visualize my large graph using python and networkx with about 215,000 vertices and 215,000 edges? I suspect as with Graphviz I will have to output into an intermediate format (although this shouldn't be that hard it won't be as easy as a builtin function) and then use another tool to read the intermediate format and then output a visualization.
So, I am looking for the following:
Output graph from networkx into an intermediate format
With new package/software/tool (ideally python-interactive) read intermediate format and visualize the large graph
If you need more information let me know!
from matplotlib import pylab
import networkx as nx
def save_graph(graph,file_name):
#initialze Figure
plt.figure(num=None, figsize=(20, 20), dpi=80)
plt.axis('off')
fig = plt.figure(1)
pos = nx.spring_layout(graph)
nx.draw_networkx_nodes(graph,pos)
nx.draw_networkx_edges(graph,pos)
nx.draw_networkx_labels(graph,pos)
cut = 1.00
xmax = cut * max(xx for xx, yy in pos.values())
ymax = cut * max(yy for xx, yy in pos.values())
plt.xlim(0, xmax)
plt.ylim(0, ymax)
plt.savefig(file_name,bbox_inches="tight")
pylab.close()
del fig
#Assuming that the graph g has nodes and edges entered
save_graph(g,"my_graph.pdf")
#it can also be saved in .svg, .png. or .ps formats
This answers your first issue.
Networkx does not have the facility to zoom into nodes. Use Gephi for this functionality.
Gephi accepts an edge list in CSV format and produces a visualization, where zooming can be done interactively.
Related
NetworkX is powerful but I was trying to plot a graph which shows node labels by default and I was surprised how tedious this seemingly simple task could be for someone new to Networkx. There is an example which shows how to add labels to the plot.
https://networkx.github.io/documentation/latest/examples/drawing/labels_and_colors.html
The problem with this example is that it uses too many steps and methods when all I want to do is just show labels which are same as the node name while drawing the graph.
# Add nodes and edges
G.add_node("Node1")
G.add_node("Node2")
G.add_edge("Node1", "Node2")
nx.draw(G) # Doesn't draw labels. How to make it show labels Node1, Node2 along?
Is there a way to make nx.draw(G) show the default labels (Node1, Node2 in this case) inline in the graph?
tl/dr: just add with_labels=True to the nx.draw call.
The page you were looking at is somewhat complex because it shows how to set lots of different things as the labels, how to give different nodes different colors, and how to provide carefully control node positions. So there's a lot going on.
However, it appears you just want each node to use its own name, and you're happy with the default color and default position. So
import networkx as nx
import pylab as plt
G=nx.Graph()
# Add nodes and edges
G.add_edge("Node1", "Node2")
nx.draw(G, with_labels = True)
plt.savefig('labels.png')
If you wanted to do something so that the node labels were different you could send a dict as an argument. So for example,
labeldict = {}
labeldict["Node1"] = "shopkeeper"
labeldict["Node2"] = "angry man with parrot"
nx.draw(G, labels=labeldict, with_labels = True)
I feel a better answer is not to use networkx to draw. They explicitly warn you that graph visualization is hard and networkx is mainly meant for graph analysis (from https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout):
Drawing
NetworkX provides basic functionality for visualizing graphs, but its main goal is to enable graph analysis rather than perform graph visualization. In the future, graph visualization functionality may be removed from NetworkX or only available as an add-on package.
Proper graph visualization is hard, and we highly recommend that people visualize their graphs with tools dedicated to that task. Notable examples of dedicated and fully-featured graph visualization tools are Cytoscape, Gephi, Graphviz and, for LaTeX typesetting, PGF/TikZ. To use these and other such tools, you should export your NetworkX graph into a format that can be read by those tools. For example, Cytoscape can read the GraphML format, and so, networkx.write_graphml(G, path) might be an appropriate choice.
thus my suggestion is to transform the graph to some format that has dedicated software for graph visualization and then draw (e.g. pydot, pygraphviz, graphviz etc). My suspicion is that pydot and pygraphviz are the best for some reason since networkx only supports those two. It seems from the docs in pygraphviz that it has a similar api so it might be the easiest to use if you already want like to use networkx (https://pygraphviz.github.io/documentation/stable/tutorial.html):
The API is very similar to that of NetworkX. Much of the NetworkX tutorial at https://networkx.org/documentation/latest/tutorial.html is applicable to PyGraphviz. See http://pygraphviz.github.io/documentation/latest/reference/api_notes.html for major differences.
In addition, pydot as of now does not really have docs (which personally bothers me. Idk if it's that it doesn't look nice on my browser or that it makes me feel that project is not being taken seriously by it's developers idk something just doesn't feel right even if it has a higher set of users pydot 15k vs pygraphviz 4k) reference: https://github.com/pydot/pydot/pull/241.
Also it seems that pygraphviz has more granular control than regular graphviz ref: Graphviz vs PyGraphViz. In addition, I don't know how to convert a networkx directly to a graphviz obj (since graphviz has the best docs and highest user base ~19k so I did prefer that), so I will go with pygraphviz for those reasons. Pygravix also has docs which although small make me happy (though not as good as graphviz but idk how to make graphviz graphs from networkx). It's hard to make these decisions but I can't stay on this forever and this seems mindful enough. Also, networkx is nice because I can transform dgl graphs to networkx too (and the relabeling was simple).
Considering those reasons let me give you the example code I wrote that does what you want using pygraphviz (but you could do it with pydot if you figured out how, transforming to pydot obj is trivial using networkx see my previous link):
# https://stackoverflow.com/questions/28533111/plotting-networkx-graph-with-node-labels-defaulting-to-node-name
import dgl
import numpy as np
import torch
import networkx as nx
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from pathlib import Path
g = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]), num_nodes=6)
print(f'{g=}')
print(f'{g.edges()=}')
# Since the actual graph is undirected, we convert it for visualization purpose.
g = g.to_networkx().to_undirected()
print(f'{g=}')
# relabel
int2label = {0: "app", 1: "cons", 2: "with", 3: "app3", 4: "app4", 5: "app5"}
g = nx.relabel_nodes(g, int2label)
# https://networkx.org/documentation/stable/reference/drawing.html#module-networkx.drawing.layout
g = nx.nx_agraph.to_agraph(g)
print(f'{g=}')
print(f'{g.string()=}')
# draw
g.layout()
g.draw("file.png")
# https://stackoverflow.com/questions/20597088/display-a-png-image-from-python-on-mint-15-linux
img = mpimg.imread('file.png')
plt.imshow(img)
plt.show()
# remove file https://stackoverflow.com/questions/6996603/how-to-delete-a-file-or-folder
Path('./file.png').expanduser().unlink()
# import os
# os.remove('./file.png')
output:
g=Graph(num_nodes=6, num_edges=5,
ndata_schemes={}
edata_schemes={})
g.edges()=(tensor([0, 0, 0, 0, 0]), tensor([1, 2, 3, 4, 5]))
g=<networkx.classes.multigraph.MultiGraph object at 0x7f8443e94250>
g=<AGraph <Swig Object of type 'Agraph_t *' at 0x7f846117a930>>
g.string()='graph "" {\n\tapp -- cons [key=0,\n\tid=0];\napp -- with [key=0,\nid=1];\napp -- app3 [key=0,\nid=2];\napp -- app4 [key=0,\nid=3];\napp -- app5 [key=0,\nid=4];\n}\n'
though I want to leave this link about pydot visualization since it seems very useful in general: Display graph without saving using pydot and probably provides the pydot answer for others if they need it. Though, I'd love to see arguments in favour of pydot.
Edit1: if you want to plot by attributed and not by label, see this answer: NetworkX node attribute drawing note that relabeling the way I suggested does not always have the intended semantics (e.g. it might join two nodes that were NOT meant to be joined).
Edit2: if you want to plot the attribute instead without self loops happening by accident see this answer: Draw more information on graph\nodes using PyGraphviz
I have a graph built with networkx and graphviz in Python using pygraphviz and networkx's graphviz_layout it is then displayed in Plotly.
I wish to change the space between nodes of the graph.
I currently have the graph displayed in plotly like this:
However, when I try to use args on the graph to change the distance between nodes like so:
pos=graphviz_layout(G,prog='dot',args='-Gnodesep="10.0" -Granksep="1.0"')
I do not see any changes on the plotly plot. Am I doing something wrong with the args?
I am visualizing various networks with networkx. Take a look at simple example
graph = nx.DiGraph()
graph.add_edge("a", "b")
graph.add_edge("a", "a")
nx.draw(graph)
plt.show()
Unfortunately, networkx plotting does not render self loops. I am aware of other feature rich packages like GraphViz and its implementation pygraphviz. However, such packages do not allow me to customize my plots (like subplots, annotations etc). I can do all of these with networkx as it can plot with matplotlib Axes. Which is very convenient for programmatic manipulations and heavy customizations. Is there way to get network plotting of GraphViz to matplotlib?
I can always embed PNG created by GraphViz into matplotlib plots using imshow. However, its results are horrible with little customization control.
It doesn’t seem like this exists yet. If you want to implement it yourself, there are a few options. If you want to leave the layout to Graphviz and just hand shapes and positions to Matplotlib, two options remain to get the data necessary for rendering:
You use the binaries (like dot) with the -Tjson option, which seems to emit all necessary data for drawing, but I didn’t find documentation for what e.g. the ops are.
You Use Graphviz as a Library. Section 2.3 (Rendering the graph) describes how to access the data.
You then feed this data into the Axes’ Artist (tutorial). Matplotlib also has a tutorial for how to draw paths.
I am not sure why you say networkx does not render self-loops. Isn't this what you are looking for?
import networkx as nx
from matplotlib import pyplot as plt
graph = nx.DiGraph()
graph.add_edges_from([("a", "b"), ("a", "a"), ("b", "b"), ("c", "b"), ("c", "c")])
nx.draw(graph, with_labels=True)
plt.show()
When using Matplotlib to generate figures with hatching (e.g. pie, bar, bubble charts), I'm having some trouble getting decent resolution out of the PDF version of the figure. Saving as EPS is fine, but as soon as I use epstopdf or MPL's savefig(*.pdf), the hatching becomes pixellated and distored... the vector nature of the image appears to have been lost.
See minimal code below.
from matplotlib import pyplot as plt
# Define hatching styles
hatching = ["/", "o"]
fig, ax = plt.subplots()
wedges, texts = ax.pie([0.4, 0.6], colors=("SteelBlue", "Tomato"))
# Apply the hatching
for j, patch in enumerate(wedges): patch.set_hatch(hatching[j])
fig.savefig("hatchtest.pdf")
I've used Gimp to zoom in on a part of the plot to illustrate the difference...
Zoomed in on the EPS figure
Zoomed in on the PDF figure
As for system specific details, I'm using Ubuntu 13.04, Python 2.7.4 with MPL 1.2.1. I've tried different backends but nothing seems to resolve this. I'd ideally like to have nice vector images in EPS and PDF so that it's all journal-friendly. Any pointers would be much appreciated.
Just a problem with Evince PDF viewer. Viewing in Adobe Reader or printing the plot gives the desired result.
I am drawing a graph with around 5K nodes in it using networkX and matplotlib. The GTK window by matplotlib has tools to zoom and visualise the graph.
Is there any way, I can save a magnified version for proper visualisation later?
import matplotlib.pyplot as plt
import networkx as nx
pos=nx.spring_layout(G) #G is my graph
nx.draw(G,pos,node_color='#A0CBE2',edge_color='#BB0000',width=2,edge_cmap=plt.cm.Blues,with_labels=True)
#plt.show()
plt.savefig("graph.png", dpi=500, facecolor='w', edgecolor='w',orientation='portrait', papertype=None, format=None,transparent=False, bbox_inches=None, pad_inches=0.1)
You have two easy options:
Up the DPI
plt.savefig("graph.png", dpi=1000)
(larger image file size)
Save as a PDF
plt.savefig("graph.pdf")
This is the best option, as the final graph is not rasterized. In theory, you should be able to zoom in indefinitely.
While not in GTK, you might want to check out NetworkX Viewer.
You may want to check this out:
plt.savefig("name.svg")
the quality is magnificent. although the dpi option is still alive.
Use this plt.savefig('name.svg') and then just upload the file to Figma -https://www.figma.com