7

I have a fairly large and messy network of nodes that I wish to display as neatly as possible.

This is how it's currently being displayed: example

First, I tried playing with the layout to see if it could generate a good output automatically.

I have tried many different nx layouts, but they all display similar results. I have also tried answers from all of these stack exchange questions:

How to increase node spacing for networkx.spring_layout

Drawing a huge graph with networkX and matplotlib

NetworkX - Stop Nodes from Bunching Up - Tried Scale/K parameters

Fix position of subset of nodes in NetworkX spring graph

Here is the code I am using:

import networkx as nx
import matplotlib.pyplot as plt\

def generate_plot(connections, filename):

    G=nx.Graph()
    G.add_edges_from(connections)

    nx.draw(G)

    plt.show()
    #plt.savefig(filename)

and here is the data that I am trying to display:

connections = [(0, 36), (0, 113), (2, 11), (2, 12), (2, 26), (2, 27), (2, 28), (2, 29), (2, 32), (2, 33), (2, 34), (2, 35), (2, 82), (3, 41), (4, 41), (5, 3), (6, 3), (11, 7), (11, 10), (11, 13), (11, 42), (12, 10), (12, 164), (26, 10), (26, 100), (27, 10), (27, 164), (28, 10), (28, 92), (29, 56), (29, 58), (29, 79), (29, 91), (29, 99), (29, 100), (29, 101), (29, 102), (30, 59), (30, 83), (30, 99), (31, 55), (31, 56), (31, 57), (31, 74), (31, 91), (31, 96), (31, 100), (31, 113), (31, 134), (31, 164), (32, 10), (33, 10), (34, 10), (34, 164), (35, 10), (35, 91), (35, 100), (36, 64), (36, 74), (36, 82), (36, 91), (36, 107), (36, 99), (38, 41), (39, 40), (39, 41), (39, 59), (40, 41), (40, 47), (40, 91), (40, 99), (41, 3), (41, 39), (41, 40), (43, 68), (43, 69), (45, 50), (46, 51), (46, 69), (46, 99), (47, 49), (47, 91), (47, 107), (47, 100), (47, 101), (47, 113), (48, 76), (50, 68), (50, 69), (51, 68), (51, 76), (51, 114), (52, 46), (52, 47), (52, 65), (53, 42), (53, 107), (53, 99), (53, 100), (53, 101), (53, 113), (54, 76), (55, 74), (55, 96), (55, 99), (56, 99), (56, 100), (56, 109), (57, 29), (57, 64), (57, 91), (57, 96), (57, 107), (57, 100), (58, 91), (58, 99), (58, 100), (58, 101), (58, 102), (59, 30), (59, 46), (59, 47), (59, 61), (59, 83), (59, 99), (59, 100), (59, 101), (60, 3), (60, 12), (60, 26), (60, 27), (60, 29), (60, 30), (60, 31), (60, 35), (60, 36), (60, 40), (60, 42), (60, 44), (60, 49), (60, 55), (60, 56), (60, 57), (60, 58), (60, 59), (60, 61), (60, 64), (60, 74), (60, 75), (60, 79), (60, 81), (60, 82), (60, 83), (60, 86), (60, 90), (60, 91), (60, 92), (60, 93), (60, 94), (60, 96), (60, 107), (60, 99), (60, 100), (60, 101), (60, 102), (60, 111), (60, 112), (60, 113), (60, 116), (60, 126), (60, 129), (60, 134), (60, 135), (60, 136), (60, 140), (60, 144), (60, 150), (60, 152), (60, 162), (60, 164), (60, 179), (60, 195), (61, 91), (61, 107), (61, 100), (61, 101), (61, 113), (61, 135), (62, 79), (62, 102), (63, 59), (64, 29), (64, 36), (64, 91), (64, 99), (64, 100), (64, 101), (64, 140), (65, 12), (65, 27), (65, 29), (65, 30), (65, 31), (65, 34), (65, 35), (65, 43), (65, 45), (65, 50), (65, 56), (65, 57), (65, 58), (65, 59), (65, 60), (65, 61), (65, 66), (65, 67), (65, 72), (65, 75), (65, 81), (65, 82), (65, 91), (65, 92), (65, 96), (65, 107), (65, 99), (65, 100), (65, 101), (65, 102), (65, 104), (65, 109), (65, 129), (65, 140), (65, 142), (65, 156), (65, 164), (67, 68), (67, 69), (67, 195), (68, 60), (69, 51), (69, 53), (69, 68), (69, 195), (70, 12), (70, 26), (70, 29), (70, 31), (70, 35), (70, 47), (70, 56), (70, 58), (70, 59), (70, 61), (70, 66), (70, 75), (70, 79), (70, 82), (70, 83), (70, 93), (70, 96), (70, 107), (70, 99), (70, 100), (70, 101), (70, 126), (70, 129), (70, 135), (70, 136), (70, 162), (70, 164), (71, 12), (71, 26), (71, 29), (71, 31), (71, 35), (71, 47), (71, 56), (71, 58), (71, 59), (71, 61), (71, 66), (71, 75), (71, 79), (71, 83), (71, 96), (71, 107), (71, 99), (71, 100), (71, 101), (71, 126), (71, 135), (71, 162), (71, 164), (72, 29), (72, 35), (72, 36), (72, 46), (72, 47), (72, 55), (72, 57), (72, 58), (72, 60), (72, 61), (72, 64), (72, 66), (72, 70), (72, 71), (72, 74), (72, 75), (72, 76), (72, 79), (72, 86), (72, 90), (72, 91), (72, 93), (72, 94), (72, 95), (72, 96), (72, 107), (72, 99), (72, 100), (72, 101), (72, 102), (72, 111), (72, 112), (72, 116), (72, 126), (72, 129), (72, 144), (73, 83), (74, 96), (74, 100), (75, 100), (76, 29), (76, 31), (76, 42), (76, 44), (76, 49), (76, 55), (76, 56), (76, 59), (76, 61), (76, 66), (76, 74), (76, 78), (76, 83), (76, 91), (76, 93), (76, 96), (76, 107), (76, 109), (76, 113), (76, 114), (76, 116), (76, 134), (76, 140), (77, 30), (77, 44), (77, 49), (77, 61), (77, 74), (77, 78), (77, 83), (77, 96), (77, 109), (77, 140), (78, 61), (78, 91), (78, 92), (79, 44), (79, 99), (80, 42), (80, 64), (80, 65), (80, 75), (80, 83), (80, 134), (80, 135), (80, 136), (80, 144), (80, 155), (81, 35), (81, 91), (81, 100), (82, 10), (83, 84), (83, 85), (83, 86), (83, 107), (83, 100), (84, 194), (84, 195), (87, 36), (87, 88), (87, 142), (87, 144), (88, 59), (88, 83), (88, 134), (88, 135), (88, 136), (88, 144), (88, 158), (88, 162), (89, 61), (89, 135), (89, 141), (90, 36), (91, 96), (91, 113), (93, 96), (93, 107), (93, 134), (93, 135), (94, 74), (94, 96), (95, 61), (95, 134), (95, 135), (95, 162), (96, 35), (96, 74), (96, 91), (96, 99), (96, 100), (96, 101), (98, 12), (98, 26), (98, 27), (98, 29), (98, 30), (98, 31), (98, 34), (98, 35), (98, 41), (98, 56), (98, 57), (98, 58), (98, 59), (98, 60), (98, 61), (98, 70), (98, 75), (98, 79), (98, 81), (98, 82), (98, 83), (98, 84), (98, 87), (98, 91), (98, 92), (98, 95), (98, 96), (98, 107), (98, 99), (98, 100), (98, 101), (98, 106), (98, 134), (98, 135), (98, 142), (98, 147), (98, 152), (98, 159), (99, 91), (99, 113), (99, 164), (100, 91), (100, 101), (100, 113), (100, 164), (101, 57), (101, 91), (101, 113), (101, 164), (102, 101), (103, 44), (103, 61), (103, 140), (104, 56), (104, 90), (104, 101), (104, 102), (104, 104), (104, 129), (104, 140), (105, 83), (105, 135), (106, 2), (106, 29), (106, 30), (106, 31), (106, 36), (106, 41), (106, 48), (106, 56), (106, 57), (106, 58), (106, 59), (106, 60), (106, 61), (106, 62), (106, 63), (106, 65), (106, 66), (106, 68), (106, 70), (106, 71), (106, 72), (106, 74), (106, 75), (106, 76), (106, 77), (106, 78), (106, 79), (106, 80), (106, 81), (106, 82), (106, 83), (106, 84), (106, 85), (106, 87), (106, 89), (106, 90), (106, 91), (106, 92), (106, 93), (106, 94), (106, 95), (106, 96), (106, 107), (106, 99), (106, 100), (106, 101), (106, 102), (106, 103), (106, 104), (106, 105), (106, 108), (106, 110), (106, 111), (106, 112), (106, 116), (106, 119), (106, 123), (106, 124), (106, 125), (106, 126), (106, 127), (106, 128), (106, 129), (106, 130), (106, 131), (106, 134), (106, 135), (106, 136), (106, 137), (106, 138), (106, 139), (106, 140), (106, 141), (106, 142), (106, 144), (106, 146), (106, 147), (106, 148), (106, 149), (106, 151), (106, 152), (106, 153), (106, 154), (106, 157), (106, 158), (106, 159), (106, 160), (106, 161), (106, 162), (106, 164), (106, 194), (108, 42), (108, 61), (108, 76), (108, 109), (108, 110), (108, 114), (109, 42), (109, 91), (109, 113), (109, 164), (110, 76), (111, 114), (112, 114), (114, 0), (114, 26), (114, 29), (114, 30), (114, 31), (114, 35), (114, 36), (114, 40), (114, 42), (114, 44), (114, 47), (114, 49), (114, 53), (114, 55), (114, 56), (114, 57), (114, 59), (114, 61), (114, 64), (114, 74), (114, 75), (114, 81), (114, 82), (114, 86), (114, 91), (114, 93), (114, 96), (114, 107), (114, 99), (114, 100), (114, 101), (114, 102), (114, 109), (114, 129), (114, 134), (114, 135), (114, 140), (114, 164), (114, 179), (115, 10), (115, 31), (115, 164), (116, 114), (119, 150), (120, 157), (121, 137), (122, 137), (123, 163), (124, 117), (124, 125), (124, 130), (124, 150), (124, 163), (125, 126), (126, 117), (126, 135), (127, 134), (128, 135), (129, 36), (129, 91), (130, 131), (131, 134), (131, 135), (132, 157), (133, 137), (134, 36), (134, 74), (134, 109), (134, 135), (135, 36), (135, 74), (135, 136), (135, 156), (136, 36), (137, 134), (138, 139), (139, 135), (140, 107), (140, 134), (140, 136), (141, 118), (141, 135), (141, 144), (142, 36), (142, 61), (142, 64), (142, 83), (142, 118), (142, 129), (142, 134), (142, 135), (142, 136), (142, 140), (142, 141), (142, 143), (142, 144), (142, 150), (142, 152), (142, 156), (142, 158), (142, 162), (142, 164), (142, 195), (143, 135), (144, 36), (144, 134), (144, 135), (144, 136), (144, 162), (145, 134), (146, 134), (146, 135), (146, 155), (147, 29), (147, 44), (147, 46), (147, 47), (147, 118), (147, 134), (147, 135), (147, 136), (147, 140), (147, 144), (147, 156), (147, 158), (147, 164), (148, 136), (148, 150), (149, 134), (149, 135), (149, 136), (149, 141), (150, 134), (150, 164), (151, 150), (152, 134), (152, 135), (152, 156), (152, 162), (153, 134), (153, 135), (153, 162), (154, 150), (155, 134), (156, 135), (157, 134), (158, 136), (158, 140), (159, 135), (160, 134), (160, 135), (160, 155), (162, 36), (162, 61), (162, 74), (162, 96), (162, 134), (162, 135), (162, 144), (167, 171), (168, 83), (169, 99), (170, 83), (170, 85), (171, 2), (172, 195), (173, 78), (174, 78), (175, 60), (175, 66), (175, 70), (175, 142), (176, 94), (176, 120), (176, 121), (176, 122), (176, 123), (176, 132), (176, 133), (176, 137), (176, 138), (176, 145), (176, 157), (177, 12), (177, 26), (177, 27), (177, 28), (177, 29), (177, 30), (177, 31), (177, 33), (177, 34), (177, 35), (177, 36), (177, 44), (177, 55), (177, 56), (177, 57), (177, 58), (177, 59), (177, 61), (177, 62), (177, 63), (177, 64), (177, 74), (177, 75), (177, 78), (177, 79), (177, 81), (177, 82), (177, 86), (177, 89), (177, 90), (177, 91), (177, 93), (177, 94), (177, 96), (177, 107), (177, 99), (177, 100), (177, 101), (177, 102), (177, 109), (177, 113), (177, 118), (177, 128), (177, 129), (177, 134), (177, 135), (177, 136), (177, 139), (177, 140), (177, 141), (177, 144), (177, 148), (177, 149), (177, 150), (177, 151), (177, 152), (177, 153), (177, 154), (177, 159), (177, 162), (178, 35), (180, 37), (182, 31), (183, 31), (184, 185), (185, 29), (185, 30), (185, 31), (185, 44), (185, 79), (185, 166), (185, 187), (185, 190), (187, 185), (188, 164), (188, 187), (188, 190), (189, 108), (190, 185), (192, 193), (195, 164)]

I am hoping to be able to spread out the nodes more and display them in a hierarchical manner.

I would prefer to be able to move the nodes around manually , similar to this animation, but with the nodes staying where they are placed instead of snapping back. However, if you can display them neatly without the need for manual interaction, that would work too!

Alexander
  • 163
  • 1
  • 10
  • Three comments: 1) Fruchterman-Reingold layout (aka `spring_layout`) expects a single connected component. Your out-of-the-box layout would be much improved if you computed the layout for each component separately, and then combined the layouts in a sensible manner. If have an answer [here](https://stackoverflow.com/questions/53120739/lots-of-edges-on-a-graph-plot-in-python/53156709#53156709) that outlines how to do that. – Paul Brodersen May 14 '19 at 09:28
  • 1
    2) If you still want to drag nodes around, I have a little network visualization library that has some networkx integration [here](https://github.com/paulbrodersen/netgraph). If you use the `InteractiveGraph` class, you drag nodes around without them snapping back. – Paul Brodersen May 14 '19 at 09:28
  • 3) If you want a hierarchical layout, then the `dot` / `neato` / graphviz default layout might suit your needs more. There are some [bindings in `networkx` to graphviz](https://networkx.github.io/documentation/stable/reference/drawing.html#graphviz-agraph) that would allow you to do that. – Paul Brodersen May 14 '19 at 09:38

1 Answers1

4

Here is an MWE using netgraph on a networkx graph object.

import numpy as np
import matplotlib.pyplot as plt; plt.ion()
import networkx
import netgraph # pip install netgraph

# Construct sparse, directed, weighted graph
total_nodes = 20
weights = np.random.rand(total_nodes, total_nodes)
connection_probability = 0.1
is_connected = np.random.rand(total_nodes, total_nodes) <= connection_probability
graph = np.zeros((total_nodes, total_nodes))
graph[is_connected] = weights[is_connected]

# construct a networkx graph
g = networkx.from_numpy_array(graph, networkx.DiGraph)

# decide on a layout
pos = networkx.layout.spring_layout(g)

# Create an interactive plot.
# NOTE: you must retain a reference to the object instance!
# Otherwise the whole thing will be garbage collected after the initial draw
# and you won't be able to move the plot elements around.
plot_instance = netgraph.InteractiveGraph(graph, node_positions=pos)

######## drag nodes around #########

# To access the new node positions:
node_positions = plot_instance.node_positions
Paul Brodersen
  • 11,221
  • 21
  • 38
  • This works for me, take note to include `%matplotlib notebook` in your code if you are working on Jupyter notebook as seen the issue [here](https://github.com/paulbrodersen/netgraph/issues/21). – Goh Jia Yi Apr 23 '22 at 05:59