% STD_READEEGFIELD - read field from ALLEEG structure
%
% Usage:
% >> [dataOut, ~, xvals] = std_readeegfield(datasetinfo, ALLEEG, ...
% designvar, fieldName, 'key', val)
% Inputs:
% datasetinfo - STUDY.datasetinfo structure array corresponding to the
% ALLEEG variable below
% ALLEEG - vector of EEG datasets
% designvar - [struct] design variable. For example STUDY.design(1)
% fieldName - [string or cell] fieldnames to return. For example 'pnts' will
% return the number of points EEG.pnts. { 'roi' 'MIM' }
% will return the MIM array.
%
% Optional inputs:
% 'xvalfield' - [string or cell] fieldnames to return.
% 'xvallimit' - [min max] select data within the specific range for the
% first dimension of the output
% 'xvalaverage' - ['on'|'off'] average the first dimension of the output
% and squeeze the output. Default is 'off'.
%
% Output:
% dataOut - cell array of value
% xvals - x values
%
% note: the output matches the output of std_readfile because this
% function can be called by STD_READDATA
%
% Example:
% [STUDY,aa,~,~,~,~,~,info] = std_readdata(STUDY, ALLEEG, 'customread', ...
% 'std_readeegfield', 'customparams', {{ 'etc', 'eegstats', 'alpha_asymmetry' }}, 'ndim', 1);
%
% Author: Arnaud Delorme, CERCO, 2006-
% 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 [dataOut, params, xvals, yvals, events,dataOutSubj] = std_readeegfield(datasetinfo, ALLEEG, designvar, fieldName, varargin)
dataOut = {};
params = [];
xvals = [];
yvals = [];
events = [];
if nargin < 2
help std_readroifield;
return
end
% std_readfile parameters could be useful but most are ignored
opt = finputcheck(varargin, { ...
'xvalfield' '' [] {};
'xvalaverage' 'string' { 'on','off' } 'off';
'xvallimits' 'real' [] [] }, 'std_readeegfield', 'ignore');
if ~iscell(fieldName)
fieldName = { fieldName };
end
if ~iscell(opt.xvalfield)
opt.xvalfield = { opt.xvalfield };
end
% check data
for iDes = 1:length(designvar)
if ~isfield(datasetinfo, designvar(iDes).label)
error('This function read fields of the EEG structure so it can only handle STUDY designs comparing datasets (not trials within datasets)')
end
end
if length(designvar) == 1
for iVar1 = 1:length(designvar(1).value)
[dataOut{iVar1}, dataOutSubj{iVar1}] = getDataCell( designvar(1).value{iVar1}, { datasetinfo.(designvar(1).label) }, ALLEEG, datasetinfo, fieldName);
end
else
for iVar1 = 1:length(designvar(1).value)
for iVar2 = 1:length(designvar(2).value)
[dataOut{iVar1, iVar2},dataOutSubj{iVar1, iVar2}] = getDataCell2( designvar(1).value{iVar1}, { datasetinfo.(designvar(1).label) }, ...
designvar(2).value{iVar2}, { datasetinfo.(designvar(2).label) }, ALLEEG, datasetinfo, fieldName);
end
end
end
% return xvals and yvals
ind = find(~cellfun(@isempty, dataOut(:)));
if ~isempty(ind)
ind = ind(1);
if size(dataOut{ind},1) > 1
xvals = 1:size(dataOut{ind},1);
if size(dataOut{ind},2) > 2
yvals = 1:size(dataOut{ind},2);
end
elseif size(dataOut{ind},2) > 2
xvals = 1:size(dataOut{ind},2);
end
if ~isempty(opt.xvalfield)
xvals = getfield( ALLEEG(1), opt.xvalfield{:} );
end
end
% select xvals
if ~isempty(opt.xvallimits)
[xvals, indBegin, indEnd] = indicesselect(xvals, opt.xvallimits);
for iDat = 1:length(dataOut(:))
if ~isempty(dataOut{iDat})
dataOut{iDat} = dataOut{iDat}(indBegin:indEnd,:,:,:);
end
end
end
if strcmpi(opt.xvalaverage, 'on')
for iDat = 1:length(dataOut(:))
if ~isempty(dataOut{iDat})
dataOut{iDat} = squeeze(mean(dataOut{iDat}));
if size(dataOut{iDat},1) == 1
dataOut{iDat} = transpose(dataOut{iDat});
end
end
end
end
% combine cell arrays
% -------------------
function dataOut = combinecell( dataTmp )
persistent warnflag
if isempty(dataTmp)
dataOut = {};
elseif all(cellfun(@isempty, dataTmp))
dataOut = [];
elseif length(dataTmp) == 1
dataOut = dataTmp{1};
else
if any(~cellfun(@isempty, dataTmp)) && isempty(warnflag)
warning('Some condition have no data for at least one subject; check design')
warnflag = true;
end
% average values
count = 0;
dataOut = {};
for iVar = 1:length(dataTmp)
if ~isempty(dataTmp{iVar})
count = count + 1;
if isempty(dataOut)
dataOut = dataTmp{iVar};
else
dataOut = dataOut + dataTmp{iVar};
end
end
end
dataOut = dataOut/count;
end
% get data from ALLEEG 1
% ----------------------
function [dataOut,dataSubjOut] = getData1( varValue, varList, ALLEEG, datasetinfo, fieldName)
if ischar(varList{1}) && ~ischar(varValue), varValue = num2str(varValue); end
datInd = find(cellfun(@(x)isequal(x, varValue), varList));
if isempty(datInd)
dataOut = {[]};
dataSubjOut = {[]};
else
for iDat = 1:length(datInd)
dataOut{iDat} = getfield(ALLEEG(datInd(iDat)), fieldName{:});
dataSubjOut{iDat} = datasetinfo(datInd(iDat));
end
end
% get data from ALLEEG 2
% ----------------------
function [dataOut,dataSubjOut] = getData2( varValue1, varList1, varValue2, varList2, ALLEEG, datasetinfo, fieldName)
if ischar(varList1{1}) && ~ischar(varValue1), varValue1 = num2str(varValue1); end
if ischar(varList2{1}) && ~ischar(varValue2), varValue2 = num2str(varValue2); end
datInd1 = cellfun(@(x)isequal(x, varValue1), varList1);
datInd2 = cellfun(@(x)isequal(x, varValue2), varList2);
datInd = find( datInd1 & datInd2 );
if isempty(datInd)
dataOut = {[]};
dataSubjOut = {[]};
else
for iDat = 1:length(datInd)
dataOut{iDat} = getfield(ALLEEG(datInd(iDat)), fieldName{:});
dataSubjOut{iDat} = datasetinfo(datInd(iDat));
end
end
% get data from cells 1
% ---------------------
function [dataOut,dataSubjOut] = getDataCell( varValue, varList, ALLEEG, datasetinfo, fieldName)
if ~iscell(varValue)
[dataTmp,dataSubjTmp] = getData1( varValue, varList, ALLEEG, datasetinfo, fieldName);
else
count = 1;
for iVar = length(varValue):-1:1
[dataTmp2,dataSubjTmp2] = getData1( varValue{iVar}, varList, ALLEEG, datasetinfo, fieldName);
dataTmp( count:count+length(dataTmp2)-1) = dataTmp2;
dataSubjTmp(count:count+length(dataTmp2)-1) = dataSubjTmp2;
count = count+1;
end
end
dataOut = combinecell(dataTmp);
dataSubjOut = combinecell(dataSubjTmp);
% get data from cells 2
% ---------------------
function [dataOut,dataSubjOut] = getDataCell2( varValue1, varList1, varValue2, varList2, ALLEEG, datasetinfo, fieldName)
if ~iscell(varValue1) && ~iscell(varValue2)
[dataTmp,dataSubjTmp] = getData2( varValue1, varList1, varValue2, varList2, ALLEEG, datasetinfo, fieldName);
else
count = 1;
if iscell(varValue1) && ~iscell(varValue2)
for iVar = length(varValue1):-1:1
[dataTmp2,dataSubjTmp2] = getData2( varValue1{iVar}, varList1, varValue2, varList2, ALLEEG, datasetinfo, fieldName);
dataTmp( count:count+length(dataTmp2)-1) = dataTmp2;
dataSubjTmp(count:count+length(dataTmp2)-1) = dataSubjTmp2;
count = count+1;
end
elseif ~iscell(varValue1) && iscell(varValue2)
for iVar = length(varValue2):-1:1
[dataTmp2,dataSubjTmp2] = getData2( varValue1, varList1, varValue2{iVar}, varList2, ALLEEG, datasetinfo, fieldName);
dataTmp( count:count+length(dataTmp2)-1) = dataTmp2;
dataSubjTmp(count:count+length(dataTmp2)-1) = dataSubjTmp2;
count = count+1;
end
elseif iscell(varValue1) && iscell(varValue2)
for iVar1 = length(varValue1):-1:1
for iVar2 = length(varValue2):-1:1
[dataTmp2,dataSubjTmp2] = getData2( varValue1{iVar1}, varList1, varValue2{iVar2}, varList2, ALLEEG, datasetinfo, fieldName);
dataTmp( count:count+length(dataTmp2)-1) = dataTmp2;
dataSubjTmp(count:count+length(dataTmp2)-1) = dataSubjTmp2;
count = count+1;
end
end
else
error('Unknown configuration')
end
end
dataOut = combinecell(dataTmp);
dataSubjOut = combinecell(dataSubjTmp);
% select range for xvals
% ----------------------
function [measureRange, indBegin, indEnd] = indicesselect(measureRange, measureLimits)
indBegin = 1;
indEnd = length(measureRange);
if ~isempty(measureRange) && ~isempty(measureLimits) && (measureLimits(1) > measureRange(1) || measureLimits(end) < measureRange(end))
indBegin = min(find(measureRange >= measureLimits(1)));
indEnd = max(find(measureRange <= measureLimits(end)));
measureRange = measureRange(indBegin:indEnd);
end