NWB alignment#
EthoGraph stores session metadata (trial timing, media paths, stream
offsets) in NWB. For .nwb sources the source file is used directly —
no sidecar is created and edits go back into the source. For other
formats (xarray .nc, .npz, pynapple folders) a sidecar
.ethograph/alignment.nwb is written next to the data file to tie
features to video, audio, ephys, and trial structure.
This page explains what the alignment file contains and how to read / write it. For the step-by-step workflow of creating one alongside a multi-trial dataset, see Multi-trial setup.
What the alignment file contains#
Concept |
Stored as |
Read via |
|---|---|---|
Trial timing |
|
|
Media files |
|
|
Stream rates |
|
|
Stream offsets |
|
|
Cameras / mics |
Device names parsed from ImageSeries names |
|
Trial-relative vs session-absolute time#
EthoGraph uses two time conventions, and the alignment file is what connects them:
Trial-relative (
onset_s,offset_s, internal feature time): each trial starts at0.0. This matches pose trackers, video files, and per-trial audio recordings.Session-absolute (
onset_global,offset_global, ephys timestamps): time is measured from the start of the recording session.
Conversion uses the trials table: onset_global = alignment.start_time(trial) + onset_s.
Reading an existing alignment file#
from ethograph.io.nwb_alignment import NWBAlignment
alignment = NWBAlignment("my_project/.ethograph/alignment.nwb")
print(alignment.trials_df)
print(alignment.cameras) # ["cam-1", "cam-2"]
print(alignment.mics) # ["mic-1"]
print(alignment.start_time(1)) # 0.0
alignment.close()
The same interface is exposed via dt.nwb_alignment on a loaded TrialTree
and via app_state.nwb_alignment inside the GUI.
See NWBAlignment for the full API.
Creating an alignment file#
Two builders cover the common cases. Both produce a valid NWB file that the GUI loads without further conversion.
align_media_per_trial — media maps 1:1 to trials#
import pandas as pd
from ethograph.io.nwb_alignment import align_media_per_trial
trial_table = pd.DataFrame({
"trial": [1, 2, 3],
"start_time": [0.0, 300.0, 600.0],
"stop_time": [299.5, 599.5, 899.5],
"video_cam-1": ["t1.mp4", "t2.mp4", "t3.mp4"],
"pose_cam-1": ["t1.h5", "t2.h5", "t3.h5"],
"audio_mic-1": ["t1.wav", "t2.wav", "t3.wav"],
})
align_media_per_trial(
trial_table,
stream_rates={"video": 30.0, "pose": 30.0, "audio": 48000.0},
output_path=".ethograph/alignment.nwb",
)
Column convention: {stream}_{device} — e.g. video_cam-1, audio_mic-1,
pose_cam-1. Extra columns (e.g. stimulus, condition) become trial
attributes and flow through to label TSV exports.
align_media_from_streams — session-wide or mixed files#
For recordings where audio or ephys is one continuous session file, or the ephys clock has its own starting offset, use the stream-oriented builder:
from ethograph.io.nwb_alignment import align_media_from_streams
streams = [
{"name": "video_cam-1", "files": ["t1.mp4", "t2.mp4", "t3.mp4"], "rate": 30.0},
{"name": "audio_mic-1", "files": ["session.wav"], "rate": 48000.0, "starting_time": 0.0},
{"name": "ephys_probe-1", "files": ["session.dat"], "rate": 30000.0, "starting_time": 0.5},
]
align_media_from_streams(trials_df, streams, ".ethograph/alignment.nwb")
See Multi-trial setup for full worked examples and
stream-spec options (timestamps, starting_time, per-device rates).
References#
NWBAlignment— reader APIalign_media_per_trial()— per-trial builderalign_media_from_streams()— session-wide builderMulti-trial setup — multi-trial setup walkthrough
Data Format Requirements — dataset format requirements