5
0
mirror of https://github.com/cwinfo/yggdrasil-map synced 2024-11-14 15:30:28 +00:00
yggdrasil-map/web/graphPlotter.py

106 lines
3.0 KiB
Python
Raw Normal View History

import pygraphviz as pgv
import time
import json
import networkx as nx
from networkx.algorithms import centrality
import urllib
def position_nodes(nodes, edges):
2015-07-27 19:16:01 +00:00
G = pgv.AGraph(strict=True, directed=False, size='10!')
2015-07-27 19:16:01 +00:00
for n in nodes.values():
G.add_node(n.ip, label=n.label, coords=n.coords)
2015-07-27 19:16:01 +00:00
for e in edges:
G.add_edge(e.a.ip, e.b.ip, len=1.0)
2015-07-27 19:16:01 +00:00
G.layout(prog='neato', args='-Gepsilon=0.0001 -Gmaxiter=100000')
2015-07-27 19:16:01 +00:00
return G
def compute_betweenness(G):
ng = nx.Graph()
for start in G.iternodes():
others = G.neighbors(start)
for other in others:
ng.add_edge(start, other)
c = centrality.betweenness_centrality(ng)
for k, v in c.items():
c[k] = v
return c
def canonalize_ip(ip):
return ':'.join( i.rjust(4, '0') for i in ip.split(':') )
def load_db():
#with open('nodedb/nodes') as f:
# return dict([ (canonalize_ip(v[0]), v[1]) for v in [ l.split(None)[:2] for l in f.readlines() ] if len(v) > 1 ])
url = "https://raw.githubusercontent.com/yakamok/yggdrasil-nodelist/master/nodelist"
f = urllib.urlopen(url)
return dict([ (canonalize_ip(v[0]), v[1]) for v in [ l.split(None)[:2] for l in f.readlines() ] if len(v) > 1 ])
def get_graph_json(G):
2015-07-27 19:16:01 +00:00
max_neighbors = 1
for n in G.iternodes():
neighbors = len(G.neighbors(n))
if neighbors > max_neighbors:
max_neighbors = neighbors
print 'Max neighbors: %d' % max_neighbors
out_data = {
'created': int(time.time()),
'nodes': [],
'edges': []
}
centralities = compute_betweenness(G)
db = load_db()
2015-07-27 19:16:01 +00:00
for n in G.iternodes():
neighbor_ratio = len(G.neighbors(n)) / float(max_neighbors)
pos = n.attr['pos'].split(',', 1)
centrality = centralities.get(n.name, 0)
2018-11-17 22:34:09 +00:00
size = 5*(1 + 1*centrality)
name = db.get(canonalize_ip(n.name))
# If label isn't the default value, set name to that instead
if n.attr['label'] != n.name.split(':')[-1]: name = n.attr['label']
2015-07-27 19:16:01 +00:00
out_data['nodes'].append({
'id': n.name,
'label': name if name else n.attr['label'],
'name': name,
'coords': n.attr['coords'],
2015-07-27 19:16:01 +00:00
'x': float(pos[0]),
'y': float(pos[1]),
'color': _gradient_color(neighbor_ratio, [(100, 100, 100), (0, 0, 0)]),
'size': size,
'centrality': '%.4f' % centrality
2015-07-27 19:16:01 +00:00
})
for e in G.iteredges():
out_data['edges'].append({
'sourceID': e[0],
'targetID': e[1]
})
return json.dumps(out_data)
def _gradient_color(ratio, colors):
2015-07-27 19:16:01 +00:00
jump = 1.0 / (len(colors) - 1)
gap_num = int(ratio / (jump + 0.0000001))
2015-07-27 19:16:01 +00:00
a = colors[gap_num]
b = colors[gap_num + 1]
2015-07-27 19:16:01 +00:00
ratio = (ratio - gap_num * jump) * (len(colors) - 1)
2015-07-27 19:16:01 +00:00
r = a[0] + (b[0] - a[0]) * ratio
g = a[1] + (b[1] - a[1]) * ratio
b = a[2] + (b[2] - a[2]) * ratio
2015-07-27 19:16:01 +00:00
return '#%02x%02x%02x' % (r, g, b)