Python – How to display directed multigraph with different node shapes using networkx.draw()

Question:

I have seen a similar question here and its accepted answer for a digraph. The idea for a digraph is to add nodes to as many different subgraphs as there are node shapes (‘o’, ‘d’, ‘s’, etc.), then add edges between nodes and finally plot each using the Python networkx library.

For a multidigraph, I tried the sample code below without adding edges, just to check that node shapes are as required. After poring over the official doc, I only can draw a blank graph (literally). So are the files to which I write.

I’m missing something basic. Any pointer welcome.

import matplotlib.pyplot as plt
import networkx as nx
import pydot

rn = list()
rn_colmap = []                     # round node color_map
rn_sizmap = []                     # round node

sn = list()
sn_colmap = []                     # square node color_map
sn_sizmap = []                     # square node size_map

g_out = "/whatever/path/to/file_out"

G = nx.MultiDiGraph()

for n_idx in range(len(my_nodes)):
    if my_nodes[n_idx] in nodes_A:
        rn.append(my_nodes[n_idx])
        rn_colmap.append('r')
        rn_sizmap.append(300)
    else:
        sn.append(my_nodes[n_idx])
        sn_colmap.append('b')
        sn_sizmap.append(600)

rnG = G.subgraph(rn)
snG = G.subgraph(sn)

rn_pos = nx.spring_layout(rnG,iterations=3)
sn_pos = nx.spring_layout(snG,iterations=3)

plt.figure(figsize=(12,12), frameon=False)
    
nx.draw(rnG,
        rn_pos,
        node_size = rn_sizmap,
        node_color = rn_colmap,
        node_shape = 'o',
        alpha=0.9,
        with_labels = True,
        font_size=12,
        font_weight='bold',
        font_family='sans-serif',
       )

nx.draw(snG,
        sn_pos,
        node_size = sn_sizmap,
        node_color = sn_colmap,
        node_shape = 's',
        alpha=0.9,
        with_labels = True,
        font_size=12,
        font_weight='bold',
        font_family='sans-serif',
       )

nx.drawing.nx_pydot.write_dot(G, g_out + '.dot')
plt.savefig(g_out + '.png')
nx.write_gml(G,g_out + '.gml.gz')    

plt.show()

G.clear()
plt.close()
Asked By: Cbhihe

||

Answers:

I just realized that I need to properly declare my sub-graphs before populating them with the appropriate complete graph’s nodes of interest.

So the code becomes:

import matplotlib.pyplot as plt
import networkx as nx
import pydot

rn = list()
rn_colmap = []                     # round node color_map
rn_sizmap = []                     # round node

sn = list()
sn_colmap = []                     # square node color_map
sn_sizmap = []                     # square node size_map

g_out = "/whatever/path/to/file_out"

G = nx.MultiDiGraph()
rnG = G.__class__()                # declare/instantiate sub-graphs
snG = G.__class__()

for n_idx in range(len(my_nodes)):
    G.add_node(my_nodes[n_idx])    # populate main graph
    
    if my_nodes[n_idx] in nodes_A:
        rn.append(my_nodes[n_idx])
        rn_colmap.append('r')
        rn_sizmap.append(300)
    else:
        sn.append(my_nodes[n_idx])
        sn_colmap.append('b')
        sn_sizmap.append(600)

rnG = G.subgraph(rn)
snG = G.subgraph(sn)

# Remaining code is identical to corresponding code section in OP:

rn_pos = nx.spring_layout(rnG,iterations=3)
sn_pos = nx.spring_layout(snG,iterations=3)

plt.figure(figsize=(12,12), frameon=False)

nx.draw(rnG,
        rn_pos,
        node_size = rn_sizmap,
        node_color = rn_colmap,
        node_shape = 'o',
        alpha=0.9,
        with_labels = True,
        font_size=12,
        font_weight='bold',
        font_family='sans-serif',
       )

nx.draw(snG,
        sn_pos,
        node_size = sn_sizmap,
        node_color = sn_colmap,
        node_shape = 's',
        alpha=0.9,
        with_labels = True,
        font_size=12,
        font_weight='bold',
        font_family='sans-serif',
       )

nx.drawing.nx_pydot.write_dot(G, g_out + '.dot')
plt.savefig(g_out + '.png')
nx.write_gml(G,g_out + '.gml.gz')    

plt.show()

G.clear()
plt.close()
Answered By: Cbhihe