Separate edge arrows in python/networkx directed graph - python

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')

Related

Change graph layout (aka. node positioning algorithm) in pyvis

When using networkx.draw() it is possible to specify different node positioning algorithms that change the graph layout using the pos keyword argument. For example:
import networkx as nx
import matplotlib.pyplot as plt
# create a graph
G = nx.dodecahedral_graph()
# draw with different layouts
plt.figure()
nx.draw(G,pos=nx.circular_layout(G))
plt.figure()
nx.draw(G,pos=nx.spring_layout(G))
gives you these two different layouts:
Is it possible to do this using pyvis?
Yes, mainly there are four types:
BarnesHut
ForceAtlas2Based
Repulsion
HierachicalRepulsion
you can check their effects by setting the option show_buttons(filter_=["physics"]):
net = Network(...)
net.show_buttons(filter_=["physics"])
on the drop-down that appears (the option 'solver')

creating dynamic graph python NetworkX

I am attempting to build a dynamic graph in python using networkX. I've got some code to build a static graph. I'm looking for some advice as to how to alter it for dynamic graphing to improve the visualization, maybe using networkx d3 or plotly. The context is to graph a conversation.
nx.draw_networkx(speech, pos=nx.spring_layout(speech))
plt.draw()
static_images_dir = "./static/images"
if not os.path.exists(static_images_dir):
os.makedirs(static_images_dir)
plt.savefig(os.path.join(static_images_dir, "speech.png"))
#plt.show()
plt.close()
return speech
I am not sure if that's what you mean by dynamic, but maybe something like this?
import networkx as nx
import numpy as np
import matplotlib.pylab as plt
import hvplot.networkx as hvnx
import holoviews as hv
from bokeh.models import HoverTool
hv.extension('bokeh')
A = np.matrix([[0,1,1,0,0],[1,0,1,0,0],[1,1,0,1,1],[0,0,1,0,1],[0,0,1,1,0]])
G = nx.from_numpy_matrix(A)
pos = nx.spring_layout(G)
nx.draw_networkx(G, pos, node_color='lightgray')
plt.show()
hvnx.draw(G, pos, node_color='lightgray').opts(tools=[HoverTool(tooltips=[('index', '#index_hover')])])
Which produces the output:
Normal static graph
Dynamic graph you can interact with

Python Graphs: Latex Math rendering of node labels

I am using the following code to create a pygraphviz graph. But is it possible to make it render latex math equations (see Figure 1)? If not, is there an alternative python library that plots similar graphs but supports latex rendering ?
import networkx as nx
from networkx.drawing.nx_agraph import to_agraph
G=nx.DiGraph()
G.add_node(1,color='blue',style='filled',
fillcolor='white',shape='square', label="$3x+2$")
G.add_node(2)
G.add_node(3)
G.add_edge(1, 2)
G.add_edge(1, 3)
G.add_edge(3, 4)
A = to_agraph(G)
A.layout('dot')
A.draw('test1.png')
This results in the following figure
Figure 1
Maybe https://dot2tex.readthedocs.org/en/latest/ will work for you?
Try
import dot2tex
texcode = dot2tex.dot2tex(A.to_string(), format='tikz', crop=True)

How to show node labels when using matplotlib.pyplot?

I'm using Python to conduct social network analysis, very simple kind, and as a newbie (to both SNA and Python).
When drawing a graph using Terminal on my mac, I've tried every method I can but still can only draw nodes and edges, but no label of nodes in or beside them.
What scripts should I use to make the labels visible?
>>> import networkx as nx
>>> import networkx.generators.small as gs
>>> import matplotlib.pyplot as plt
>>> g = gs.krackhardt_kite_graph()
>>> nx.draw(g)
>>> plt.show()
EdChum gave a good answer. Another option which will by default not show the axes and produces a graph that takes up slightly more of the figure is to use nx.draw but give it the argument with_labels = True. (for nx.draw, you need to set with_labels to True, but for nx.draw_networkx it defaults to True).
import networkx as nx
import networkx.generators.small as gs
import matplotlib.pyplot as plt
g = gs.krackhardt_kite_graph()
nx.draw(g,with_labels=True)
plt.savefig('tmp.png')
Be aware that there is a bug such that sometimes plt.show() will not show the labels. From what I've been able to tell, it's not in networkx, but rather has something to do with the rendering. It saves fine, so I haven't worried about following up on it in detail. It shows up for me using ipython on a macbook. Not sure what other systems it's on. More detail at pylab/networkx; no node labels displayed after update
Try using draw_networkx:
import networkx as nx
import networkx.generators.small as gs
import matplotlib.pyplot as plt
g = gs.krackhardt_kite_graph()
nx.draw_networkx(g)
plt.show()
This results in:
with_labels is by default True so not necessary to specify

open .dot formatted graph from python

As I can plot curves with matplotlib in python, I wonder if there are any ways to show .dot graphs somehow. I have a string describing a graph:
graph name{
1--2;
}
Somehow pass it to a viewer program?
Maybe not exactly what you intend to do, but you can use pygraphviz and print your graph to a file:
import pygraphviz as pgv
G=pgv.AGraph()
G.add_edge('1','2')
G.layout()
G.draw('file.png')
(or you can just import a .dot file using G = pgv.AGraph('file.dot'))
Then you can always use Image or openCV to load your file and show it in the viewer.
I don't think pygraphviz allows you to to that directly though.
EDIT:
I recently found out another way and remembered your question: NetworkX lets you do that. Here's how:
Either create your graph using NetworkX directly. It is convenient that most of the commands of NetworkX are the same as those in pygraphviz. Then simply send to matplotlib and plot it there:
import networkx as nx
import matplotlib.pyplot as plt
G = nx.Graph()
G.add_edge('1','2')
nx.draw(G)
plt.show()
Or you can import your .dot file through pygraphviz and then transform it into a networkx object:
import pygraphviz as pgv
import networkx as nx
import matplotlib.pyplot as plt
Gtmp = pgv.AGraph('file.dot')
G = nx.Graph(Gtmp)
nx.draw(G)
plt.show()
So now you have more options :)

Categories

Resources