-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathimportdata.m
721 lines (637 loc) · 22 KB
/
importdata.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
function [out, delimiter, headerlines] = importdata(varargin)
%IMPORTDATA Load data from file.
%
% IMPORTDATA(FILENAME) loads data from FILENAME into the workspace.
%
% A = IMPORTDATA(FILENAME) loads data into A.
%
% IMPORTDATA(FILENAME, DELIM) interprets DELIM as the column separator in
% ASCII file FILENAME. DELIM must be a string. Use '\t' for tab.
%
% IMPORTDATA(FILENAME, DELIM, NHEADERLINES) loads data from ASCII file
% FILENAME, reading numeric data starting from line NHEADERLINES+1.
%
% [A DELIM] = IMPORTDATA(...) returns the detected delimiter character
% for the input ASCII file.
%
% [A DELIM NHEADERLINES] = IMPORTDATA(...) returns the detected number of
% header lines in the input ASCII file.
%
% [...] = IMPORTDATA('-pastespecial', ...) loads data from the system
% clipboard rather than from a file.
%
% Notes:
%
% If IMPORTDATA recognizes the file extension, it calls the MATLAB helper
% function designed to import the associated file format. Otherwise,
% IMPORTDATA interprets the file as a delimited ASCII file.
%
% When the helper function returns more than one nonempty output,
% IMPORTDATA combines the outputs into a structure array. For details,
% type "doc importdata" at the command prompt.
%
% For ASCII files and spreadsheets, IMPORTDATA expects to find numeric
% data in a rectangular form (that is, like a matrix). Text headers can
% appear above or to the left of numeric data. To import ASCII files
% with numeric characters anywhere else, including columns of character
% data or formatted dates or times, use TEXTSCAN instead of IMPORTDATA.
% When importing spreadsheets with columns of nonnumeric data, IMPORTDATA
% cannot always correctly interpret the column and row headers.
%
% Examples:
%
% 1) Import and display an image:
%
% nebula_im = importdata('ngc6543a.jpg');
% image(nebula_im);
%
% 2) Using a text editor, create an ASCII file called myfile.txt:
%
% Day1 Day2 Day3 Day4 Day5 Day6 Day7
% 95.01 76.21 61.54 40.57 5.79 20.28 1.53
% 23.11 45.65 79.19 93.55 35.29 19.87 74.68
% 60.68 1.85 92.18 91.69 81.32 60.38 44.51
% 48.60 82.14 73.82 41.03 0.99 27.22 93.18
% 89.13 44.47 17.63 89.36 13.89 19.88 46.60
%
% Import the file, and view columns 3 and 5:
%
% M = importdata('myfile.txt', ' ', 1);
% for k = [3, 5]
% disp(M.colheaders{1, k})
% disp(M.data(:, k))
% disp(' ')
% end
%
% See also LOAD, TEXTSCAN, OPEN, LOAD, UIIMPORT.
% Copyright 1984-2011 The MathWorks, Inc.
% $Revision: 1.17.4.42 $ $Date: 2011/10/22 22:05:06 $
narginchk(1,4);
nargoutchk(0,3);
FileName = varargin{1};
if nargin > 1
delim.requested = varargin{2};
else
delim.requested = NaN;
end
if nargin > 2
requestedHeaderLines = varargin{3};
else
requestedHeaderLines = NaN;
end
out = [];
if nargout > 1
delim.printed = [];
delimiter = [];
end
if nargout > 2
headerlines = 0;
end
bFlatten = true;
if nargin > 3 && isfield(varargin{4}, 'Flatten')
FlattenInput = varargin{4}.Flatten;
if islogical(FlattenInput) && isscalar(FlattenInput)
bFlatten = FlattenInput;
end
end
if strcmpi(FileName,'-pastespecial')
% fetch data from clipboard
cb = clipboard('paste');
if isnan(delim.requested)
delim.printed = guessdelim(cb);
delim.requested = delim.printed;
else
delim.printed = sprintf(delim.requested);
end
%When importing data from clipboard, do not warn of format mismatches.
bWarn = false;
try
[out.data, out.textdata, headerlines] = parse(cb, ...
delim, requestedHeaderLines, bWarn);
catch %#ok<CTCH>
error(message('MATLAB:importdata:InvalidClipboardData'));
end
out = LocalRowColShuffle(out);
delimiter = delim.printed;
else
% attempt extracting descriptive information about file
warnState = warning('off', 'MATLAB:xlsfinfo:ActiveX');
warnState(2) = warning('off', 'MATLAB:audiovideo:avifinfo:FunctionToBeRemoved');
try
[FileType,~,loadCmd,descr] = finfo(FileName);
warning(warnState);
catch %#ok<CTCH>
warning(warnState);
error(message('MATLAB:importdata:FileNotFound'));
end
% Test success of FINFO call
if strcmp(descr,'FileInterpretError')
% Generate a warning that FINFO could not interpret data file
warning(message('MATLAB:importdata:InvalidDataSection'));
out.data=[]; % return an empty matrix object
out.textdata={}; % return an empty cell object
return
end
delim.printed = NaN;
delimiter = delim.printed;
%Just in case we found incorrect command, i.e. the name was a
%coincidence, we'll try to load, but if we fail, we'll try to load
%using other means.
loaded = 0;
if ~isempty(loadCmd) && ~strcmp(loadCmd,'importdata')
try
out.data = feval(loadCmd, FileName);
loaded = 1;
catch exception %#ok<NASGU>
end
end
if (loaded == 0)
if (strncmp(FileType, 'xls', 3) > 0)
out = readFromExcelFile(FileName, descr, out, bFlatten);
else
switch FileType
case 'ods'
out = readFromExcelFile(FileName, descr, out, bFlatten);
case 'wk1'
[out.data, out.textdata] = wk1read(FileName);
out = LocalRowColShuffle(out);
case 'avi'
S = warning('off', 'MATLAB:audiovideo:aviread:FunctionToBeRemoved');
cleaner = onCleanup(@()warning(S));
out = aviread(FileName);
case 'im'
[out.cdata, out.colormap, out.alpha] = imread(FileName);
case {'au','snd'}
[out.data, out.fs] = auread(FileName);
case 'wav'
[out.data, out.fs] = wavread(FileName);
case 'mat'
wasError = false;
try
if ~isempty(whos('-file',FileName))
% call load with -mat option
out = load('-mat',FileName);
else
wasError = true;
end
catch exception %#ok<NASGU>
wasError = true;
end
if wasError
% call load with -ascii option
out = load('-ascii',FileName);
end
if isempty(out)
error(message('MATLAB:importdata:InvalidFile'));
end
otherwise
% try to treat as hidden mat file
try
out = load('-mat',FileName);
catch exception %#ok<NASGU>
out = [];
end
if isempty(out)
try
% file is an unknown format, treat it as text
[out, delimiter, headerlines] = LocalTextRead(FileName, delim, requestedHeaderLines);
catch myException
finalException = CatalogException(message('MATLAB:importdata:UnableToRead'));
finalException = finalException.addCause(myException);
throw(finalException);
end
end
end
end
end
end
if (length(out) == 1 && isstruct(out))
% remove empty fields from output struct
names = fieldnames(out);
for i = 1:length(names)
if isempty(out.(names{i}))
out = rmfield(out, names{i});
end
end
if ~isempty(out)
% flatten output struct if single variable
names = fieldnames(out);
if bFlatten && length(names) == 1
out = out.(names{1});
elseif isempty(names)
out = [];
end
end
end
function [out, delimiter, headerlines] = LocalTextRead(filename, delim, hlines)
% get the delimiter for the file
if isnan(delim.requested)
fid = fopen(filename);
str = fread(fid, 4096,'*char')';
fclose(fid);
delim.printed = guessdelim(str);
delim.requested = delim.printed;
else
delim.printed = sprintf(delim.requested);
end
delimiter = delim.printed;
fileString = fileread(filename);
bWarn = true;
[out.data, out.textdata, headerlines] = parse(fileString, delim, hlines, bWarn);
out = LocalRowColShuffle(out);
function out = LocalRowColShuffle(in)
out = in;
if isempty(in) || ~isfield(in, 'data') || ~isfield(in,'textdata') || isempty(in.data) || isempty(in.textdata)
return;
end
[dm, dn] = size(in.data);
[tm, tn] = size(in.textdata);
if tn == 1 && tm == dm
% use as row headers
out.rowheaders = in.textdata(:,end);
elseif tn == dn
% use last row as col headers
out.colheaders = in.textdata(end,:);
end
function [numericData, textData, numHeaderRows] = parse(fileString, ...
delim, headerLines, bWarnOnMismatch)
%This is the function which takes in a string and parses it into
%"spreadsheet" type data.
narginchk(1,4);
numericData = [];
textData = {};
numHeaderRows = 0;
% gracefully handle empty
if isempty(fileString) && isempty(regexp(fileString,'\S','once'));
%regexp is faster than all(isspace(fileString));
return;
end
% validate delimiter
if length(delim.printed) > 1
error(message('MATLAB:importdata:InvalidDelimiter'))
end
if nargin < 3
headerLines = NaN;
end
%Arbitrarily set the maximum size for a line, used to calculate this but it
%was slow, so we went with all in one line or the old maximum it would
%check.
bufsize = min(1000000, max(numel(fileString),100)) + 5;
% use what user asked for header lines if specified
[numDataCols, numHeaderRows, numHeaderCols, numHeaderChars] = ...
analyze(fileString, delim, headerLines, bufsize);
% fetch header lines and look for a line of column headers
headerLine = {};
headerData = {};
origHeaderData = headerData;
useAsCells = 1;
if numHeaderRows
firstLineOffset = numHeaderRows - 1;
if firstLineOffset > 0
headerData = textscan(fileString,'%[^\n\r]',firstLineOffset,...
'whitespace','','delimiter','\n','bufsize', bufsize);
origHeaderData = headerData{1};
if numDataCols
headerData = [origHeaderData, cell(length(origHeaderData), numHeaderCols + numDataCols - 1)];
else
headerData = [origHeaderData, cell(length(origHeaderData), numHeaderCols)];
end
else
headerData = emptyCharCell(0, numHeaderCols + numDataCols);
end
Data = textscan(fileString,'%[^\n\r]',1,'headerlines',firstLineOffset,...
'delimiter',delim.requested,'bufsize', bufsize);
headerLine = Data{1};
origHeaderLine = headerLine;
useAsCells = 0;
if ~isempty(delim.printed) && ~isempty(headerLine) && ~isempty(strfind(deblank(headerLine{:}), delim.printed))
cellLine = split(headerLine{:}, delim);
%Trailing spaces are not treated as extra delimiters
if (delim.printed ~= ' ' && isequal(headerLine{:}(end),delim.printed))
cellLine(end+1) = {''};
end
if length(cellLine) == numHeaderCols + numDataCols
headerLine = cellLine;
useAsCells = 1;
end
end
if ~useAsCells
if numDataCols
headerLine = [origHeaderLine, emptyCharCell(1, numHeaderCols + numDataCols - 1)];
else
headerLine = [origHeaderLine, emptyCharCell(1, numHeaderCols)];
end
end
end
formatString = [repmat('%q', 1, numHeaderCols) repmat('%n', 1, numDataCols)];
% now try for the whole shootin' match
try
if numDataCols
%When the delimiter is a space, multiple spaces do NOT mean
%multiple delimiters. Thus, call textscan such that it will
%treat them as one.
multipleDelimsAsOne = isequal(delim.printed,' ');
if strfind(delim.printed, '%')
commentStyle = '';
else
commentStyle = '%';
end
Data = textscan(fileString,formatString,'delimiter',delim.requested, ...
'MultipleDelimsAsOne', multipleDelimsAsOne, 'CommentStyle', commentStyle, ...
'bufsize', 1000*bufsize, 'headerlines',numHeaderRows, 'CollectOutput', true);
if (numHeaderCols)
numericData = Data{2};
else
numericData = Data{1};
end
end
wasError = false;
catch exception %#ok
wasError = true;
end
if nargout > 1
if numHeaderCols > 0
textData = emptyCharCell(size(Data{1}, 1), numDataCols+numHeaderCols);
textData(:, 1:numHeaderCols) = Data{1};
end
if ~isempty(headerLine)
textData = [headerLine; textData];
end
if ~isempty(headerData)
textData = [headerData; textData];
end
end
clear('Data');
if (numDataCols && numHeaderCols && (size(textData, 1) ~= numHeaderRows + size(numericData, 1)))
wasError = true;
end
% if the first pass failed to read the whole shootin' match, try again using the character offset
if wasError && numHeaderChars
wasError = false;
% rebuild format string
formatString = ['%' num2str(numHeaderChars) 'c' repmat('%n', 1, numDataCols)];
%When the delimiter is a space, multiple spaces do NOT mean
%multiple delimiters. Thus, call textscan such that it will
%treat them as one.
multipleDelimsAsOne = isequal(delim.printed,' ');
if strfind(delim.printed, '%')
commentStyle = '';
else
commentStyle = '%';
end
Data = textscan(fileString,formatString,'delimiter', delim.requested, ...
'MultipleDelimsAsOne', multipleDelimsAsOne, 'returnonerror', 1, 'CommentStyle', commentStyle, ...
'bufsize', bufsize, 'headerlines',numHeaderRows, 'CollectOutput', true);
textCharData = Data{1};
numericData = Data{2};
numHeaderCols = 1;
if ~isempty(numericData)
numRows = size(numericData, 1);
else
numRows = length(textCharData);
end
if numDataCols
headerData = [origHeaderData, ...
emptyCharCell(length(origHeaderData), numHeaderCols + numDataCols - 1)];
else
headerData = [origHeaderData, ...
emptyCharCell(length(origHeaderData), numHeaderCols)];
end
if ~useAsCells
if numDataCols
headerLine = [origHeaderLine, ...
emptyCharCell(1, numHeaderCols + numDataCols - 1)];
else
headerLine = [origHeaderLine, emptyCharCell(1, numHeaderCols)];
end
end
if nargout > 1 && ~isempty(textCharData)
textCellData = cellstr(textCharData);
if ~isempty(headerLine)
textData = [headerLine; ...
textCellData(1:numRows), ...
emptyCharCell(numRows, numHeaderCols + numDataCols - 1)];
else
textData = [textCellData(1:numRows), ...
emptyCharCell(numRows, numHeaderCols + numDataCols - 1)];
end
if ~isempty(headerData)
textData = [headerData; textData];
end
end
end
if bWarnOnMismatch && wasError
warning(message('MATLAB:importdata:FormatMismatch'));
end
if nargout > 1 && ~isempty(textData)
textData = TrimTrailing(@(x)cellfun('isempty', x), textData);
end
if ~isempty(numericData)
numericData = TrimTrailing(@(x)(isnan(x)), numericData);
end
function out = emptyCharCell(m,n)
%Create a cell array with empty strings of a given size
out = repmat({''}, [m, n]);
function [numColumns, numHeaderRows, numHeaderCols, numHeaderChars] = ...
analyze(fileString, delim, header, bufsize)
%ANALYZE count columns, header rows and header columns
numColumns = 0;
numHeaderRows = 0;
numHeaderCols = 0;
numHeaderChars = 0;
if ~isnan(header)
numHeaderRows = header;
end
Data = textscan(fileString,'%[^\n\r]',1,'headerlines',numHeaderRows,...
'delimiter',delim.requested,'bufsize', bufsize);
thisLine = Data{1};
if isempty(thisLine)
return;
end
thisLine = thisLine{:};
[isvalid, numHeaderCols, numHeaderChars] = isvaliddata(thisLine, delim);
if ~isvalid && isnan(header)
numHeaderRows = numHeaderRows + 1;
Data = textscan(fileString,'%[^\n\r]',1,'headerlines',numHeaderRows,...
'delimiter',delim.requested, 'bufsize', bufsize);
thisLine = Data{1};
if isempty(thisLine)
return;
end
thisLine = thisLine{1};
[isvalid, numHeaderCols, numHeaderChars] = isvaliddata(thisLine, delim);
while ~isvalid
% stop now if the user specified a number of header lines
if ~isnan(header) && numHeaderRows == header
break;
end
numHeaderRows = numHeaderRows + 1;
if numHeaderRows >= 1000
%Assume no data.
Data = textscan(fileString,'%[^\n\r]','headerlines',numHeaderRows,...
'delimiter',delim.requested, 'bufsize', bufsize);
thisLine = Data{1};
numHeaderRows = length(thisLine) + numHeaderRows;
break;
end
Data = textscan(fileString,'%[^\n\r]',1,'headerlines',numHeaderRows,...
'delimiter',delim.requested, 'bufsize', bufsize);
thisLine = Data{1};
if isempty(thisLine)
break;
end
thisLine = thisLine{1};
[isvalid, numHeaderCols, numHeaderChars] = isvaliddata(thisLine, delim);
end
end
% This check could happen earlier
if ~isnan(header) && numHeaderRows >= header
numHeaderRows = header;
end
if isvalid
% determine num columns
%remove trailing spaces. Spaces are different from other delimiters.
thisLine = regexprep(thisLine, ' +$', '');
delimiterIndexes = strfind(thisLine, delim.printed);
if all(delim.printed ==' ') && length(delimiterIndexes) > 1
delimiterIndexes = delimiterIndexes([true diff(delimiterIndexes) ~= 1]);
delimiterIndexes = delimiterIndexes(delimiterIndexes > 1);
end
% format string should have 1 more specifier than there are delimiters
numColumns = length(delimiterIndexes) + 1;
if numHeaderCols > 0
% add one to numColumns because the two set of columns share a delimiter
numColumns = numColumns - numHeaderCols;
end
end
function [status, numHeaderCols, numHeaderChars] = isvaliddata(fileString, delim)
% ISVALIDDATA delimiters and all numbers or e or + or . or -
% what about single columns???
numHeaderCols = 0;
numHeaderChars = 0;
if isempty(delim.printed)
% with no delimiter, the line must be all numbers, +, . or -
status = isdata(fileString);
return
end
status = 0;
if ~strcmp(delim.printed,'"')
fileString = regexprep(fileString, '"[^"]*"','""');
end
delims = strfind(fileString, delim.printed);
if isempty(delims)
checkstring = fileString;
if isempty(regexp(checkstring, '\S', 'once'))
% Just a blank line, not actually data.
status = 0;
return
end
else
checkstring = fileString(delims(end)+1:end);
end
% if there is data at the end of the line, it's legit
if isdata(checkstring)
try
[cellstring indices] = split(fileString, delim);
numNonEmptyCols = find(cellfun('isempty',deblank(cellstring)) == false, 1, 'last');
numHeaderCols = maxNotData(cellstring);
% use contents of 1st data cell to find num leading chars
if numHeaderCols > 0
numHeaderChars = indices(numHeaderCols);
end
if (numHeaderCols == numNonEmptyCols)
numHeaderCols = 0;
numHeaderChars = 0;
else
status = 1;
end
catch exception %#ok<NASGU>
numHeaderCols = 0;
numHeaderChars = 0;
end
end
function index = maxNotData(cellstring)
len = length(cellstring);
index = 0;
for i = len:-1:1
if ~isdata(cellstring{i})
index = i;
break;
end
end
function status = isdata(fileString)
%ISDATA true if string can be shoved into a number or if it's allwhite
if isempty(regexp(fileString, '\S', 'once'))
status = 1;
else
[~,b,c] = sscanf(fileString, '%g');
status = isempty(c) && b == 1;
end
function [cellOut indOut] = split(fileString, delim)
%SPLIT rip string apart
if delim.printed == ' '
%Multiple spaces are often used as a "fixed-width", thus we treat them
%differently.
cellOut = textscan(fileString,'%s','delimiter',delim.requested,...
'multipleDelimsAsOne', 1, 'whitespace','');
indOut = regexp(strtrim(fileString),' [^ ]') ;
else
cellOut = textscan(fileString,'%s','delimiter',delim.requested,...
'whitespace','');
indOut = strfind(fileString,delim.printed);
end
cellOut = (cellOut{1})';
function out = TrimTrailing(operation, out)
% Trim trailing that use a certain operation
cols = size(out,2);
while cols >= 1
if ~all(operation(out(:,cols)))
break;
end
cols = cols - 1;
end
% trim trailing empty rows from textData
rows = size(out,1);
while rows >= 1
if ~all(operation(out(rows,1:cols)))
break;
end
rows = rows - 1;
end
if rows < size(out,1) || cols < size(out,2)
out = out(1:rows,1:cols);
end
function out = readFromExcelFile(FileName, descr,out, bFlatten)
warnState = warning('off', 'MATLAB:xlsread:Mode');
warnState(2) = warning('off', 'MATLAB:xlsread:ActiveX');
cleanupObj = onCleanup(@()warning(warnState));
if bFlatten && length(descr) == 1
baseSubs = {struct('type', {}, 'subs', {})};
else
names = genvarname(descr);
baseSubs = num2cell(struct('type','.', 'subs', names));
end
% top level fields so assignments below work right
for i = 1:length(descr)
[n,s,raw] = xlsread(FileName,descr{i});
likely_row = size(raw,1) - size(n,1);
if ~isempty(n)
out = subsasgn(out, [substruct('.','data') baseSubs{i}], n);
end
if ~isempty(s)
out = subsasgn(out, [substruct('.', 'textdata') baseSubs{i}], s);
end
if ~isempty(s) && ~isempty(n)
[dm, dn] = size(n);
[tm, tn] = size(s);
if tn == 1 && tm == dm
out = subsasgn(out, [substruct('.', 'rowheaders') baseSubs{i}], s(:,end));
elseif tn == dn && likely_row > 0 && tm >= likely_row
out = subsasgn(out, [substruct('.', 'colheaders') baseSubs{i}], s(likely_row, :));
end
end
end
% ------------------------------------------------
function me = CatalogException(message)
% Helper function for MException
me = MException(message.Identifier, '%s', message.getString);