Tutorial: raw public NWB to an animal-level robustness report
This is FiberPhotometry's canonical end-to-end product tutorial. It starts with six immutable public NWB files, validates their acquisition and event structure, runs a declared primary analysis and eight-universe preprocessing multiverse, and writes a checksummed evidence bundle.
The tutorial reanalyzes a bounded subset of DANDI:000971, the public data for Seiler et al. (2022). It asks a descriptive question: across these six animals, how different is the DMS response to rewarded versus unrewarded active nose pokes, and how sensitive is that answer to defensible preprocessing and response-window choices?
It does not test phenotype differences, estimate phenotype prevalence, or independently confirm the source publication. Read the frozen scientific protocol before interpreting the output.
Install
The repository uses its locked uv environment. No global Python is required:
Run
The first run downloads 2.20 GB into
~/Library/Caches/fiberphotometry/dandi-000971-tutorial. Every file is checked
against its frozen byte size and SHA-256 digest. Repeated runs reuse only verified
files.
To put the cache or artifacts elsewhere:
uv run python examples/dandi_000971_reward_tutorial.py \
--cache-dir /path/to/cache \
--output-dir /path/to/artifacts
Step 1: inspect before inference
preflight.json is written before any multiverse result. For every animal it
records:
- the immutable DANDI asset and verified digest;
- source and analysis sampling rates;
- all active nose pokes;
- rewarded and unrewarded boundary-complete events;
- events excluded solely because their full
[-5, 1.5]second window was not acquired; - structural failures, which are retained without replacement.
Reward labels are not inferred from fluorescence. The NWB conversion exposes reward timestamps separately, and the adapter requires each reward to match exactly one active nose-poke timestamp.
Step 2: understand the primary analysis
The primary workflow applies a fourth-order 3 Hz zero-phase filter to DMS calcium and isosbestic measurements, robustly fits the reference with IRLS, calculates fitted-reference dF/F, and summarizes each event as its 0-1.5 second mean minus its -5-0 second baseline mean.
Events are averaged within condition and animal before the rewarded-minus-
unrewarded contrast is inferred. Six animals—not hundreds of events—define the
population uncertainty. primary-analysis.json records the paired interval,
assumptions, package version, timestamp, input fingerprint, and inference engine.
Step 3: read the multiverse as a robustness analysis
The same animals, events, labels, estimand, and inferential unit are used in all eight universes:
| Decision | Alternatives |
|---|---|
| Reference correction | OLS or robust IRLS |
| Filtering | no additional filter or fourth-order 3 Hz zero-phase filter |
| Response window | 0-0.5 s or 0-1.5 s |
multiverse.json retains successes and every blocked, failed, or incompatible
workflow. report.html shows the reference estimate, estimate range, direction
stability, decision summaries, and leave-one-animal-out sensitivity. The number of
nominally significant universes is deliberately not the headline.
Step 4: verify the evidence bundle
The result directory contains:
dandi-000971-tutorial-artifacts/
├── preflight.json
├── primary-analysis.json
├── multiverse.json
├── report.html
└── manifest.json
manifest.json records the package version, scientific protocol, completion
status, and SHA-256 digest of every result artifact. A collaborator can rerun the
same command against the same immutable source assets and compare those machine-
readable objects. Execution timestamps may differ; scientific specifications,
input fingerprints, estimates, and deterministic inferential results should not.
The frozen reference execution is committed under
benchmarks/dandi-000971-tutorial-v0.1,
and its scientific interpretation is reported in the
v0.1 results. Read those artifacts
before downloading the cohort if you only want to inspect the product output.
What to change for your own study
Replace only the acquisition adapter and event loader at first. Preserve the
canonical RecordingInput boundary, declare the experimental units and estimand,
and build a bounded multiverse before looking at aggregate outcomes. Do not copy
the six-animal cohort, windows, filter, or reference method as universal defaults:
they are defensible choices for this worked example, not rules for all indicators,
tasks, or acquisition systems.