Working with the NwbFile Object
When you read an NWB file with nwbRead, you get back an NwbFile object that serves as the main interface to all the data in the file.
NwbFile Example
For illustration, we’ll run the ecephys tutorial and read the resulting NWB file:
evalc("run('tutorials/ecephys.mlx')"); % Run tutorial with suppressed output
nwb = nwbRead('tutorials/ecephys_tutorial.nwb');
disp(nwb)
NwbFile with properties:
nwb_version: '2.8.0'
file_create_date: [1×1 types.untyped.DataStub]
identifier: 'Mouse5_Day3'
session_description: 'mouse in open exploration'
session_start_time: [1×1 types.untyped.DataStub]
timestamps_reference_time: [1×1 types.untyped.DataStub]
acquisition: [2×1 types.untyped.Set]
analysis: [0×1 types.untyped.Set]
general: [0×1 types.untyped.Set]
general_data_collection: ''
general_devices: [1×1 types.untyped.Set]
general_experiment_description: ''
general_experimenter: [1×1 types.untyped.DataStub]
general_extracellular_ephys: [4×1 types.untyped.Set]
general_extracellular_ephys_electrodes: [1×1 types.hdmf_common.DynamicTable]
general_institution: 'University of My Institution'
general_intracellular_ephys: [0×1 types.untyped.Set]
general_intracellular_ephys_experimental_conditions: []
general_intracellular_ephys_filtering: ''
general_intracellular_ephys_intracellular_recordings: []
general_intracellular_ephys_repetitions: []
general_intracellular_ephys_sequential_recordings: []
general_intracellular_ephys_simultaneous_recordings: []
general_intracellular_ephys_sweep_table: []
general_keywords: ''
general_lab: ''
general_notes: ''
general_optogenetics: [0×1 types.untyped.Set]
general_optophysiology: [0×1 types.untyped.Set]
general_pharmacology: ''
general_protocol: ''
general_related_publications: [1×1 types.untyped.DataStub]
general_session_id: 'session_1234'
general_slices: ''
general_source_script: ''
general_source_script_file_name: ''
general_stimulus: ''
general_subject: []
general_surgery: ''
general_virus: ''
general_was_generated_by: [1×1 types.untyped.DataStub]
intervals: [0×1 types.untyped.Set]
intervals_epochs: []
intervals_invalid_times: []
intervals_trials: []
processing: [1×1 types.untyped.Set]
scratch: [0×1 types.untyped.Set]
stimulus_presentation: [0×1 types.untyped.Set]
stimulus_templates: [0×1 types.untyped.Set]
units: [1×1 types.core.Units]
>>
This object contains properties that represent the contents of the NWB file, including metadata about the experiment and data containers for raw and processed data. The object is hierarchical, meaning you can access nested data using dot notation.
For an overview of the NWB file structure, see the NWB File Structure section of the NWB Documentation, or for technical details, refer to the NWB Format Specification.
Note
One key difference between the NwbFile object and the NWB schema is that some top-level groups (e.g. general, intervals and stimulus) and their subgroups are flattened into top level properties of the NwbFile object. This flattening enables easier upfront property access in the MATLAB API, but does not change the on‑disk layout of the NWB file.
Data Types in NWB Files
There are 3 primary data types you will encounter when working with NWB files:
MATLAB fundamental classes (e.g.,
char,numeric,cell)NWB schema-defined types (e.g.,
types.core.TimeSeries,types.core.ElectricalSeries,types.hdmf_common.DynamicTable)Utility types (e.g.,
types.untyped.Set,types.untyped.DataStub)
Finding Data: The searchFor Method
When working with complex NWB files, manually exploring every property can be time-consuming. The NwbFile.searchFor() method lets you search for specific types of data across the entire file:
electricalseries_map = nwb.searchFor('ElectricalSeries')
electricalseries_map =
Map with properties:
Count: 3
KeyType: char
ValueType: any
>>
The searchFor method returns a MATLAB containers.Map object where:
Keys are the paths (within the file) to each found object
Values are the actual data objects
% See what was found
paths = electricalseries_map.keys(); % Cell array of paths
objects = electricalseries_map.values(); % Cell array of objects
% Display the paths
for i = 1:length(paths)
fprintf('Found %s at: %s\n', class(objects{i}), paths{i});
end
Found types.core.ElectricalSeries at: /acquisition/ElectricalSeries
Found types.core.ElectricalSeries at: /processing/ecephys/nwbdatainterface/FilteredEphys/electricalseries/FilteredElectricalSeries
Found types.core.ElectricalSeries at: /processing/ecephys/nwbdatainterface/LFP/electricalseries/ElectricalSeries
>>
Including Subclasses:
Some searches benefit from including related data types. Use the 'includeSubClasses' option:
% Find all types of time series (including specialized ones)
all_timeseries = nwb.searchFor('TimeSeries', 'includeSubClasses');
disp(all_timeseries.values')
{1×1 types.core.ElectricalSeries }
{1×1 types.core.SpikeEventSeries }
{1×1 types.core.ElectricalSeries }
{1×1 types.core.ElectricalSeries }
{1×1 types.core.DecompositionSeries}
>>
This is useful because many NWB data types are specialized versions of more general types.
Retrieving Found Objects: The resolve Method
Once you’ve found data using searchFor, you can retrieve specific objects either directly from the values of the containers.Map object or using their paths with the NwbFile.resolve() method:
all_electricalseries_paths = electricalseries_map.keys(); % Cell array of paths
first_path = all_electricalseries_paths{1};
% Retrieve the object using its path
electricalseries_obj = nwb.resolve(first_path);
The resolve method is particularly useful when you:
Want to access objects found through
searchForHave a specific path and want to retrieve the object
Working with the Data
Once you have a data object (whether found through navigation, search, or resolve), you can access its contents:
% Most data objects have a .data property
raw_data = electricalseries_obj.data.load();
raw_data_size = size(raw_data)
% Check for additional metadata
fprintf('Description: %s\n', electricalseries_obj.description);
raw_data_size =
12 3000
Description: no description
>>
Remember that data is not loaded into memory until you call .load(). This allows you to work with very large files without overwhelming system memory. See the section on DataStubs and DataPipes for more information.
The Connection to HDF5
Under the hood, NWB files are stored in HDF5 format, which is why you see path-like structures (e.g., /acquisition/ElectricalSeries). However, the NwbFile object abstracts away most of the HDF5 complexity, allowing you to work with the data using familiar MATLAB syntax.