"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This chapter will cover how to plot network node/link graphs in Bokeh using NetworkX. For information on creating graph renderers from a low level, see [Visualizing Network Graphs](https://docs.bokeh.org/en/latest/docs/user_guide/graph.html)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.io import show, output_notebook\n",
"from bokeh.plotting import figure\n",
"\n",
"output_notebook()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting from NetworkX\n",
"\n",
"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. \n",
"\n",
"The example below shows a Bokeh plot of `nx.desargues_graph()`, setting some of the node and edge properties."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import networkx as nx\n",
"from bokeh.models import Range1d, Plot\n",
"from bokeh.plotting import from_networkx\n",
"\n",
"G = nx.desargues_graph()\n",
"\n",
"# We could use figure here but don't want all the axes and titles\n",
"plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2, 2))\n",
"\n",
"# Create a Bokeh graph from the NetworkX input using nx.spring_layout\n",
"graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))\n",
"plot.renderers.append(graph)\n",
"\n",
"# Set some of the default node glyph (Circle) properties\n",
"graph.node_renderer.glyph.update(size=20, fill_color=\"orange\")\n",
"\n",
"# Set some edge properties too\n",
"graph.edge_renderer.glyph.line_dash = [2,2]\n",
"\n",
"show(plot)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Exercise: try a different NetworkX layout, and set some properies on `graph.edge_renderer.glyph` \n",
"# and `graph.node_renderer.glyph`\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Adding Extra Data Columns.\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.models import HoverTool\n",
"from bokeh.palettes import Category20_20\n",
"\n",
"G = nx.desargues_graph() # always 20 nodes\n",
"\n",
"# We could use figure here but don't want all the axes and titles\n",
"plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2, 2))\n",
"\n",
"# Create a Bokeh graph from the NetworkX input using nx.spring_layout\n",
"graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))\n",
"plot.renderers.append(graph)\n",
"\n",
"# Add some new columns to the node renderer data source\n",
"graph.node_renderer.data_source.data['index'] = list(range(len(G)))\n",
"graph.node_renderer.data_source.data['colors'] = Category20_20\n",
"\n",
"graph.node_renderer.glyph.update(size=20, fill_color=\"colors\")\n",
"\n",
"plot.add_tools(HoverTool(tooltips=\"index: @index\"))\n",
"\n",
"show(plot)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Exercise: Add your own columns for other node or edge properties e.g. fill_alpha or line_color,\n",
"# or to show other fields in a tooltoip\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Inspection and Selection Policies\n",
"\n",
"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:\n",
"\n",
" graph.inspection_policy = NodesAndLinkedEdges()\n",
" \n",
"as the example below demonstrates."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from bokeh.models.graphs import NodesAndLinkedEdges\n",
"from bokeh.models import Circle, HoverTool, MultiLine\n",
"\n",
"G = nx.gnm_random_graph(15, 30)\n",
"\n",
"# We could use figure here but don't want all the axes and titles\n",
"plot = Plot(x_range=Range1d(-2, 2), y_range=Range1d(-2 ,2))\n",
"\n",
"# Create a Bokeh graph from the NetworkX input using nx.spring_layout\n",
"graph = from_networkx(G, nx.spring_layout, scale=1.8, center=(0,0))\n",
"plot.renderers.append(graph)\n",
"\n",
"# Blue circles for nodes, and light grey lines for edges\n",
"graph.node_renderer.glyph = Circle(size=25, fill_color='#2b83ba')\n",
"graph.edge_renderer.glyph = MultiLine(line_color=\"#cccccc\", line_alpha=0.8, line_width=2)\n",
"\n",
"# green hover for both nodes and edges\n",
"graph.node_renderer.hover_glyph = Circle(size=25, fill_color='#abdda4')\n",
"graph.edge_renderer.hover_glyph = MultiLine(line_color='#abdda4', line_width=4)\n",
"\n",
"# When we hover over nodes, highlight adjecent edges too\n",
"graph.inspection_policy = NodesAndLinkedEdges()\n",
"\n",
"plot.add_tools(HoverTool(tooltips=None))\n",
"\n",
"show(plot)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Exercise: try a different inspection (or selection) policy like NodesOnly or EdgesAndLinkedNodes\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Next Section"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Click on this link to go to the next notebook: [09 - Geographic Plots](09%20-%20Geographic%20Plots.ipynb).\n",
"\n",
"To go back to the overview, click [here](00%20-%20Introduction%20and%20Setup.ipynb)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}