HoloViews encapsulates your continuous or discrete data into storable, composable, sliceable objects, leveraging matplotlib or Bokeh for visualization and IPython/Jupyter Notebook for maximum productivity.

Main features:

  • Preserves your raw data while allowing rapid, interactive exploratory analysis.
  • Builds even complex, composite visualizations that are easily customized.
  • Succinct, declarative style allows you to keep all the necessary code visible, ensuring your workflow is transparent and fully reproducible.
  • You can select, slice, or transform only the relevant data that is currently of interest.
  • You can store your raw data as HoloViews objects via pickling, for later analysis or visualization even without the code that generated it.
  • Strong support for the IPython/Jupyter Notebook, including tab-completion throughout and convenient IPython magics (with all functionality available from pure Python as well).
  • Seamless (optional) interaction with Pandas Dataframes.
  • And much, much more!

The IPython/Jupyter notebook environment and matplotlib or bokeh allow you to do interactive exploration and analysis of your data and measurements, using the rich ecosystem of tools available in Python . However, your notebooks can very quickly fill up with verbose, specialized plotting code whenever you want to visualize your data, which is often. To make all this practical, you can use HoloViews to greatly improve your productivity, requiring orders of magnitude fewer lines of code and letting you focus on your data itself, not on writing code to visualize and display it.

Here we will show some of the main features of HoloViews, focusing on why it is useful for scientists and engineers.

In [1]:
import holoviews as hv
import numpy as np

A simple function

First, let us define a mathematical function to explore, using the Numpy array library:

In [2]:
def sine(x, phase=0, freq=100):
    return np.sin((freq * x + phase))

We will examine the effect of varying phase and frequency:

In [3]:
phases = np.linspace(0,2*np.pi,11) # Explored phases
freqs = np.linspace(50,150,5)      # Explored frequencies

Over a specific spatial area, sampled on a grid:

In [4]:
dist = np.linspace(-0.5,0.5,202)   # Linear spatial sampling
x,y = np.meshgrid(dist, dist)
grid = (x**2+y**2)                 # 2D spatial sampling

Compact data visualization

With HoloViews, we can immediately view our simple function by creating Image and Curve objects to visualize the 2D arrays and 1D cross-sections generated by the sine function, respectively:

In [5]:
freq1 = hv.Image(sine(grid, freq=50))  + hv.Curve(zip(dist, sine(dist**2, freq=50)))
freq2 = hv.Image(sine(grid, freq=200)) + hv.Curve(zip(dist, sine(dist**2, freq=200)))
(freq1 + freq2).cols(2)

As you can see, Image takes a 2D numpy array as input and Curve accepts a list of (x,y) points. With the + operator we can lay these elements out together and with .cols(2) we can arrange them into two columns.

HoloViews objects like Image and Curve are a great way to work with your data, because they display so easily and flexibly, yet preserve the raw data (the Numpy array in this case) in the .data attribute. Calling matplotlib directly to generate such a figure would take much, much more code, e.g., to label each of the axes, to create a figure with subfigures, etc. Moreover, such code would be focused on the plotting, whereas with HoloViews you can focus directly on what matters: your data, letting it plot itself. Because the HoloViews code is so succinct, you don't need to hide it away in some difficult-to-maintain external script; you can simply type what you want to see right in the notebook, changing it at will and being able to come back to your analysis just as you left it.

Only two element types are shown above, but HoloViews supports many other types of element that behave in the same way: scatter points, histograms, tables, vectorfields, RGB images, 3D plots, annotations , and many more as shown in the Elements overview . All of these can be combined easily to create even quite complex plots with a minimum of code to write or maintain.

Interactive exploration

We can interactively explore this simple function if we declare the dimensions of the parameter space to be explored ( dimensions ) as well as the specific samples to take in this parameter space ( keys ):

In [6]:
dimensions = ['Phase', 'Frequency']
keys = [(p,f) for p in phases for f in freqs]

Now we create a high-dimensional HoloMap to explore: The tuple keys are the points in the parameter space, and the values are the corresponding Image objects:

In [7]:
items = [(k, hv.Image(sine(grid, *k), vdims=['Amplitude'])) for k in keys]
circular_wave = hv.HoloMap(items, kdims=dimensions)

You can still compose as many visualization elements as you wish together. Here is a demonstration of how to generate the horizontal cross-section of the circular wave using Curve elements. This is then positioned next to our circular wave:

In [8]:
items = [(k, hv.Curve(zip(dist, sine(dist**2, *k)))) for k in keys]
sections = hv.HoloMap(items, kdims=dimensions)
circular_wave + sections

You can then easily export your HoloMap objects to an interactive notebook, video formats, or GIF animations to use on a web page.

Succinct Analysis

HoloViews is focused on making your data readily available, both for visualization and for numerical analysis. Because HoloViews objects preserve your raw data, you can use any Python analysis tools you wish, such as those in the SciPy library. We also support some very general-purpose data analysis and manipulation operations directly in HoloViews, exploiting the generality of the HoloViews data structures to simplify common tasks.

Here, we pick a point on the circular wave at (0,0.25) and plot the amplitude value as a function of phase. The circular wave is shown annotated with a point at the chosen position. Note how we can still interactively explore the remaining dimensions, namely Frequency .

In [9]:
sample_pos = (0,0.25)
annotated = circular_wave * hv.Points([sample_pos])
sample = circular_wave.sample(samples=[sample_pos]).to.curve('Phase', 'Amplitude', ['Frequency'])
annotated + sample

Note that the spatial frequency of our curve plot is not affected by the frequency of our wave. That is because the phase always spans exactly one cycle at any of the chosen frequencies.

Here is the circular wave annotated with contours at the 0.5 level, followed by a thresholded version of the same wave, and then the gradient of this pattern, along with a histogram of the gradient values:

In [10]:
%output holomap='gif'

Note that GIF support requires ImageMagick which is installed by default on many Linux installations and may be installed on OSX using brew . For more information on how to install ImageMagick (including Windows instructions) see the installation page .

In [11]:
%%opts Image (cmap='gray') Contours (color='r')
from holoviews.operation import contours, threshold, gradient
m = hv.HoloMap([(p, hv.Image(sine(grid, phase=p))) for p in phases], kdims=['Phase'])
contours(m, levels=[0.5]) + threshold(m, level=0.5) + gradient(m).hist(bin_range=(0,0.7))