{
 "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> RGB Element</dd>\n",
    "  <dt>Dependencies</dt> <dd>Plotly</dd>\n",
    "  <dt>Backends</dt>\n",
    "    <dd><a href='../bokeh/RGB.ipynb'>Bokeh</a></dd>\n",
    "    <dd><a href='../matplotlib/RGB.ipynb'>Matplotlib</a></dd>\n",
    "    <dd><a href='./RGB.ipynb'>Plotly</a>\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('plotly')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``RGB`` represents a regularly spaced 2D grid of an underlying continuous space of RGB(A) (red, green, blue, and alpha) color space values. The definition of the grid closely matches the semantics of an Image and in the simplest case the grid may be specified as a ``NxMx3`` or ``NxMx4`` array of values along with a bounds.  An RGB may also be defined through explicit and regularly spaced x/y-coordinate arrays. The two most basic supported constructors of an ``RGB`` element therefore include:\n",
    "\n",
    "    RGB((X, Y, R, G, B))\n",
    "\n",
    "where ``X`` is a 1D array of shape ``M``, ``Y`` is a 1D array of shape ``N`` and ``R``/``G``/``B`` are 2D array of shape ``NxM``, or equivalently:\n",
    "\n",
    "    RGB(Z, bounds=(x0, y0, x1, y1))\n",
    "\n",
    "where Z is a 3D array of stacked R/G/B arrays with shape NxMx3/4 and the bounds define the (left, bottom, right, top) edges of the four corners of the grid. Other gridded formats which support declaring of explicit x/y-coordinate arrays such as xarray are also supported. See the [Gridded Datasets](../../../user_guide/09-Gridded_Datasets.ipynb) user guide for all the other accepted data formats.\n",
    "\n",
    "One of the simplest ways of creating an ``RGB`` element is to load an image file (such as PNG) off disk, using the ``load_image`` classmethod:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.RGB.load_image('../assets/penguins.png')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you have ``PIL`` or [``pillow``](https://python-pillow.org) installed, you can also pass in a PIL Image as long as you convert it to Numpy arrays first:\n",
    "\n",
    "```\n",
    "from PIL import Image\n",
    "hv.RGB(np.array(Image.open('../assets/penguins.png')))\n",
    "```\n",
    "\n",
    "This Numpy-based method for constructing an ``RGB`` can be used to stack up arbitrary 2D arrays into a color image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "x,y = np.mgrid[-50:51, -50:51] * 0.1\n",
    "\n",
    "r = 0.5*np.sin(np.pi  +3*x**2+y**2)+0.5\n",
    "g = 0.5*np.sin(x**2+2*y**2)+0.5\n",
    "b = 0.5*np.sin(np.pi/2+x**2+y**2)+0.5\n",
    "\n",
    "hv.RGB(np.dstack([r,g,b]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see how the RGB object is created from the original channels as gray `Image` elements:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "opts.defaults(opts.Image(cmap='gray'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we can index the components:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.Image(r,label=\"R\") + hv.Image(g,label=\"G\") + hv.Image(b,label=\"B\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "``RGB`` also supports an optional alpha channel, which will be used as a mask revealing or hiding any ``Element``s it is overlaid on top of:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "mask = 0.5*np.sin(0.2*(x**2+y**2))+0.5\n",
    "rgba = hv.RGB(np.dstack([r,g,b,mask]))\n",
    "\n",
    "bg = hv.Image(0.5*np.cos(x*3)+0.5, label=\"Background\") * hv.VLine(x=0,label=\"Background\")\n",
    "overlay = (bg*rgba).relabel(\"RGBA Overlay\")\n",
    "bg + hv.Image(mask,label=\"Mask\") + overlay"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "RGB elements can be positioned in the plot space using their bounds, with transparency if defined for that image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "hv.Overlay([hv.RGB.load_image('../assets/penguins.png', bounds=(2*i,2*i,3*i,3*i))\n",
    "            for i in range(1,8)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "One additional way to create RGB objects is via the separate [ImaGen](https://github.com/pyviz-topics/imagen) library, which creates parameterized streams of images for experiments, simulations, or machine-learning applications.\n",
    "\n",
    "For full documentation and the available style and plot options, use ``hv.help(hv.RGB).``"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
