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 quantem.widget as qw
qw.profile()

import numpy as np
import torch

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

volume_dataset = show3d_gold(size="small")
quantem.widget  0.0.1rc44.dev0
  install       editable checkout
  commit        2d009a7f61ee (dirty checkout)
quantem.gpu     0.0.1rc18.dev0
  install       local build
  commit        not recorded
quantem         0.1.10
  install       installed package
  commit        not recorded
webgpu kernels  fa4a86c (fa4a86cfee85), pinned fa4a86cfee85ea719be2dd98206d2098f0dd3344
torch           2.14.1+cu130  device=cpu
python          3.12.15
show3d_gold(size='small') crops from every 8th pixel of the 4096x4096 image; size='full' crops native pixels.
Source: gold_haadf_npy 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.

Each data pixel is drawn as a sharp block (nearest neighbour), also when you zoom in. Switch on Smooth to interpolate bilinearly between pixels; it changes only the display.

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

Compare one plane with a moving average#

Set Avg to 3 or 4, scrub, and press Play. This is a moving mean, not a depth projection or a reconstruction update. The centered window shifts inward at the ends, without wrapping or shortening: with Avg 3, centers 0 and 1 use frames 0–2; center 2 uses 1–3. Return to Avg 1 to inspect individual planes. The source array remains unchanged.

This demonstration stack contains moving crops, not measured depth slices. Apply the same controls to your own (depth, row, col) volume to inspect depth. For an actual projected phase, first check whether your array stores phase per plane or potential requiring an interaction constant and thickness conversion; averaging is not interchangeable with summing.

stack.avg_window = 3

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 re-embeds the display stack the browser plays from, bumps the frame sequence used by the frontend renderer, and clamps the current slice to the new stack.

live3d = Show3D(np.stack(live_frames), fps=4)
while acquiring:
    live_frames.append(next_frame())
    live3d.set_image(np.stack(live_frames))

Each call re-sends the whole display stack to the browser.

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