import networkx
from math import sqrt
network = networkx.read_gml('ep2016.gml')
layout = networkx.spring_layout(network,
k=1.1/sqrt(network.number_of_nodes()),
iterations=100)
# https://en.wikipedia.org/wiki/Force-directed_graph_drawing
(id) | x | y | node_name | ... |
---|---|---|---|---|
0 | 21 | 3 | da_bjoerni | ... |
1 | 14 | 7 | user47 | ... |
... | ... | ... | ... | ... |
from bokeh.models import ColumnDataSource
nodes, nodes_coordinates = zip(*sorted(layout.items()))
nodes_xs, nodes_ys = list(zip(*nodes_coordinates))
nodes_source = ColumnDataSource(dict(x=nodes_xs, y=nodes_ys,
name=nodes))
from bokeh.plotting import show, figure
from bokeh.io import output_notebook
from bokeh.models import HoverTool
hover = HoverTool(tooltips=[('name', '@name'), ('id', '$index')])
plot = figure(plot_width=800, plot_height=400,
tools=['tap', hover, 'box_zoom', 'reset'])
r_circles = plot.circle('x', 'y', source=nodes_source, size=10,
color='blue', level = 'overlay')
def get_edges_specs(_network, _layout):
d = dict(xs=[], ys=[], alphas=[])
weights = [d['weight'] for u, v, d in _network.edges(data=True)]
max_weight = max(weights)
calc_alpha = lambda h: 0.1 + 0.6 * (h / max_weight)
# example: { ..., ('user47', 'da_bjoerni', {'weight': 3}), ... }
for u, v, data in _network.edges(data=True):
d['xs'].append([_layout[u][0], _layout[v][0]])
d['ys'].append([_layout[u][1], _layout[v][1]])
d['alphas'].append(calc_alpha(data['weight']))
return d
lines_source = ColumnDataSource(get_edges_specs(network, layout))
r_lines = plot.multi_line('xs', 'ys', line_width=1.5,
alpha='alphas', color='navy',
source=lines_source)
show(plot)
<Bokeh Notebook handle for In[7]>
centrality =\
networkx.algorithms.centrality.betweenness_centrality(network)
# first element are nodes again
_, nodes_centrality = zip(*sorted(centrality.items()))
max_centraliy = max(nodes_centrality)
nodes_source.add([7 + 10 * t / max_centraliy
for t in nodes_centrality],
'centrality')
'centrality'
import community # python-louvain
partition = community.best_partition(network)
p_, nodes_community = zip(*sorted(partition.items()))
nodes_source.add(nodes_community, 'community')
community_colors = ['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33','#a65628', '#b3cde3','#ccebc5','#decbe4','#fed9a6','#ffffcc','#e5d8bd','#fddaec','#1b9e77','#d95f02','#7570b3','#e7298a','#66a61e','#e6ab02','#a6761d','#666666']
nodes_source.add([community_colors[t % len(community_colors)]
for t in nodes_community],
'community_color')
'community_color'
r_circles.glyph.size = 'centrality'
r_circles.glyph.fill_color = 'community_color'
show(plot)
<Bokeh Notebook handle for In[11]>
ColumnDataSource.selected
{
# line or patch glyph selections
'0d': {'get_view': {}, 'glyph': None,
'indices': []},
# all other glyph selections
'1d': {'indices': [73]},
# [multi]line or patch selections
'2d': {'indices': []}
}
def remove_node():
idx = nodes_source.selected['1d']['indices'][0]
# update networkX network
node = nodes_source.data['name'][idx]
network.remove_node(node)
# update layout
layout.pop(node)
# update nodes ColumnDataSource
new_source_data = dict()
for column in nodes_source.column_names:
new_source_data[column] =\
[e for i, e in enumerate(nodes_source.data[column])
if i != idx]
nodes_source.data = new_source_data
# update lines ColumnDataSource
lines_source.data = get_edges_specs(network, layout)
The slides and code can be found at:
https://github.com/blue-yonder/documents