{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"contentcontainer med left\" style=\"margin-left: -50px;\">\n",
    "<dl class=\"dl-horizontal\">\n",
    "  <dt>Title</dt> <dd> Path Element</dd>\n",
    "  <dt>Dependencies</dt> <dd>Bokeh</dd>\n",
    "  <dt>Backends</dt> <dd><a href='./Path.ipynb'>Bokeh</a></dd> <dd><a href='../matplotlib/Path.ipynb'>Matplotlib</a></dd>\n",
    "</dl>\n",
    "</div>"
   ]
  },
  {
   "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('bokeh')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Path`` element represents one more lines, connecting arbitrary points in two-dimensional space. ``Path`` supports plotting an individual line or multiple subpaths, which should be supplied as a list. Each path should be defined in a columnar format such as NumPy arrays, DataFrames or dictionaries for each column. For a full description of the path geometry data model see the [Geometry Data User Guide](../user_guide/Geometry_Data.ipynb).\n",
    "\n",
    "In this example we will create a Lissajous curve, which describe complex harmonic motion:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "lin = np.linspace(0, np.pi*2, 200)\n",
    "\n",
    "def lissajous(t, a, b, delta):\n",
    "    return (np.sin(a * t + delta), np.sin(b * t), t)\n",
    "\n",
    "path = hv.Path([lissajous(lin, 3, 5, np.pi/2)])\n",
    "path.opts(color='black', line_width=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "If you looked carefully the ``lissajous`` function actually returns three columns, respectively for the x, y columns and a third column describing the point in time. By declaring a value dimension for that third column we can also color the Path by time. Since the value is cyclical we will also use a cyclic colormap (``'hsv'``) to represent this variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "path = hv.Path([lissajous(lin, 3, 5, np.pi/2)], vdims='time')\n",
    "path.opts(cmap='hsv', color='time', line_width=4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we do not provide a ``color`` overlaid ``Path`` elements will cycle colors just like other elements do unlike ``Curve`` a single ``Path`` element can contain multiple lines that are disconnected from each other. A ``Path`` can therefore often useful to draw arbitrary annotations on top of an existing plot.\n",
    "\n",
    "A ``Path`` Element accepts multiple formats for specifying the paths, the simplest of which is passing a list of ``Nx2`` arrays of the x- and y-coordinates, alternative we can pass lists of coordinates. In this example we will create some coordinates representing rectangles and ellipses annotating an ``RGB`` image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "angle = np.linspace(0, 2*np.pi, 100)\n",
    "baby = list(zip(0.15*np.sin(angle),  0.2*np.cos(angle)-0.2))\n",
    "\n",
    "adultR = [(0.25, 0.45), (0.35,0.35), (0.25, 0.25), (0.15, 0.35), (0.25, 0.45)]\n",
    "adultL = [(-0.3, 0.4), (-0.3, 0.3), (-0.2, 0.3), (-0.2, 0.4),(-0.3, 0.4)]\n",
    "scene = hv.RGB.load_image('../assets/penguins.png')\n",
    "\n",
    "overlay = (scene * hv.Path([adultL, adultR, baby]) * hv.Path([baby]))\n",
    "overlay.opts(opts.Path(line_width=4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Path`` can also be used as a means to display a number of lines with the same sampling along the x-axis at once. If we initialize the ``Path`` with a tuple of x-coordinates and stacked y-coordinates, we can quickly view a number of lines at once. Here we will generate a number of random traces each slightly offset along the y-axis:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "N, NLINES = 100, 10\n",
    "paths = hv.Path((np.arange(N), np.random.rand(N, NLINES) + np.arange(NLINES)[np.newaxis, :]))\n",
    "paths2 = hv.Path((np.arange(N), np.random.rand(N, NLINES) + np.arange(NLINES)[np.newaxis, :]))\n",
    "\n",
    "overlay = paths * paths2\n",
    "overlay.opts(width=600)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For full documentation and the available style and plot options, use ``hv.help(hv.Path).``"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
