Introduction ¶

Welcome to HoloViews!

This tutorial explains the basics of how to use HoloViews to explore your data. If this is your first contact with HoloViews, you may want to start by looking at our showcase to get a good idea of what can be achieved with HoloViews. If this introduction does not cover the type of visualizations you need, you should check out our Elements and Containers components to see what else is available.

What is HoloViews? ¶

HoloViews allows you to collect and annotate your data in a way that reveals it naturally, with a minimum of effort needed for you to see your data as it actually is . HoloViews is not a plotting library -- it connects your data to plotting code implemented in other packages, such as matplotlib or Bokeh . HoloViews is also not primarily a mass storage or archival data format like HDF5 -- it is designed to package your data to make it maximally visualizable and viewable interactively.

If you supply just enough additional information to the data of interest, HoloViews allows you to store, index, slice, analyze, reduce, compose, display, and animate your data as naturally as possible. HoloViews makes your numerical data come alive, revealing itself easily and without extensive coding.

Here are a few of the things HoloViews allows you to associate with your data:

• The Element type . This encapsulates your data and is the most fundamental indicator of how your data can be analyzed and displayed. For instance, if you wrap a 2D numpy array in a  Image  it will be displayed as an image with a colormap by default, a  Curve  will be presented as a line plot on an axis, and so on. Once your data has been encapsulated in an  Element  object, other  Elements  can easily be created from it, such as obtaining a  Curve  by taking a cross-section of a  Image  .
• Dimensions of your data . The key dimensions (  kdims  ) describe how your data can be indexed. The value dimensions (  vdims  ) describe what the resulting indexed data represents. A numerical  Dimension  can have a name, type, range, and unit. This information allows HoloViews to rescale and label axes and allows HoloViews be smart in how it processes your data.
• The multi-dimensional space in which your data resides . This may be space as we normally think of it (in x , y , and z coordinates). It may be the spatial position of one component relative to another. Or it may be an entirely abstract space, such as a parameter space or a list of experiments done on different days. Whatever multi-dimensional space characterizes how one chunk of your data relates to another chunk, you can embed your data in that space easily, sparsely populating whatever region of that space you want to analyze.
• How your data should be grouped for display . In short, how you want your data to be organized for visualization. If you have a collection of points that was computed from an image, you can easily overlay your points over the image. As a result you have something that both displays sensibly, and is grouped together in a semantically meaningful way.

HoloViews can display your data even if it knows only the Element type, which lets HoloViews stay out your way when initially exploring your data, offering immediate feedback with reasonable default visualizations. As your analysis becomes more complex and your research progresses, you may offer more of the useful metadata above so that HoloViews will automatically improve your displayed figures accordingly. Throughout, all you need to supply is this metadata plus optional and separate plotting hints (such as choosing specific colors if you like), rather than having to write cumbersome code to put figures together or having to paste bits together manually in an external drawing or plotting program.

Note that the HoloViews data components have only minimal required dependencies (Numpy and Param, both with no required dependencies of their own). This data format can thus be integrated directly into your research or development code, for maximum convenience and flexibility (see e.g. the ImaGen library for an example). Plotting implementations are currently provided for matplotlib and Bokeh, and other plotting packages could be used for the same data in the future if needed. Similarly, HoloViews provides strong support for the IPython/Jupyter notebook interface, and we recommend using the notebook for building reproducible yet interactive workflows , but none of the components require IPython either. Thus HoloViews is designed to fit into your existing workflow, without adding complicated dependencies.

Getting Started ¶

To enable IPython integration, you need to load the IPython extension as follows:

In [1]:
import holoviews as hv
hv.notebook_extension()

HoloViewsJS successfully loaded in this cell.

We'll also need Numpy for some of our examples:

In [2]:
import numpy as np


Interactive Documentation ¶

HoloViews has very well-documented and error-checked constructors for every class (provided by the Param library). There are a number of convenient ways to access this information interactively. E.g. if you have imported  holoviews  and  Element  and have instantiated an object of that type:

import holoviews as hv
hv.Element(None, group='Value', label='Label')


You can now access the online documentation in the following ways:

•  hv.help(Element)  or  hv.help(e)  : description and parameter documentation for an object or type
•  hv.help(Element,pattern="group")  : only show help items that match the specified regular expression (the string "group" in this example)
•  Element(<Shift+TAB>  in IPython: Repeatedly pressing  <Shift+TAB>  after opening an object constructor will get you more information on each press, eventually showing the full output of  hv.help(Element) 
•  hv.help(Element, visualization=True)  or  hv.help(e, visualization=True)  : description of options for visualizing an  Element  or the specific object  e  , not the options for the object itself
•  %%output info=True  on an IPython/Jupyter notebook cell or  %output info=True  on the whole notebook: show  hv.help(o, visualization=True)  for every HoloViews object  o  as it is returned in a cell.

Lastly, you can tab-complete nearly all arguments to HoloViews classes, so if you try  Element(vd<TAB>  , you will see the available keyword arguments (  vdims  in this case). All of these forms of help are described in detail in the options tutorial.

A simple visualization ¶

To begin, let's see how HoloViews stays out your way when initially exploring some data. Let's view an image, selecting the appropriate RGB Element . Now, although we could immediately load our image into the  RGB  object, we will first load it into a raw Numpy array (by specifying  array=True  ):

In [3]:
parrot = hv.RGB.load_image('../assets/macaw.png', array=True)
print("%s with shape %s" % (type(parrot),parrot.shape))

<type 'numpy.ndarray'> with shape (400, 400, 4)


As we can see this 400×400 image data array has four channels (the fourth being an unused alpha channel). Now let us make an  RGB  element to wrap up this Numpy array with its associated label:

In [4]:
rgb_parrot = hv.RGB(parrot, label='Macaw')
rgb_parrot

Out[4]:

Here  rgb_parrot  is an  RGB  HoloViews element, which requires 3 or 4 dimensional data and can store an associated label.  rgb_parrot  is not a plot -- it is just a data structure with some metadata. The  holoviews.ipython  extension, in turn, makes sure that any  RGB  element is displayed appropriately, i.e. as a color image with an associated optional title, plotted using matplotlib. But the  RGB  object itself does not have any connection to the plotting library, and stores no data about the plot, just its own data, which is sufficient for the external plotting routines to visualize the data usefully and meaningfully. And the same plot can be generated outside of IPython just as easily, e.g. to save as a  .png  or  .svg  file.

Because  rgb_parrot  is just our actual data, it can be composed with other objects, pickled, and analyzed as-is. For instance, we can still access the underlying Numpy array easily via the  .data  attribute, and can verify that it is indeed our actual data:

In [5]:
rgb_parrot.data is parrot

Out[5]:
True

Note that this is generally true throughout HoloViews; if you pass a HoloViews element a Numpy array of the right shape, the  .data  attribute will simply be a reference to the data you supplied. If you use an alternative data format when constructing an element, such as a Python list, a Numpy array of the appropriate type will be created and made available through the  .data  attribute. You can always use the identity check demonstrated above if you want to make absolutely sure your raw data is being used directly.

As you compose these objects together, you will see that a complex visualization is not simply a visual display, but a rich data structure containing all the raw data or analyzed data ready for further manipulation and analysis.

Viewing individual color channels

For some image analysis purposes, working in RGB colour space is too limiting. It is often more flexible to work with a single N×M array at a time and visualize the data in each channel using a colormap. To do this we need the Image  Element  instead of the  RGB   Element  .

To illustrate, let's start by visualizing the total luminance across all the channels of the parrot image, choosing a specific colormap using the HoloViews  %%opts  IPython cell magic .  %%opts Image  allows us to pass plotting hints to the underlying visualization code for  Image  objects:

In [6]:
%%opts Image style(cmap='coolwarm')
luminance = hv.Image(parrot.sum(axis=2), label='Summed Luminance')
luminance

Out[6]:

As described in the Options tutorial, the same options can also be specified in pure Python, though not quite as succinctly.

The resulting plot is what we would expect: dark areas are shown in blue and bright areas are shown in red. Notice how the plotting hints (your desired colormap in this case) are kept entirely separate from your actual data, so that the Image data structure contains only your actual data and the metadata that describes it, not incidental information like matplotlib or Bokeh options. We will now set the default colormap to grayscale for all subsequent cells using the  %opt  command, and look at a single color channel by building an appropriate  Image  element:

In [7]:
%opts Image style(cmap='gray')
red = hv.Image(parrot[:,:,0], label='Red')
red

Out[7]:

Here we created the red  Image  directly from the NumPy array  parrot  . You can also make a lower-dimensional HoloViews component by slicing a higher-dimensional one. For instance, now we will combine this manually constructed red channel with green and blue channels constructed by slicing the  rgb_parrot   RGB  HoloViews object to get the appropriate  Image  objects:

In [8]:
channels = red + rgb_parrot[:,:,'G'].relabel('Green') + rgb_parrot[:,:,'B'].relabel('Blue')
channels

Out[8]:

Here we have combined these three HoloViews objects using the compositional operator  +  to create a new object named  channels  . When  channels  is displayed by the IPython/Jupyter notebook, each  Image  is shown side by side, with appropriate labels. In this format, you can see that the parrot looks quite distinctly different in the red channel than the green and blue channel.

Note that the  channels  object isn't merely a display of three elements side by side, but a new composite object of type  Layout  containing our three  Image  objects:

In [9]:
print(channels)

:Layout
.Image.Red   :Image   [x,y]   (z)
.Image.Green :Image   [x,y]   (G)
.Image.Blue  :Image   [x,y]   (B)


Here the syntax  :Layout  means that this is an object of Python type  Layout  . The entries below it show that this  Layout  contains three items accessible via different attributes of the  channels  object, i.e.  channels.Image.Red  ,  channels.Image.Green  , and  channels.Image.Blue  . The string  :Image  indicates that each object is of type  Image  .

The attributes provide an easy way to get to the objects inside  channels  . In this case, the attributes were set by the  +  operator when it created the  Layout  , with the first level from the optional  group  of each object (discussed below, here inheriting from the type of the object), and the second from the  label  we defined for each object above. As for other HoloViews objects, tab completion is provided, so you can type  channels.I<TAB>.B<TAB>  to get the Blue channel:

In [10]:
channels.Image.Blue

Out[10]:

You can see that for each item in the  Layout  , using  print()  shows us its Python type (  Image  ) and the attributes needed to access it (  .Image.Blue  in this case). The remaining items in brackets and parentheses in the printed representation will be discussed below.

Since we can access the channels easily, we can recompose our data how we like, e.g. to compare the Red and Blue channels side by side:

In [11]:
channels.Image.Red + channels.Image.Blue

Out[11]:

Notice how the labels we have set are useful for both the titles and for the indexing, and are thus not simply plotting-specific details -- they are semantically meaningful metadata describing this data. There are also sublabels A and B generated automatically for each subfigure; these can be changed or disabled if you prefer.

In [12]:
%%opts Layout [sublabel_format="{alpha}"]
channels.Image.Red + channels.Image.Green + channels.Image.Green

Out[12]: