Plotting N-D data#


This particular guide uses the old plotting backend which is now deprecated and will be removed in the future. See Migrating to the New Backend for general migration instructions. And see the documentation of Plopp for details on plotting with the new backend.

Data with any number of dimensions can also be plotted in Scipp.


The buttons and sliders in this notebook will have no effect in the online documentation pages, as there is no kernel to perform the operations. These will only work inside a Jupyter notebook.

%matplotlib widget
import numpy as np
import scipp as sc

Default representation#

Data with 3 or more dimensions are by default represented by a 2-D image, accompanied by sliders to navigate the extra dimensions (one slider per dimension above 2).

N = 20
M = 30
L = 20
K = 10
xx = np.arange(N, dtype=np.float64)
yy = np.arange(M, dtype=np.float64)
zz = np.arange(L, dtype=np.float64)
qq = np.arange(K, dtype=np.float64)
x, y, z, q = np.meshgrid(xx, yy, zz, qq, indexing='ij')
b = N/20.0
c = M/2.0
d = L/2.0
r = np.sqrt(((x-c)/b)**2 + ((y-c)/b)**2 + ((z-d)/b)**2  + ((q-d)/b)**2)
a = np.sin(r)
d = sc.Dataset()
d['Some4Ddata'] = sc.Variable(dims=['x', 'y', 'z', 'Q_x'], values=a)
d.coords['x'] = sc.Variable(dims=['x'], values=xx)
d.coords['y'] = sc.Variable(dims=['y'], values=yy)
d.coords['z'] = sc.Variable(dims=['z'], values=zz)
d.coords['Q_x'] = sc.Variable(dims=['Q_x'], values=qq)
/home/runner/work/scipp/scipp/.tox/docs/lib/python3.8/site-packages/scipp/plotting/ VisibleDeprecationWarning: You are using Scipp's deprecated plotting backend. This will be removed in Scipp v23.08.0 (August 2023) or after. See for details and a migration guide.

Slider controls#

  • Each dimension comes with two sliders to control the position of the slice and its thickness.

  • Upon figure creation, the thickness is set to the first bin width. Only the data contained in that bin is displayed. The thickness can be increased by an integer number of bins, and the data inside those bins will either be summed or averaged (see note below).

  • Changing the slice thickness will also change the color range, and the Rescale button can be used to automatically rescale the colorbar to the limits of the currently displayed data.

  • Each dimension control comes with a Continuous Update checkbox, which is applied by default. If this is unselected, the plot will only update once the slider has been released.


You can automatically recalculate the intensity range using the Rescale button on the left of the plot. When zooming or changing thickness, the enclosed viewed region is used to calculate the new intensities. In the general case the intensities are calculated as the mean of the values within.

In the special case of your variable having units of counts, the intensities are summed.

Changing axes dimensions#

By default, the two innermost dimensions are used for the image, and the rest will be allocated to a slider. This can be changed, either interactively using the buttons, or by changing the dimension order using transpose:

d['Some4Ddata'].transpose(dims=['z', 'y', 'Q_x', 'x']).plot()
/home/runner/work/scipp/scipp/.tox/docs/lib/python3.8/site-packages/scipp/plotting/ VisibleDeprecationWarning: You are using Scipp's deprecated plotting backend. This will be removed in Scipp v23.08.0 (August 2023) or after. See for details and a migration guide.

Profile picking#

Finally, each dimension also comes with a Profile button which allows to display one of the additional dimensions as a profile underneath the main plot.

  • When hovering the mouse over the top image, the profile below is updated according to the mouse position.

  • Clicking on the image will save the current profile with a random color.

  • Clicking on an existing marker on the image will delete the corresponding saved profile.

3-D scatter plots#


3-D visualization requires pythreejs to be installed. Use either pip or conda:

- conda install -c conda-forge pythreejs
- pip install pythreejs

3-D scatter plots can be created using plot(projection='3d', positions='xyz'), where the mandatory positions keyword argument is used to set the name of the position coord (here 'xyz') to use as position vectors:

N = 1000
M = 100
theta = np.random.random(N) * np.pi
phi = np.random.random(N) * 2.0 * np.pi
r = 10.0 + (np.random.random(N) - 0.5)
x = r * np.sin(theta) * np.sin(phi)
y = r * np.sin(theta) * np.cos(phi)
z = r * np.cos(theta)

a = np.arange(M*N).reshape([M, N]) * np.sin(y)
da = sc.DataArray(
    data=sc.array(dims=['time', 'xyz'], values=a),
        'xyz':sc.vectors(dims=['xyz'], unit='m', values=np.array([x, y, z]).T),
        'time':sc.array(dims=['time'], unit='s', values=np.arange(M).astype(float))})
da.plot(projection='3d', positions='xyz')
/home/runner/work/scipp/scipp/.tox/docs/lib/python3.8/site-packages/scipp/plotting/ VisibleDeprecationWarning: You are using Scipp's deprecated plotting backend. This will be removed in Scipp v23.08.0 (August 2023) or after. See for details and a migration guide.

Cut surfaces to slice data in 3-D can be enabled using buttons below the scene. When using a cut surface, the upper value of the opacity slider controls the opacity of the slice, while the lower value of the slider controls the opacity of the background.

The scatter-plot functionality can also be used to create 3-D plots of dense data with slicing functionality. In this case we must first create a coordinate with positions:

d2 = d['y', :10].copy()
d2.coords['dummy-pos'] = sc.geometry.position(*[d2.coords[dim] for dim in ['x', 'y', 'z']])
sc.plot(d2, projection='3d', positions='dummy-pos')
/home/runner/work/scipp/scipp/.tox/docs/lib/python3.8/site-packages/scipp/ VisibleDeprecationWarning: sc.geometry.position has been deprecated and will be removed in Scipp v23.09.0. Use scipp.spatial.as_vectors instead.

In the above example creating the coordinate was simple, since all three coords (x, y, and z) had the same unit. In general you may need to:

  • Set a consistent fake unit before using before calling sc.geometry.position.

  • Convert bin-edge coordinates to normal coordinates.

It may be simpler to use dummy ranges as coordinates in that case:

ranges = [sc.arange(dim=dim, start=0.0, stop=d2.sizes[dim]) for dim in ['x', 'y', 'z']]
d2.coords['dummy-pos'] = sc.geometry.position(*ranges)
sc.plot(d2, projection='3d', positions='dummy-pos')

LAMP’s Superplot#

A 1d projection is also available for multi-dimensional data, with the possibility to keep/remove lines that are plotted, a behavior we copied from LAMP’s Superplot which was very popular in the neutron physics community.

sc.plot(d, projection='1d')