-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathpcm_plotModelLikelihood.m
242 lines (229 loc) · 9.38 KB
/
pcm_plotModelLikelihood.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
function [T] = pcm_plotModelLikelihood(T,M,varargin)
% function [T] = pcm_plotModelLikelihood(T,M,varargin)
%
% Plots the scaled log likelihood of the pattern component
% model(s) specified in M as a barplot or boxplot. Errorbars reflect 'sem'
% (standard error of the mean; default) or 'std' (standard deviation).
%
% Two options for the noise ceiling:
% - Plot the entire noise ceiling (upper and lower- assuming the
% 'upperceil' option is used; see Options) as a gray patch.
% - Plot only the lower noise ceiling as a black line (if no 'upperceil' is
% supplied).
%
% Likelihoods are scaled such that zero is the likelihood of the null model.
% If 'normalize' is set to 1, then likelihoods are normalized to set upper
% ceiling to 1. For normalization, you must supply 'upperceil'; group fit of
% the noiseceiling model from pcm_fitModelGroup (no crossvalidation).
%
% The upper noise ceiling is the group fit of the noiseceiling model.
% The lower noise ceiling is the fit of the crossvalidated noiseceiling model.
%
% Two options to plot individual subject fits from pcm_fitModelIndivid:
% - submitted T structure contains info for only one subject
% - OR, specify subject of T structure to plot using 'subj' option
%
% Default is to plot group average likelihoods for each model fit.
%
% Returns structure T with likelihood_norm field (the scaled likelihoods).
%
% NOTE: If field T.likelihood_norm already exists, function still
% normalizes values and overwrites this field. Exercise caution.
%
% ----------------------------- Inputs ------------------------------------
%
% M: Model structure. Accepts 'Name' field to label bars in plot.
% T: Output structure of model fits from pcm_fitModelCrossval
%
% ----------------------------- Options -----------------------------------
%
% 'Nnull': Null model #. Default is 1.
% 'Nceil': Noiseceiling model #. If set to NaN, upper noise ceiling is
% not plotted as a line/patch. If no # is given nor is it
% set to NaN, the first model labeled 'noiseceiling' will
% be used for plotting.
% 'varfcn': Error function used for errorbars. 'sem' (default) or 'std'
% 'mindx': Models to plot likelihoods for. Default is to plot all
% but those used for scaling likelihoods.
% 'subj': Specify single subjcet to plot fit of. NOTE: T will still
% be returned with scaled likelihoods for all subjects.
% 'upperceil': Upper noise ceiling SNx1 vector (usually group fit from noise ceiling model)
% 'normalize': Normalizes all log-likelihoods to upper noise ceiling (Pseudo-R2)
% Default is no (0)
% 'style': Specificy whether the plot will be 'bar' (default) or 'dot'.
% 'plotceil': Plot the noise ceiling(s). Default is yes. Shouldn't be
% used when plotting single subject, individual fits
% (because lower noise ceiling will not be
% crossvalidated fit by default).
% 'colors': Cell of RGB cells for likelihood colors. Defaults included
%
% ----------------------------- Outputs -----------------------------------
%
% T: Input structure returned with scaled likelihood fit fields:
% 'likelihood_norm' : Scaled crossvalidated likelihoods
%
% - - - - - - -
% Defaults
% - - - - - - -
Nnull = 1; % null model #
Nceil = []; % noiseceiling model #
varfcn = 'sem'; % errorbar metric
mindx = []; % models to plot
subj = []; % specify specific subject(s) to plot
upperceil = []; % upper noise ceiling vector (size equal to number of subjs)
normalize = 0; % normalize likelihoods to upper noise ceiling
style = 'bar'; % plotting style. 'bar' or 'dot'
plotceil = 1; % turn on/off plotting of noise ceilings
ceilcolor = [0.8 0.8 0.8]; % noise ceiling patch color
colors = {[.7 0 0],... % red
[0 0 .7],... % blue
[.9 .6 0],... % orange
[0 0.6 0.6],... % cyan
[0.5 0 0.5],... % purple
[0.2 0.6 0.2]}; % green
colors = {colors{:},colors{:},colors{:},colors{:}};
pcm_vararginoptions(varargin,{'Nnull','Nceil','upperceil','colors',...
'varfcn','mindx','subj','normalize','style','ceilcolor','plotceil'});
% - - - - - - -
% Check inputs
% - - - - - - -
if ~(isstruct(T))
error('T is not pcm result structure. Check inputs.')
end
% Check subj (determine if plotting group average or individual's data).
if (~isempty(subj) || length(T.SN)==1)
% User didn't specify specific subject, but T only has one subject.
if isempty(subj)
subj = T.SN;
end
% Take only data for specified subject.
sf = @(x) x(subj,:);
T = structfun(sf,T,'UniformOutput',false);
elseif (isempty(subj))
% Plotting group avg.
subj = 1:length(T.SN);
end;
% Locate models for likelihood scaling (first check type, then name).
if isnan(Nceil)
Nceil = [];
normalize = 0;
else
if isempty(Nceil) % noise ceiling model
for m=1:length(M)
if (strcmp(M{m}.name,'noiseceiling'));
Nceil = m;
end
end
end
end;
% Determine models being plotted.
if isempty(mindx)
mindx = 1:length(M);
mindx([Nnull,Nceil]) = []; % get model numbers for all models except null and noiseceiling
end
% Check # of colors.
if length(mindx) > length(colors)
error('More models to be plotted than colors available')
end;
% Set the error function.
switch varfcn
case 'sem'
vfcn = @(x)std(x)/sqrt(length(x));
case 'std'
vfcn = @std;
otherwise
error('Unkown variance function for errobars')
end
% Determine plotting and errorbar functions.
switch style
case 'bar'
plot_fcn = @(x,y) bar(x,y,'FaceColor',colors{x},...
'EdgeColor',colors{x});
ebar_fcn = @(x,ub,lb) line([x,x-0.1; x,x+0.1],[ub,ub; (ub+lb)/2,ub],...
'LineWidth',2,...
'Color',[0 0 0]);
case 'dot'
plot_fcn = @(x,y) plot(x,y,'MarkerFaceColor',colors{x},...
'MarkerEdgeColor',[0 0 0],...
'MarkerSize',12,...
'Marker','o');
ebar_fcn = @(x,ub,lb) line([x,x-0.05,x-0.05; x,x+0.05,x+0.05],[ub,ub,lb; lb,ub,lb],...
'LineWidth',2,...
'Color',[0 0 0]);
end
% - - - - - - -
% Scale Likelihoods
% - - - - - - -
% Scale likelihoods between null and ceiling fits.
% Make all data relative to the the null model.
T.likelihood_norm = bsxfun(@minus,T.likelihood,T.likelihood(:,Nnull)); % null fit is 0
% Correct the upper noise ceiling for the new zero point.
if (~isempty(upperceil))
upperceil = upperceil - T.likelihood(:,Nnull);
end;
if (normalize)
if (isempty(upperceil))
error(sprintf('The normalize option is currently set to 1 but no noise ceiling is provided. Please either: \n - provide upper noise ceiling for normalization (see ''upperceil'' option) \n - set ''normalize'' option to 0 (see ''normalize'' option)'));
end;
T.likelihood_norm = bsxfun(@rdivide,T.likelihood_norm,upperceil); % ceiling fit is 1
upperceil = 1; % Set the upper noise ceiling to 1.
end;
% - - - - - - -
% Plot scaled fits
% - - - - - - -
cla; % Clear current axis
i = 1;
for m = mindx
% Model fit(s)
Y = mean(T.likelihood_norm(:,m));
% Error of fit(s)
U = vfcn(T.likelihood_norm(:,m));
% Set xtick label
if isfield(M{m},'name') && (~isempty(M{m}.name))
labels{i} = M{m}.name;
else
labels{i} = sprintf('Model %d',m);
end
% Plot model's fit
plot_fcn(i,Y);
hold on;
% Plot errorbars (if group fits)
if length(subj)>1; ebar_fcn(i,Y+U,Y-U); end
% update ticker
i = i + 1;
end;
hold off;
% - - - - - - -
% Plot noise ceilings
% - - - - - - -
i = length(mindx)+1;
% Find lower noise ceiling.
lowerceil = T.likelihood_norm(:,Nceil);
if (~isempty(lowerceil) && ~isempty(upperceil) && plotceil)
% Draw a patch encompassing area between upper and lower noise ceilings
v = [0,mean(lowerceil); 0,mean(upperceil); i,mean(upperceil); i,mean(lowerceil)];
f = [1:4];
patch('Vertices',v,'Faces',f,'EdgeColor',ceilcolor,...
'FaceColor',ceilcolor,'FaceAlpha',.75);
% draw lower noise ceiling as black dotted line
line([0;i],[mean(lowerceil);mean(lowerceil)],'LineWidth',1.5,'Color','k','LineStyle','-.');
elseif (~isempty(lowerceil) && isempty(upperceil) && plotceil)
% Only draw the lower noise ceiling (upper not given when fcn called)
% as grey line.
line([0;i],[mean(lowerceil);mean(lowerceil)],'LineWidth',1.5,'Color',[0.5 0.5 0.5],'LineStyle','-.');
elseif (~isempty(upperceil) && isempty(lowerceil) && plotceil)
% Only draw the upper noise ceiling (lower not given when fcn called)
% as grey line.
line([0;i],[mean(upperceil);mean(upperceil)],'LineWidth',1.5,'Color',[0.5 0.5 0.5],'LineStyle','-.');
end;
% Adjust figure labels and limit scales
ylims = get(gca,'YLim');
set(gca,'XTick',[1:i-1]);
set(gca,'XTickLabel',labels);
set(gca,'XLim',[0.5 i-0.5]);
% set(gca,'YLim',[0 ylims(2)]);
if normalize
ylabel('Normalized log-likelihood');
else
ylabel('Log-likelihood');
end