{
 "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> Bivariate Element</dd>\n",
    "  <dt>Dependencies</dt> <dd>Bokeh, Matplotlib, SciPy</dd>\n",
    "  <dt>Backends</dt> <dd><a href='./Bivariate.ipynb'>Bokeh</a></dd> <dd><a href='../matplotlib/Bivariate.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",
    "hv.extension('bokeh')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``Bivariate`` provides a convenient way to visualize a 2D distribution of values as a [Kernel density estimate](https://en.wikipedia.org/wiki/Kernel_density_estimation) and therefore provides a 2D extension to the ``Distribution`` element. Kernel density estimation is a non-parametric way to estimate the probability density function of a random variable.\n",
    "\n",
    "The KDE works by placing a Gaussian kernel at each sample with the supplied bandwidth, which are then summed to produce the density estimate. By default the bandwidth is determined using the Scott's method, which usually produces good results, but it may be overridden by an explicit value.\n",
    "\n",
    "To start with we will create a ``Bivariate`` with 1,000 normally distributed samples:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "normal = np.random.randn(1000, 2)\n",
    "hv.Bivariate(normal)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A ``Bivariate`` might be filled or not and we can define a ``cmap`` to control the coloring:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.Bivariate(normal).opts(\n",
    "    opts.Bivariate(cmap='Blues', colorbar=True, filled=True, toolbar='above', width=350))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can set explicit values for the ``bandwidth`` to see the effect. Since the densities will vary across the ``NdLayout`` we will enable axiswise normalization ensuring they are normalized separately:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.NdLayout({bw: hv.Bivariate(normal).opts(bandwidth=bw, axiswise=True)\n",
    "            for bw in [0.05, 0.1, 0.5, 1]}, 'Bandwidth').cols(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Underlying the ``Bivariate`` element is the ``bivariate_kde`` operation, which computes the KDE for us automatically when we plot the element. We can also use this operation directly and print the output highlighting the fact that the operation simply returns an ``Contours`` or ``Polygons`` element. It also affords more control over the parameters letting us directly set not only the ``bandwidth`` and ``cut`` values but also a ``x_range``, ``y_range``, ``bw_method`` and the number of samples (``n_samples``) to approximate the KDE with:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from holoviews.operation.stats import bivariate_kde\n",
    "dist = hv.Bivariate(normal)\n",
    "kde = bivariate_kde(dist, x_range=(-4, 4), y_range=(-4, 4), bw_method='silverman', n_samples=20)\n",
    "kde"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For full documentation and the available style and plot options, use ``hv.help(hv.Bivariate).``"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
