NWB alignment#

The NWB alignment file (<project>/.ethograph/alignment.nwb) stores trial timing, media file paths, and stream offsets. It is the single source of truth for “what file corresponds to what trial, and when did it start”.

See NWB alignment for the user-facing walkthrough and Media and alignment on a TrialTree for runtime access via dt.nwb_alignment.


Creating alignment files#

ethograph.io.nwb_alignment.align_media_per_trial(trial_table, stream_rates=None, output_path=None, session_description='NWB file for media alignment (ethograph generated).', media_root=None, pose_fps=None)[source]#

Create an alignment.nwb from a trial table.

This is the primary user-facing function for creating alignment files.

Parameters:

trial_table (pd.DataFrame) – DataFrame with trial column and {stream}_{device} filename columns. start_time / stop_time are optional – omit for aligned-to-trial data.

stream_rates

Sampling rate per stream. Must include every stream that has columns in the table. Example: {"video": 30.0, "audio": 48000.0, "pose": 30.0}

output_path

Where to write the .nwb file.

Return type:

Path to the created NWB file.

Examples

>>> import pandas as pd, ethograph as eto
>>> table = pd.DataFrame({
...     "trial": [1, 2, 3],
...     "video_cam-1": ["t1.mp4", "t2.mp4", "t3.mp4"],
...     "pose_cam-1": ["t1.h5", "t2.h5", "t3.h5"],
... })
>>> eto.create_alignment(table, {"video": 30.0, "pose": 30.0}, "out/.ethograph/alignment.nwb")
ethograph.io.nwb_alignment.align_media_from_streams(trials, streams, output_path)[source]#

Create an alignment.nwb for unaligned / complex scenarios.

The trials table contains only timing (no filenames). All file references go into ImageSeries acquisition items.

Parameters:
  • trials (DataFrame) – DataFrame with trial, start_time, stop_time.

  • streams (list[dict]) –

    List of stream dicts, each with:

    {
        "name": "video_cam-1",       # acquisition item name
        "files": ["t1.mp4", ...],    # one per trial (full paths)
        "rate": 30.0,                # sampling rate
    }
    

    For session-wide files (one file spanning all trials):

    {
        "name": "audio_mic-1",
        "files": ["session.wav"],
        "rate": 44100.0,
        "starting_time": 0.0,        # when file starts in session time
    }
    

    For streams with explicit timestamps (irregular):

    {
        "name": "ephys_probe-1",
        "files": ["session.dat"],
        "timestamps": np.array([0.0, 0.001, ...]),
    }
    

  • output_path (str | Path) – Where to write the .nwb file.

Return type:

Path to the created NWB file.

Examples

Per-trial video + pose, session-wide audio:

>>> trials = pd.DataFrame({
...     "trial": [1, 2, 3],
...     "start_time": [0.0, 10.5, 22.3],
...     "stop_time": [8.2, 19.1, 30.0],
... })
>>> streams = [
...     {"name": "video_cam-1", "files": ["t1.mp4", "t2.mp4", "t3.mp4"], "rate": 30.0},
...     {"name": "pose_cam-1", "files": ["t1.h5", "t2.h5", "t3.h5"], "rate": 30.0},
...     {"name": "audio_mic-1", "files": ["session.wav"], "rate": 48000.0, "starting_time": 0.0},
... ]
>>> eto.create_alignment_from_streams(trials, streams, ".ethograph/alignment.nwb")
ethograph.io.nwb_alignment.make_nwb_alignment(nwb_path=None)[source]#

Create a EmpytAlignment from an NWB path, falling back to base EmpytAlignment.

ethograph.io.nwb_alignment.discover_nwb(nc_path)[source]#

Find an NWB session file near a data file.

Search order: 1. <dir>/.ethograph/alignment.nwb 2. Any .nwb file in <dir>/.ethograph/

Return type:

Path | None

ethograph.io.nwb_alignment.sync_acquisition_for_streams(nwbfile, stream_rates)[source]#

Create ImageSeries acquisition items for ALL external media streams.

Reads the trials table to discover {stream}_{device} columns. For each stream+device pair, creates an ImageSeries in nwbfile.acquisition with external_file, starting_frame, and rate (or timestamps if offsets are present).

Parameters:
  • nwbfile (NWBFile) – NWB file with a populated trials table.

  • stream_rates (dict[str, float]) – Mapping of stream name to sampling rate, e.g. {"video": 30.0, "audio": 44100.0, "pose": 30.0}.

Return type:

None

ethograph.io.nwb_alignment.edit_nwb(path)[source]#
ethograph.io.nwb_alignment.update_trials_columns(nwb_path, trial_column, updates, stream_rates=None)[source]#
Return type:

None


Reading alignment metadata#

class ethograph.io.nwb_alignment.NWBAlignment(nwb_path)[source]#

Session metadata backed by an NWB file.

All external media (video, audio, pose) are stored as ImageSeries in acquisition with {stream}_{device} naming. Timing comes from rate or timestamps on the ImageSeries.

devices(stream)[source]#

Discover devices from trials table columns AND acquisition items.

Three sources, checked in order:

  1. Trials table columns (video_cam_1 -> device cam_1).

  2. Acquisition ImageSeries following {stream}_{device} naming.

  3. Acquisition ImageSeries whose external_file extensions match known media types (e.g. .mp4 -> video, .wav -> audio).

Return type:

list[str]

electrical_series()[source]#

Discover ElectricalSeries in acquisition. Returns list of {name, path, n_channels, rate}.

Return type:

list[dict]

get_stream_rate(stream, device=None)[source]#

Read the sampling rate for a stream from its acquisition ImageSeries.

Return type:

float | None

property has_real_timing: bool#

Whether the trials table has meaningful start/stop times.

Returns False when all trials have identical placeholder timing (e.g. start=0.0, stop=1.0 for every row), which indicates the NWB was generated without real session timing.

resolve_media_path(trial, stream, device=None, fallback_folder=None)[source]#

Resolve the full path for a media file.

  1. Try the ImageSeries external_file path for this trial (if on disk).

  2. Fallback: trial table filename + fallback_folder.

  3. Returns None if unresolvable.

Return type:

str | None

stream_offset_for_trial(trial, stream, device=None)[source]#

Trial-relative time of sample 0 for a stream’s file.

For per-trial aligned media returns 0.0. For session-wide media returns the file’s start relative to the trial. Reads timing from the acquisition ImageSeries.

Return type:

float

class ethograph.io.nwb_alignment.TableAlignment(trials_df)[source]#

Alignment backed by a tabular dataframe with trial timing columns.

Expected columns are trial, start_time, and stop_time. This is used as a fallback when no suitable alignment NWB is available.

class ethograph.io.nwb_alignment.EmpytAlignment[source]#

Base session metadata interface with null-object defaults.

NWBAlignment overrides these with real NWB-backed implementations. When no NWB file is available, the base class is used directly.


NWB import helpers#

ethograph.io.nwb_import.read_trials_table(nwb)[source]#
Return type:

DataFrame

ethograph.io.nwb_import.probe_electrical_series(nwb)[source]#

List all ElectricalSeries in nwb.acquisition.

Return type:

list[dict]

ethograph.io.nwb_import.probe_label_sources(nwb)[source]#

List all potential interval label sources in the NWB file.

Return type:

list[dict]