% STD_PLODTMAT - plot design matrix and info associated with the study for
% each subject. Designed to be used directly (as a callback
% function of button plot) from pop_studydesign
% Usage:
% >> std_plotdmat(STUDY.design(1),STUDY.datasetinfo)
%
% Inputs:
% datasetinfo - datasetinfo
% design - Structure with the fields {name,filepath,variable,
% cases, include, deletepreviousfiles} for each variable
% in the design. i.e. STUDY.design(1)
%
% Outputs:
%
% See also:
% pop_studydesign
%
% Author: Ramon Martinez-Cancino & Arnaud Delorme, SCCN, 2014
%
% Copyright (C) 2014 Ramon Martinez-Cancino,
%
% 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 std_plotmat(design,datasetinfo)
% Set var stuff
listsubj = unique(design.cases.value,'sorted'); % assuming cases.value will be always the subjects
varindx = 1:length(design.variable);
% checking if 'group' var (temporal commit to detect group vars, right now only detecting variable 'group')
groupindx = find(strcmp({design.variable.label},'group'));
if ~isempty(groupindx)
varindx(groupindx) = [];
end
flag.dmatextend = true;
flag.textdisp = 1;
flag.subj = 1;
setappdata(0,'flag',flag);
handles.figmode = 0; % Change to 1 if info in GUI. 0 -> info in commandline
% Creating GUI
% Positions and settings
%--------------------------------------------------------------------------
mainfig_pos = [.509 .465 .306 .519];
Text1_pos = [.120 .946 .191 .030];
Text2_pos = [.080 .208 .432 .029];
Text3_pos = [.397 .855 .24 .024];
Text4_pos = [.680 .946 .201 .030];
Text5_pos = [.380 .946 .201 .030];
checkbox_sort_pos = [.422 .896 .242 .035];
popup_subject_pos = [.124 .896 .224 .035];
disp_click_pos = [.7 .896 .183 .035];
if handles.figmode
axes_pos = [.118 .306 .817 .513];
listbox1_pos = [.12 .018 .817 .178];
else
axes_pos = [.118 .1 .817 .650];
end
GUI_FONTSIZE = 12;
AXES_FONTSIZE = 12;
COLOR = [.66 .76 1];
figunits = 'Normalized';
% Main fig
%--------------------------------------------------------------------------
handles.mainfig = figure('MenuBar' ,'none',...
'Name' ,['Design Matrix: ' design.name],...
'NumberTitle' ,'off',...
'Units' ,figunits,...
'Color' ,COLOR,...
'Position' ,mainfig_pos,...
'Visible' ,'off');
% Data in mainfig
setappdata(handles.mainfig,'design',design);
setappdata(handles.mainfig,'flag',flag);
setappdata(handles.mainfig,'datasetinfo',datasetinfo);
% Edit
%--------------------------------------------------------------------------
if handles.figmode
handles.disp_prop = uicontrol('Style','Edit');
set(handles.disp_prop,'String' ,'Loading..',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'BackgroundColor' ,COLOR,...
'Enable' ,'inactive',...
'Min' ,1,...
'Max' ,30,...
'Position' ,listbox1_pos);
end
handles.edit_dispclick = uicontrol('Style','Edit');
set(handles.edit_dispclick,'String' ,' ',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,'Normalized',...
'enable' ,'off',...
'ForegroundColor' , [1 1 1],...
'BackgroundColor' ,[0 0 0],...
'Position' ,disp_click_pos);
% Axes
%--------------------------------------------------------------------------
handles.axes1 = axes('unit', 'normalized', 'position', axes_pos);
handles.axes2 = axes('unit' ,'normalized', ...
'Position' ,axes_pos, ...
'XAxisLocation' ,'top',...
'YAxisLocation' ,'right',...
'Color' ,'none',...
'YTick' ,[],...
'YTickLabel' ,'');
% Popupmenu
%--------------------------------------------------------------------------
handles.popup_sort = uicontrol('Style','Popupmenu');
handles.popup_subject = uicontrol('Style','Popupmenu');
set(handles.popup_sort,'String' ,'',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'Position' ,checkbox_sort_pos,...
'callback' ,{@callback_popup_subject,handles});
set(handles.popup_subject,'String' ,listsubj,...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'Position' ,popup_subject_pos,...
'callback' ,{@callback_popup_subject,handles});
callback_popup_subject('', '', handles);
set(handles.mainfig, 'visible','on');
axes(handles.axes1);
% Text
%--------------------------------------------------------------------------
handles.Text1 = uicontrol('Style','Text');
set(handles.Text1,'String' ,'Select subject',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'BackgroundColor' ,COLOR,...
'Position' ,Text1_pos);
if handles.figmode
handles.Text2 = uicontrol('Style','Text');
set(handles.Text2,'String' ,'Subject Variables Design',...
'FontSize' ,GUI_FONTSIZE,...
'FontWeight' ,'bold',...
'Units' ,figunits,...
'BackgroundColor' ,COLOR,...
'Position' ,Text2_pos);
end
% handles.Text3 = uicontrol('Style','Text');
% set(handles.Text3,'String' ,'Design Matrix',...
% 'FontSize' ,GUI_FONTSIZE+4,...
% 'FontWeight' ,'bold',...
% 'Units' ,figunits,...
% 'BackgroundColor' ,COLOR,...
% 'Position' ,Text3_pos);
handles.Text4 = uicontrol('Style','Text');
set(handles.Text4,'String' ,'Value on Click',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'BackgroundColor' ,COLOR,...
'Position' ,Text4_pos);
handles.Text5 = uicontrol('Style','Text');
set(handles.Text5,'String' ,'Sort by: ',...
'FontSize' ,GUI_FONTSIZE,...
'Units' ,figunits,...
'BackgroundColor' ,COLOR,...
'Position' ,Text5_pos);
%--------------------------------------------------------------------------
% Callbacks
%--------------------------------------------------------------------------
function callback_popup_subject(src,eventdata,handles)
AXES_FONTSIZE = 11;
design = getappdata(handles.mainfig,'design');
flag = getappdata(handles.mainfig,'flag');
datasetinfo = getappdata(handles.mainfig,'datasetinfo');
set(handles.edit_dispclick, 'String', ' ', ...
'ForegroundColor' , [1 1 1]);
listsubj = unique(design.cases.value,'sorted'); % assuming cases.value will be always the subjects
if isfield(handles,'popup_subject')
indtmp = get(handles.popup_subject, 'Value');
else
indtmp = 1;
end
inner_subj_flag = 1;
if flag.subj ~= indtmp
flag.textdisp = 1;
flag.subj = indtmp;
inner_subj_flag = 0;
end
subj = listsubj{indtmp};
% Retrieving all trials and values for this subject
dsetinfo_subjindx = sort(find(strcmp({datasetinfo.subject},subj))); % in datasetinfo
trialinfo = std_combtrialinfo(datasetinfo, dsetinfo_subjindx); % Combining trialinfo
ntrials = 0;
for i = 1 : length(dsetinfo_subjindx)
startendindx(i,1) = ntrials + 1;
ntrials = ntrials + length(datasetinfo(dsetinfo_subjindx(i)).trialinfo);
startendindx(i,2) = ntrials;
end
% call function to build design matrix
[tmpdmat,allLabels,catflag] = std_builddesignmat(design, trialinfo, flag.dmatextend);
set(handles.popup_sort,'String' , [ ' ' allLabels ] );
% Removing NANs (Thanks Cyril!!!)
check = find(sum(isnan(tmpdmat),2));
tmpdmat(check,:) = [];
% Checking checkbox to sort/unsort
dmatsortindex = 1:size(tmpdmat, 1);
if get(handles.popup_sort, 'Value') ~= 1
[tmp,dmatsortindex] = sortrows(tmpdmat,get(handles.popup_sort, 'Value')-1);
if inner_subj_flag, flag.textdisp = 0; end
end
% Updating the design info
text2display(1) = {['Design Name: ' design.name]}; %Name of the design
% Name and values of Regressors
for i = 1:length(design.variable) % Loop per condition
allvarstmp = '[';
for j = 1 : length(design.variable(i).value)
% allvarstmp = [allvarstmp ' ' num2str(design.variable(i).value{j})];
% --
if ischar(design.variable(i).value{j})
allvarstmp = [allvarstmp ' ' design.variable(i).value{j}];
elseif iscell(design.variable(i).value{j})
% Concat all vals
varnametmp = design.variable(i).value{j}{1};
for ivar = 2: length(design.variable(i).value{j})
varnametmp = [varnametmp '&' design.variable(i).value{j}{ivar}];
end
allvarstmp = [allvarstmp ' ' varnametmp];
elseif isnumeric(design.variable(i).value{j})
allvarstmp = [allvarstmp ' ' int2str(design.variable(i).value{j})];
end
% --
end
allvarstmp = [allvarstmp ' ]'];
ncond(i) = length(design.variable(i).value);
text2display(2*i) = {['Regressor ' num2str(i) ' : ' design.variable(i).label]};
text2display(2*i + 1) = {['Regressor ' num2str(i) ' values :' allvarstmp]};
end
text2display(2*(i+1)) = {['Regressor ' num2str(i+1) ' : Baseline' ]};
text2display(2*(i+1) + 1) = {['Regressor ' num2str(i+1) ' values : [1]' ]};
% Display values
if handles.figmode
set(handles.disp_prop,'String',text2display,'HorizontalAlignment', 'left','FontSize', AXES_FONTSIZE);
elseif flag.textdisp
display('----------------------------------------')
display(['--- Subject ' subj ' Variables Design---'])
disp(text2display(:));
display('----------------------------------------')
handles.notdisp = 0;
end
% Normalizing tmpdmat for plot
normtmpdmat = nan(size(tmpdmat));
for iCol = 1:size(tmpdmat,2)
dmat_den = (max(tmpdmat(:,iCol))-min(tmpdmat(:,iCol)));
if length(unique(tmpdmat(:,iCol))) <= 2, tmpdmat(:,iCol) = ~tmpdmat(:,iCol); end % flip colors
if dmat_den ~= 0
normtmpdmat(:,iCol) = (tmpdmat(:,iCol)-min(tmpdmat(:,iCol)))/dmat_den;
else
normtmpdmat(:,iCol) = deal(max(tmpdmat(:,iCol)));
end
end
% Plot matrix
set(handles.mainfig,'CurrentAxes',handles.axes1);
handles.figure = imagesc(normtmpdmat(dmatsortindex,:));
colormap(flipud(colormap('gray')));
xlabel('Regressors',...
'FontWeight', 'normal',...
'FontSize', AXES_FONTSIZE+4);
ylabel('Trials',...
'FontWeight', 'Normal',...
'FontSize', AXES_FONTSIZE+4);
set(handles.axes1,'XTick',1:size(tmpdmat,2))
set(handles.axes2','XTick' ,get(handles.axes1, 'XTick'),...
'XTickLabel', allLabels,...
'xticklabelrotation', 15,...
'XLim' , get(handles.axes1, 'XLim'),...
'FontSize' , AXES_FONTSIZE+2);
set(handles.axes1,'FontSize', AXES_FONTSIZE+2)
set(handles.figure, 'ButtonDownFcn', {@callback_dmatclick,handles,tmpdmat(dmatsortindex,:),design});
setappdata(handles.mainfig,'flag',flag);
drawnow;
%--------------------------------------------------------------------------
function callback_dmatclick(src,eventdata,handles,tmpdmat,design)
axesHandle = get(src,'Parent');
coordinates = get(axesHandle,'CurrentPoint');
coordinates = round(coordinates(1,1:2));
tmpdmatval = tmpdmat(coordinates(2), coordinates(1));
flag = getappdata(handles.mainfig,'flag');
if flag.dmatextend && coordinates(1) <= size(tmpdmat,2)-1
for i = 1:length(design.variable)
nvars = numel(design.variable(i).value);
if nvars == 0, nvars = 1; end
reg_varind_tmp{i} = ones(1,nvars)*i;
end
reg_varind = cell2mat(reg_varind_tmp);
indx1 = reg_varind(coordinates(1));
else
indx1 = coordinates(1);
end
if coordinates(1) <= size(tmpdmat,2)-1
if isfield(design.variable(indx1),'vartype') && strcmp(design.variable(indx1).vartype, 'categorical')
if ~flag.dmatextend
val = design.variable(indx1).value(tmpdmatval);
else
val = tmpdmatval;
end
else
% Note: When an old STUDY is used without modifying the variables,
% the structure 'STUDY.design' does not have the field 'vartype'.
val = tmpdmatval;
end
else
val = 1;
end
if isnumeric(val)
val = num2str(val);
end
set(handles.edit_dispclick, 'String', val, ...
'ForegroundColor' , [0 0 0]);