11

I'm trying to draw a graph of any network running my script. I use scapy to collect packets and would like to have a node per computer communicating, and an edge per connection.

The issue is I can't find a way to visualize the graph well enough on my screen. So far combining networkx with matlib.pyplot managed to bring the best results, but it still seems pretty random and chaotic, the tags are hard to read, nodes are on top of each other, etc'. It is also preferable to have the ability to interact with the graph - move nodes around, hover over nodes/edges to get extra info, perhaps zoom in or even cluster together nodes so that when you click on the cluster you can see which nodes compose the cluster.

Since analyzing the network data and adding nodes&edges to the graph will be tedious for you to read, I'm adding only the relevant part here (the part that actually shows the graph I built):

pos = nx.spring_layout(Graph, scale=2)
edge_labels = nx.get_edge_attributes(Graph, "Protocol")
nx.draw(Graph,pos, with_labels=True, node_size=600, font_size=8, font_weight='bold')
nx.draw_networkx_edge_labels(Graph, pos, edge_labels=edge_labels, font_size=8)
plt.show()

(I imported networks as nx and matplotlib.pyplot as plt)

I also tried graphviz, ploty and bokeh but couldn't really make them work and after troubleshooting on Google got the impression that anyway they won't fix my problem, and I also tried adjustText - but I could not manage to fit it in my code in any way (can't find how to get the text attribute of my graph) and Holoviews - but it refuses to show an image no matter what I try (even if I copy and paste examples from their site - either python says that '%opts...' is invalid syntax, or if I try changing options any other way the code just runs until it ends and doesn't show anything on the screen.

This is what the graph looks like: This is what the graph looks like

I'm finding a lot of partial solutions online so none of them work, does anybody has a comprehensive solution?

yo1122
  • 311
  • 4
  • 17
  • 2
    A couple of years ago I gave up trying to use everything you mentioned and used `d3`. https://github.com/d3/d3-force – keithpjolley Sep 17 '18 at 11:42
  • 2
    Have you checked out [Vega](https://vega.github.io/vega/) and related tools? See [this interactive example](https://vega.github.io/vega/examples/force-directed-layout/) or a force-directed graph. Not sure if [Vega-lite](https://vega.github.io/vega-lite/) or [Altair](https://altair-viz.github.io/) can do that too... Then there are the more dated Lyra ([example](http://idl.cs.washington.edu/projects/lyra/app/#?example=les-mis)) or [GraphScape](http://idl.cs.washington.edu/papers/graphscape/). [graph-tool](https://graph-tool.skewed.de/) (which is not Vega) is pretty good too, and very fast. – jdehesa Sep 17 '18 at 12:09
  • How many nodes/edges are there in the network you are trying to plot? – abc Sep 17 '18 at 15:10
  • It's hard to say how many nodes - as many as there are computers in the companies that will use these products. Alternatively - as many as there are subnets/vlans in those companies (looking into several options) So I recon anywhere between a couple dozen and a couple thousand. The decision I will make will also depend on whether the solution I will find is can scale to deal with these different sizes. About the other comments - I will add those options to my todo list and post another comment here. – yo1122 Sep 17 '18 at 15:21
  • 1
    First: shameless plug for [netgraph](https://github.com/paulbrodersen/netgraph), which started out as a fork of the networkx plotting tools but lets you move nodes around after plotting them. It also does things such as auto-scale your labels such that they fit inside the nodes. APIs are very similar, so you should not have any problems there. – Paul Brodersen Sep 18 '18 at 09:07
  • Second: you need to realize that screen space is limited. You can only fit so much text and plot elements on a screen in a legible size at any given point in time. You also wouldn't try to display 100k words on one page. Similarly, you can't expect to show a 1k plot elements (nodes, edges) simultaneously and expect the human brain to able to make sense of it all. If I were you, I would think about displaying large networks first at very coarse granularity (maybe a graph of connected subnetworks), then build tools to zoom into individual subnetworks. – Paul Brodersen Sep 18 '18 at 09:13
  • I like using [plotly's Dash Cytoscape](https://dash.plot.ly/cytoscape). [Graphistry](https://www.graphistry.com/) is also a nice (but not free) option. But in reality, anything beyond a few hundred to a thousand nodes is not going to plot well and look like a mess. Graphistry is my favorite for graphs of that size, but for freeware you should really think about how much you need to show in the graph. – CJ Sullivan Sep 12 '19 at 19:21
  • Does this answer your question? [Django and interactive graph/network visualization](https://stackoverflow.com/questions/8840255/django-and-interactive-graph-network-visualization) – erdogant Jun 22 '20 at 18:08

2 Answers2

1

Drawing heavy graphs with plt can be a bit problematic, the problem here is not only with the data, it is also a problem for a human eye to get a lot of information in one look. My suggestion is to use a more advanced graph visualization library, for example, ipycytoscape. you can define also styles and more features with it that will match your demands

from ipycytoscape import CytoscapeWidget
graph_draw = ipycytoscape.CytoscapeWidget()
graph_draw.graph.add_graph_from_networkx(nx_graph, directed=True)

In addition, if you will use CytoscapeWidget you can interact with the graph and match the focus of the view to the part in the graph that interests you the most.

Shay Nehmad
  • 1,103
  • 1
  • 12
  • 25
Eyal Asulin
  • 290
  • 1
  • 6
0

You can tune the hyper-parameters (k and iterations) of the nx.spring_layout to arrange the nodes. Once you tune the parameters, the connected nodes will be close to each other, and not-contacted nodes will maintain a maximum possible distance.

pos = nx.spring_layout(G,k=0.1, iterations=20)
Malinda
  • 336
  • 2
  • 12