{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from itertools import islice\n",
    "\n",
    "import numpy as np\n",
    "import holoviews as hv\n",
    "from holoviews import opts\n",
    "from holoviews.plotting.links import RangeToolLink\n",
    "\n",
    "hv.extension('bokeh')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This demo demonstrates how to link two plots using the RangeToolLink along both axes. This can be useful to get an overview and a detailed view of some data at the same time."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Declare data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mandelbrot_generator(h,w, maxit, bounds):\n",
    "    \"Generator that yields the mandlebrot set.\"\n",
    "    (l,b,r,t) = bounds\n",
    "    y,x = np.ogrid[b:t : h*1j, l:r:w*1j]\n",
    "    c = x+y*1j\n",
    "    z = c\n",
    "    divtime = maxit + np.zeros(z.shape, dtype=int)\n",
    "    for i in range(maxit):\n",
    "        z  = z**2 + c\n",
    "        diverge = z*np.conj(z) > 2**2\n",
    "        div_now = diverge & (divtime==maxit)\n",
    "        divtime[div_now] = i\n",
    "        z[diverge] = 2\n",
    "        yield divtime\n",
    "\n",
    "def mandelbrot(h,w, n, maxit, bounds):\n",
    "    \"Returns the mandelbrot set computed to maxit\"\n",
    "    iterable =  mandelbrot_generator(h,w, maxit, bounds)\n",
    "    return next(islice(iterable, n, None))\n",
    "\n",
    "bounds = (-2,-1.4,0.8,1.4)\n",
    "mbset = mandelbrot(800, 800, 45, 46, bounds)\n",
    "\n",
    "mbset_image = hv.Image(mbset, bounds=bounds)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Declare plot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Having declared an ``Image`` of the Mandelbrot set we make a smaller and larger version of it. The smaller ``source`` will serve as an overview containing the ``RangeTool`` which allows selecting the region to show in the larger ``target`` plot. We can control which axes should be linked to the ``RangeTool`` with the axes parameter on the ``RangeToolLink``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "src = mbset_image.clone(link=False).opts(width=300, height=300)\n",
    "tgt = mbset_image.opts(width=500, height=500, xaxis=None, yaxis=None, clone=True)\n",
    "# Declare a RangeToolLink between the x- and y-axes of the two plots\n",
    "RangeToolLink(src, tgt, axes=['x', 'y'])\n",
    "\n",
    "(tgt + src).opts(\n",
    "    opts.Image(default_tools=[]),\n",
    "    opts.Layout(shared_axes=False))"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
