{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "import datashader as ds\n",
    "import panel as pn\n",
    "\n",
    "from numba import jit\n",
    "from datashader import transfer_functions as tf\n",
    "from colorcet import palette_n\n",
    "\n",
    "pn.extension()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This example demonstrates how to use the ``pn.interact`` function to trigger updates in an image of a Clifford [attractor](https://en.wikipedia.org/wiki/Attractor) generated using the [Datashader](https://datashader.org) library."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "@jit(nopython=True)\n",
    "def clifford_trajectory(a, b, c, d, x0, y0, n):\n",
    "    xs, ys = np.zeros(n), np.zeros(n)\n",
    "    xs[0], ys[0] = x0, y0\n",
    "    for i in np.arange(n-1):\n",
    "        xs[i+1] = np.sin(a * ys[i]) + c * np.cos(a * xs[i])\n",
    "        ys[i+1] = np.sin(b * xs[i]) + d * np.cos(b * ys[i])\n",
    "    return xs, ys\n",
    "\n",
    "ps = {k:p[::-1] for k,p in palette_n.items()}\n",
    "\n",
    "def clifford_plot(a=1.9, b=1.9, c=1.9, d=0.8, n=1000000, cmap=ps['kbc']):\n",
    "    cvs = ds.Canvas(plot_width=600, plot_height=600)\n",
    "    xs, ys = clifford_trajectory(a, b, c, d, 0, 0, n)\n",
    "    df = pd.DataFrame(dict(x=xs,y=ys))\n",
    "    agg = cvs.points(df, 'x', 'y')\n",
    "    return tf.shade(agg, cmap=cmap)\n",
    "\n",
    "pane = pn.interact(clifford_plot, a=(0,2), b=(0,2), c=(0,2), d=(0,2), n=(1,2e7), cmap=ps)\n",
    "logo = \"https://tinyurl.com/y9c2zn65/logo_stacked_s.png\"\n",
    "text = \"\"\"<H4>Use the widgets to vary the parameters of this \n",
    "<a href=\"https://anaconda.org/jbednar/clifford_attractor\">Clifford attractor</a>.\n",
    "<br><br>Note that many values result in nearly blank plots that contain only \n",
    "a few scattered points.</H4>\"\"\"\n",
    "\n",
    "pn.Row(pn.Column(logo, text, pane[0]), pane[1]).servable()"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
