when I pass multigraph numpy adjacency matrix to networkx (using from_numpy_matrix function) and then try to draw the graph using matplotlib, it ignores the multiple edges.
how can I make it draw multiple edges as well ?
when I pass multigraph numpy adjacency matrix to networkx (using from_numpy_matrix function) and then try to draw the graph using matplotlib, it ignores the multiple edges.
how can I make it draw multiple edges as well ?
Graphviz does a good job drawing parallel edges. You can use that with NetworkX by writing a dot file and then processing with Graphviz (e.g. neato layout below). You'll need pydot or pygraphviz in addition to NetworkX
In [1]: import networkx as nx
In [2]: G=nx.MultiGraph()
In [3]: G.add_edge(1,2)
In [4]: G.add_edge(1,2)
In [5]: nx.write_dot(G,'multi.dot')
In [6]: !neato -T png multi.dot > multi.png
On NetworkX 1.11 and newer, nx.write_dot
doesn't work as per issue on networkx github. The workaround is to call write_dot
using
from networkx.drawing.nx_pydot import write_dot
or
from networkx.drawing.nx_agraph import write_dot
!neato -T png multi.dot > multi.png
. Can somebody explain me? –
Salutary You can use matplotlib directly using the node positions you calculate.
G=nx.MultiGraph ([(1,2),(1,2),(1,2),(3,1),(3,2)])
pos = nx.random_layout(G)
nx.draw_networkx_nodes(G, pos, node_color = 'r', node_size = 100, alpha = 1)
ax = plt.gca()
for e in G.edges:
ax.annotate("",
xy=pos[e[0]], xycoords='data',
xytext=pos[e[1]], textcoords='data',
arrowprops=dict(arrowstyle="->", color="0.5",
shrinkA=5, shrinkB=5,
patchA=None, patchB=None,
connectionstyle="arc3,rad=rrr".replace('rrr',str(0.3*e[2])
),
),
)
plt.axis('off')
plt.show()
G.edges(keys=True)
(indexes the multiple edges between two nodes), define a text position, e.g. a simple one would be text_pos = ((pos[e[0]][0]+pos[e[1]][0])/2+0.1*pos[e[2]], (pos[e[0]][1]+pos[e[1]][1])/2+0.1*pos[e[2]] )
, then after the arrow annotation part, put ax.text(text_pos[0], text_pos[1], text, ha='center')
–
Kennykeno You can use pyvis package.
I just copy-paste this code from my actual project in Jupyter notebook.
from pyvis import network as pvnet
def plot_g_pyviz(G, name='out.html', height='300px', width='500px'):
g = G.copy() # some attributes added to nodes
net = pvnet.Network(notebook=True, directed=True, height=height, width=width)
opts = '''
var options = {
"physics": {
"forceAtlas2Based": {
"gravitationalConstant": -100,
"centralGravity": 0.11,
"springLength": 100,
"springConstant": 0.09,
"avoidOverlap": 1
},
"minVelocity": 0.75,
"solver": "forceAtlas2Based",
"timestep": 0.22
}
}
'''
net.set_options(opts)
# uncomment this to play with layout
# net.show_buttons(filter_=['physics'])
net.from_nx(g)
return net.show(name)
G = nx.MultiDiGraph()
[G.add_node(n) for n in range(5)]
G.add_edge(0, 1, label=1)
G.add_edge(0, 1, label=11)
G.add_edge(0, 2, label=2)
G.add_edge(0, 3, label=3)
G.add_edge(3, 4, label=34)
plot_g_pyviz(G)
net.show_buttons(filter_=['physics'])
and copy paste JS code. using-the-configuration-ui-to-dynamically-tweak-network-settings –
Wedekind Warning: When cdn_resources is 'local' jupyter notebook has issues displaying graphics on chrome/safari. Use cdn_resources='in_line' or cdn_resources='remote' if you have issues viewing graphics in a notebook.
I tried adding pvnet.Network.cdn_resources = 'in_line'
/remote as the first line of the function, but I got the same error. –
Kennykeno Refer to atomh33ls's answer
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import random as rd
column_from = 'from_here'
column_to = 'to_there'
column_attribute = 'edges_count'
# test data
pdf = pd.DataFrame([
['a', 'b', 3],
['b', 'a', 1],
['a', 'c', 1],
['b', 'c', 1],
['a', 'd', 1],
['e', 'b', 2],
['c', 'f', 1],
['f', 'g', 1]],
columns=[column_from, column_to, column_attribute])
with pd.option_context('display.max_rows', None, 'display.max_columns', None): # more options can be specified also
print(pdf)
def get_adjacency_matrix(pdf):
id_set = set(pdf[column_from].drop_duplicates().values.tolist() +
pdf[column_to].drop_duplicates().values.tolist())
id_dict_kv = {k : v for k, v in enumerate(id_set)}
id_dict_vk = {v : k for k, v in id_dict_kv.items()}
count = len(id_set)
adjacency_matrix = np.zeros([count, count], dtype='int32')
for row in pdf.itertuples():
index_from = id_dict_vk[getattr(row, column_from)]
index_to = id_dict_vk[getattr(row, column_to)]
adjacency_matrix[index_from, index_to] += getattr(row, column_attribute)
label_mapping = id_dict_kv
return adjacency_matrix, label_mapping
def pdf_to_MDG(pdf):
adjacency_matrix, label_mapping = get_adjacency_matrix(pdf)
G = nx.from_numpy_matrix(adjacency_matrix, parallel_edges=True, create_using=nx.MultiDiGraph())
G = nx.relabel_nodes(G, label_mapping)
return G
MDG = pdf_to_MDG(pdf)
edges_data = MDG.edges.data(column_weight)
print(edges_data)
#—————————————————————————————just see the below: draw MultiDiGraph—————————————————————————————————
pos = nx.spring_layout(MDG, seed = 1)
nx.draw(MDG, pos, with_labels=True, edge_color = (1,1,1))
for e in MDG.edges:
plt.gca().annotate("",
xy=pos[e[1]],
xycoords='data',
xytext=pos[e[0]],
textcoords='data',
arrowprops=dict(arrowstyle="->", color="0",
shrinkA=15, shrinkB=15,
patchA=None, patchB=None,
connectionstyle="arc3,rad=rrr".replace('rrr',str(rd.random()*0.5+0.1)))
)
plt.axis('off')
plt.show()
output:
from_here to_there edges_count
0 a b 3
1 b a 1
2 a c 1
3 b c 1
4 a d 1
5 e b 2
6 c f 1
7 f g 1
[('c', 'f', 1), ('e', 'b', 1), ('e', 'b', 1), ('b', 'c', 1), ('b', 'a', 1), ('f', 'g', 1), ('a', 'c', 1), ('a', 'd', 1), ('a', 'b', 1), ('a', 'b', 1), ('a', 'b', 1)]
Very much building on the answer of @Lee, but wanting to get labels on the nodes and wanting the arrows to point in the correct direction, I arrived at the following:
from matplotlib import pyplot as plt
G = <YOUR MULTIGRAPH HERE>
pos = nx.random_layout(G)
names = {name: name for name in G.nodes}
nx.draw_networkx_nodes(G, pos, node_color = 'b', node_size = 250, alpha = 1)
nx.draw_networkx_labels(G,pos,names,font_size=12,font_color='w')
ax = plt.gca()
for e in G.edges:
ax.annotate("",
xy=pos[e[1]], xycoords='data',
xytext=pos[e[0]], textcoords='data',
arrowprops=dict(arrowstyle="->", color="0",
shrinkA=10, shrinkB=10,
patchA=None, patchB=None,
connectionstyle="arc3,rad=rrr".replace('rrr',str(0.3*e[2])
),
),
)
plt.axis('off')
plt.show()
© 2022 - 2024 — McMap. All rights reserved.