{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", "
\n", " \n", " \n", " \n", " \n", "

Bokeh Tutorial

\n", "
\n", "\n", "

08. Graph and Network Plots

" ] }, { "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 }