{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
\n", "
Title
Graph Element
\n", "
Dependencies
Matplotlib
\n", "
Backends
\n", "
Matplotlib
\n", "
Bokeh
\n", "
\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import holoviews as hv\n", "from holoviews import opts\n", "\n", "hv.extension('matplotlib')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The ``Graph`` element provides an easy way to represent and visualize network graphs. It differs from other elements in HoloViews in that it consists of multiple sub-elements. The data of the ``Graph`` element itself are the abstract edges between the nodes. By default the element will automatically compute concrete ``x`` and ``y`` positions for the nodes and represent them using a ``Nodes`` element, which is stored on the Graph. The abstract edges and concrete node positions are sufficient to render the ``Graph`` by drawing straight-line edges between the nodes. In order to supply explicit edge paths we can also declare ``EdgePaths``, providing explicit coordinates for each edge to follow.\n", "\n", "To summarize a ``Graph`` consists of three different components:\n", "\n", "* The ``Graph`` itself holds the abstract edges stored as a table of node indices.\n", "* The ``Nodes`` hold the concrete ``x`` and ``y`` positions of each node along with a node ``index``. The ``Nodes`` may also define any number of value dimensions, which can be revealed when hovering over the nodes or to color the nodes by.\n", "* The ``EdgePaths`` can optionally be supplied to declare explicit node paths.\n", "\n", "This reference document describes only basic functionality, for a more detailed summary on how to work with network graphs in HoloViews see the [User Guide](../../../user_guide/Network_Graphs.ipynb).\n", "\n", "#### A simple Graph\n", "\n", "Let's start by declaring a very simple graph connecting one node to all others. If we simply supply the abstract connectivity of the ``Graph``, it will automatically compute a layout for the nodes using the ``layout_nodes`` operation, which defaults to a circular layout:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Declare abstract edges\n", "N = 8\n", "node_indices = np.arange(N)\n", "source = np.zeros(N)\n", "target = node_indices\n", "\n", "simple_graph = hv.Graph(((source, target),))\n", "simple_graph" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Directed graphs\n", "\n", "The Graph element also allows indicating the directionality of graph edges using arrows. To enable the arrows set ``directed=True`` and to optionally control the ``arrowhead_length`` provide a length as a fraction of the total graph extent:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "simple_graph.opts(directed=True, arrowhead_length=0.08)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Accessing the nodes and edges\n", "\n", "We can easily access the ``Nodes`` and ``EdgePaths`` on the ``Graph`` element using the corresponding properties:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "simple_graph.nodes + simple_graph.edgepaths" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Additional features\n", "\n", "\n", "Next we will extend this example by supplying explicit edges, node information and edge weights. By constructing the ``Nodes`` explicitly we can declare an additional value dimensions, which are revealed when hovering and/or can be mapped to the color by specifying the ``color``. We can also associate additional information with each edge by supplying a value dimension to the ``Graph`` itself, which we can map to a color using the ``edge_color``." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Node info\n", "np.random.seed(7)\n", "x, y = simple_graph.nodes.array([0, 1]).T\n", "node_labels = ['Output']+['Input']*(N-1)\n", "edge_weights = np.random.rand(8)\n", "\n", "# Compute edge paths\n", "def bezier(start, end, control, steps=np.linspace(0, 1, 100)):\n", " return (1-steps)**2*start + 2*(1-steps)*steps*control+steps**2*end\n", "\n", "paths = []\n", "for node_index in node_indices:\n", " ex, ey = x[node_index], y[node_index]\n", " paths.append(np.column_stack([bezier(x[0], ex, 0), bezier(y[0], ey, 0)]))\n", "\n", "# Declare Graph\n", "nodes = hv.Nodes((x, y, node_indices, node_labels), vdims='Type')\n", "graph = hv.Graph(((source, target, edge_weights), nodes, paths), vdims='Weight')\n", "\n", "graph.opts(\n", " opts.Graph(cmap=['blue', 'red'], edge_cmap='viridis', edge_color='Weight', node_color='Type'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For full documentation and the available style and plot options, use ``hv.help(hv.Graph).``" ] } ], "metadata": { "language_info": { "name": "python", "pygments_lexer": "ipython3" } }, "nbformat": 4, "nbformat_minor": 2 }