Scatter3d plot with slider#

In this example, we combine a three-dimensional scatter plot with a slider, which is used to navigate the time dimension of our data.

[1]:
import plopp as pp
import plopp.widgets as pw
import scipp as sc
import numpy as np

Generate data on a curved panel#

We first generate some data that represents events detected on a cylindrical detector panel, as a function of time.

[2]:
nphi = 100
nz = 20
nt = 50

r = sc.scalar(10.0, unit='m')
phi = sc.linspace('phi', 0, np.pi, nphi, unit='rad')
z = sc.linspace('z', -3.0, 3.0, nz, unit='m')
t = sc.linspace('time', 0.0, 6.0, 50, unit='s')

x = r * sc.cos(phi)
y = r * sc.sin(phi)

h, _ = np.histogramdd(np.random.standard_normal(size=[10_000, 3]), bins=(nt, nz, nphi))
a = sc.array(dims=['time', 'z', 'phi'], values=h, unit='counts')
sizes = a.sizes.copy()
del sizes['time']

da = sc.DataArray(
    data=a.flatten(dims=['z', 'phi'], to='pixel'),
    coords={
        'x': sc.broadcast(x, sizes=sizes).flatten(to='pixel'),
        'y': sc.broadcast(z, sizes=sizes).flatten(to='pixel'),
        'z': sc.broadcast(y, sizes=sizes).flatten(to='pixel'),
        'time': t,
    },
)
da
[2]:
Show/Hide data repr Show/Hide attributes
scipp.DataArray (830.27 KB)
    • time: 50
    • pixel: 2000
    • time
      (time)
      float64
      s
      0.0, 0.122, ..., 5.878, 6.0
      Values:
      array([0. , 0.12244898, 0.24489796, 0.36734694, 0.48979592, 0.6122449 , 0.73469388, 0.85714286, 0.97959184, 1.10204082, 1.2244898 , 1.34693878, 1.46938776, 1.59183673, 1.71428571, 1.83673469, 1.95918367, 2.08163265, 2.20408163, 2.32653061, 2.44897959, 2.57142857, 2.69387755, 2.81632653, 2.93877551, 3.06122449, 3.18367347, 3.30612245, 3.42857143, 3.55102041, 3.67346939, 3.79591837, 3.91836735, 4.04081633, 4.16326531, 4.28571429, 4.40816327, 4.53061224, 4.65306122, 4.7755102 , 4.89795918, 5.02040816, 5.14285714, 5.26530612, 5.3877551 , 5.51020408, 5.63265306, 5.75510204, 5.87755102, 6. ])
    • x
      (pixel)
      float64
      m
      10.0, 9.995, ..., -9.995, -10.0
      Values:
      array([ 10. , 9.99496542, 9.97986676, ..., -9.97986676, -9.99496542, -10. ])
    • y
      (pixel)
      float64
      m
      -3.0, -3.0, ..., 3.0, 3.0
      Values:
      array([-3., -3., -3., ..., 3., 3., 3.])
    • z
      (pixel)
      float64
      m
      0.0, 0.317, ..., 0.317, 1.225e-15
      Values:
      array([0.00000000e+00, 3.17279335e-01, 6.34239197e-01, ..., 6.34239197e-01, 3.17279335e-01, 1.22464680e-15])
    • (time, pixel)
      float64
      counts
      0.0, 0.0, ..., 0.0, 0.0
      Values:
      array([[0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], ..., [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.], [0., 0., 0., ..., 0., 0., 0.]])

A slider selecting a single data slice#

We then construct our interface with a slider, a node that slices our data at the index of the slider, and a scatter3dfigure.

[3]:
# Use Plopp's widget to slice dimensions
slider = pw.SliceWidget(da, dims=['time'])
slider_node = pp.widget_node(slider)

slice_node = pw.slice_dims(data_array=da, slices=slider_node)

fig = pp.scatter3dfigure(slice_node, pixel_size=0.3)

# Set slider in the middle so panel isn't all dark
slider.controls['time']['slider'].value = 23

pp.widgets.Box([fig, slider])
[3]:

A slider slicing out a range#

It is also possible to use a RangeSliceWidget to create a slider with two handles that selects a data range instead of slicing using a single index:

[4]:
# Use Plopp's widget to slice dimensions
slider = pw.RangeSliceWidget(da, dims=['time'])
slider_node = pp.widget_node(slider)

slice_node = pw.slice_dims(data_array=da, slices=slider_node)

# Sum over the selected range of time dimension
sum_slices = pp.Node(sc.sum, slice_node, dim='time')

fig = pp.scatter3dfigure(sum_slices, pixel_size=0.3)

# Set slider in the middle so panel isn't all dark
slider.controls['time']['slider'].value = (0, 12)

pp.widgets.Box([fig, slider])
[4]:
[5]:
pp.show_graph(fig)
[5]:
../_images/gallery_scatter3d-with-slider_8_0.svg