# Elements ¶

 Element  s are the basic building blocks for any HoloViews visualization. These are the objects that can be composed together using the various Container types. Here in this overview, we show an example of how to build each of these  Element  s directly out of Python or Numpy data structures. An even more powerful way to use them is by collecting similar  Element  s into a HoloMap, as described in Exploring Data , so that you can explore, select, slice, and animate them flexibly, but here we focus on having small, self-contained examples. Complete reference material for each type can be accessed using our documentation system . This tutorial uses the default matplotlib plotting backend; see the Bokeh Elements tutorial for the corresponding bokeh plots.

## Element types ¶

This class hierarchy shows each of the  Element  types. Each type is named for the default or expected way that the underlying data can be visualized. E.g., if your data is wrapped into a  Surface  object, it will display as a 3D surface by default, whereas the same data embedded in an  Image  object will display as a 2D raster image. But please note that the specification and implementation for each  Element  type does not actually include any such visualization -- the name merely serves as a semantic indication that you ordinarily think of the data as being laid out visually in that way. The actual plotting is done by a separate plotting subsystem, while the objects themselves focus on storing your data and the metadata needed to describe and use it.

This separation of data and visualization is described in detail in the Options tutorial , which describes all about how to find out the options available for each  Element  type and change them if necessary, from either Python or IPython Notebook. When using this tutorial interactively in an IPython/Jupyter notebook session, we suggest adding  %output info=True  after the call to  notebook_extension  below, which will pop up a detailed list and explanation of the available options for visualizing each  Element  type, after that notebook cell is executed. Then, to find out all the options for any of these  Element  types, just press  <Shift-Enter>  on the corresponding cell in the live notebook.

The types available:

 Element 
The base class of all  Elements  .

###  Charts:  ¶

 Curve 
A continuous relation between a dependent and an independent variable.
 ErrorBars 
A collection of x-/y-coordinates with associated error magnitudes.
 Spread 
Continuous version of ErrorBars.
 Area 
 Bars 
Data collected and binned into categories.
 Histogram 
Data collected and binned in a continuous space using specified bin edges.
 BoxWhisker 
Distributions of data varying by 0-N key dimensions.
 Scatter 
Discontinuous collection of points indexed over a single dimension.
 Points 
Discontinuous collection of points indexed over two dimensions.
 VectorField 
Cyclic variable (and optional auxiliary data) distributed over two-dimensional space.
 Spikes 
A collection of horizontal or vertical lines at various locations with fixed height (1D) or variable height (2D).
 SideHistogram 
Histogram binning data contained by some other  Element  .

###  Chart3D Elements:  ¶

 Surface 
Continuous collection of points in a three-dimensional space.
 Scatter3D 
Discontinuous collection of points in a three-dimensional space.
 Trisurface 
Continuous but irregular collection of points interpolated into a Surface using Delaunay triangulation.

###  Raster Elements:  ¶

 Raster 
The base class of all rasters containing two-dimensional arrays.
 QuadMesh 
Raster type specifying 2D bins with two-dimensional array of values.
 HeatMap 
Raster displaying sparse, discontinuous data collected in a two-dimensional space.
 Image 
Raster containing a two-dimensional array covering a continuous space (sliceable).
 RGB 
Image with 3 (R,G,B) or 4 (R,G,B,Alpha) color channels.
 HSV 
Image with 3 (Hue, Saturation, Value) or 4 channels.

###  Tabular Elements:  ¶

 ItemTable 
Ordered collection of key-value pairs (ordered dictionary).
 Table 
Collection of arbitrary data with arbitrary key and value dimensions.

###  Annotations:  ¶

 VLine 
Vertical line annotation.
 HLine 
Horizontal line annotation.
 Spline 
Bezier spline (arbitrary curves).
 Text 
Text annotation on an  Element  .
 Arrow 
Arrow on an  Element  with optional text label.

###  Paths:  ¶

 Path 
Collection of paths.
 Contours 
Collection of paths, each with an associated value.
 Polygons 
Collection of filled, closed paths with an associated value.
 Bounds 
Box specified by corner positions.
 Box 
Box specified by center position, radius, and aspect ratio.
 Ellipse 
Ellipse specified by center position, radius, and aspect ratio.

##  Element  ¶

The basic or fundamental types of data that can be visualized.

 Element  is the base class for all the other HoloViews objects shown in this section.

All  Element  objects accept  data  as the first argument to define the contents of that element. In addition to its implicit type, each element object has a  group  string defining its category, and a  label  naming this particular item, as described in the Introduction .

When rich display is off, or if no visualization has been defined for that type of  Element  , the  Element  is presented with a default textual representation:

In [1]:
import holoviews as hv
hv.notebook_extension()
hv.Element(None, group='Value', label='Label')

Out[1]:
:Element

In addition,  Element  has key dimensions (  kdims  ), value dimensions (  vdims  ), and constant dimensions (  cdims  ) to describe the semantics of indexing within the  Element  , the semantics of the underlying data contained by the  Element  , and any constant parameters associated with the object, respectively. Dimensions are described in the Introduction .

The remaining  Element  types each have a rich, graphical display as shown below.

##  Chart  Elements ¶

Visualization of a dependent variable against an independent variable

The first large class of  Elements  is the  Chart  elements. These objects have at least one fully indexable, sliceable key dimension (typically the x axis in a plot), and usually have one or more value dimension(s) (often the y axis) that may or may not be indexable depending on the implementation. The key dimensions are normally the parameter settings for which things are measured, and the value dimensions are the data points recorded at those settings.

As described in the Columnar Data tutorial , the data can be stored in several different internal formats, such as a NumPy array of shape (N, D), where N is the number of samples and D the number of dimensions. A somewhat larger list of formats can be accepted, including any of the supported internal formats, or

1. As a list of length N containing tuples of length D.
2. As a tuple of length D containing iterables of length N.

###  Curve  ¶

In [2]:
import numpy as np
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
hv.Curve(points)

Out[2]:

A  Curve  is a set of values provided for some set of keys from a continuously indexable 1D coordinate system , where the plotted values will be connected up because they are assumed to be samples from a continuous relation.

###  ErrorBars  ¶

In [3]:
np.random.seed(7)
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2) for i in np.linspace(0, 100, 11)]
hv.Curve(points) * hv.ErrorBars(errors)

Out[3]:

 ErrorBars  is a set of x-/y-coordinates with associated error values. Error values may be either symmetric or asymmetric, and thus can be supplied as an Nx3 or Nx4 array (or any of the alternative constructors Chart Elements allow).

In [4]:
%%opts ErrorBars (capthick=3)
points = [(0.1*i, np.sin(0.1*i)) for i in range(100)]
errors = [(0.1*i, np.sin(0.1*i), np.random.rand()/2, np.random.rand()/4) for i in np.linspace(0, 100, 11)]
hv.Curve(points) * hv.ErrorBars(errors, vdims=['y', 'yerrneg', 'yerrpos'])

Out[4]:

###  Spread  ¶

 Spread  elements have the same data format as the  ErrorBars  element, namely x- and y-values with associated symmetric or assymetric errors, but are interpreted as samples from a continuous distribution (just as  Curve  is the continuous version of  Scatter  ). These are often paired with an overlaid  Curve  to show both the mean (as a curve) and the spread of values; see the Columnar Data tutorial for examples.

##### Symmetric ¶
In [5]:
np.random.seed(42)
xs = np.linspace(0, np.pi*2, 20)
err = 0.2+np.random.rand(len(xs))

Out[5]:
##### Asymmetric ¶
In [6]:
%%opts Spread (facecolor='indianred' alpha=1)
xs = np.linspace(0, np.pi*2, 20)
vdims=['y', 'yerrneg', 'yerrpos'])

Out[6]:

###  Area  ¶

Area under the curve

By default the Area Element draws just the area under the curve, i.e. the region between the curve and the origin.

In [7]:
xs = np.linspace(0, np.pi*4, 40)
hv.Area((xs, np.sin(xs)))

Out[7]:

Area between curves

When supplied a second value dimension the area is defined as the area between two curves.

In [8]:
X  = np.linspace(0,3,200)
Y = X**2 + 3
Y2 = np.exp(X) + 2
Y3 = np.cos(X)
hv.Area((X, Y, Y2), vdims=['y', 'y2']) * hv.Area((X, Y, Y3), vdims=['y', 'y3'])

Out[8]:

#### Stacked areas ¶

Areas are also useful to visualize multiple variables changing over time, but in order to be able to compare them the areas need to be stacked. Therefore the  operation  module provides the  stack_area  operation which makes it trivial to stack multiple Area in an (Nd)Overlay.

In this example we will generate a set of 5 arrays representing percentages and create an Overlay of them. Then we simply call the  stack_area  operation on the Overlay to get a stacked area chart.

In [9]:
values = np.random.rand(5, 20)
percentages = (values/values.sum(axis=0)).T*100

overlay = hv.Overlay([hv.Area(percentages[:, i], vdims=[hv.Dimension('value', unit='%')]) for i in range(5)])
overlay + hv.Area.stack(overlay)

Out[9]:

###  Bars  ¶

In [10]:
data = [('one',8),('two', 10), ('three', 16), ('four', 8), ('five', 4), ('six', 1)]
bars = hv.Bars(data, kdims=[hv.Dimension('Car occupants', values='initial')], vdims=['Count'])
bars + bars[['one', 'two', 'three']]

WARNING:root:Dimension: The 'initial' string for dimension values is no longer supported.

Out[10]:

 Bars  is an  NdElement  type, so by default it is sorted. To preserve the initial ordering specify the  Dimension  with values set to 'initial', or you can supply an explicit list of valid dimension keys.

 Bars  support up to three key dimensions which can be laid by  'group'  ,  'category'  , and  'stack'  dimensions. By default the key dimensions are mapped onto the first, second, and third  Dimension  of the  Bars  object, but this behavior can be overridden via the  group_index  ,  category_index  , and  stack_index  options. You can also style each bar the way you want by creating style groups for any combination of the three dimensions. Here we color_by  'category'  and  'stack'  , so that a given color represents some combination of those two values (according to the key shown).

In [11]:
%%opts Bars [color_by=['category', 'stack'] legend_position='top']
from itertools import product
np.random.seed(1)
groups, categories, stacks = ['A', 'B'], ['a', 'b'], ['I', 'II']
keys = product(groups, categories, stacks)
hv.Bars([(k, np.random.rand()*100) for k in keys],
kdims=['Group', 'Category', 'Stack'], vdims=['Count'])

Out[11]:

###  BoxWhisker  ¶

The  BoxWhisker  Element allows representing distributions of data varying by 0-N key dimensions. To represent the distribution of a single variable, we can create a BoxWhisker Element with no key dimensions and a single value dimension:

In [12]:
hv.BoxWhisker(np.random.randn(200), kdims=[], vdims=['Value'])

Out[12]:

BoxWhisker Elements support any number of dimensions and may also be rotated. To style the boxes and whiskers, supply  boxprops  ,  whiskerprops  , and  flierprops  .

In [13]:
%%opts BoxWhisker [fig_size=200 invert_axes=True]
style = dict(boxprops=dict(color='gray', linewidth=1), whiskerprops=dict(color='indianred', linewidth=1))
groups = [chr(65+g) for g in np.random.randint(0, 3, 200)]
hv.BoxWhisker((groups, np.random.randint(0, 5, 200), np.random.randn(200)),
kdims=['Group', 'Category'], vdims=['Value'])(style=style).sort()

Out[13]:

 BoxWhisker  Elements may also be used to represent a distribution as a marginal plot by adjoining it using  <<  .

In [14]:
points = hv.Points(np.random.randn(500, 2))
points << hv.BoxWhisker(points['y']) << hv.BoxWhisker(points['x'])

Out[14]:

###  Histogram  ¶

In [15]:
np.random.seed(1)
data = [np.random.normal() for i in range(10000)]
frequencies, edges = np.histogram(data, 20)
hv.Histogram(frequencies, edges)

Out[15]:

 Histogram  s partition the  x  axis into discrete (but not necessarily regular) bins, showing counts in each as a bar.

Almost all Element types, including  Histogram  , may be projected onto a polar axis by supplying  projection='polar'  as a plot option.

In [16]:
%%opts Histogram [projection='polar' show_grid=True]
data = [np.random.rand()*np.pi*2 for i in range(100)]
frequencies, edges = np.histogram(data, 20)
hv.Histogram(frequencies, edges, kdims=['Angle'])

Out[16]:

###  Scatter  ¶

In [17]:
%%opts Scatter (color='k', marker='s', s=50)
np.random.seed(42)
points = [(i, np.random.random()) for i in range(20)]
hv.Scatter(points) + hv.Scatter(points)[12:20]

Out[17]:

Scatter is the discrete equivalent of Curve, showing y values for discrete x values selected. See  Points  for more information.

The marker shape specified above can be any supported by matplotlib , e.g.  s  ,  d  , or  o  ; the other options select the color and size of the marker. For convenience with the bokeh backend , the matplotlib marker options are supported using a compatibility function in HoloViews.

###  Points  ¶

In [18]:
np.random.seed(12)
points = np.random.rand(50,2)
hv.Points(points) + hv.Points(points)[0.6:0.8,0.2:0.5]

Out[18]:

As you can see,  Points  is very similar to  Scatter  , and can produce some plots that look identical. However, the two  Element  s are very different semantically. For  Scatter  , the dots each show a dependent variable y for some x , such as in the  Scatter  example above where we selected regularly spaced values of x and then created a random number as the corresponding y . I.e., for  Scatter  , the y values are the data; the x s are just where the data values are located. For  Points  , both x and y are independent variables, known as  key_dimensions  in HoloViews:

In [19]:
for o in [hv.Points(points,name="Points "), hv.Scatter(points,name="Scatter")]:
for d in ['key','value']:
print("%s %s_dimensions: %s " % (o.name, d, o.dimensions(d,label=True)))

Points  key_dimensions: ['x', 'y']
Points  value_dimensions: []
Scatter key_dimensions: ['x']
Scatter value_dimensions: ['y']


The  Scatter  object expresses a dependent relationship between x and y , making it useful for combining with other similar  Chart  types, while the  Points  object expresses the relationship of two independent keys x and y with optional  vdims  (zero in this case), which makes  Points  objects meaningful to combine with the  Raster  types below.

Of course, the  vdims  need not be empty for  Points  ; here is an example with two additional quantities for each point, as  value_dimension  s z and α visualized as the color and size of the dots, respectively. The point sizes can be tweaked using the option  scaling_factor  , which determines the amount by which each point width or area is scaled, depending on the value of  scaling_method  .

In [20]:
%%opts Points [color_index=2 size_index=3 scaling_method="width" scaling_factor=10]
np.random.seed(10)
data = np.random.rand(100,4)

points = hv.Points(data, vdims=['z', 'alpha'])
points + points[0.3:0.7, 0.3:0.7].hist()

Out[20]:

Such a plot wouldn't be meaningful for  Scatter  , but is a valid use for  Points  , where the x and y locations are independent variables representing coordinates, and the "data" is conveyed by the size and color of the dots.

###  Spikes  ¶

Spikes represent any number of horizontal or vertical line segments with fixed or variable heights. There are a number of disparate uses for this type. First of all, they may be used as a rugplot to give an overview of a one-dimensional distribution. They may also be useful in more domain-specific cases, such as visualizing spike trains for neurophysiology or spectrograms in physics and chemistry applications.

In the simplest case, a Spikes object represents coordinates in a 1D distribution:

In [21]:
%%opts Spikes (alpha=0.4)
xs = np.random.rand(50)
ys = np.random.rand(50)
hv.Points((xs, ys)) * hv.Spikes(xs)

Out[21]:

When supplying two dimensions to the Spikes object, the second dimension will be mapped onto the line height. Optionally, you may also supply a cmap and color_index to map color onto one of the dimensions. This way we can, for example, plot a mass spectrogram:

In [22]:
%%opts Spikes (cmap='Reds')
hv.Spikes(np.random.rand(20, 2), kdims=['Mass'], vdims=['Intensity'])

Out[22]:

Another possibility is to draw a number of spike trains as you would encounter in neuroscience. Here we generate 10 separate random spike trains and distribute them evenly across the space by setting their  position  . By also declaring some  yticks  , each spike train can be labeled individually:

In [23]:
%%opts Spikes NdOverlay [show_legend=False]
hv.NdOverlay({i: hv.Spikes(np.random.randint(0, 100, 10), kdims=['Time'])(plot=dict(position=0.1*i))
for i in range(10)})(plot=dict(yticks=[((i+1)*0.1-0.05, i) for i in range(10)]))

Out[23]:

Finally, we may use  Spikes  to visualize marginal distributions as adjoined plots using the  <<  adjoin operator:

In [24]:
%%opts Spikes (alpha=0.05) [spike_length=1]
points = hv.Points(np.random.randn(500, 2))
points << hv.Spikes(points['y']) << hv.Spikes(points['x'])

Out[24]:

###  VectorField  ¶

In [25]:
%%opts VectorField [size_index=3]
y,x  = 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 = [x,y,sine_rings, exp_falloff]
hv.VectorField(vector_data)

Out[25]:

As you can see above, here the x and y positions are chosen to make a regular grid. The arrow angles follow a sinsoidal ring pattern, and the arrow lengths fall off exponentially from the center, so this plot has four dimensions of data (direction and length for each x,y position).

Using the IPython  %%opts  cell-magic (described in the Options tutorial , along with the Python equivalent), we can also use color as a redundant indicator to the direction or magnitude:

In [26]:
%%opts VectorField [size_index=3] VectorField.A [color_index=2] VectorField.M [color_index=3]
hv.VectorField(vector_data, group='A') + hv.VectorField(vector_data, group='M')

Out[26]:

The vector fields above were sampled on a regular grid, but any collection of x,y values is allowed:

In [27]:
n=20
x=np.linspace(1,3,n)
y=np.sin(np.linspace(0,2*np.pi,n))/4
hv.VectorField([x,y,x*5,np.ones(n)]) * hv.VectorField([x,-y,x*5,np.ones(n)])

Out[27]:

###  SideHistogram  ¶

The  .hist  method conveniently adjoins a histogram to the side of any  Chart  ,  Surface  , or  Raster  component, as well as many of the container types (though it would be reporting data from one of these underlying  Element  types). For a  Raster  using color or grayscale to show values (see  Raster  section below), the side histogram doubles as a color bar or key.

In [28]:
import numpy as np
np.random.seed(42)
points = [(i, np.random.normal()) for i in range(800)]
hv.Scatter(points).hist()

Out[28]:

##  Chart3D  Elements ¶

###  Surface  ¶

In [29]:
%%opts Surface (cmap='jet' rstride=20, cstride=2)
hv.Surface(np.sin(np.linspace(0,100*np.pi*2,10000)).reshape(100,100))

Out[29]:

Surface is used for a set of gridded points whose associated value dimension represents samples from a continuous surface; it is the equivalent of a  Curve  but with two key dimensions instead of just one.

###  Scatter3D  ¶

In [30]:
%%opts Scatter3D [azimuth=40 elevation=20]
y,x = np.mgrid[-5:5, -5:5] * 0.1
heights = np.sin(x**2+y**2)
hv.Scatter3D(zip(x.flat,y.flat,heights.flat))

Out[30]:

 Scatter3D  is the equivalent of  Scatter  but for two key dimensions, rather than just one.

###  Trisurface  ¶

The  Trisurface  Element renders any collection of 3D points as a Surface by applying Delaunay triangulation. It thus supports arbitrary, non-gridded data, but it does not support indexing to find data values, since finding the closest ones would require a search.

In [31]:
%%opts Trisurface [fig_size=200] (cmap='hot_r')
hv.Trisurface((x.flat,y.flat,heights.flat))

Out[31]:

##  Raster  Elements ¶

A collection of raster image types

The second large class of  Elements  is the raster elements. Like  Points  and unlike the other  Chart  elements,  Raster Elements  live in a 2D key-dimensions space. For the  Image  ,  RGB  , and  HSV  elements, the coordinates of this two-dimensional key space are defined in a continuously indexable coordinate system . We can use  np.meshgrid  to define the appropriate sampling along the  x  and  y  dimensions:

In [32]:
x,y = np.meshgrid(np.linspace(-5,5,101), np.linspace(5,-5,101))


###  Raster  ¶

A  Raster  is the base class for image-like  Elements  , but may be used directly to visualize 2D arrays using a color map. The coordinate system of a  Raster  is the raw indexes of the underlying array, with integer values always starting from (0,0) in the top left, with default extents corresponding to the shape of the array. The  Image  subclass visualizes similarly, but using a continuous Cartesian coordinate system suitable for an array that represents some underlying continuous region.

In [33]:
hv.Raster(np.sin(x**2+y**2))

Out[33]:

###  QuadMesh  ¶

The basic  QuadMesh  is a 2D grid of bins specified as x-/y-values specifying a regular sampling or edges, with arbitrary sampling and an associated 2D array containing the bin values. The coordinate system of a  QuadMesh  is defined by the bin edges, therefore any index falling into a binned region will return the appropriate value. Unlike  Image  objects, slices must be inclusive of the bin edges.

In [34]:
n = 21
xs = np.logspace(1, 3, n)
ys = np.linspace(1, 10, n)

Out[34]:

QuadMesh may also be used to represent an arbitrary mesh of quadrilaterals by supplying three separate 2D arrays representing the coordinates of each quadrilateral in a 2D space. Note that when using  QuadMesh  in this mode, slicing and indexing semantics and most operations will currently not work.

In [35]:
coords = np.linspace(-1.5,1.5,n)
X,Y = np.meshgrid(coords, coords);
Qx = np.cos(Y) - np.cos(X)
Qz = np.sin(Y) + np.sin(X)
Z = np.sqrt(X**2 + Y**2)

Out[35]:

###  HeatMap  ¶

A  HeatMap  displays like a typical raster image, but the input is a dictionary indexed with two-dimensional keys, not a Numpy array or Pandas dataframe. As many rows and columns as required will be created to display the values in an appropriate grid format. Values unspecified are left blank, and the keys can be any Python datatype (not necessarily numeric). One typical usage is to show values from a set of experiments, such as a parameter space exploration, and many other such visualizations are shown in the Containers and Exploring Data tutorials. Each value in a  HeatMap  is labeled explicitly by default, and so this component is not meant for very large numbers of samples. With the default color map, high values (in the upper half of the range present) are colored orange and red, while low values (in the lower half of the range present) are colored shades of blue.

In [36]:
data = {(chr(65+i),chr(97+j)): i*j for i in range(5) for j in range(5) if i!=j}
hv.HeatMap(data).sort()

Out[36]:

###  Image  ¶

Like  Raster  , a HoloViews  Image  allows you to view 2D arrays using an arbitrary color map. Unlike  Raster  , an  Image  is associated with a 2D coordinate system in continuous space , which is appropriate for values sampled from some underlying continuous distribution (as in a photograph or other measurements from locations in real space). Slicing, sampling, etc. on an  Image  all use this continuous space, whereas the corresponding operations on a  Raster  work on the raw array coordinates.

To make the coordinate system clear, we'll define two arrays called  xs  and  ys  with a non-square aspect and map them through a simple function that illustrate how these inputs relate to the coordinate system:

In [37]:
bounds=(-2,-3,5,2)   # Coordinate system: (left, bottom, top, right)
xs,ys = np.meshgrid(np.linspace(-2,5,50), np.linspace(2,-3, 30))
(hv.Image(np.sin(xs)+ys, bounds=bounds)
+ hv.Image(np.sin(xs)+ys, bounds=bounds)[0:3, -2.5:2])

Out[37]:

Notice how, because our declared coordinate system is continuous, we can slice with any floating-point value we choose.