Note
Go to the end to download the full example code.
Spinning spiral scatter#
Example of a spinning spiral scatter.
This example with 1 million points runs at 125 fps on an AMD RX 570.

/opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/pygfx/objects/_ruler.py:266: RuntimeWarning: divide by zero encountered in divide
screen_full = (ndc_full[:, :2] / ndc_full[:, 3:4]) * half_canvas_size
/opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/pygfx/objects/_ruler.py:266: RuntimeWarning: invalid value encountered in divide
screen_full = (ndc_full[:, :2] / ndc_full[:, 3:4]) * half_canvas_size
/opt/hostedtoolcache/Python/3.12.9/x64/lib/python3.12/site-packages/pygfx/objects/_ruler.py:278: RuntimeWarning: invalid value encountered in divide
screen_sel = (ndc_sel[:, :2] / ndc_sel[:, 3:4]) * half_canvas_size
/home/runner/work/fastplotlib/fastplotlib/fastplotlib/graphics/_features/_base.py:18: UserWarning: casting float64 array to float32
warn(f"casting {array.dtype} array to float32")
# test_example = false
import numpy as np
import fastplotlib as fpl
# number of points
n = 100_000
# create data in the shape of a spiral
phi = np.linspace(0, 30, n)
xs = phi * np.cos(phi) + np.random.normal(scale=1.5, size=n)
ys = np.random.normal(scale=1, size=n)
zs = phi * np.sin(phi) + np.random.normal(scale=1.5, size=n)
data = np.column_stack([xs, ys, zs])
# generate some random sizes for the points
sizes = np.abs(np.random.normal(loc=0, scale=1, size=n))
figure = fpl.Figure(
cameras="3d",
size=(700, 560),
canvas_kwargs={"max_fps": 500, "vsync": False}
)
spiral = figure[0, 0].add_scatter(data, cmap="viridis_r", alpha=0.5, sizes=sizes)
# pre-generate normally distributed data to jitter the points before each render
jitter = np.random.normal(scale=0.001, size=n * 3).reshape((n, 3))
def update():
# rotate around y axis
spiral.rotate(0.005, axis="y")
# add small jitter
spiral.data[:] += jitter
# shift array to provide a random-sampling effect
# without re-running a random generator on each iteration
# generating 1 million normally distributed points takes ~50ms even with SFC64
jitter[1000:] = jitter[:-1000]
jitter[:1000] = jitter[-1000:]
figure.add_animations(update)
figure.show()
# pre-saved camera state
camera_state = {
'position': np.array([-0.13046005, 20.09142224, 29.03347696]),
'rotation': np.array([-0.44485092, 0.05335406, 0.11586037, 0.88647469]),
'scale': np.array([1., 1., 1.]),
'reference_up': np.array([0., 1., 0.]),
'fov': 50.0,
'width': 62.725074768066406,
'height': 8.856056690216064,
'zoom': 0.75,
'maintain_aspect': True,
'depth_range': None
}
figure[0, 0].camera.set_state(camera_state)
figure[0, 0].axes.visible = False
if fpl.IMGUI:
# show fps with imgui overlay
figure.imgui_show_fps = True
# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively
# please see our docs for using fastplotlib interactively in ipython and jupyter
if __name__ == "__main__":
print(__doc__)
fpl.loop.run()
Total running time of the script: (1 minutes 23.100 seconds)