Plotting 1-D data#

scipp offers a number of different ways to plot data from a DataArray or a Dataset. It uses the matplotlib graphing library to do so.

[1]:
import numpy as np
import scipp as sc

Basic plot#

Plotting is done using the plot function. Generally the information in a dataset is sufficient to produce a useful plot out of the box.

For example, a simple plot from a 1D dataset is produced as follows:

[2]:
d = sc.Dataset()
N = 50
d['Signal'] = sc.Variable(dims=['tof'], values=5.0 + 5.0*np.sin(np.arange(N, dtype=float)/5.0),
                          unit=sc.units.counts)
d.coords['tof'] = sc.Variable(dims=['tof'], values=np.arange(N).astype(float),
                                unit=sc.units.us)
sc.plot(d)

With error bars#

Error bars are shown automatically if variances are present in the data:

[3]:
d['Signal'].variances = np.square(np.random.random(N))
sc.plot(d)

Note that the length of the errors bars is the standard-deviation, i.e., the square root of the variances stored in the data.

Multiple variables on the same axes#

Plotting a Dataset with multiple entries#

If a dataset contains more than one 1D variable with the same coordinates, they are plotted on the same axes:

[4]:
d['Background'] = sc.Variable(dims=['tof'], values=3.0*np.random.random(N),
                              unit=sc.units.counts)
sc.plot(d)

It is possible to hide the error bars with

[5]:
sc.plot(d, errorbars=False)

We can always plot just a single item of the dataset.

[6]:
sc.plot(d['Background'])

Overplotting using a dict of DataArrays#

One can also supply the plot function with a dict of data arrays. Compatible data arrays will be overplotted on the same axes:

[7]:
sc.plot({"My sample": d['Signal'], "My background": d["Background"]})

Note that the newly supplied names (keys) have also been adopted as the graph names.

We can also overplot sections of interest with the help of slicing.

[8]:
sc.plot({"My sample": d['Signal']['tof', 10:40], "My background": d["Background"]})

This overplotting is useful for plotting slices of a 2D data array:

[9]:
M = 100
L = 5
xx = np.arange(M, dtype=float)
yy = np.arange(L, dtype=float)
x, y = np.meshgrid(xx, yy)
b = M/20.0
c = M/5.0
e = L/10.0
r = np.sqrt(((x-c)/b)**2 + (y/e)**2)
a = np.sin(r)
d2d = sc.DataArray(data=sc.Variable(dims=['y', 'x'], values=a, unit=sc.units.counts))
d2d.coords['x'] = sc.Variable(dims=['x'], values=xx, unit=sc.units.m)
d2d.coords['y'] = sc.Variable(dims=['y'], values=yy, unit=sc.units.m)
sc.plot({f'slice-{i}': d2d['y', i] for i in range(L)})

Or using the collapse helper function, which returns a dict of data arrays:

[10]:
sc.plot(sc.collapse(d2d, keep='x'))

Customizing linestyles, markers and colors#

Linestyles can be customized following the Matplotlib syntax. For instance, it is possible to connect the dots by setting linestyle='solid':

[11]:
sc.plot(d, linestyle='solid')

Marker colors and symbols can be changed via the color and marker keyword arguments:

[12]:
sc.plot(d, color=['red', '#30D5F9'], marker=['s', 'x'])

The supplied color and marker arguments can also be a list of integers, which correspond to one of the pre-defined colors or markers (which were taken from matplotlib). In addition, the grid can also be displayed:

[13]:
sc.plot(d, color=[6, 8], grid=True)

Logarithmic scales#

Use the keyword arguments scale and norm to apply logarithmic scales to the horizontal and vertical axes, respectively.

[14]:
sc.plot(d, norm='log', scale={'tof': 'log'})

Histograms#

Histograms are automatically generated if the coordinate is bin edges:

[15]:
histogram = sc.DataArray(data=sc.Variable(dims=['tof'],
                                          values=20.0 + 20.0*np.cos(np.arange(N-1, dtype=float) / 3.0),
                                          unit=sc.units.counts),
                         coords={'tof':d.coords['tof']})
sc.plot(histogram)

and with error bars

[16]:
histogram.variances = 5.0*np.random.random(N-1)
sc.plot(histogram)

The histogram color can be customized:

[17]:
sc.plot(histogram, color='#000000')

Multiple 1D variables with different dimensions#

scipp.plot also supports multiple 1-D variables with different dimensions (note that the data entries are grouped onto the same graph if they have the same dimension and unit):

[18]:
M = 60
d['OtherSample'] = sc.Variable(dims=['x'], values=10.0*np.random.rand(M),
                                   unit=sc.units.s)
d['OtherNoise'] = sc.Variable(dims=['x'], values=7.0*np.random.rand(M),
                                  variances=3.0*np.random.rand(M),
                                  unit=sc.units.s)
d['SomeKgs'] = sc.Variable(dims=['x'], values=20.0*np.random.rand(M),
                                   unit=sc.units.kg)
d.coords['x'] = sc.Variable(dims=['x'],
                              values=np.arange(M).astype(float),
                              unit=sc.units.m)
sc.plot(d)

Custom labels along x axis#

Sometimes one wishes to have labels along the x axis instead of the dimension-coordinate. This can be achieved via the labels keyword argument by specifying which dimension should run along the x axis:

[19]:
d1 = sc.Dataset()
N = 100
x = np.arange(N, dtype=float)
d1['Sample'] = sc.Variable(dims=['tof'],
                           values=np.sqrt(x),
                           unit=sc.units.counts)
d1.coords['tof'] = sc.Variable(dims=['tof'],
                                 values=x,
                                 unit=sc.units.us)
d1.coords['somelabels'] = sc.Variable(dims=['tof'],
                                      values=np.linspace(101., 105., N),
                                      unit=sc.units.s)
sc.plot(d1, labels={'tof': 'somelabels'})

Plotting masks#

If a dataset item contains masks, the symbols of masks data points will have a thick black contour in a 1D plot:

[20]:
d4 = sc.Dataset()
N = 50
x = np.arange(N).astype(float)
d4['Sample'] = sc.Variable(dims=['tof'], values=3*np.sin(x/5)+3,
                           unit=sc.units.counts)
d4['Background'] = sc.Variable(dims=['tof'], values=1.0*np.random.rand(N),
                               unit=sc.units.counts)
d4.coords['tof'] = sc.Variable(dims=['tof'], values=x,
                                 unit=sc.units.us)
d4['Sample'].masks['mask1'] = sc.Variable(dims=['tof'],
                                          values=np.where(np.abs(x-40) < 10, True, False))
d4['Background'].masks['mask1'] = ~d4['Sample'].masks['mask1']
d4['Background'].masks['mask1']['tof', 0:20].values = np.zeros(20, dtype=bool)
sc.plot(d4)

Checkboxes below the plot can be used to hide/show the individual masks. A global toggle button is also available to hide/show all masks in one go.

The color of the masks can be changed as follows:

[21]:
sc.plot(d4, masks={'color': 'red'})

Masks on histograms#

Masks on a histogram show up as a thick black line:

[22]:
N = 50
x = np.arange(N+1).astype(float)
d4 = sc.DataArray(data=sc.Variable(dims=['tof'], values=3*np.sin(x[:-1]/5)+3, unit=sc.units.counts))
d4.coords['tof'] = sc.Variable(dims=['tof'], values=x, unit=sc.units.us)
d4.masks['mask1'] = sc.Variable(dims=['tof'], values=np.where(np.abs(x[:-1]-40) < 10, True, False))
sc.plot(d4)

Plotting time series#

When plotting data with time-series (dtype=datetime64) coordinates, a special axis tick label formatting, which dynamically adapts to the zoom level, is used.

[23]:
time = sc.array(dims=['time'], values=np.arange(np.datetime64('2017-01-01T12:00:00'),
                                                np.datetime64('2017-01-01T13:00:00'), 20))
N = time.sizes['time']
data = sc.DataArray(data=sc.array(dims=['time'],
                                  values=np.arange(N) + 50.*np.random.random(N),
                                  unit="K"),
                    coords={'time':time})
data.plot(title="Temperature as a function of time")

Saving figures#

Static pdf or png copies of the figures can be saved to file (note that any buttons displayed under a figure are not saved to file). This is achieved as follows:

[24]:
sc.plot(d4, filename='my_1d_figure.pdf')