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.
- 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.
import holoviews as hv import numpy as np hv.notebook_extension()
First, let us define a mathematical function to explore, using the Numpy array library:
def sine(x, phase=0, freq=100): return np.sin((freq * x + phase))
We will examine the effect of varying phase and frequency:
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:
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
With HoloViews, we can immediately view our simple function by creating
objects to visualize the 2D arrays and 1D cross-sections generated by the
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,
takes a 2D numpy array as input and
accepts a list of
points. With the
operator we can lay these elements out together and with
we can arrange them into two columns.
HoloViews objects like
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
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.
We can interactively explore this simple function if we declare the dimensions of the parameter space to be explored (
) as well as the specific samples to take in this parameter space (
dimensions = ['Phase', 'Frequency'] keys = [(p,f) for p in phases for f in freqs]
Now we create a high-dimensional
to explore: The tuple keys are the points in the parameter space, and the values are the corresponding
items = [(k, hv.Image(sine(grid, *k), vdims=['Amplitude'])) for k in keys] circular_wave = hv.HoloMap(items, kdims=dimensions) circular_wave
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
elements. This is then positioned next to our circular wave:
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
objects to an interactive notebook, video formats, or GIF animations to use on a web page.
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
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
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:
%%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))