Tutorial 7: Reading session files¶
Prerequisites¶
Tutorial 6: Managing subjects, and at least one session on disk (Tutorial 2 produced one).
What you'll learn¶
- Which files a session writes and what each one is for.
- How to load a session in Python with the bundled readers.
- What the format version field means for reading old data.
1. The files a session writes¶
Every session writes a small, fixed set of files into its acquisition directory.
The names share a .msw. infix so they are easy to find and unambiguous:
| File | Contents |
|---|---|
<basename>.msw.session.yaml |
session metadata: format version, task, subject, setup, and the resolved settings |
<basename>.msw.df.jsonl |
trial-by-trial data: one JSON record per line |
<basename>.msw.log |
human-readable run log |
<basename>.msw.plot_spec.yaml |
the task's plot specification (see Tutorial 8) |
The <basename> encodes the identity of the run as
subject__datetime__task, so a file is self-describing even out of context.
2. The session metadata file¶
*.msw.session.yaml is the human-readable record of what ran. Its first field is
the one that matters most for durability:
msw_format_version: 2
process:
task: sequence
subject: mouse001
setup: rig-a
session_basename: mouse001__20260526_100149_223167__sequence
task_settings:
start_level: 7
stop_trials: 500
msw_format_version records the on-disk layout the session was written with.
Readers use it to interpret older files correctly, so a session written years
ago still loads. You do not have to track versions yourself: the readers do it.
3. The trial data file¶
*.msw.df.jsonl is line-delimited JSON. The first line is a version header; each
later line is one trial:
{"_msw_version": "1.0"}
{"trial_index": 0, "outcome": "correct", "reward_ul": 3.0, ...}
{"trial_index": 1, "outcome": "incorrect", "reward_ul": 0.0, ...}
The exact trial fields are defined by the task, not the framework, so they vary between protocols. Treat the JSONL as the source of truth for what happened on each trial.
4. Load a session in Python¶
Rather than parse these files by hand, use the bundled reader API. It returns a structured object with the metadata and the trial data already loaded into a pandas DataFrame:
from murineshiftwork.readers import load_session
session = load_session(
"/home/you/data/mouse001/"
"mouse001__20260526_100149_223167__session__sequence/"
"mouse001__20260526_100149_223167__sequence"
)
print(session.subject) # 'mouse001'
print(session.task) # 'sequence'
print(session.msw_version) # software version that wrote it
print(session.df.head()) # trial-by-trial DataFrame
print(session.settings_task) # the resolved task settings as a dict
The readers handle format detection for you: session.is_complete tells you
whether all expected artifacts were present, and the reader transparently loads
older on-disk formats.
5. Load many sessions at once¶
To load every session for one animal, point load_subject at the subject's data
directory:
from murineshiftwork.readers import load_subject
sessions = load_subject("/home/you/data/mouse001")
for s in sessions:
print(s.basename, len(s.df) if s.df is not None else 0, "trials")
load_acquisition does the same for a single acquisition container (useful for
multi-protocol sessions). All three return the same session object type, so your
analysis code does not branch on how the data was grouped.
You now know¶
A session writes a fixed set of .msw. files, with msw_format_version
guaranteeing old data stays readable. The murineshiftwork.readers API loads
one session, one acquisition, or a whole subject into a uniform structured object
with a pandas DataFrame, so you can start analysis without parsing files by hand.
Next¶
Tutorial 8: The plot spec. For the full file layout and reader return fields, see Session Files.