Skip to content

Commit

Permalink
Added draft of fifth section demonstrating live data
Browse files Browse the repository at this point in the history
  • Loading branch information
jlstevens committed Jun 16, 2017
1 parent 08e5354 commit 99cbbfb
Showing 1 changed file with 273 additions and 0 deletions.
273 changes: 273 additions & 0 deletions guides/getting_started/5-Live_Data.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,273 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Live Data\n",
"\n",
"The 'Getting Started' Guide has up until this point demonstrate how HoloViews objects can wrap your data and be given a rich, useful representation. This has assumed that the data was available in memory so that it could be used to construct the appropriate object.\n",
"\n",
"The assumption that the data is immediately available in memory for analysis and visualization does not hold in many different scenarios. The data of interest may exist on some remote server making it unavailable locally until it is fetched. In other situations, the data may exist on the local disk but be too large to fit into memory. Perhaps the data doesn't even exit yet: it may be the result of some computation yet to be performed or the outcome of some live live process with the corresponding measurement not yet made.\n",
"\n",
"All these examples are of *live data* that can be made available to HoloViews using the appropriate Python process. In this section, we will see how HoloViews allows you to build visualizations that update dynamically to newly available data and that can even respond to live user interaction. <br><br>\n",
"\n",
"<center><div class=\"alert alert-info\" role=\"alert\"><b>Note: </b>To work with live data, you need a live server which is why the output shown below are GIF animations. If you run this notebook yourself, you will be able to try out your own interactions and compare them to the displayed GIF animations.</center>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A computational process"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There are many possible examples of live data including financial data feeds, real-time scientific measurements and sophisticated numerical simulations. Here we will consider the path traced by two very simple equations:\n",
"\n",
"$$x_{n+1} = \\sin(ay_n) + c \\cos(ax_n)$$\n",
"$$y_{n+1} = \\sin(bx_n) + d \\cos(by_n)$$\n",
"\n",
"These equations define the 'Clifford Attractor' described in the book \"Chaos In Wonderland\" by [Cliff Pickover](https://en.wikipedia.org/wiki/Clifford_A._Pickover). Now let's write a simple Python function to iterate these two equations starting from position ``(x0,y0)``:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def clifford(a,b,c,d,x0,y0):\n",
" xn,yn = x0,y0\n",
" coords = [(x0,y0)]\n",
" for i in range(10000):\n",
" x_n1 = np.sin(a*yn) + c*np.cos(a*xn)\n",
" y_n1 = np.sin(b*xn) + d*np.cos(b*yn)\n",
" xn,yn = x_n1,y_n1\n",
" coords.append((xn,yn))\n",
" return coords"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we run this function now, we'll get a list of 10000 tuples which won't be very informative. We will want to visualize this path in two-dimensional space so now we import NumPy and HoloViews:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import holoviews as hv\n",
"import numpy as np\n",
"hv.extension('bokeh')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The ``Curve`` element accepts the output of our ``clifford`` function, making it trivial to define a function that when called gives us a visualization:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%opts Curve [show_grid=False xaxis=None yaxis=None]\n",
"def clifford_attractor(a,b,c,d):\n",
" return hv.Curve(clifford(a,b,c,d,x0=0,y0=0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The first line with the ``%opts`` line magic disables axes and grids. We can then view the output for some combination of values for ``a,b,c`` and ``d``, starting from the origin:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%opts Curve (line_width=0.03 color='red')\n",
"clifford_attractor(a =-1.5, b=1.5, c=1, d=0.75 )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This gives us a snapshot for the four chosen values, what we really would like to do is to interact with the four-dimensional parameter space directly."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Live parameter exploration"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To dynamically explore these parameters, we can start by declaring a ``DynamicMap``, passing in our function instead of a dictionary of ``Image`` elements as we saw in the [Introduction](1-Introduction.ipynb). We declare the four arguments of our function as ``kdims``:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"dmap = hv.DynamicMap(clifford_attractor, kdims=['a','b','c','d'])\n",
"dmap"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"HoloViews does not yet have the information needed to give us a visualization as we have not specified the ranges that the 'a','b','c' and 'd' dimension can take. We can now do this easily with the ``redim`` method:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%opts Curve (line_width=0.03 color='green')\n",
"# When run live, this cell's output should match the behavior of the GIF below\n",
"dmap.redim.range(a=(-1.5,-1),b=(1.5,2),c=(1,1.2),d=(0.75,0.8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src='https://s3-eu-west-1.amazonaws.com/assets.holoviews.org/gifs/guides/getting_started/5-Live_Data/live_data_1.gif'>"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note how the HoloViews options system described in the [Customization section](2-Customization.ipynb) continues to work with the ``DynamicMap``."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Live interaction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The concept of the ``DynamicMap`` also supports live interaction (when using the Bokeh plotting extension) via the *streams system*. A stream is simple a parameter of a corresponding stream class that is configured to track some variable reflecting a user interaction. For this example we'll use ``PointerXY`` to get the ``x`` and ``y`` value of the mouse as it hovers over the plot."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from holoviews.streams import PointerXY"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can extend our function to accept the ``x`` and ``y`` values of the pointer to set the initial ``x0`` and ``y0`` values of the attractor. In addition, we can use this position to create a red point that follows the cursor, some text to show the position of this point and finally a red line segment to show the first step taken when computing the attractor:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def interactive(a,b,c,d,x=0,y=0):\n",
" coords = clifford(a,b,c,d,x0=x,y0=y)\n",
" return (hv.Curve(coords) * hv.Points(coords[0]) * hv.Curve(coords[:2], group='Init')\n",
" * hv.Text(-0.75,1.35, 'x:{x:.2f} y:{y:.2f}'.format(x=coords[0][0],y=coords[0][1])))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All we have do is created an ``Overlay`` as described in the [Introduction](1-Introduction.ipynb) containing the our clifford attractor curve and a few other HoloViews elements parameterized accordingly, including ``Points`` and the ``Text`` annotation. Now by passing this function to ``DynamicMap`` and setting the ranges as before, we have an explorable visualization you can interact with directly:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%%opts Curve (line_width=0.03 color='blue') Points (color='red' size=10) Curve.Init (color='red' line_width=2)\n",
"# When run live, this cell's output should match the behavior of the GIF below\n",
"dmap = hv.DynamicMap(interactive, kdims=['a','b','c','d'], streams=[PointerXY(x=0,y=0)])\n",
"dmap.redim.range(a=(-1.4,-1),b=(1.6,1.8),c=(1,1.5),d=(0.7,0.8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<img src='https://s3-eu-west-1.amazonaws.com/assets.holoviews.org/gifs/guides/getting_started/5-Live_Data/live_data_2.gif'></img>\n",
"\n",
"By exploring with the mouse, see if you can find the fixedpoint location (where the next step maps you to the same position) located at ``x=0.18,y=0.65`` with parameters ``a=1.4, b=1.6, c=1`` and ``d=0.7``.\n",
"\n",
"To learn more about the streams system please consult the [User Guide] and checkout our [Linked streams gallery]."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

0 comments on commit 99cbbfb

Please sign in to comment.