how to draw multigraph in networkx using matplotlib or graphviz

Question:

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 ?

Asked By: Binary Baba

||

Answers:

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

enter image description here

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

Answered By: Aric

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

enter image description here

Answered By: Lee

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)

result

Answered By: cnstntn.kndrtv

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

the output img

Answered By: givedrug