This notebook serves as a reference for all the container types in HoloViews, with an extensive list of small, self-contained examples wherever possible, allowing each container type to be understood and tested independently. The container types generally need to contain Elements to be useful, which are described separately. We first cover the tree-based containers, which are used in many of the examples elsewhere:

[``Layout``](#Layout)
Collect components into a tree, displaying them side by side (``+`` operator)
[``Overlay``](#Overlay)
Collect components into a tree, displaying them on top of one another (``*`` operator)

The remaining container types are most useful for exploring parameter spaces:

[``HoloMap``](#HoloMap)
Visualize N-dimensional spaces using sliders or as an animation.
[``GridSpace``](#GridSpace)
Parameter space in two dimensions laid out in a grid.
[``NdLayout``](#NdLayout)
Parameter space of any dimensionality in a layout with titles.
[``NdOverlay``](#NdOverlay)
Parameter space of any dimensionality in an overlay with a legend

There is a separate Composing Data tutorial explaining how each of these can be combined and nested, once you are familiar with the individual containers.

Trees


In [ ]:
import numpy as np
import holoviews as hv
%reload_ext holoviews.ipython

To display detailed information about each object displayed in this notebook run the following code in a cell:

%output info=True

For convenience, in this tutorial we have specified %output info=True, which will pop up a detailed list and explanation of the available options for visualizing each container type, after that notebook cell is executed. So, to find out all the options for any of these container types, just press <Shift-Enter> on the corresponding cell in the live notebook. See the Options tutorial tutorial for detailed information about how to set or examine these options for a given component.

Layout

Layout places nearly any possible components alongside each other, as described in more detail in the Introductory tutorial. The .cols() method of Layout can be used to regroup the components into the specified number of columns for display, if desired.


In [ ]:
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
pair = hv.Curve(points) + hv.ItemTable([('A',1),('B',2)])
pair

Layout subfigure labels

By default, a Layout will label the subfigures as in A and B above. You can easily configure this behaviour by setting the sublabel_format option to None (no sublabels at all), or "{numeric}": 2, "{roman}": ii, "{Roman}": II, "{alpha}": b, or "{Alpha}": B, and you can also change the sublabel size and relative position:


In [ ]:
%%opts Layout [sublabel_format="({numeric})."] Curve [sublabel_size=20] ItemTable [sublabel_position=(0.05, 0.8) sublabel_size=10]
pair

You can also set these options globally if you consistently prefer a different style, or to disable the subfigure labelling altogether, either using a line magic:

%opts Layout [sublabel_format=None]

or Python code:

from holoviews.core.options import Store, Options
Store.options.Layout = Options('plot', sublabel_format=None)

from holoviews.plotting import ElementPlot
ElementPlot.set_param(sublabel_size=30,sublabel_position=(1.0,-0.1))

Layout with custom aspects

The aspect ratios of Elements in a Layout can also be adjusted allowing you to quickly compose a complex figure.


In [ ]:
%%opts Image.A [aspect=1.5] Image.C [aspect=0.5 sublabel_position=(-0.7, 0.85) xticks=3]
np.random.seed(42)
(hv.Image(np.random.rand(25, 25), group='A') +
 hv.Image(np.random.rand(25, 25), group='B') +
 hv.Image(np.random.rand(25, 25), group='C'))

When aspects vary across elements, there is no single valid arrangement suitable for presenting the elements together. For instance, in the above example, the widths are kept constant while the heights are varying due to the differences in the element aspect ratios. An alternative arrangement may be achieved by setting the aspect_weight plot option from 0 (the default value shown above) to 1.0:


In [ ]:
%%opts Layout [aspect_weight=1.0] Image.A [aspect=1.5] Image.C [aspect=0.5 sublabel_position=(-0.7, 0.85) xticks=3]
np.random.seed(42)
(hv.Image(np.random.rand(25, 25), group='A') +
 hv.Image(np.random.rand(25, 25), group='B') +
 hv.Image(np.random.rand(25, 25), group='C'))

The aspect_weight parameter can take any value between 0 and 1 which will adjust how any Layout containing elements with non square-aspects are presented. Note that when there are multiple rows and columns and many elements with different aspect ratios, it is often necessary to explore the effect of changing this parameter to generate a suitable plot.

Using Empty as a placeholder in Layout

In order to arrange elements within a Layout, it can sometimes be useful to introduce empty gaps. For this the Empty pseudo-element may be used as follows:


In [ ]:
import numpy as np
from holoviews import Curve, ItemTable, Empty
sine_points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
cosine_points = [(0.1*i, np.cos(0.1*i)) for i in range(100)]
(hv.ItemTable([('A',1),('B',2)]) + hv.Curve(sine_points) + hv.Empty() + hv.Curve(cosine_points)).cols(2)

The Empty pseudo-element contains no data, cannot be customized in any way as is never associated with a sub-label. The reason Empty is called a pseudo element is that it is only allowed to be used in Layout and cannot be used as an element in any other type of container.

Overlay

Overlays are often built using * as in the Introductory tutorial, but they can also be built by hand. Using vector_data from the VectorField Element example, we can overlay the vector field on top of an Image component (or any other component, though not all combinations will be useful or clear due to occlusion):


In [ ]:
%%opts VectorField (color='r') Image (cmap='gray')
x,y  = np.mgrid[-10:10,-10:10] * 0.25
sine_rings  = np.sin(x**2+y**2)*np.pi+np.pi
exp_falloff = 1/np.exp((x**2+y**2)/8)

vector_data = np.array([x.flatten()/5.,           # X positions
                        y.flatten()/5.,           # Y positions
                        sine_rings.flatten(),     # Arrow angles
                        exp_falloff.flatten()])   # Arrow sizes

hv.Image(sine_rings) * hv.VectorField(vector_data.T)

Parameter Spaces

HoloViews also supplies container classes useful for visualizing parameter spaces or phase spaces, i.e. large collections of results for various combinations of parameters.

In addition to the container types discussed here, the HeatMap Element is also useful for visualizing small two-dimensional parameter spaces that have a single value for each location in the space. See also the separate Lancet tool, which works well with HoloViews for launching and collating results from separate computational jobs covering large parameter spaces, which HoloViews can then analyze with ease.

Specifying arbitrary parameter spaces

First let us define some numpy arrays which we will use to define the types of parameter space below.


In [ ]:
frequencies =  np.linspace(0.5,2.0,5)
phases = np.linspace(0, np.pi*2, 5)
x,y = np.mgrid[-50:51, -50:51] * 0.1

A parameter space of Image elements


In [ ]:
def sine_array(phase, freq):
    return np.sin(phase + (freq*x**2+freq*y**2))

matrices = {(p, f): hv.Image(sine_array(p, f), label='Sinusoid Ring', group='Amplitude')
          for f in [0.5, 1.0,  1.5,  2.0]    # Frequencies
          for p in [0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi]}  # Phases

To illustrate that matrices is a dictionary indexed by (phase, frequency) here are two of the dictionary elements side by side:


In [ ]:
matrices[0,0.5] + matrices[np.pi,0.5]

A parameter space of Curve elements


In [ ]:
def sine_curve(phase, freq, samples=102):
    xvals = [0.1* i for i in range(samples)]
    return [(x, np.sin(phase+freq*x)) for x in xvals]

curves = {(round(p,2), f): hv.Curve(sine_curve(p,f)) 
          for f in [1,2,3,4,5]                               # Frequencies
          for p in [0, np.pi/2, np.pi, 3*np.pi/2, 2*np.pi]}  # Phases

Here we display two of our curves and then overlay them together with * (which chooses new colors for each new curve according to a predefined color cycle that can be selected as a plot option):


In [ ]:
curves[0,1] + curves[3.14, 2] + curves[0,1] * curves[3.14, 2]

HoloMap

A HoloMap is a very powerful multi-dimensional data structure that can hold a very large number of similar Element objects, e.g. those measured for different values in a parameter space, and then allows easy exploration, animation, and slicing of the parameter and value spaces. Usage of this type is covered extensively in the Exploring Data tutorial. Here we show how a HoloMap can be used to explore all of the different Image objects created for each combination of phase and frequency:


In [ ]:
%%opts Image (cmap='gray')
hv.HoloMap(matrices, kdims=['phase', 'frequency'])

GridSpace

Whenever a HoloMap has more than one item to display, it will be visualized as an animation or using slider widgets as above, displaying one item (e.g. one Element) at any given time. If you have up to a two-dimensional parameter space, you can see all your data items at once using a GridSpace to lay out your data with labelled axes:


In [ ]:
%%output size=140
ring_space  = hv.GridSpace(matrices, kdims=['phase', 'frequency'])
curve_space = hv.GridSpace(curves,   kdims=['phase', 'frequency'])
ring_space + curve_space

Of course, each item in the grid can also be a combination of other plots, such as an Overlay or an NdOverlay (below).

NdLayout

GridSpace is great when you have a two-dimensional parameter space, but fails to scale well beyond that. For higher-dimensional parameter spaces, you can use an NdLayout, where the varying key dimensions are shown in the titles of the elements:


In [ ]:
from holoviews import NdLayout
hv.NdLayout(matrices, kdims=['phase', 'frequency'])[0:1.6, 0:2].cols(3)

NdOverlay

NdOverlay is to Overlay what NdLayout is to Layout, in other words it is a way of looking at a parameter space as an Overlay. This generally makes NdOverlay less useful than NdLayout, because some element types don't overlay nicely over each other (e.g. multiple Image elements just obscure one another). Also, though the NdOverlay is more compact, it is easy for an NdOverlay to present too much data at once.

Unlike a regular Overlay, the elements of an NdOverlay must always be of the same type.

To demonstrate this, we will overlay several of the curves from our phase space. To make sure the result is legible, we filter our parameter space down to four curves:


In [ ]:
%%output size=150
four_curves = {(p, f): val for ((p,f), val) in curves.items() if p <=np.pi/2 and f<=2}
hv.NdOverlay(four_curves, kdims=['Phase', 'Frequency'])

Because NdOverlay ensures all the contained elements are of the same type, it can now supply a useful legend. As with everything in HoloViews, overlaying is a very general concept, and it works with any other type that can be meaningfully overlaid. Here is another example using Points:


In [ ]:
%%output size=150
np.random.seed(10)
extents = (-3, -3, 3, 3)
hv.NdOverlay({1: hv.Points(np.random.normal(size=(50,2)), extents=extents),
              2: hv.Points(np.random.normal(size=(50,2)), extents=extents),
              3: hv.Points(np.random.normal(size=(50,2)), extents=extents)},
             kdims=['Cluster'])