import numpy as np import holoviews as hv hv.extension('bokeh')
Instantly viewable HoloViews objects include elements (discussed already) and containers (collections of elements or other containers). Here we’ll introduce two types of containers for collecting viewable objects, each typically created from the existing objects using a convenient operator syntax:
+):** A collection of any HoloViews objects to be displayed side by side.
*): A collection of HoloViews objects to be displayed overlaid on one another with the same axes.
The Layout and Overlay containers allow you to mix types in any combination, and have an ordering but no numerical or categorical key dimension with which to index the objects. In contrast, the Dimensioned containers discussed later, such as
NdLayout, do not allow mixed types, and each item has an associated numerical or categorical index (key).
Because you can compose a mix of any HoloViews elements into layouts and overlays, these types of container are very common, which is why they have dedicated composition operators. This user guide describes how you can build and organize your data using these two types of composition.
To show how layouts and overlays work with heterogeneous types, we will use these two elements throughout this notebook:
xs = [0.1* i for i in range(100)] curve = hv.Curve((xs, [np.sin(x) for x in xs])) scatter = hv.Scatter((xs[::5], np.linspace(0,1,20)))
Layout can contain any HoloViews object except an
NdLayout. (See Building Composite Objects for the full details about the ways containers can be composed.)
You can build a
Layout from two or more HoloViews objects of any type by using the
curve + scatter
In this example, we have a
Layout composed of a
Curve element and a
Scatter element, and they happen to share the same
Layout from a list#
+ syntax is not convenient, you can also build a
Layout using its constructor directly, which is useful if you want to create a
Layout of an arbitrary length:
curve_list = [hv.Curve((xs, [np.sin(f*x) for x in xs])) for f in [0.5, 0.75]] scatter_list = [hv.Scatter((xs[::5], f*np.linspace(0,1,20))) for f in [-0.5, 0.5]] layout = hv.Layout(curve_list + scatter_list).cols(2) layout
Note the use of the
.cols method to specify the number of columns, wrapping to the next row in scanline order (left to right, then top to bottom).
Layout has two-level attribute access#
Overlay are tree-based data structures that can hold arbitrarily heterogeneous collections of HoloViews objects, and are quite different from the dictionary-like dimensioned containers (which will be described in later guides).
As mentioned previously in Annotating Data, HoloViews objects have string
label parameters, which can be used to select objects in the
Layout using two-level attribute access. First let us see how to index the above example, where the
label parameters were left unspecified on creation:
:Layout .Curve.I :Curve [x] (y) .Curve.II :Curve [x] (y) .Scatter.I :Scatter [x] (y) .Scatter.II :Scatter [x] (y)
As you can see, the
layout object consists of four different elements, each mapping from
y. You can use the “dot” syntax shown in the repr to select individual elements from the layout:
layout2 = layout.Curve.I + layout.Scatter.II layout2
Here we create a second layout by indexing two elements from our earlier
layout object and using
+ between them. We see that the first level of indexing is the
group string (which defaults to the element class name) followed by the label, which wasn’t set and is therefore mapped to an automatically generated Roman numeral (I,II,III,IV, etc.).
As group and label were again not specified, our new
Layout will also use
Curve.I for the curve, but as there is only one scatter element, it will have
Scatter.I to index the scatter:
Now let’s return to the first simple layout example, this time setting a group and label as introduced in the Annotating Data guide:
xs = [0.1* i for i in range(100)] low_freq = hv.Curve((xs, [np.sin(x) for x in xs]), group='Sinusoid', label='Low Frequency') linpoints = hv.Scatter((xs[::5], np.linspace(0,1,20)), group='Linear Points', label='Demo') labelled = low_freq + linpoints labelled
As you can see, the group and label are used for titling the plots. They also determine how the objects are accessed:
labelled.Linear_Points.Demo + labelled.Sinusoid.Low_Frequency
You are encouraged to use the group and label names as appropriate for organizing your own data. They should let you easily refer to groups of data that are meaningful to your domain, e.g. for Applying Customizations.
Overlay can contain any HoloViews elements, but the only container type it can contain is
NdOverlay. Building Composite Objects provides the full details on how containers can be composed.
Other than being composed with
* and displaying elements together in the same space,
Overlay shares many of the same concepts as layout. The rest of this section will show the overlay equivalents of the manipulations shown above for layout.
First, composition with
* instead of
+ results in a single overlaid plot, rather than side-by-side plots:
curve * scatter
Overlay from a list#
Overlay can be built explicitly from a list, just like a
curve_list = [hv.Curve((xs, [np.sin(f*x) for x in xs])) for f in [0.5, 0.75]] scatter_list = [hv.Scatter((xs[::5], f*np.linspace(0,1,20))) for f in [-0.5, 0.5]] overlay = hv.Overlay(curve_list + scatter_list) overlay
As you can see, a special feature of
Overlay compared to
Layout is that overlays use color cycles to help keep the overlaid plots distinguishable, which you can learn about in Applying Customization.
Overlay also has two-level attribute access#
Overlay is fundamentally a tree structure holding arbitrarily heterogeneous HoloViews objects, unlike the dimensioned containers.
Overlay objects also make use of the
label parameters, introduced in Annotating Data, for two-level attribute access.
Once again, let us see how to index the above example where the
label parameters were left unspecified:
:Overlay .Curve.I :Curve [x] (y) .Curve.II :Curve [x] (y) .Scatter.I :Scatter [x] (y) .Scatter.II :Scatter [x] (y)
overlay.Curve.I * overlay.Scatter.II
Here we create a second overlay by indexing two elements from our earlier
overlay object and using
* between them. We see that the first level is the
group string (which defaults to the element class name) followed by the label, which wasn’t set and is therefore mapped to a Roman numeral.
Now let’s return to the first simple overlay example, this time setting
label as introduced in the Annotating Data guide:
high_freq = hv.Curve((xs, [np.sin(2*x) for x in xs]), group='Sinusoid', label='High Frequency') labelled = low_freq * high_freq * linpoints labelled
Once again, this example follows the corresponding
Layout example, although this time we added a high-frequency curve to demonstrate how
label are now used to generate the legend (as opposed to the title, as it was for
The following example shows how
label affect access:
labelled.Linear_Points.Demo * labelled.Sinusoid.High_Frequency * labelled.Sinusoid.Low_Frequency
This new re-ordered
Overlay switches the z-ordering as well as the legend color of the two sinusoidal curves. The colors and other plot options can be set for specific groups and labels as described in
Layouts of overlays#
Of course, layouts work with both elements and overlays:
overlay + labelled + labelled.Sinusoid.Low_Frequency
Overlay are designed to be easy to explore and inspect with tab completion. Try running:
In a code cell and you should see the first levels of indexing (
Scatter) conveniently listed at the top. If this is not the case, you may need to enable improved tab-completion as described in Configuring HoloViews.
Having seen how to compose viewable objects, the next section shows how to apply customizations.