/
std_makedesign.m
404 lines (379 loc) · 19.2 KB
/
std_makedesign.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
% STD_MAKEDESIGN - create a new or edit an existing STUDY.design by
% selecting specific factors to include in subsequent
% 1x2 or 2x2 STUDY measures and statistical computations
% for this design. A STUDY may have many factors
% (task or stimulus conditions, subject groups, session
% numbers, trial types, etc.), but current EEGLAB
% STUDY statistics functions apply only to at most two
% (paired or unpaired) factors. A STUDY.design may
% also be (further) restricted to include only specific
% subjects, datasets, or trial types.
% Usage:
% >> [STUDY] = std_makedesign(STUDY, ALLEEG); % create a default design
% >> [STUDY] = std_makedesign(STUDY, ALLEEG, designind, 'key', 'val' ...);
%
% Inputs:
% STUDY - EEGLAB STUDY set
% ALLEEG - vector of the EEG datasets included in the STUDY structure
% designind - [integer > 0] index (number) of the new STUDY design {default: 1}
%
% Optional inputs:
% 'name' - ['string'] mnemonic design name (ex: 'Targets only')
% {default: 'Design d', where d = designind}
% 'variable1' - ['string'] - first independent variable or contrast. Must
% be a field name in STUDY.datasetinfo or in
% STUDY.datasetinfo.trialinfo. Typical choices include (task
% or other) 'condition', (subject) 'group', (subject) 'session',
% or other condition/group/session factors in STUDY.datasetinfo
% -- for example (subject factor) 'gender' or (condition factor)
% 'timeofday', etc. If trial type variables are defined in
% STUDY.datasetinfo.trialinfo, they may also be used here
% -- for example, 'stimcolor'. However, in this case datasets
% consist of heterogeneous sets of trials of different types,
% so many dataset Plot and Tools menu items may not give
% interpretable results and will thus be made unavailable for
% selection {default: 'condition'}
% 'values1' - {cell array of 'strings'} - 'variable1' instances to include
% in the design. For example, if 'variable1' is 'condition'and
% three values for 'condition' (e.g., 'a' , 'b', and 'c')
% are listed in STUDY.datasetinfo, then 'indval1', { 'a' 'b' }
% will contrast conditions 'a' and 'b', and datasets for
% condition 'c' will be ignored. To combine conditions, use
% nested '{}'s. For example, to combine conditions 'a' and
% 'b' into one condition and contrast it to condition 'c',
% specify 'indval1', { { 'a' 'b' } 'c' } {default: all values
% of 'variable1' in STUDY.datasetinfo}
% 'variable2' - ['string'] - second independent variable name, if any. Typically,
% this might refer to ('unpaired') subject group or (typically
% 'paired') session number, etc.
% 'values2' - {cell array of 'strings'} - variable2 values to include in the
% design {default: all}. Here, 'var[12]' must be field names
% in STUDY.datasetinfo or STUDY.datasetinfo.trialinfo.
% 'subjselect' - {cell array} subject codes of specific subjects to include
% in the STUDY design {default: all subjects in the specified
% conditions, groups, etc.} If 'datselect' is also specified,
% only datasets meeting both criteria are included.
% 'rmfiles' - ['on'|'off'] remove from the STUDY all data measure files
% NOT included in this design. Selecting this option will
% remove all the old measure files associated with the previous
% definition of this design. {default: 'off'}
% 'filepath' - [string] file path for saving precomputed files. Default is
% empty meaning it is in the same folder as the data.
% 'delfiles' - ['on'|'off'|'limited'] delete data files
% associated with the design specified as parameter. 'on'
% delete all data files related to the design. 'limited'
% deletes all data files contained in the design. 'limited'
% will not delete data files from other STUDY using the same
% files. Default is 'off'.
%
% Output:
% STUDY - The input STUDY with a new design added and designated
% as the current design.
%
% Examples:
% STUDY = std_makedesign(STUDY, ALLEEG); % make default design
%
% % create design with 1 independent variable equal to 'condition'
% STUDY = std_makedesign(STUDY, ALLEEG, 2, 'variable1', 'condition');
%
% % create design with 1 independent variable equal to 'condition'
% % but only consider the sub-condition 'stim1' and 'stim2' - of course
% % such conditions must be present in the STUDY
% STUDY = std_makedesign(STUDY, ALLEEG, 2, 'variable1', 'condition', ...
% 'values1', { 'stim1' 'stim2' });
%
% % create design and only include subject 's1' and 's2'
% STUDY = std_makedesign(STUDY, ALLEEG, 2, 'variable1', 'condition', ...
% 'subjselect', { 's1' 's2' });
%
% Author: Arnaud Delorme, Institute for Neural Computation UCSD, 2010-
% Copyright (C) Arnaud Delorme, arno@salk.edu
%
% This file is part of EEGLAB, see http://www.eeglab.org
% for the documentation and details.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
%
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
% THE POSSIBILITY OF SUCH DAMAGE.
function [STUDY, com] = std_makedesign(STUDY, ALLEEG, designind, varargin)
if nargin < 2
help std_makedesign;
return;
end
if nargin < 3
designind = 1;
end
defdes.name = sprintf('STUDY.design %d', designind);
defdes.cases.label = 'subject';
defdes.cases.value = {};
defdes.variable(1).label = 'condition';
defdes.variable(2).label = 'group';
defdes.variable(3).label = '';
defdes.variable(4).label = '';
defdes.variable(1).value = {};
defdes.variable(2).value = {};
defdes.variable(3).value = {};
defdes.variable(4).value = {};
defdes.variable(1).vartype = 'categorical';
defdes.variable(2).vartype = 'categorical';
defdes.filepath = '';
defdes.include = {};
orivarargin = varargin;
if ~isempty(varargin) && isstruct(varargin{1})
defdes = varargin{1};
varargin(1) = [];
end
if isempty(defdes.filepath), defdes.filepath = ''; end
if length(defdes.variable) == 0, defdes.variable(1).label = 'continuous'; defdes.variable(1).vartype = 'categorical'; defdes.variable(1).value = {}; end
if length(defdes.variable) == 1, defdes.variable(2).label = 'continuous'; defdes.variable(2).vartype = 'categorical'; defdes.variable(2).value = {}; end
if length(defdes.variable) == 2, defdes.variable(3).label = 'continuous'; defdes.variable(3).vartype = 'categorical'; defdes.variable(3).value = {}; end
if length(defdes.variable) == 3, defdes.variable(4).label = 'continuous'; defdes.variable(4).vartype = 'categorical'; defdes.variable(4).value = {}; end
for iVar = 1:4
if isempty(defdes.variable(iVar).vartype), defdes.variable(iVar).vartype = 'continuous'; end
if isempty(defdes.variable(iVar).label) , defdes.variable(iVar).label = ''; end
end
opt = finputcheck(varargin, {'variable1' 'string' [] defdes.variable(1).label;
'variable2' 'string' [] defdes.variable(2).label;
'variable3' 'string' [] defdes.variable(3).label;
'variable4' 'string' [] defdes.variable(4).label;
'values1' {'real','cell' } [] defdes.variable(1).value;
'values2' {'real','cell' } [] defdes.variable(2).value;
'values3' {'real','cell' } [] defdes.variable(3).value;
'values4' {'real','cell' } [] defdes.variable(4).value;
'vartype1' 'string' {'categorical' 'continuous'} defdes.variable(1).vartype;
'vartype2' 'string' {'categorical' 'continuous'} defdes.variable(2).vartype;
'vartype3' 'string' {'categorical' 'continuous'} defdes.variable(3).vartype;
'vartype4' 'string' {'categorical' 'continuous'} defdes.variable(4).vartype;
'name' 'string' {} defdes.name;
'filepath' 'string' {} defdes.filepath;
'datselect' 'cell' {} defdes.include;
'dataselect' 'cell' {} {};
'subjselect' 'cell' {} defdes.cases.value;
'delfiles' 'string' { 'on','off', 'limited' } 'off';
'verbose' 'string' { 'on','off' } 'on';
'defaultdesign' 'string' { 'on','off','forceoff'} fastif(nargin < 3, 'on', 'off') }, ...
'std_makedesign', 'ignore');
if ischar(opt), error(opt); end
if ~isempty(opt.dataselect), opt.datselect = opt.dataselect; end
if strcmpi(opt.variable1, 'none'), opt.variable1 = ''; end
if strcmpi(opt.variable2, 'none'), opt.variable2 = ''; end
%if iscell(opt.values1), for i = 1:length(opt.values1), if iscell(opt.values1{i}), opt.values1{i} = cell2str(opt.values1{i}); end; end; end
%if iscell(opt.values2), for i = 1:length(opt.values2), if iscell(opt.values2{i}), opt.values2{i} = cell2str(opt.values2{i}); end; end; end
% check inputs
% ------------
[indvars, indvarvals, ~, paired] = std_getindvar(STUDY);
if isfield(STUDY.datasetinfo, 'trialinfo')
alltrialinfo = { STUDY.datasetinfo.trialinfo };
dattrialselect = cellfun(@(x)([1:length(x)]), alltrialinfo, 'uniformoutput', false);
else alltrialinfo = cell(length(STUDY.datasetinfo));
for i=1:length(ALLEEG), dattrialselect{i} = [1:ALLEEG(i).trials]; end
end
% get values for each independent variable
% ----------------------------------------
m1 = strmatch(opt.variable1, indvars, 'exact'); if isempty(m1), opt.variable1 = ''; end
m2 = strmatch(opt.variable2, indvars, 'exact'); if isempty(m2), opt.variable2 = ''; end
m3 = strmatch(opt.variable3, indvars, 'exact'); if isempty(m3), opt.variable3 = ''; end
m4 = strmatch(opt.variable4, indvars, 'exact'); if isempty(m4), opt.variable4 = ''; end
if isempty(opt.values1) && ~isempty(opt.variable1), opt.values1 = indvarvals{m1}; end
if isempty(opt.values2) && ~isempty(opt.variable2), opt.values2 = indvarvals{m2}; end
if isempty(opt.values3) && ~isempty(opt.variable3), opt.values3 = indvarvals{m3}; end
if isempty(opt.values4) && ~isempty(opt.variable4), opt.values4 = indvarvals{m4}; end
if isempty(opt.variable1), opt.values1 = { '' }; end
if isempty(opt.variable2), opt.values2 = { '' }; end
if isempty(opt.variable3), opt.values3 = { '' }; end
if isempty(opt.variable4), opt.values4 = { '' }; end
% build command list for history
% ------------------------------
listcom = { 'name' opt.name 'delfiles' opt.delfiles 'defaultdesign' opt.defaultdesign };
if ~isempty(opt.variable1), listcom = { listcom{:} 'variable1' opt.variable1 'values1' opt.values1 'vartype1' opt.vartype1 }; end
if ~isempty(opt.variable2), listcom = { listcom{:} 'variable2' opt.variable2 'values2' opt.values2 'vartype2' opt.vartype2 }; end
if ~isempty(opt.variable3), listcom = { listcom{:} 'variable3' opt.variable3 'values3' opt.values3 'vartype3' opt.vartype3 }; end
if ~isempty(opt.variable4), listcom = { listcom{:} 'variable4' opt.variable4 'values4' opt.values4 'vartype4' opt.vartype4 }; end
if ~isempty(opt.subjselect), listcom = { listcom{:} 'subjselect' opt.subjselect }; end
if ~isempty(opt.datselect), listcom = { listcom{:} 'datselect' opt.datselect }; end
if ~isempty(opt.filepath), listcom = { listcom{:} 'filepath' opt.filepath }; end
if ~isempty(opt.datselect), listcom = { listcom{:} 'datselect' opt.datselect }; end
% select specific subjects
% ------------------------
datsubjects = { STUDY.datasetinfo.subject };
if ~isempty(opt.subjselect)
allsubjects = opt.subjselect;
else
allsubjects = unique_bc( datsubjects );
end
% delete design files
% ---------------------
if strcmpi(opt.delfiles, 'on')
myfprintf(opt.verbose, 'Deleting all files pertaining to design %d\n', designind);
for index = 1:length(ALLEEG)
files = fullfile(ALLEEG(index).filepath, sprintf(opt.verbose, 'design%d*.*', designind));
files = dir(files);
for indf = 1:length(files)
delete(fullfile(ALLEEG(index).filepath, files(indf).name));
end
end
elseif strcmpi(opt.delfiles, 'limited')
myfprintf(opt.verbose, 'Deleting all files for STUDY design %d\n', designind);
for index = 1:length(STUDY.design(designind).cell)
filedir = [ STUDY.design(designind).cell(index).filebase '.dat*' ];
filepath = fileparts(filedir);
files = dir(filedir);
for indf = 1:length(files)
%disp(fullfile(filepath, files(indf).name));
delete(fullfile(filepath, files(indf).name));
end
end
for index = 1:length(STUDY.design(designind).cell)
filedir = [ STUDY.design(designind).cell(index).filebase '.ica*' ];
filepath = fileparts(filedir);
files = dir(filedir);
for indf = 1:length(files)
%disp(fullfile(filepath, files(indf).name));
delete(fullfile(filepath, files(indf).name));
end
end
end
% preselect data
% --------------
datselect = [1:length(STUDY.datasetinfo)];
if ~isempty(opt.datselect)
fprintf(2, '**********************************\n')
fprintf(2, 'The ''datselect'' option is obsolete\n')
fprintf(2, '**********************************\n\n')
error('This version of EEGLAB no longer support ''datselect''; please remove it from the list of inputs')
for ind = 1:2:length(opt.datselect)
[ dattmp, dattrialstmp ] = std_selectdataset( STUDY, ALLEEG, opt.datselect{ind}, opt.datselect{ind+1});
datselect = intersect_bc(datselect, dattmp);
dattrialselect = intersectcell(dattrialselect, dattrialstmp);
end
end
datselect = intersect_bc(datselect, strmatchmult(allsubjects, datsubjects));
des.name = opt.name;
des.filepath = opt.filepath;
if ~isempty(opt.variable1)
des.variable(1).label = opt.variable1;
des.variable(1).value = opt.values1;
des.variable(1).vartype = opt.vartype1;
des.variable(1).pairing = paired{m1};
end
if ~isempty(opt.variable2)
des.variable(2).label = opt.variable2;
des.variable(2).value = opt.values2;
des.variable(2).vartype = opt.vartype2;
des.variable(2).pairing = paired{m2};
end
if ~isempty(opt.variable3)
des.variable(3).label = opt.variable3;
des.variable(3).value = opt.values3;
des.variable(3).vartype = opt.vartype3;
des.variable(3).pairing = paired{m3};
end
if ~isempty(opt.variable4)
des.variable(4).label = opt.variable4;
des.variable(4).value = opt.values4;
des.variable(4).vartype = opt.vartype4;
des.variable(4).pairing = paired{m4};
end
des.include = opt.datselect;
des.cases.label = 'subject';
des.cases.value = opt.subjselect;
if isempty(des.cases.value), des.cases.value = STUDY.subject; end
fieldorder = { 'name' 'filepath' 'variable' 'cases' 'include' };
if ~isfield(des, 'variable'), des.variable = []; end
des = orderfields(des, fieldorder);
try
STUDY.design = orderfields(STUDY.design, fieldorder);
catch
STUDY.design = [];
end
if ~isfield(STUDY, 'design') || isempty(STUDY.design)
STUDY.design = des;
else
STUDY.design(designind) = des; % fill STUDY.design
end
STUDY = std_addvarlevel(STUDY, designind);
% remove empty variables
if designind <= length(STUDY.design)
for iVar = length(STUDY.design(designind).variable):-1:1
if isempty(STUDY.design(designind).variable(iVar).label)
STUDY.design(designind).variable(iVar) = [];
end
end
end
% reorder variable putting single value var at the end
% this allows selecting some specific conditions and still processing the
% data in EEGLAB standard stat functions
if length(STUDY.design(designind).variable) > 2
if all(cellfun(@(x)isequal(x, 'categorical'), { STUDY.design(designind).variable(3).vartype })) % only categorical
varLen = cellfun(@(x)length(x), {STUDY.design(designind).variable.value});
indLen1 = find(varLen == 1);
STUDY.design(designind).variable = [ STUDY.design(designind).variable(setdiff(1:length(varLen), indLen1)) STUDY.design(designind).variable(indLen1) ];
end
end
% select the new design in the STUDY output
% -----------------------------------------
STUDY.currentdesign = designind;
STUDY = std_selectdesign(STUDY, ALLEEG, designind);
STUDY.cache = [];
% build output command
% --------------------
com = sprintf('STUDY = std_makedesign(STUDY, ALLEEG, %d, %s);', designind, vararg2str( listcom ) );
% ---------------------------------------------------
% return intersection of cell arrays
% ----------------------------------
function res = intersectcell(a, b, c)
if nargin > 2
res = intersectcell(a, intersectcell(b, c));
else
for index = 1:length(a)
res{index} = intersect_bc(a{index}, b{index});
end
end
% perform multi strmatch
% ----------------------
function res = strmatchmult(a, b)
res = [];
for index = 1:length(a)
res = [ res strmatch(a{index}, b, 'exact')' ];
end
% remove blanks
% -------------
function res = rmblk(a)
if iscell(a), a = cell2str(a); end
if ~ischar(a), a = num2str(a); end
res = a;
res(find(res == ' ')) = '_';
res(find(res == '\')) = '_';
res(find(res == '/')) = '_';
res(find(res == ':')) = '_';
res(find(res == ';')) = '_';
res(find(res == '"')) = '_';
function strval = cell2str(vals);
strval = vals{1};
for ind = 2:length(vals)
strval = [ strval ' - ' vals{ind} ];
end
function tmpfile = checkfilelength(tmpfile)
if length(tmpfile) > 120
tmpfile = tmpfile(1:120);
end
function myfprintf(verbose, varargin)
if strcmpi(verbose, 'on'), fprintf(varargin{:}); end