<commit_before>{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href='http://www.holoviews.org'><img src=\"assets/header_logo.png\" alt=\"HoloViews logo\" width=\"20%;\" align=\"left\"/></a>\n",
    "<div style=\"float:right;\"><h2>06. Custom Interactivity</h2></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "In the [exploring with containers](./03-exploration-with-containers.ipynb) section, the [``DynamicMap``](http://holoviews.org/reference/containers/bokeh/DynamicMap.html) container was introduced."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import holoviews as hv\n",
    "hv.extension('bokeh')"
   ]
  }
 ],
 "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,<commit_msg>Added introduction to streams system<commit_after>{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<a href='http://www.holoviews.org'><img src=\"assets/header_logo.png\" alt=\"HoloViews logo\" width=\"20%;\" align=\"left\"/></a>\n",
    "<div style=\"float:right;\"><h2>06. Custom Interactivity</h2></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "In the [exploring with containers](./03-exploration-with-containers.ipynb) section, the [``DynamicMap``](http://holoviews.org/reference/containers/bokeh/DynamicMap.html) container was introduced. In that section, the arguments to the callable returning elements was supplied by HoloViews sliders. In this section, we will generalize the ways in which you can generate values to update a ``DynamicMap``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import holoviews as hv\n",
    "hv.extension('bokeh', 'matplotlib')\n",
    "%opts Ellipse [xaxis=None yaxis=None] (color='red' line_width=2)\n",
    "%opts Box [xaxis=None yaxis=None] (color='blue' line_width=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A simple ``DynamicMap``"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let us now create a simple [``DynamicMap``](http://holoviews.org/reference/containers/bokeh/DynamicMap.html) using three *annotation* elements, namely [``Box``](http://holoviews.org/reference/elements/bokeh/Ellipse.html), [``Text``](http://holoviews.org/reference/elements/bokeh/Ellipse.html) and [``Ellipse``](http://holoviews.org/reference/elements/bokeh/Ellipse.html):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def annotations(angle):\n",
    "    radians = (angle / 180) * np.pi\n",
    "    return (hv.Box(0,0,4, orientation=np.pi/4) \n",
    "            * hv.Ellipse(0,0,(2,4), orientation=radians) \n",
    "            * hv.Text(0,0,'{0}º'.format(float(angle))))\n",
    "\n",
    "hv.DynamicMap(annotations, kdims=['angle']).redim.range(angle=(0, 360)).redim.label(angle='angle (º)')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This example uses the concepts introduced  in the [exploring with containers](./03-exploration-with-containers.ipynb) section and as before, the argument ``angle`` is supplied by the position of the 'angle' slider."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introducing Streams"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "HoloViews offers a way of supplying the ``angle`` value to our annotation function through means other than sliders, namely via the *streams* system which you can learn about in our [responding to events](http://holoviews.org/user_guide/Responding_to_Events.html) user guide.\n",
    " \n",
    " All stream classes are found in the ``streams`` submodule and are subclasses of ``Stream``. You can use ``Stream`` directly to make custom stream classes via the ``define`` classmethod:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from holoviews.streams import Stream\n",
    "Angle = Stream.define('Angle', angle=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here ``Angle`` is capitalized as it is a parameterized sub*class* of ``Stream`` with a numeric *angle* parameter, with a default value of zero. You can verify this using ``hv.help``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.help(Angle)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can declare a ``DynamicMap`` where instead of specifying ``kdims``, we instantiate ``Angle`` with an ``angle`` of 45º and pass it to the ``streams`` parameter of the [``DynamicMap``](http://holoviews.org/reference/containers/bokeh/DynamicMap.html):"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "As expected, we see our ellipse with an angle of 45º as specified via the ``angle`` parameter of our ``Angle`` instance. In itself, this wouldn't be very useful but given that we have a handle on our [``DynamicMap``](http://holoviews.org/reference/containers/bokeh/DynamicMap.html) ``dmap``, we can use the ``event`` method to update the ``angle`` parameter value and update the plot:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "dmap.event(angle=90)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "*When running this cell, the visualization above will jump to the 90º position!*\n",
    "\n",
    "This simple example shows how you can use to ``event`` method to update a visualization with any value you can generate in Python."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Exercise: Regenerate the DynamicMap, initializing the angle to 15 degrees"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Exercise: Use dmap.event to set the angle shown to 145 degrees."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Exercise: Do not specify an initial angle so that the default value of 0 degrees is used."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# Exercise: Use the cell magic %%output backend='matplotlib' to try the above with matplotlib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise: Declare a DynamicMap using annotations2 and AngleAndSize\n",
    "# Then use the event method to set the size to 1.5 and the angle to 30 degrees\n",
    "def annotations2(angle, size):\n",
    "    radians = (angle / 180) * np.pi\n",
    "    return (hv.Box(0,0,4, orientation=np.pi/4) \n",
    "            * hv.Ellipse(0,0,(size,size*2), orientation=radians) \n",
    "            * hv.Text(0,0,'{0}º'.format(float(angle))))\n",
    "\n",
    "AngleAndSize = Stream.define('AngleAndSize', angle=0., size=1.)"
   ]
  }
 ],
 "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,
{'fraction_non_alphanumeric': 0.19103661436043748, 'fraction_numerical': 0.010699001426533523, 'mean_word_length': 3.248989898989899, 'pattern_counts': {'":': 136, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '512145', 'n_tokens_mistral': 3029, 'n_tokens_neox': 2938, 'n_words': 704}