Skip to content

Commit 6d47856

Browse files
authored
Merge pull request #278 from NeurodataWithoutBorders/schema-2.3.0
Schema 2.3.0
2 parents 8ddf90c + 392f72f commit 6d47856

File tree

122 files changed

+9519
-3588
lines changed

Some content is hidden

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

122 files changed

+9519
-3588
lines changed

+tests/+system/DynamicTableTest.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ function addContainer(~, file)
1919
'id', id(i),...
2020
'tablepath', '/intervals/trials');
2121
end
22-
t = table(id(101:200), (101:200) .', (102:201) .', mat2cell(rand(500,1),...
23-
repmat(5, 100, 1)), repmat({'TRUE'}, 100, 1),...
22+
t = table(id(101:200), (101:200) .', (102:201) .',...
23+
mat2cell(rand(500,1), repmat(5, 100, 1)), repmat({'TRUE'}, 100, 1),...
2424
'VariableNames', {'id', 'start_time', 'stop_time', 'randomvalues', 'stringdata'});
2525
file.intervals_trials.addRow(t);
2626
end

+tests/+system/UnitTimesIOTest.m

+4-17
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,10 @@
22
methods
33
function addContainer(~, file)
44
vdata = rand(10,1);
5-
vd = types.hdmf_common.VectorData('data', vdata, 'description', 'descr');
6-
7-
spike_loc = '/units/spike_times';
8-
vd_ref = [...
9-
types.untyped.RegionView(spike_loc, 1),...
10-
types.untyped.RegionView(spike_loc, 2:5),...
11-
types.untyped.RegionView(spike_loc, 9:10)...
12-
];
13-
vi = types.hdmf_common.VectorIndex('data', vd_ref,...
14-
'target', types.untyped.ObjectView(spike_loc));
15-
ei = types.hdmf_common.ElementIdentifiers('data', 1:3);
16-
file.units = types.core.Units(...
17-
'colnames', {'spike_times'},...
18-
'description', 'test Units',...
19-
'spike_times', vd, ...
20-
'spike_times_index', vi,...
21-
'id', ei);
5+
file.units = types.core.Units('description', 'test Units', 'colnames', {'spike_times'});
6+
file.units.addRow('spike_times', vdata(1), 'tablepath', '/units');
7+
file.units.addRow('spike_times', vdata(2:5));
8+
file.units.addRow('spike_times', vdata(6:end));
229
end
2310

2411
function c = getContainer(~, file)

+types/+util/+dynamictable/addRawData.m

+9-14
Original file line numberDiff line numberDiff line change
@@ -26,29 +26,24 @@ function addRawData(DynamicTable, column, data, index)
2626
if ~isempty(index)
2727
if isprop(DynamicTable, index)
2828
VecInd = DynamicTable.(index);
29-
else
29+
elseif isprop(DynamicTable, 'vectorindex') % Schema < 2.3.0
3030
VecInd = DynamicTable.vectorindex.get(index);
31+
else
32+
VecInd = DynamicTable.vectordata.get(index);
3133
end
3234

33-
if isa(VecInd.data, 'types.untyped.DataPipe')
34-
if 0 == VecInd.data.dims
35-
raggedOffset = 0;
36-
else
37-
raggedOffset = VecInd.data.load(VecInd.data.dims);
38-
end
39-
else
40-
if isempty(VecInd.data)
41-
raggedOffset = 0;
42-
else
43-
raggedOffset = VecInd.data(end);
44-
end
35+
raggedOffset = 0;
36+
if isa(VecInd.data, 'types.untyped.DataPipe') && 0 < VecInd.data.dims
37+
raggedOffset = double(VecInd.data.load(VecInd.data.dims));
38+
elseif ~isempty(VecInd.data)
39+
raggedOffset = double(VecInd.data(end));
4540
end
4641

4742
raggedValue = raggedOffset + size(data, 1);
4843
if isa(VecInd.data, 'types.untyped.DataPipe')
4944
VecInd.data.append(raggedValue);
5045
else
51-
VecInd.data = [VecInd.data; raggedValue];
46+
VecInd.data = [double(VecInd.data); raggedValue];
5247
end
5348
end
5449

+types/+util/+dynamictable/addTableRow.m

+10-8
Original file line numberDiff line numberDiff line change
@@ -34,23 +34,25 @@ function addTableRow(DynamicTable, subTable, varargin)
3434
TypeMap = types.util.dynamictable.getTypeMap(DynamicTable);
3535
for i = 1:length(rowNames)
3636
rn = rowNames{i};
37-
rv = subTable.(rn);
37+
rowColumn = subTable.(rn);
3838

3939
if isKey(TypeMap, rn)
40-
validateType(TypeMap(rn), rv);
40+
validateType(TypeMap(rn), rowColumn);
4141
end
4242

4343
% instantiate vector index here because it's dependent on the table
4444
% fullpath.
4545
vecIndName = types.util.dynamictable.getIndex(DynamicTable, rn);
46-
if isempty(vecIndName) && ~iscellstr(rv) && iscell(rv)
46+
if isempty(vecIndName) && (~isempty(p.Results.tablepath) || (~iscellstr(rowColumn) && iscell(rowColumn)))
4747
vecIndName = types.util.dynamictable.addVecInd(DynamicTable, rn, p.Results.tablepath);
4848
end
49-
if ~iscell(rv) || iscellstr(rv)
50-
rv = {rv};
51-
end
52-
for i = 1:length(rv)
53-
types.util.dynamictable.addRawData(DynamicTable, rn, rv{i}, vecIndName);
49+
for j = 1:length(rowColumn)
50+
if iscell(rowColumn)
51+
rv = rowColumn{j};
52+
else
53+
rv = rowColumn(j);
54+
end
55+
types.util.dynamictable.addRawData(DynamicTable, rn, rv, vecIndName);
5456
end
5557
end
5658

+types/+util/+dynamictable/addVarargRow.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ function addVarargRow(DynamicTable, varargin)
4848
% instantiate vector index here because it's dependent on the table
4949
% fullpath.
5050
vecIndName = types.util.dynamictable.getIndex(DynamicTable, rn);
51-
if isempty(vecIndName) && size(rv, 1) > 1
51+
if isempty(vecIndName) && (~isempty(p.Results.tablepath) || size(rv, 1) > 1)
5252
vecIndName = types.util.dynamictable.addVecInd(DynamicTable, rn, p.Results.tablepath);
5353
end
5454
types.util.dynamictable.addRawData(DynamicTable, rn, rv, vecIndName);
@@ -72,7 +72,7 @@ function addVarargRow(DynamicTable, varargin)
7272

7373
function validateType(TypeStruct, rv)
7474
if strcmp(TypeStruct.type, 'cellstr')
75-
assert(iscellstr(rv) || (ischar(rv) && 1 == size(rv, 1)),...
75+
assert(iscellstr(rv) || (ischar(rv) && (isempty(rv) || 1 == size(rv, 1))),...
7676
'MatNWB:DynamicTable:AddRow:InvalidType',...
7777
'Type of value must be a cell array of character vectors or a scalar character');
7878
else

+types/+util/+dynamictable/addVecInd.m

+12-6
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@
1919
else
2020
VecData = DynamicTable.vectordata.get(colName);
2121
end
22-
if isa(VecData.data, 'types.untyped.DataPipe')
23-
oldDataHeight = VecData.data.offset;
24-
else
25-
oldDataHeight = size(VecData.data, 1);
22+
23+
if ~isempty(VecData)
24+
if isa(VecData.data, 'types.untyped.DataPipe')
25+
oldDataHeight = VecData.data.offset;
26+
else
27+
oldDataHeight = size(VecData.data, 1);
28+
end
2629
end
2730
end
2831

@@ -31,10 +34,13 @@
3134
% directly to each row index.
3235
VecIndex = types.hdmf_common.VectorIndex(...
3336
'target', vecTarget,...
34-
'data', [0:(oldDataHeight-1)] .'); %#ok<NBRAK>
37+
'data', [0:(oldDataHeight-1)] .',...
38+
'description', sprintf('Index into column %s', colName)); %#ok<NBRAK>
3539
if isprop(DynamicTable, vecIndName)
3640
DynamicTable.(vecIndName) = VecIndex;
37-
else
41+
elseif isprop(DynamicTable, 'vectorindex')
3842
DynamicTable.vectorindex.set(vecIndName, VecIndex);
43+
else
44+
DynamicTable.vectordata.set(vecIndName, VecIndex);
3945
end
4046
end

+types/+util/+dynamictable/clear.m

+4-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ function clear(DynamicTable)
66

77
DynamicTable.vectordata = types.untyped.Set(@(nm, val)types.util.checkConstraint(...
88
'vectordata', nm, struct(), {'types.hdmf_common.VectorData'}, val));
9-
DynamicTable.vectorindex = types.untyped.Set(@(nm, val)types.util.checkConstraint(...
10-
'vectorindex', nm, struct(), {'types.hdmf_common.VectorIndex'}, val));
9+
if isprop(DynamicTable, 'vectorindex') % Schema version <2.3.0
10+
DynamicTable.vectorindex = types.untyped.Set(@(nm, val)types.util.checkConstraint(...
11+
'vectorindex', nm, struct(), {'types.hdmf_common.VectorIndex'}, val));
12+
end
1113
end

+types/+util/+dynamictable/getIndex.m

+26-8
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,33 @@
1010
'MatNWB:GetIndex:InvalidColumn',...
1111
'Column name not found `%s`', column);
1212

13-
vecIndKeys = keys(DynamicTable.vectorindex);
14-
for i = 1:length(vecIndKeys)
15-
vik = vecIndKeys{i};
16-
if isVecIndColumn(DynamicTable.vectorindex.get(vik), column)
17-
indexName = vik;
13+
% after Schema version 2.3.0, VectorIndex objects subclass VectorData which
14+
% meant that vectorindex and vectordata sets could be combined.
15+
isLegacyDynamicTable = isprop(DynamicTable, 'vectorindex');
16+
if isLegacyDynamicTable
17+
vecKeys = keys(DynamicTable.vectorindex);
18+
else
19+
vecKeys = keys(DynamicTable.vectordata);
20+
end
21+
for i = 1:length(vecKeys)
22+
vk = vecKeys{i};
23+
if isLegacyDynamicTable
24+
vecData = DynamicTable.vectorindex.get(vk);
25+
else
26+
vecData = DynamicTable.vectordata.get(vk);
27+
end
28+
if ~isa(vecData, 'types.hdmf_common.VectorIndex')
29+
continue;
30+
end
31+
if isVecIndColumn(vecData, column)
32+
indexName = vk;
1833
return;
1934
end
2035
end
2136

37+
% check if dynamic table object has extended properties which point to
38+
% vector indices. These are specifically defined by the schema to be
39+
% properties.
2240
DynamicTableProps = properties(DynamicTable);
2341
isPropVecInd = false(size(DynamicTableProps));
2442
for i = 1:length(DynamicTableProps)
@@ -27,10 +45,10 @@
2745

2846
DynamicTableProps = DynamicTableProps(isPropVecInd);
2947
for i = 1:length(DynamicTableProps)
30-
vik = DynamicTableProps{i};
31-
VecInd = DynamicTable.(vik);
48+
vk = DynamicTableProps{i};
49+
VecInd = DynamicTable.(vk);
3250
if isVecIndColumn(VecInd, column)
33-
indexName = vik;
51+
indexName = vk;
3452
return;
3553
end
3654
end

+types/+util/+dynamictable/getRow.m

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,8 +66,10 @@
6666
function indMap = getIndexInd(DynamicTable, indexName, matInd)
6767
if isprop(DynamicTable, indexName)
6868
VectorIndex = DynamicTable.(indexName);
69-
else
69+
elseif isprop(DynamicTable, 'vectorindex') % Schema version < 2.3.0
7070
VectorIndex = DynamicTable.vectorindex.get(indexName);
71+
else
72+
VectorIndex = DynamicTable.vectordata.get(indexName);
7173
end
7274

7375
matInd = unique(matInd);

+types/+util/+dynamictable/getTypeMap.m

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
return;
99
end
1010
TypeStruct = struct('type', '', 'dims', [0, 0]);
11-
for i = length(DynamicTable.colnames)
11+
for i = 1:length(DynamicTable.colnames)
1212
colnm = DynamicTable.colnames{i};
1313
if isprop(DynamicTable, colnm)
1414
colVecData = DynamicTable.(colnm);

+types/+util/checkDtype.m

+4-3
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@
2323
subv = val(names{i});
2424
end
2525
assert(isvector(subv),...
26-
['types.util.checkDtype: struct of arrays as a compound type ',...
27-
'cannot have multidimensional data in their fields. Field data ',...
28-
'shape must be scalar or vector to be valid.']);
26+
'MatNWB:CheckDType:MultiDimStructArrays',...
27+
['struct of arrays as a compound type ',...
28+
'cannot have multidimensional data in their fields. ',...
29+
'Field data shape must be scalar or vector to be valid.']);
2930
sizes(i) = length(subv);
3031
end
3132
sizes = unique(sizes);

+types/+util/correctType.m

+23-1
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,33 @@
1818
elseif strcmp(type, 'uint')
1919
val = uint64(val);
2020
else
21-
val = feval(type, val);
21+
val = feval(fitIntType(val, type), val);
2222
end
2323
elseif strcmp(type, 'numeric') && ~isnumeric(val)
2424
val = double(val);
2525
elseif strcmp(type, 'bool')
2626
val = logical(val);
2727
end
28+
end
29+
30+
function fittingIntType = fitIntType(val, minType)
31+
intSizeScale = [8 16 32 64];
32+
typeMatch = regexp(minType, '(u?int)(\d+)', 'once', 'tokens');
33+
prefix = typeMatch{1};
34+
minSize = str2double(typeMatch{2});
35+
36+
minVal = min(val(:));
37+
maxVal = max(val(:));
38+
minSizeMask = intSizeScale == minSize;
39+
assert(any(minSizeMask), 'NWB:CorrectType:InvalidIntSize',...
40+
'Minimum integer size `%s` not supported.', minType);
41+
for i = find(minSizeMask, 1):length(intSizeScale)
42+
fittingIntType = sprintf('%s%d', prefix, intSizeScale(i));
43+
if all(intmin(fittingIntType) <= minVal) && all(intmax(fittingIntType) >= maxVal)
44+
return;
45+
end
46+
end
47+
48+
error('NWB:CorrectType:UnfittableInt', 'Could not fit integer into range %d-%d',...
49+
minVal, maxVal);
2850
end

0 commit comments

Comments
 (0)