Bokeh Tutorial

08. Graph and Network Plots

This chapter will cover how to plot network node/link graphs in Bokeh using NetwortkX. For information on creating graph renderers from a low level, see Visualizing Network Graphs

In [1]:
from bokeh.io import show, output_notebook
from bokeh.plotting import figure

output_notebook()
Loading BokehJS ...

Plotting from NetworkX

The easiest way to plot network graphs with Bokeh is to use the from_networkx function. This function accepts any NetworkX graph and returns a Bokeh GraphRenderer that can be added to a plot. The GraphRenderer has node_renderer and edge_renderer properties that contain the Bokeh renderers that draw the nodes and edges, respectively.

The example below shows a Bokeh plot of nx.desargues_graph(), setting some of the node and edge properties.

In [2]:
import networkx as nx
from bokeh.models import Range1d, Plot
from bokeh.models.graphs import from_networkx

G = nx.desargues_graph()

# We could use figure here but don't want all the axes and titles
plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2, 2))

# Create a Bokeh graph from the NetworkX input using nx.spring_layout
graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))
plot.renderers.append(graph)

# Set some of the default node glyph (Circle) properties
graph.node_renderer.glyph.update(size=20, fill_color="orange")

# Set some edge properties too
graph.edge_renderer.glyph.line_dash = [2,2]

show(plot)
In [3]:
# Exercise: try a different NetworkX layout, and set some properies on `graph.edge_renderer.glyph` 
# and `graph.node_renderer.glyph`

Adding Extra Data Columns.

The node_renderer and edge_renderer properties of the graph renderer each have a data_source that is a standard ColumnDataSource that you can add new data to, e.g. to drive a hover tool, or to specify colors for the renderer. The example below demonstates both.

In [4]:
from bokeh.models import HoverTool
from bokeh.palettes import Category20_20

G = nx.desargues_graph() # always 20 nodes

# We could use figure here but don't want all the axes and titles
plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2, 2))

# Create a Bokeh graph from the NetworkX input using nx.spring_layout
graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))
plot.renderers.append(graph)

# Add some new columns to the node renderer data source
graph.node_renderer.data_source.data['index'] = list(range(len(G)))
graph.node_renderer.data_source.data['colors'] = Category20_20

graph.node_renderer.glyph.update(size=20, fill_color="colors")

plot.add_tools(HoverTool(tooltips="index: @index"))

show(plot)
In [5]:
# Exercise: Add your own columns for other node or edge properties e.g. fill_alpha or line_color,
# or to show other fields in a tooltoip

Inspection and Selection Policies

Bokeh graph renderers have inspection_policy and selection_policy properties. These can be used to control how hover inspections highlight the graph, or how selection tools make selections. These properties may be set to any of the inpection policies in bokeh.graphs. For instance, if a user hovers over a node, you may wish to highlight all the associated edges as well. This can be accomplished by setting the inspection policy:

graph.inspection_policy = NodesAndLinkedEdges()

as the example below demonstrates.

In [6]:
from bokeh.models.graphs import NodesAndLinkedEdges
from bokeh.models import Circle, HoverTool, MultiLine

G = nx.gnm_random_graph(15, 30)

# We could use figure here but don't want all the axes and titles
plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2 ,2))

# Create a Bokeh graph from the NetworkX input using nx.spring_layout
graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))
plot.renderers.append(graph)

# Blue circles for nodes, and light grey lines for edges
graph.node_renderer.glyph = Circle(size=25, fill_color='#2b83ba')
graph.edge_renderer.glyph = MultiLine(line_color="#cccccc", line_alpha=0.8, line_width=2)

# green hover for both nodes and edges
graph.node_renderer.hover_glyph = Circle(size=25, fill_color='#abdda4')
graph.edge_renderer.hover_glyph = MultiLine(line_color='#abdda4', line_width=4)

# When we hover over nodes, highlight adjecent edges too
graph.inspection_policy = NodesAndLinkedEdges()

plot.add_tools(HoverTool(tooltips=None))

show(plot)
In [7]:
# Exercise: try a different inspection (or selection) policy like NodesOnly or EdgesAndLinkedNodes