{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### **Title**: HeatMap Tap stream example\n",
    "\n",
    "**Description**: A linked streams example demonstrating how use Tap stream on a HeatMap. The data contains the incidence of measles across US states by year and week (obtained from [Project Tycho](http://www.tycho.pitt.edu)). The HeatMap represents the mean measles incidence per year. On tap the Histogram on the right will generate a Histogram of the incidences for each week in the selected year and state.\n",
    "    \n",
    "**Dependencies**: Bokeh\n",
    "\n",
    "**Backends**: [Bokeh](./Tap.ipynb)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import panel as pn\n",
    "import numpy as np\n",
    "import holoviews as hv\n",
    "from holoviews import opts\n",
    "\n",
    "hv.extension('bokeh', width=90)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's look at an extremely simple example. \n",
    "\n",
    "We will create an empty `hv.Points` element and set it as the source for the `Tap` stream. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create an empty Points element\n",
    "points = hv.Points([])\n",
    "# Create the Tap stream with the points element as the source\n",
    "# We set the x and y here with starting values\n",
    "stream = hv.streams.Tap(source=points, x=np.nan, y=np.nan)\n",
    "\n",
    "# Create a callback for a dynamic map\n",
    "def location(x, y):\n",
    "    \"\"\"Create an empty plot with a changing label\"\"\"\n",
    "    return hv.Points([], label='x: %0.3f, y: %0.3f' % (x, y))\n",
    "\n",
    "\n",
    "# Connect the Tap stream to the tap_histogram callback\n",
    "tap_dmap = hv.DynamicMap(location, streams=[stream])\n",
    "\n",
    "# Overlay the Points element (which is linked to the tap stream) with the location plot\n",
    "points * tap_dmap"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's see what it looks like if we used Panel to give us more control over layout and event triggering"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create an empty Points element\n",
    "points = hv.Points([])\n",
    "# Create the Tap stream with the points element as the source\n",
    "# We set the x and y here with starting values\n",
    "stream = hv.streams.Tap(source=points, x=np.nan, y=np.nan)\n",
    "\n",
    "# make a function that displays the location when called.\n",
    "def location(x, y):\n",
    "    \"\"\"Display pane showing the x and y values\"\"\"\n",
    "    return pn.pane.Str('Click at %0.3f, %0.3f' % (x, y), width=200)\n",
    "\n",
    "# Display the points and the function output, updated\n",
    "# whenever the stream values change\n",
    "layout = pn.Row(points, pn.bind(location, x=stream.param.x, y=stream.param.y))\n",
    "# display the container\n",
    "layout"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we will now look at a more complex example."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Declare dataset\n",
    "df = pd.read_csv('http://assets.holoviews.org/data/diseases.csv.gz', compression='gzip')\n",
    "dataset = hv.Dataset(df, vdims=('measles','Measles Incidence'))\n",
    "\n",
    "# Declare HeatMap\n",
    "heatmap = hv.HeatMap(dataset.aggregate(['Year', 'State'], np.mean),\n",
    "                     label='Average Weekly Measles Incidence').select(Year=(1928, 2002))\n",
    "\n",
    "# Declare Tap stream with heatmap as source and initial values\n",
    "posxy = hv.streams.Tap(source=heatmap, x=1951, y='New York')\n",
    "\n",
    "# Define function to compute histogram based on tap location\n",
    "def tap_histogram(x, y):\n",
    "    return hv.Curve(dataset.select(State=y, Year=int(x)), kdims='Week',\n",
    "                   label=f'Year: {x}, State: {y}')\n",
    "\n",
    "# Connect the Tap stream to the tap_histogram callback\n",
    "tap_dmap = hv.DynamicMap(tap_histogram, streams=[posxy])\n",
    "\n",
    "# Get the range of the aggregated data we're using for plotting\n",
    "cmin, cmax = dataset.aggregate(['Year', 'State'], np.mean).range(dim='measles')\n",
    "# Adjust the min value since log color mapper lower bound must be >0.0\n",
    "cmin += 0.0000001\n",
    "\n",
    "# Display the Heatmap and Curve side by side\n",
    "(heatmap + tap_dmap).opts(\n",
    "    opts.Curve(framewise=True, height=500, line_color='black', width=375, yaxis='right'),\n",
    "    opts.HeatMap(clim=(cmin, cmax), cmap='RdBu_r', \n",
    "                 fontsize={'xticks': '6pt'}, height=500, logz=True,\n",
    "                 tools=['hover'], width=700, xrotation=90,\n",
    "                 )\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center><img src=\"https://assets.holoviews.org/gifs/examples/streams/bokeh/heatmap_tap.gif\" width=80% style=\"max-width: 800px\"></center>"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
