Show3D#

Open in Colab

Show3D scrubs a 3D stack slice by slice: a focal series, time series, tomographic reconstruction, or a sequence of related images. Drag the slider, press the play controls, or use the arrow keys to move through the stack.

This tutorial uses a real gold HAADF image from bobleesj/quantem-data. show3d_gold(size="small") makes a calibrated moving-crop stack from that image, so the documentation and Colab examples use real microscope data while still loading quickly.

Tip

Run this exact notebook with the Colab badge above, or View or download this notebook on GitHub. For finished results, use HTML and file export to export interactive HTML or share a trusted notebook with widget state.

import numpy as np
import torch

from quantem.widget import Show3D
from quantem.widget.datasets import show3d_gold

volume_dataset = show3d_gold(size="small")
Source: gold-haadf (widget-tutorials/shared) from Hugging Face
Full image: 4096 x 4096 uint16
Stack: (32, 256, 256), stride 8, pixel size 0.1489 nm

Scrub the real-data stack#

The helper returns a quantem Dataset3d, so depth and lateral calibration travel with the stack. Show3D reads that metadata automatically and draws a physical scale bar without widget-level pixel-size arguments. Here the FFT starts at 2.0×; every FFT tile or inset keeps its live N.N× multiplier visible while you zoom.

Show3D(volume_dataset, show_fft=True, fft_layout="right", fft_overlay_zoom=2.0)

Trigger a fresh render in an existing widget#

For live stacks, display one Show3D object and update it with set_image() as new frames arrive. set_image() is the render trigger: it writes a fresh current-frame transfer, bumps the frame sequence used by the frontend renderer, invalidates playback buffers, and clamps the current slice to the new stack.

In a real acquisition loop, pass offline=False so frames stream from the kernel instead of being re-embedded on every append:

live3d = Show3D(np.stack(live_frames), offline=False, fps=4)  # streams, nothing embedded
while acquiring:
    live_frames.append(next_frame())
    live3d.set_image(np.stack(live_frames))

The executed example below keeps the default offline embedding instead, so the widget on this documentation page stays scrubbable without a kernel - the set_image() mechanics are identical either way.

live_frames = [frame for frame in volume_dataset.array[:4]]
live3d = Show3D(
    np.stack(live_frames),
    labels=[f"frame {i + 1}" for i in range(len(live_frames))],
    fps=4,
)
live3d
live_frames.extend(volume_dataset.array[4:8])
live3d.set_image(
    np.stack(live_frames),
    labels=[f"frame {i + 1}" for i in range(len(live_frames))],
)
live3d.slice_idx = len(live_frames) - 1