Instructor solutions and discussion prompts

Instructor solutions and discussion prompts#

Run this independent solution notebook after the main lesson. The working example below opens the same layers and creates both movie types. Learner answers need not match one specific camera angle or colormap.

Suggested answers#

  1. Slice versus projection: a slice selects a z plane; a maximum projection combines the brightest values across z and loses depth. A projected crossing is not proof of contact.

  2. Contrast and gamma: these alter displayed brightness, not stored TIFF values. Saturated screen colors can conceal intensity differences. Explain settings when comparing figures.

  3. Points versus tracks: points are individual supplied detections; tracks link observations with a shared identifier. Rendering them does not verify the detection or linking algorithm.

  4. Coordinate alignment: images sampled every four source voxels use scale four. The original point/track coordinates already refer to source voxels; scaling them by four again misaligns the layers.

  5. Time: 30 frames at 5 playback fps make a six-second video. Acquisition interval is a separate metadata quantity and has not been confirmed in this release.

  6. Physical measurements: reporting speed in micrometres per second requires verified voxel calibration, acquisition times, correct coordinate transforms, and scientifically validated tracks.

  7. Memory: downsampling reduces spatial array size; lazy loading defers reads; neither reduces the transfer of an already-selected large remote file.

  8. Independent challenge: a defensible result states its biological question, dimensional view, display settings, relevant uncertainty, and why the chosen overlay helps.

The following code is a model workflow. The main notebook contains the corresponding individual layer calls; this solution uses their shared helper to avoid another long copy. Close any other napari viewer first.

%gui qt
from pathlib import Path
ROOT = next(p for p in (Path.cwd(), *Path.cwd().parents)
            if (p / "data" / "zenodo-manifest.json").is_file())
DATA = ROOT / "data" / "teaching"
print(DATA)
from napari_workshop.render import create_scene, export_time_series
from napari_animation import Animation
from datetime import datetime
viewer, metadata = create_scene(DATA)
OUTPUT = ROOT / "outputs" / datetime.now().strftime("animation-%Y%m%d-%H%M%S-%f")
OUTPUT.mkdir(parents=True)

Use a small camera turn first. Rotation angles describe the view; they do not change the sample or track coordinates. Both keyframes below use acquired frame 10. You may also capture these states through the animation wizard in the Plugins menu.

viewer.dims.set_current_step(0, 10)
animation = Animation(viewer)
viewer.camera.angles = (0, 0, 90)
animation.capture_keyframe()
viewer.camera.angles = (25, 15, 110)
animation.capture_keyframe(steps=30)
animation.animate(str(OUTPUT / "rotation.mp4"), fps=10, canvas_only=True)

Next, hold the camera still and export one screenshot per acquired frame. The helper streams frames to the encoder, then reads the movie to verify its frame count and dimensions. It creates a new subfolder and records export settings in export.json. Do not reuse an existing subfolder for another run.

movie = export_time_series(viewer, OUTPUT / "acquired-time", metadata["timepoints"], fps=5)
print(movie)

Compare: the camera animation moves your viewpoint around one observation. The time-series movie changes the observed data. Neither creates additional measured timepoints. If combining the two, label time clearly and explain which changes are due to viewing geometry.

Try it: change playback fps to 10 and export into a new folder. How does duration change? Is the inferred experimental acquisition interval altered? Save a preferred view before trying longer exports. PNG screenshots remain a useful fallback if video playback is unavailable.

viewer.close()