Customizing Plots

In [1]:
import pandas as pd
import numpy as np
import holoviews as hv
hv.extension('bokeh', 'matplotlib')

As introduced in the Customization section of the 'Getting Started' guide, HoloViews separates the notion of content from presentation. This is achieved using a tree datastructure containing simply keyword values that specify how elements are to appear, either by type, by their group and label specification as introduced in Annotating Data or for individual element instances.

In addition, HoloViews has the notion of Renderer instance that normally work behind the scenes to control how output is generated for the selected plotting extension. In this guide, we will first show how you can customize the visual styling with the options system and then how you can easily control the output options of renderers.

Visual options and styling

The different types of visual options will be illustrated using the example introduced in the Customization getting started guide. First we create a curve and a spikes element:

In [2]:
spike_train = pd.read_csv('../assets/spike_train.csv.gz')
curve  = hv.Curve( spike_train, 'milliseconds', 'Hertz')
spikes = hv.Spikes(spike_train, 'milliseconds', [])

And now we display it as we did in the getting started guide:

In [3]:
%%output size=150
%%opts Curve  [height=100 width=600 xaxis=None tools=['hover']]
%%opts Curve (color='red' line_width=1.5)
%%opts Spikes [height=100 width=600 yaxis=None] (color='grey' line_width=0.25)
curve  = hv.Curve( spike_train, 'milliseconds', vdims='Hertz')
spikes = hv.Spikes(spike_train, 'milliseconds', vdims=[])
(curve+spikes).cols(1)
Out[3]:

Introducing plot and style options

This example allows us to expand on the concepts introduced in the Customization getting started guide. First, we note that two things are immediately apparent (1) almost all the customization is going on at the top of the cell, leaving the declaration of our elements and layout nearly unchanged and (2) this customization syntax that is specific to IPython and the Jupyter notebook and is not valid Python. We will use this syntax in this section but it is important to note that we have regular Python equivalents to these tools as will be described shortly.

Let's start with the one difference to how our layout is declared, namely the use of .cols(1) at the end. If you delete the lines starting with % at the top of the cell and re-execute it, you will see this simply rearranges the default layout to a single column format, with the curve above the spikes instead of next to it.

Now let us go through the lines starting with %%output and %%opts , starting with the first line:

%%output size=150

This is the output cell magic which customizes the output format of a particular cell by instructing the active plotting renderer with the desired size. There is a corresponding cell line magic to set things globally and a hv.output utility (for both local and global settings) that you can read about below. All these output tools accept a size options which in this case sets our plot size to 150% of the default.

Next we have:

%%opts Curve  [height=100 width=600 xaxis=None show_grid=False tools=['hover']]

This is the opts cell magic which customizes the visual presentation of elements displayed in a particular cell. In this case, it specifies a set of keywords relevant to our Curve element in square brackets. These list of keywords are plot options that specify the settings that HoloViews is to use to plot Curve elements.

In this case we want to make an elongated Curve plot to make it easier to view the timeseries and to allow for a corresponding elongated spikes plot underneath which is why we specified the width and height keywords. We also want to disable the xaxis (our Curve plot will give us a suitable millisecond below). Finally with tools=['hover'] we add the Bokeh hover tool to our plot: try hovering your pointer over the red curve to see the exact values of each sample!

The next line specifies a second set of keywords relating to our Curve element:

%%opts Curve (color='red' line_width=1.5)

In this case, our list of keywords are in parentheses specifying style options with are Bokeh specific and passed down directly from HoloViews to Bokeh. The color and line_width options are not part of the HoloViews API but keywords used to customize the appearance of Bokeh glyphs .

Lastly we have use the %%opts cell magic to customize the appearance of our Spikes element:

%%opts Spikes [height=100 width=600 yaxis=None] (color='grey' line_width=0.25)

This introduces no new concepts other than the fact that you can declare plot and style options on the same line. In these plot options, we match the elongated height and width values of the curve and disable the yaxis. In the style options we make the spikes 'grey' in color with a line_width value of 0.25.

In addition to plot and style options, there are normalization norm options that will be discussed shortly. Now we have worked through a concrete examples, we can now describe the syntax used in more detail.

Option specification syntax

Here are the three types of visualization options in HoloViews:

Option types

style options:

style options are passed directly to the underlying rendering backend that actually draws the plots, allowing you to control the details of how it behaves. The default backend is matplotlib, but there are other backends either using matplotlib's options (e.g. mpld3 ), or their own sets of options (e.g. bokeh ).

For whichever backend has been selected, HoloViews can tell you which options are supported, but you will need to see the plotting library's own documentation (e.g. matplotlib , bokeh ) for the details of their use.

HoloViews has been designed to be easily extensible to additional backends in the future, such as Plotly , Cairo, VTK, or D3.js, and if one of those backends were selected then the supported style options would differ.

plot options:

Each of the various HoloViews plotting classes declares various Parameters that control how HoloViews builds the visualization for that type of object, such as plot sizes and labels. HoloViews uses these options internally; they are not simply passed to the underlying backend. HoloViews documents these options fully in its online help and in the Reference Manual . These options may vary for different backends in some cases, depending on the support available both in that library and in the HoloViews interface to it, but we try to keep any options that are meaningful for a variety of backends the same for all of them.

norm options:

norm options are a special type of plot option that are applied orthogonally to the above two types, to control normalization. Normalization refers to adjusting the properties of one plot relative to those of another. For instance, two images normalized together would appear with relative brightness levels, with the brightest image using the full range black to white, while the other image is scaled proportionally. Two images normalized independently would both cover the full range from black to white. Similarly, two axis ranges normalized together will expand to fit the largest range of either axis, while those normalized separately would cover different ranges. See the norm options section below.

Selecting with type , group and label

The three types of option mentioned above can be associated with HoloViews objects at three levels of specificity: at the level of the element type , by the assigned element group and then by the assigned label .

Here is an example of the three levels of specificity using different curves below:

In [4]:
%%opts Curve (color='blue')
%%opts Curve.Sinusoid (color='red')
%%opts Curve.Sinusoid.Squared [interpolation='steps-mid'] (color='green')
xs = np.linspace(-np.pi,np.pi,100)
curve = hv.Curve((xs, xs/3))
group_curve1 = hv.Curve((xs, np.sin(xs)), group='Sinusoid')
group_curve2 = hv.Curve((xs, np.sin(xs+np.pi/4)), group='Sinusoid')
label_curve = hv.Curve((xs, np.sin(xs)**2), group='Sinusoid', label='Squared')
layout = curve * group_curve1 * group_curve2 * label_curve
layout
Out[4]:

The straight line has no group and label so it gets 'blue' from the Curve level of specificity. The two sine curves are red as they both have the group specification of 'Sinusoid'. Lastly we has a sine squared curve with the same group label of 'Sinusoid' but it also has the label 'Squared' which is why it is green.

Dictionary format

HoloViews avoids string parsing and special syntax (other than the basic operators described in Composing Elements ) where possible. For this reason, all options are fundamentally reduced to a simple dictionary format. For example, here is the pure Python equivalent of the options shown above, using the opts method that will be described shortly:

In [5]:
dict_spec = {'Curve':{'style':dict(color='blue')}, 
             'Curve.Sinusoid':{'style':dict(color='red')}, 
             'Curve.Sinusoid.Squared ': {'style':dict(color='green'), 'plot':dict(interpolation='steps-mid')}}
dcurve = hv.Curve((xs, xs/3))
dgroup_curve1 = hv.Curve((xs, np.sin(xs)), group='Sinusoid')
dgroup_curve2 = hv.Curve((xs, np.sin(xs+np.pi/4)), group='Sinusoid')
dlabel_curve = hv.Curve((xs, np.sin(xs)**2), group='Sinusoid', label='Squared')
dlayout = dcurve * dgroup_curve1 * dgroup_curve2 * dlabel_curve
dlayout.opts(dict_spec)
Out[5]:

Although it is as simple as possible, this format is tedious and verbose to use: HoloViews allows you to specify all your options separate from your elements in one specifiation which means there is a minimum possible complexity. For this reason, the most commonly used format is the succinct string format describe below, which is parsed into the dictionary format behind the scenes.

Yaml equivalent

HoloViews defines its own string options specification format described in the next section. Although HoloViews does not support yaml directly, it is instructive to see how the dictionary format is expressed in yaml :

Curve:
    style: {color: 'blue'}
Curve.Sinusoid:
    style: {color: 'red'}
Curve.Sinusoid.Squared:
    style: {color: 'green'}
    plot:  {interpolation: 'steps-mid'}

The reason HoloViews does not encourage the use of yaml is that yaml to literals and cannot express richer objects that can be used in options such as Cycle or Palette .

String format

We have seen the string format in this notebook as passed to the %%opts cell magic. Here is the definition of this format which is just a succinct way of specifing the dictionary format:

[[path] [normalization] [plotting options] [style options]]+

path:             A dotted type.group.label specification
                  (e.g. Image.Grayscale.Photo)

normalization:    List of normalization options delimited by braces.
                  One of | -axiswise | -framewise | +axiswise | +framewise |
                  E.g. { +axiswise +framewise }

plotting options: List of plotting option keywords delimited by
                  square brackets. E.g. [show_title=False]

style options:    List of style option keywords delimited by
                  parentheses. E.g. (lw=10 marker='+')

Applying options

Here are the different ways of applying the options specifications and the accepted format:

  • The %%opts cell magic : IPython specific syntax applies to displayed object [string format]
  • The %opts line magic : IPython specific syntax applied globally [string format]
  • The .opts method : Pure python method of HoloViews objects [string format, dictionary format] .
  • The hv.opts utility : Pure python equivalent to %opts and %%opts [string format, dictionary format]

In the notebook environment, the recommended approach is to use %opts for global settings at the top of the notebook, then %%opts to customize the output of specific cells and finally the .opts method as necessary. The hv.opts utility is mostly intended for use in Python scripts.

%%opts

As shown in the examples above, customizes a particular HoloViws output displayed in a code cell. This application is not global and persists for that object which means settings stay in place if the object is re-displayed. Only accepts the string specification format. All cell magics need to appear above any code in the cells they are used in and cannot be used if there is no code in the cell. Only accepts the string specification syntax.

%opts

The %opts line magic is used to set global settings at the level of the notebook they are used in. If there are options you want to use throughout a notebook, they should be specified with %opts at the top of the notebook. Line magics can appear anywhere at the start of a line, whether in isolation or anywhere inside a cell containing code. Only accepts the string specification syntax.

.opts method

Used to specify options to a specific holoviews object. Useful to parameterize options programatically that can be hard to specify otherwise:

In [6]:
hv.Overlay([hv.Curve((xs, np.sin(xs)**(i+1))).opts(style=dict(color=color, alpha=i+1/3.0)) 
            for (i, color) in enumerate(['red','green','blue'])])
Out[6]:

Note that you can split the dictionary format into groups using style , plot and norm keywords.

hv.opts utility

The hv.opts utility is for use in Python scripts. It can accept an object as an argment in which case it behaves like the %%opts cell magic or if it isn't supplied an object, it behaves like the %opts line magic. Accepts either the string or dict specification format.

Customizing output

In addition to style and plot options, you may want to specify the active plotting extension, the output format, the output size and other similar options. Here is how you can do this:

  • The %%output cell magic : IPython specific syntax applies to displayed object [string format]
  • The %output line magic : IPython specific syntax applied globally [string format]
  • The hv.output utility : Pure python equivalent to %output and %%output [string format, dictionary format] .

Selecting a plotting extension

At the start of this user guide, we used:

hv.extension('bokeh', 'matplotlib')

This enabled both the bokeh and matplotlib plotting extensions but activated the bokeh extension as it was listed first. We can switch to matplotlib for a single cell:

In [7]:
%%output backend='matplotlib'
hv.Curve((xs, np.cos(xs)))
Out[7]:

Because we used the cell magic, matplotlib was only used for that cell and bokeh is still active. We can now change the size of the label_curve we customized in bokeh earlier (with the %%opts cell magic) using the output cell magic and save it to an HTML file in disk by supplying a filename:

In [8]:
%%output size=80 filename='small_curve'
label_curve
Out[8]:

%output

The %output line magic acts exactly like the %%output cell magic except it acts globally. For instance, you can use this at the top of a notebook to make all visualizations bigger or smaller.

hv.output utility

The hv.output utility is the pure Python version of the magics which can accept keyword dictionaries as well as the string format used above. If supplied with an object, acts like the cell magic but this will have no effect unless a filename is supplied to save output to disk (see below). If not object is supplied, acts like the %output line magic.

Other output options

Here are some of the other options supported by the output utilities and magics:

  • size : Output size as a percentage of the original size.
  • filename : Cell magic or hv.output utility only. Save output to given filename.
  • fig : Output format for single frames. Options are backend dependent.
  • holomap : Display format for HoloMap , can be 'widgets' or 'scrubber'
  • dpi : The output resolution (where applicable)

Using the output and options system together, you should be able to customize your plots to your liking in a succinct manner.


Right click to download this notebook from GitHub.