Skip to content

Commit 6ede4d4

Browse files
authored
Merge branch 'add-mixin-for-type-with-group-properties' into update-tutorials-with-dot-syntax-for-sets
2 parents 58de3aa + 8dcaddc commit 6ede4d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+5221
-1060
lines changed

+matnwb/+utility/DynamicPropertyManager.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
function obj = DynamicPropertyManager(targetObject, nameRegistry, propArgs)
2929
% Create a new DynamicPropertyManager for the target object
3030
arguments
31-
targetObject dynamicprops
31+
targetObject dynamicprops % Note: No size constraint because types.untyped.Set (a possible input type) overrides size and has an irregular size.
3232
nameRegistry (1,1) matnwb.utility.NameRegistry = matnwb.utility.NameRegistry
3333
propArgs.propertyAddedFunction function_handle = function_handle.empty
3434
propArgs.propertyRemovedFunction function_handle = function_handle.empty

+tests/+factory/ElectrodeTable.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
device = types.core.Device;
99
nwbFile.general_devices.set('testDevice', device);
1010

11-
electrodeTable = types.hdmf_common.DynamicTable(...
11+
electrodeTable = types.core.ElectrodesTable(...
1212
'colnames', {'location', 'group', 'group_name', 'label'}, ...
1313
'description', 'all electrodes');
1414
nwbFile.general_extracellular_ephys_electrodes = electrodeTable;

+tests/+unit/nwbExportTest.m

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ function testEmbeddedSpecs(testCase)
183183
testCase.verifyEqual(sort(embeddedNamespaces), {'core', 'hdmf-common'})
184184

185185
% Add type for extension.
186-
testDevice = types.ndx_photostim.Laser('model', 'Spectra-Physics');
186+
testDevice = types.ndx_photostim.Laser('description', 'Spectra-Physics');
187187
nwb.general_devices.set('TestDevice', testDevice);
188188

189189
nwbExport(nwb, nwbFilePath);
@@ -234,7 +234,7 @@ function testWarnIfMissingNamespaceSpecification(testCase)
234234
nwb.acquisition.set('test', ts);
235235

236236
% Add type from ndx-photostim extension.
237-
testDevice = types.ndx_photostim.Laser('model', 'Spectra-Physics');
237+
testDevice = types.ndx_photostim.Laser('description', 'Spectra-Physics');
238238
nwb.general_devices.set('TestDevice', testDevice);
239239

240240
% Simulate the rare case where a user might delete the cached

+types/+core/BaseImage.m

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
classdef BaseImage < types.core.NWBData & types.untyped.DatasetClass
2+
% BASEIMAGE - An abstract base type for image data. Parent type for Image and ExternalImage types.
3+
%
4+
% Required Properties:
5+
% data
6+
7+
8+
% OPTIONAL PROPERTIES
9+
properties
10+
description; % (char) Description of the image.
11+
end
12+
13+
methods
14+
function obj = BaseImage(varargin)
15+
% BASEIMAGE - Constructor for BaseImage
16+
%
17+
% Syntax:
18+
% baseImage = types.core.BASEIMAGE() creates a BaseImage object with unset property values.
19+
%
20+
% baseImage = types.core.BASEIMAGE(Name, Value) creates a BaseImage object where one or more property values are specified using name-value pairs.
21+
%
22+
% Input Arguments (Name-Value Arguments):
23+
% - data (any) - No description
24+
%
25+
% - description (char) - Description of the image.
26+
%
27+
% Output Arguments:
28+
% - baseImage (types.core.BaseImage) - A BaseImage object
29+
30+
obj = [email protected](varargin{:});
31+
32+
33+
p = inputParser;
34+
p.KeepUnmatched = true;
35+
p.PartialMatching = false;
36+
p.StructExpand = false;
37+
addParameter(p, 'description',[]);
38+
misc.parseSkipInvalidName(p, varargin);
39+
obj.description = p.Results.description;
40+
if strcmp(class(obj), 'types.core.BaseImage')
41+
cellStringArguments = convertContainedStringsToChars(varargin(1:2:end));
42+
types.util.checkUnset(obj, unique(cellStringArguments));
43+
end
44+
end
45+
%% SETTERS
46+
function set.description(obj, val)
47+
obj.description = obj.validate_description(val);
48+
end
49+
%% VALIDATORS
50+
51+
function val = validate_data(obj, val)
52+
end
53+
function val = validate_description(obj, val)
54+
val = types.util.checkDtype('description', 'char', val);
55+
types.util.validateShape('description', {[1]}, val)
56+
end
57+
%% EXPORT
58+
function refs = export(obj, fid, fullpath, refs)
59+
refs = [email protected](obj, fid, fullpath, refs);
60+
if any(strcmp(refs, fullpath))
61+
return;
62+
end
63+
if ~isempty(obj.description)
64+
io.writeAttribute(fid, [fullpath '/description'], obj.description);
65+
end
66+
end
67+
end
68+
69+
end

+types/+core/BehavioralEpochs.m

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
% BEHAVIORALEPOCHS - TimeSeries for storing behavioral epochs. The objective of this and the other two Behavioral interfaces (e.g. BehavioralEvents and BehavioralTimeSeries) is to provide generic hooks for software tools/scripts. This allows a tool/script to take the output one specific interface (e.g., UnitTimes) and plot that data relative to another data modality (e.g., behavioral events) without having to define all possible modalities in advance. Declaring one of these interfaces means that one or more TimeSeries of the specified type is published. These TimeSeries should reside in a group having the same name as the interface. For example, if a BehavioralTimeSeries interface is declared, the module will have one or more TimeSeries defined in the module sub-group 'BehavioralTimeSeries'. BehavioralEpochs should use IntervalSeries. BehavioralEvents is used for irregular events. BehavioralTimeSeries is for continuous data.
33
%
44
% Required Properties:
5-
% None
5+
% intervalseries
66

77

8-
% OPTIONAL PROPERTIES
8+
% REQUIRED PROPERTIES
99
properties
10-
intervalseries; % (IntervalSeries) IntervalSeries object containing start and stop times of epochs.
10+
intervalseries; % REQUIRED (IntervalSeries) IntervalSeries object containing start and stop times of epochs.
1111
end
1212
properties (Access = protected)
1313
GroupPropertyNames = {'intervalseries'}
@@ -61,9 +61,7 @@
6161
if any(strcmp(refs, fullpath))
6262
return;
6363
end
64-
if ~isempty(obj.intervalseries)
65-
refs = obj.intervalseries.export(fid, fullpath, refs);
66-
end
64+
refs = obj.intervalseries.export(fid, fullpath, refs);
6765
end
6866
end
6967

+types/+core/BehavioralEvents.m

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
classdef BehavioralEvents < types.core.NWBDataInterface & types.untyped.GroupClass & matnwb.mixin.HasUnnamedGroups
2-
% BEHAVIORALEVENTS - TimeSeries for storing behavioral events. See description of <a href="#BehavioralEpochs">BehavioralEpochs</a> for more details.
2+
% BEHAVIORALEVENTS - TimeSeries for storing behavioral events. See description of BehavioralEpochs for more details.
33
%
44
% Required Properties:
5-
% None
5+
% timeseries
66

77

8-
% OPTIONAL PROPERTIES
8+
% REQUIRED PROPERTIES
99
properties
10-
timeseries; % (TimeSeries) TimeSeries object containing behavioral events.
10+
timeseries; % REQUIRED (TimeSeries) TimeSeries object containing behavioral events.
1111
end
1212
properties (Access = protected)
1313
GroupPropertyNames = {'timeseries'}
@@ -61,9 +61,7 @@
6161
if any(strcmp(refs, fullpath))
6262
return;
6363
end
64-
if ~isempty(obj.timeseries)
65-
refs = obj.timeseries.export(fid, fullpath, refs);
66-
end
64+
refs = obj.timeseries.export(fid, fullpath, refs);
6765
end
6866
end
6967

+types/+core/BehavioralTimeSeries.m

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
classdef BehavioralTimeSeries < types.core.NWBDataInterface & types.untyped.GroupClass & matnwb.mixin.HasUnnamedGroups
2-
% BEHAVIORALTIMESERIES - TimeSeries for storing Behavoioral time series data. See description of <a href="#BehavioralEpochs">BehavioralEpochs</a> for more details.
2+
% BEHAVIORALTIMESERIES - TimeSeries for storing behavioral time series data. See description of BehavioralEpochs for more details.
33
%
44
% Required Properties:
5-
% None
5+
% timeseries
66

77

8-
% OPTIONAL PROPERTIES
8+
% REQUIRED PROPERTIES
99
properties
10-
timeseries; % (TimeSeries) TimeSeries object containing continuous behavioral data.
10+
timeseries; % REQUIRED (TimeSeries) TimeSeries object containing continuous behavioral data.
1111
end
1212
properties (Access = protected)
1313
GroupPropertyNames = {'timeseries'}
@@ -61,9 +61,7 @@
6161
if any(strcmp(refs, fullpath))
6262
return;
6363
end
64-
if ~isempty(obj.timeseries)
65-
refs = obj.timeseries.export(fid, fullpath, refs);
66-
end
64+
refs = obj.timeseries.export(fid, fullpath, refs);
6765
end
6866
end
6967

+types/+core/CompassDirection.m

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
% COMPASSDIRECTION - With a CompassDirection interface, a module publishes a SpatialSeries object representing a floating point value for theta. The SpatialSeries::reference_frame field should indicate what direction corresponds to 0 and which is the direction of rotation (this should be clockwise). The si_unit for the SpatialSeries should be radians or degrees.
33
%
44
% Required Properties:
5-
% None
5+
% spatialseries
66

77

8-
% OPTIONAL PROPERTIES
8+
% REQUIRED PROPERTIES
99
properties
10-
spatialseries; % (SpatialSeries) SpatialSeries object containing direction of gaze travel.
10+
spatialseries; % REQUIRED (SpatialSeries) SpatialSeries object containing direction of gaze travel.
1111
end
1212
properties (Access = protected)
1313
GroupPropertyNames = {'spatialseries'}
@@ -61,9 +61,7 @@
6161
if any(strcmp(refs, fullpath))
6262
return;
6363
end
64-
if ~isempty(obj.spatialseries)
65-
refs = obj.spatialseries.export(fid, fullpath, refs);
66-
end
64+
refs = obj.spatialseries.export(fid, fullpath, refs);
6765
end
6866
end
6967

+types/+core/DecompositionSeries.m

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@
22
% DECOMPOSITIONSERIES - Spectral analysis of a time series, e.g. of an LFP or a speech signal.
33
%
44
% Required Properties:
5-
% bands, data, data_unit, metric
5+
% data, data_unit, metric
66

77

88
% REQUIRED PROPERTIES
99
properties
10-
bands; % REQUIRED (DynamicTable) Table for describing the bands that this series was generated from. There should be one row in this table for each band.
1110
metric; % REQUIRED (char) The metric used, e.g. phase, amplitude, power.
1211
end
1312
% OPTIONAL PROPERTIES
1413
properties
14+
bands; % (FrequencyBandsTable) Table for describing the bands that this series was generated from.
1515
source_channels; % (DynamicTableRegion) DynamicTableRegion pointer to the channels that this decomposition series was generated from.
1616
source_timeseries; % TimeSeries
1717
end
@@ -26,7 +26,7 @@
2626
% decompositionSeries = types.core.DECOMPOSITIONSERIES(Name, Value) creates a DecompositionSeries object where one or more property values are specified using name-value pairs.
2727
%
2828
% Input Arguments (Name-Value Arguments):
29-
% - bands (DynamicTable) - Table for describing the bands that this series was generated from. There should be one row in this table for each band.
29+
% - bands (FrequencyBandsTable) - Table for describing the bands that this series was generated from.
3030
%
3131
% - comments (char) - Human-readable comments about the TimeSeries. This second descriptive field can be used to store additional information, or descriptive information if the primary description field is populated with a computer-readable string.
3232
%
@@ -101,7 +101,7 @@
101101
%% VALIDATORS
102102

103103
function val = validate_bands(obj, val)
104-
val = types.util.checkDtype('bands', 'types.hdmf_common.DynamicTable', val);
104+
val = types.util.checkDtype('bands', 'types.core.FrequencyBandsTable', val);
105105
end
106106
function val = validate_data(obj, val)
107107
val = types.util.checkDtype('data', 'numeric', val);
@@ -136,7 +136,9 @@
136136
if any(strcmp(refs, fullpath))
137137
return;
138138
end
139-
refs = obj.bands.export(fid, [fullpath '/bands'], refs);
139+
if ~isempty(obj.bands)
140+
refs = obj.bands.export(fid, [fullpath '/bands'], refs);
141+
end
140142
if startsWith(class(obj.metric), 'types.untyped.')
141143
refs = obj.metric.export(fid, [fullpath '/metric'], refs);
142144
elseif ~isempty(obj.metric)

+types/+core/Device.m

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
classdef Device < types.core.NWBContainer & types.untyped.GroupClass
2-
% DEVICE - Metadata about a data acquisition device, e.g., recording system, electrode, microscope.
2+
% DEVICE - Metadata about a specific instance of a data acquisition device, e.g., recording system, electrode, microscope. Link to a DeviceModel.model to represent information about the model of the device.
33
%
44
% Required Properties:
55
% None
@@ -8,9 +8,10 @@
88
% OPTIONAL PROPERTIES
99
properties
1010
description; % (char) Description of the device as free-form text. If there is any software/firmware associated with the device, the names and versions of those can be added to NWBFile.was_generated_by.
11-
manufacturer; % (char) The name of the manufacturer of the device, e.g., Imec, Plexon, Thorlabs.
12-
model_name; % (char) The model name of the device, e.g., Neuropixels 1.0, V-Probe, Bergamo III.
13-
model_number; % (char) The model number (or part/product number) of the device, e.g., PRB_1_4_0480_1, PLX-VP-32-15SE(75)-(260-80)(460-10)-300-(1)CON/32m-V, BERGAMO.
11+
manufacturer; % (char) DEPRECATED. The name of the manufacturer of the device, e.g., Imec, Plexon, Thorlabs. Instead of using this field, store the value in DeviceModel.manufacturer and link to that DeviceModel from this Device.
12+
model; % DeviceModel
13+
model_name; % (char) DEPRECATED. The model name of the device, e.g., Neuropixels 1.0, V-Probe, Bergamo III. Instead of using this field, create and add a new DeviceModel named the model name and link to that DeviceModel from this Device.
14+
model_number; % (char) DEPRECATED. The model number (or part/product number) of the device, e.g., PRB_1_4_0480_1, PLX-VP-32-15SE(75)-(260-80)(460-10)-300-(1)CON/32m-V, BERGAMO. Instead of using this field, store the value in DeviceModel.model_number and link to that DeviceModel from this Device.
1415
serial_number; % (char) The serial number of the device.
1516
end
1617

@@ -26,11 +27,13 @@
2627
% Input Arguments (Name-Value Arguments):
2728
% - description (char) - Description of the device as free-form text. If there is any software/firmware associated with the device, the names and versions of those can be added to NWBFile.was_generated_by.
2829
%
29-
% - manufacturer (char) - The name of the manufacturer of the device, e.g., Imec, Plexon, Thorlabs.
30+
% - manufacturer (char) - DEPRECATED. The name of the manufacturer of the device, e.g., Imec, Plexon, Thorlabs. Instead of using this field, store the value in DeviceModel.manufacturer and link to that DeviceModel from this Device.
3031
%
31-
% - model_name (char) - The model name of the device, e.g., Neuropixels 1.0, V-Probe, Bergamo III.
32+
% - model (DeviceModel) - The model of the device.
3233
%
33-
% - model_number (char) - The model number (or part/product number) of the device, e.g., PRB_1_4_0480_1, PLX-VP-32-15SE(75)-(260-80)(460-10)-300-(1)CON/32m-V, BERGAMO.
34+
% - model_name (char) - DEPRECATED. The model name of the device, e.g., Neuropixels 1.0, V-Probe, Bergamo III. Instead of using this field, create and add a new DeviceModel named the model name and link to that DeviceModel from this Device.
35+
%
36+
% - model_number (char) - DEPRECATED. The model number (or part/product number) of the device, e.g., PRB_1_4_0480_1, PLX-VP-32-15SE(75)-(260-80)(460-10)-300-(1)CON/32m-V, BERGAMO. Instead of using this field, store the value in DeviceModel.model_number and link to that DeviceModel from this Device.
3437
%
3538
% - serial_number (char) - The serial number of the device.
3639
%
@@ -46,12 +49,14 @@
4649
p.StructExpand = false;
4750
addParameter(p, 'description',[]);
4851
addParameter(p, 'manufacturer',[]);
52+
addParameter(p, 'model',[]);
4953
addParameter(p, 'model_name',[]);
5054
addParameter(p, 'model_number',[]);
5155
addParameter(p, 'serial_number',[]);
5256
misc.parseSkipInvalidName(p, varargin);
5357
obj.description = p.Results.description;
5458
obj.manufacturer = p.Results.manufacturer;
59+
obj.model = p.Results.model;
5560
obj.model_name = p.Results.model_name;
5661
obj.model_number = p.Results.model_number;
5762
obj.serial_number = p.Results.serial_number;
@@ -67,6 +72,9 @@
6772
function set.manufacturer(obj, val)
6873
obj.manufacturer = obj.validate_manufacturer(val);
6974
end
75+
function set.model(obj, val)
76+
obj.model = obj.validate_model(val);
77+
end
7078
function set.model_name(obj, val)
7179
obj.model_name = obj.validate_model_name(val);
7280
end
@@ -86,6 +94,18 @@
8694
val = types.util.checkDtype('manufacturer', 'char', val);
8795
types.util.validateShape('manufacturer', {[1]}, val)
8896
end
97+
function val = validate_model(obj, val)
98+
if isa(val, 'types.untyped.SoftLink')
99+
if isprop(val, 'target')
100+
types.util.checkDtype('model', 'types.core.DeviceModel', val.target);
101+
end
102+
else
103+
val = types.util.checkDtype('model', 'types.core.DeviceModel', val);
104+
if ~isempty(val)
105+
val = types.untyped.SoftLink(val);
106+
end
107+
end
108+
end
89109
function val = validate_model_name(obj, val)
90110
val = types.util.checkDtype('model_name', 'char', val);
91111
types.util.validateShape('model_name', {[1]}, val)
@@ -110,6 +130,9 @@
110130
if ~isempty(obj.manufacturer)
111131
io.writeAttribute(fid, [fullpath '/manufacturer'], obj.manufacturer);
112132
end
133+
if ~isempty(obj.model)
134+
refs = obj.model.export(fid, [fullpath '/model'], refs);
135+
end
113136
if ~isempty(obj.model_name)
114137
io.writeAttribute(fid, [fullpath '/model_name'], obj.model_name);
115138
end

0 commit comments

Comments
 (0)