From df3d73dee1a7b6e970201a13b7c4e8f2c7b7f302 Mon Sep 17 00:00:00 2001 From: Daniel Stephan Date: Fri, 9 Feb 2018 13:54:25 +0100 Subject: [PATCH] Added an example in the user guide on using operations on 2d elements. (#2316) --- .../user_guide/10-Transforming_Elements.ipynb | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/examples/user_guide/10-Transforming_Elements.ipynb b/examples/user_guide/10-Transforming_Elements.ipynb index 6b5904931e..6113cb13f9 100644 --- a/examples/user_guide/10-Transforming_Elements.ipynb +++ b/examples/user_guide/10-Transforming_Elements.ipynb @@ -298,6 +298,102 @@ "source": [ "Using a few additional lines we have now evaluated the operation over a number of different parameters values, allowing us to process the data with different smoothing parameters. In addition, by interacting with this visualization we can gain a better understanding of the operation parameters as well as gain insights into the structure of the underlying data.\n", "\n", + "## Operations on 2D elements\n", + "\n", + "Let's look at another example of operations in action, this time applying a simple filter to an `Image`. The basic idea is the same as above, although accessing the values to be transformed is a bit more complicated. First, we prepare an example image:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%output backend=\"matplotlib\"\n", + "\n", + "from scipy.misc import ascent\n", + "\n", + "stairs_image = hv.Image(ascent()[200:500, :], bounds=[0, 0, ascent().shape[1], 300], label=\"stairs\")\n", + "stairs_image" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We'll define a simple ``Operation``, which takes an ``Image`` and applies a high-pass or low-pass filter. We then use this to build a ``HoloMap`` of images filtered with different sigma values:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%output backend=\"matplotlib\"\n", + "\n", + "from scipy import ndimage\n", + "\n", + "class image_filter(hv.Operation):\n", + " \n", + " sigma = param.Number(default=5)\n", + " \n", + " type_ = param.String(default=\"low-pass\")\n", + "\n", + " def _process(self, element, key=None):\n", + " xs = element.dimension_values(0, expanded=False)\n", + " ys = element.dimension_values(1, expanded=False)\n", + " \n", + " # setting flat=False will preserve the matrix shape\n", + " data = element.dimension_values(2, flat=False)\n", + " \n", + " if self.p.type_ == \"high-pass\":\n", + " new_data = data - ndimage.gaussian_filter(data, self.p.sigma)\n", + " else:\n", + " new_data = ndimage.gaussian_filter(data, self.p.sigma)\n", + " \n", + " label = element.label + \" ({} filtered)\".format(self.p.type_)\n", + " # make an exact copy of the element with all settings, just with different data and label:\n", + " element = element.clone((xs, ys, new_data), label=label)\n", + " return element\n", + "\n", + "stairs_map = hv.HoloMap({sigma: image_filter(stairs_image, sigma=sigma)\n", + " for sigma in range(0, 12, 1)}, kdims=\"sigma\")\n", + "stairs_map" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Just as in the previous example, it is quite straight-forward to build a HoloMap containing results for different parameter values. Inside the ``_process()`` method, the given parameters can be accessed as ``self.p.`` (note that ``self.`` always contains the default value!). Since we did not specify the ``type_`` parameter, it defaulted to \"low-pass\".\n", + "\n", + "There are some peculiarities when applying operations to two-dimensional elements:\n", + "\n", + "- Understanding the ``dimension_values()`` method: In principle, one could use ``element.data`` to access the element's data, however, since HoloViews can wrap a wide range of data formats, ``dimension_values()`` provides an API that lets you access the data without having to worry about the type of the data. The first parameter specifies the dimension to be returned. On a 2D element like an Image or Raster the first two dimensions reference the key dimensions, so passing an index of 0 or 1 will return the x- and y-axis values respectively. Any subsequent dimensions will be value dimensions, e.g. on an Image index value 2 will refer to the intensity values and on an RGB index values 2, 3, and 4 will return the Red, Green and Blue intensities instead. Setting ``expanded=False`` yields only the axis, while the default setting ``expanded=True`` returns a value for every pixel. Specifying ``flat=False`` means that the data's matrix shape will be preserved, which is what we need for this kind of filter.\n", + "- ``Image`` and related classes come with convenient methods to convert between matrix indices and data coordinates and vice versa: ``matrix2sheet()`` and ``sheet2matrix()``. This is useful when searching for features such as peaks.\n", + "\n", + "A very powerful aspect of operations is the fact that they understand Holoviews data structures. This means it is very straight-forward to apply an operation to every element in a container. As an example, let's apply an additional high-pass filter to our HoloMap:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%%output backend=\"matplotlib\"\n", + "\n", + "image_filter(stairs_map, type_=\"high-pass\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note, that the sigma value for the high-pass filter has defaulted to 5, and the sigma value in the HoloMap still corresponds to the original low-pass filter.\n", + "\n", + "\n", "## Benefits of using ``Operation``\n", "\n", "Now that we have seen some operations in action we can get some appreciation of what makes them useful. When working with data interactively we often end up applying a lot of ad-hoc data transforms, which provides maximum flexibility but is neither reproducible nor maintainable. Operations allow us to encapsulate analysis code using a well defined interface that is well suited for building complex analysis pipelines:\n",