config#
Experiment configuration registry.
This module defines two classes:
ConfigRegisterA generic key/value registry with optional type validation and per-key change callbacks. Used as a building block by
ExperimentConfig.ExperimentConfigExperiment-aware extension of
ConfigRegisterwith default parameters (subject / session / task / LED pattern / duration), a BIDS-style path layout (experiment_dir→data_dir→bids_dir), JSON load/save, and an attachedHardwareManager.
Typical lifecycle:
cfg = ExperimentConfig("path/to/hardware.yaml")
cfg.load_json("path/to/experiment.json")
cfg.set("subject", "001")
seq = cfg.build_sequence(cfg.hardware.primary)
- class mesofield.config.ConfigRegister[source]#
Bases:
objectA registry that maintains configuration values with optional type validation.
- register(key, default=None, type_hint=None, description='', category='general')[source]#
Register a configuration parameter with metadata.
- register_choices(key, choices)[source]#
Register a list of selectable choices for a configuration key.
- class mesofield.config.ExperimentConfig[source]#
Bases:
ConfigRegisterGenerate and store experiment parameters using a configuration registry.
ExperimentConfigextendsConfigRegisterwith experiment-aware defaults (subject / session / task, LED pattern, duration, etc.), a BIDS-style path layout (experiment_dir / data_dir / bids_dir), and integration with aHardwareManager.Example
from mesofield.config import ExperimentConfig config = ExperimentConfig("path/to/hardware.yaml") # Populate from a JSON config file: config.load_json("path/to/experiment.json") config.experiment_dir = "./output" config.set("subject", "001") config.set("task", "TestTask") config.notes.append("This is a test note.") # Persist parameters and notes back to JSON: config.save_json("path/to/experiment.json")
- load_hardware(yaml_path)[source]#
Load (or reload) a hardware YAML configuration.
This replaces the current
HardwareManagerwith a new one pointed at yaml_path. Devices are not initialised untilHardwareManager.initialize()is called (which is normally done byinitialize_hardware).- Parameters:
yaml_path (str)
- Return type:
None
- property session: str#
Get the session ID as a zero-padded BIDS string (e.g. “01”).
Formatting is enforced here so paths/filenames are always padded regardless of how the raw value was entered (GUI, JSON, etc.).
- build_sequence(camera)[source]#
Build a
useq.MDASequencesized to this experiment.The loop count is derived from
num_meso_frameswhen set, or fromcamera.sampling_rate * sequence_durationotherwise. AllHardwareManagerfields are attached as sequence metadata so downstream engines (e.g.MesoEngine) can resolve the LED pattern and NI-DAQ at setup time.- Parameters:
camera (DataProducer) – The primary
DataProducerwhosesampling_ratedrives the default loop count.- Returns:
A ready-to-run
MDASequencewith a zero-interval time plan.- Return type:
MDASequence
- property dataframe#
Convert parameters to a pandas DataFrame.
- make_path(suffix, extension, bids_type=None, create_dir=False)[source]#
Build a unique BIDS-style output file path.
The returned path follows the layout
<bids_dir>/[<bids_type>/]<timestamp>_sub-<id>_ses-<id>_task-<id>_<suffix>.<ext>. If a file with that name already exists,_<n>is appended to keep the path unique.- Parameters:
suffix (str) – Trailing tag added to the filename, e.g.
"images".extension (str) – File extension without the leading dot, e.g.
"jpg".bids_type (str | None) – Optional BIDS modality subdirectory under
bids_dir(e.g."func"). WhenNone, the file is placed directly underbids_dir.create_dir (bool) – When
True, parent directories are created.
- Returns:
Absolute path to the generated file.
Example
cfg.make_path("images", "jpg", "func") # -> 'C:/save_dir/data/sub-001/ses-01/func/' # '20250110_123456_sub-001_ses-01_task-example_images.jpg'
- load_json(file_path)[source]#
Load parameters from a JSON configuration file into the config object.
- Return type:
None
- load_dict(data)[source]#
Load parameters from a dataclass instance or plain mapping.
This is the programmatic counterpart to
load_json()used by scripted procedures (seeProcedure.define_config()). Unlikeload_json()it does not touch the hardware YAML path – scripted hardware is supplied directly viaProcedure.define_hardware().data may be a
@dataclassinstance or any mapping. Both the flat and theConfiguration/Subjectsshapes are accepted.- Parameters:
data (Any)
- Return type:
None
- save_json(path=None)[source]#
Persist displayed configuration values back to the JSON file.
- Parameters:
path (str | None)
- Return type:
None
- save_json_as(path)[source]#
Write the current configuration to a new JSON file and adopt it.
Unlike
save_json()(which edits an existing file in place), this serializes the full in-memory state – registry values, subjects, and DisplayKeys – into theConfiguration/Subjects/DisplayKeysshape, then points_json_file_pathat the new file so later saves land there. Lets the GUI author an experiment.json from a hardware-only session.- Parameters:
path (str)
- Return type:
None
- select_subject(subject_id)[source]#
Apply subject-specific parameters from
self.subjects.- Parameters:
subject_id (str)
- Return type:
None
- add_subject(subject_id)[source]#
Add a new subject, seeding parameters from existing subjects.
The new subject’s parameter dict is the union of keys from existing subjects with blank string values, so all subjects share a consistent parameter set and
select_subject()will accept the new entry. Persists toexperiment.json.- Parameters:
subject_id (str)
- Return type:
None