rmeddis@0
|
1 function UTIL_plotMatrix(toPlot, method)
|
rmeddis@0
|
2 % UTIL_plotMatrix general purpose plotting utility for plotting the results
|
rmeddis@0
|
3 % of the MAP auditory model.
|
rmeddis@0
|
4 % All plots are placed in subplots of a figure (default figure 1).
|
rmeddis@38
|
5 %
|
rmeddis@0
|
6 % Input arguments:
|
rmeddis@0
|
7 % 'toPlot' is matrix (either numeric or logical)
|
rmeddis@0
|
8 % 'method' is a structure containing plot instructions
|
rmeddis@0
|
9 %
|
rmeddis@0
|
10 % mandatory parameters:
|
rmeddis@38
|
11 % method.displaydt xValues spacing between data points
|
rmeddis@38
|
12 % method.yValues yaxis labels mandatory only for 3D plots
|
rmeddis@0
|
13 %
|
rmeddis@0
|
14 % optional
|
rmeddis@38
|
15 % method.figureNo default figure(1)
|
rmeddis@38
|
16 % method.numPlots number of subPlots in the figure (default=1)
|
rmeddis@38
|
17 % method.subPlotNo number of this plot (default=1)
|
rmeddis@38
|
18 % method.zValuesRange [min max] value pair to define yaxis limits
|
rmeddis@38
|
19 % method.zValuesRange [min max] CLIMS for 3-D plot
|
rmeddis@38
|
20 % method.yLabel (string) y-axis label
|
rmeddis@38
|
21 % method.minyMaxy y-axis limits
|
rmeddis@38
|
22 % method.xLabel (string) x-axis label
|
rmeddis@38
|
23 % method.title (string) subplot title
|
rmeddis@0
|
24 % method.bar =1, to force bar histogram (single channel only)
|
rmeddis@38
|
25 % method.view 3D plot 'view' settings e.g. [-6 40]
|
rmeddis@38
|
26 % method.axes (handle) where to plot (overules all others)
|
rmeddis@38
|
27 % method.maxPixels maximum number of pixels (used to speed plotting)
|
rmeddis@38
|
28 % method.blackOnWhite =1; inverts display for 2D plots
|
rmeddis@38
|
29 % method.forceLog positive values are put on log z-scale
|
rmeddis@38
|
30 % method.rasterDotSize min value is 1
|
rmeddis@38
|
31 % method.defaultFontSize deafult= 12
|
rmeddis@38
|
32 % method.timeStart default= dt
|
rmeddis@38
|
33 % method.defaultTextColor default ='k'
|
rmeddis@38
|
34 % method.defaultAxesColor default ='k'
|
rmeddis@38
|
35 % method.nCols default = 1 (layout for subplots)
|
rmeddis@38
|
36 % method.nRows default=method.numPlots (layout for subplots
|
rmeddis@38
|
37 % method.segmentNumber plot only this segment while 'hold on'
|
rmeddis@0
|
38 %
|
rmeddis@38
|
39 % e.g.
|
rmeddis@0
|
40 % UTIL_plotMatrix(toPlot, method)
|
rmeddis@0
|
41
|
rmeddis@0
|
42 dt=method.displaydt;
|
rmeddis@38
|
43 [r cols]=size(toPlot);
|
rmeddis@38
|
44 if cols==1
|
rmeddis@38
|
45 % toPlot should be a wide matrix or a long vector
|
rmeddis@38
|
46 toPlot=toPlot';
|
rmeddis@38
|
47 end
|
rmeddis@38
|
48
|
rmeddis@38
|
49 if ~isfield(method,'numPlots') || isempty(method.numPlots)
|
rmeddis@38
|
50 method.numPlots =1;
|
rmeddis@38
|
51 method.subPlotNo =1;
|
rmeddis@38
|
52 end
|
rmeddis@38
|
53
|
rmeddis@0
|
54 if ~isfield(method,'figureNo') || isempty(method.figureNo)
|
rmeddis@0
|
55 method.figureNo=99;
|
rmeddis@0
|
56 end
|
rmeddis@38
|
57
|
rmeddis@0
|
58 % if ~isfield(method,'zValuesRange') || isempty(method.zValuesRange)
|
rmeddis@0
|
59 % method.zValuesRange=[-inf inf];
|
rmeddis@0
|
60 % end
|
rmeddis@0
|
61
|
rmeddis@0
|
62 % set some defaults
|
rmeddis@0
|
63 if ~isfield( method,'blackOnWhite') || isempty(method.blackOnWhite)
|
rmeddis@38
|
64 method.blackOnWhite=0;
|
rmeddis@0
|
65 end
|
rmeddis@0
|
66 if ~isfield(method,'timeStart')|| isempty(method.timeStart)
|
rmeddis@38
|
67 method.timeStart=dt;
|
rmeddis@0
|
68 end
|
rmeddis@0
|
69 if ~isfield(method,'objectDuration') || isempty(method.objectDuration)
|
rmeddis@0
|
70 [nRows nCols]=size(toPlot); method.objectDuration=dt*nCols;
|
rmeddis@0
|
71 end
|
rmeddis@0
|
72 if ~isfield(method,'defaultFontSize') || isempty(method.defaultFontSize)
|
rmeddis@38
|
73 method.defaultFontSize=12;
|
rmeddis@0
|
74 end
|
rmeddis@0
|
75 if ~isfield(method,'defaultTextColor') || isempty(method.defaultTextColor)
|
rmeddis@0
|
76 method.defaultTextColor='k';
|
rmeddis@0
|
77 defaultTextColor=method.defaultTextColor;
|
rmeddis@0
|
78 else
|
rmeddis@0
|
79 defaultTextColor='k';
|
rmeddis@0
|
80 end
|
rmeddis@0
|
81 if ~isfield( method,'defaultAxesColor') || isempty(method.defaultAxesColor)
|
rmeddis@38
|
82 method.defaultAxesColor=defaultTextColor;
|
rmeddis@0
|
83 end
|
rmeddis@0
|
84 defaultAxesColor=method.defaultAxesColor;
|
rmeddis@0
|
85
|
rmeddis@0
|
86 % arrangement of plots in rows and columns
|
rmeddis@0
|
87 if ~isfield(method,'nCols') || isempty(method.nRows)
|
rmeddis@0
|
88 method.nCols=1;
|
rmeddis@0
|
89 end
|
rmeddis@0
|
90 if ~isfield(method,'nRows') || isempty(method.nRows)
|
rmeddis@0
|
91 method.nRows= method.numPlots;
|
rmeddis@0
|
92 end
|
rmeddis@0
|
93
|
rmeddis@0
|
94 if ~isfield(method,'rasterDotSize') || isempty(method.rasterDotSize)
|
rmeddis@0
|
95 rasterDotSize=1;
|
rmeddis@0
|
96 else
|
rmeddis@0
|
97 rasterDotSize=method.rasterDotSize;
|
rmeddis@0
|
98 end
|
rmeddis@0
|
99
|
rmeddis@0
|
100 % user can specify either an independent axis
|
rmeddis@0
|
101 % or a subplot of the current figure
|
rmeddis@0
|
102 % if both are specified, 'axes' takes priority
|
rmeddis@0
|
103 figure(method.figureNo)
|
rmeddis@0
|
104 if isfield(method,'axes') && ~isempty(method.axes)
|
rmeddis@38
|
105 % user defines where to plot it
|
rmeddis@38
|
106 axes(method.axes);
|
rmeddis@38
|
107 method.numPlots =1;
|
rmeddis@38
|
108 method.subPlotNo =1;
|
rmeddis@38
|
109
|
rmeddis@0
|
110 else
|
rmeddis@0
|
111 % now using a regular figure
|
rmeddis@0
|
112 if method.subPlotNo>method.numPlots;
|
rmeddis@0
|
113 error('UTIL_plotMatrix: not enough subplots allocated in figure 1. Check method.numPlots')
|
rmeddis@0
|
114 end
|
rmeddis@0
|
115 % choose subplot
|
rmeddis@0
|
116 subplot(method.nRows,method.nCols,method.subPlotNo), % cla
|
rmeddis@0
|
117
|
rmeddis@0
|
118 if isfield(method,'segmentNumber') && ~isempty(method.segmentNumber)...
|
rmeddis@0
|
119 && method.segmentNumber>1
|
rmeddis@38
|
120 % in multi-segment mode do not clear the image
|
rmeddis@0
|
121 % from the previous segment
|
rmeddis@0
|
122 hold on
|
rmeddis@0
|
123 else
|
rmeddis@0
|
124 % otherwise a fresh image will be plotted
|
rmeddis@0
|
125 hold off
|
rmeddis@0
|
126 cla
|
rmeddis@0
|
127 end
|
rmeddis@0
|
128 end
|
rmeddis@0
|
129
|
rmeddis@0
|
130 [numYvalues numXvalues]=size(toPlot);
|
rmeddis@0
|
131 xValues=method.timeStart:dt:method.timeStart+dt*(numXvalues-1);
|
rmeddis@0
|
132
|
rmeddis@0
|
133 if isfield(method,'yValues') && ~isempty(method.yValues)
|
rmeddis@0
|
134 % yValues is normally a vector specifying channel BF
|
rmeddis@0
|
135 yValues=method.yValues;
|
rmeddis@0
|
136 else
|
rmeddis@0
|
137 yValues=1:numYvalues;
|
rmeddis@0
|
138 end
|
rmeddis@0
|
139
|
rmeddis@38
|
140 if round(numYvalues/length(yValues))>1
|
rmeddis@38
|
141 % case where the plot matrix is double height (e.g. LSR+HSR)
|
rmeddis@38
|
142 yValues=[yValues yValues];
|
rmeddis@38
|
143 method.plotDivider=1;
|
rmeddis@38
|
144 else
|
rmeddis@38
|
145 method.plotDivider=0;
|
rmeddis@38
|
146 end
|
rmeddis@38
|
147
|
rmeddis@0
|
148 % Now start the plot.
|
rmeddis@0
|
149 % 3D plotting for 4 or more channels
|
rmeddis@0
|
150 % otherwise special cases for fewer channels
|
rmeddis@0
|
151
|
rmeddis@0
|
152 if ~islogical(toPlot)
|
rmeddis@0
|
153 % continuous variables
|
rmeddis@0
|
154 switch numYvalues
|
rmeddis@0
|
155 case 1 % single vector (black)
|
rmeddis@0
|
156 if isfield(method,'bar') && ~isempty(method.bar)
|
rmeddis@0
|
157 % histogram
|
rmeddis@0
|
158 bar(xValues, toPlot,'k')
|
rmeddis@0
|
159 method.bar=[]; % avoid carry over between modules
|
rmeddis@0
|
160 else
|
rmeddis@0
|
161 % waveform
|
rmeddis@0
|
162 plot(xValues, toPlot,'k')
|
rmeddis@0
|
163 end
|
rmeddis@0
|
164 xlim([0 method.objectDuration])
|
rmeddis@0
|
165 if isfield(method,'zValuesRange') ...
|
rmeddis@0
|
166 && ~isempty(method.zValuesRange)
|
rmeddis@0
|
167 ylim(method.zValuesRange)
|
rmeddis@0
|
168 method.zValuesRange=[]; % avoid carry over between modules
|
rmeddis@0
|
169 end
|
rmeddis@0
|
170 if isfield(method,'yLabel') && ~isempty(method.yLabel)
|
rmeddis@0
|
171 ylabel(method.yLabel, 'color', defaultTextColor)
|
rmeddis@0
|
172 method.yLabel=[]; % avoid carry over between modules
|
rmeddis@0
|
173 end
|
rmeddis@0
|
174
|
rmeddis@0
|
175 case 2 % 2 x N vector (black and red)
|
rmeddis@0
|
176 plot(xValues, toPlot(1,:),'k'), % hold on
|
rmeddis@0
|
177 plot(xValues, toPlot(2,:),'r'), % hold off
|
rmeddis@0
|
178 xlim([0 method.objectDuration])
|
rmeddis@0
|
179 if isfield(method,'zValuesRange') ...
|
rmeddis@0
|
180 && ~isempty(method.zValuesRange)
|
rmeddis@0
|
181 ylim(method.zValuesRange)
|
rmeddis@0
|
182 method.zValuesRange=[]; % avoid carry over between modules
|
rmeddis@0
|
183 end
|
rmeddis@0
|
184 if isfield(method,'yLabel')&& ~isempty(method.yLabel)
|
rmeddis@0
|
185 ylabel(method.yLabel, 'color', defaultTextColor)
|
rmeddis@0
|
186 method.yLabel=[]; % avoid carry over between modules
|
rmeddis@0
|
187 end
|
rmeddis@0
|
188
|
rmeddis@0
|
189 case 3 % 3 x N vector (black red and green)
|
rmeddis@0
|
190 % this is used for 1 channel DRNL output
|
rmeddis@0
|
191 plot(xValues, toPlot(1,:),'k'), hold on
|
rmeddis@0
|
192 plot(xValues, toPlot(2,:),'r'), hold on
|
rmeddis@0
|
193 plot(xValues, toPlot(3,:),'g'), hold off
|
rmeddis@0
|
194 xlim([0 method.objectDuration])
|
rmeddis@0
|
195 if isfield(method,'zValuesRange') ...
|
rmeddis@0
|
196 && ~isempty(method.zValuesRange)
|
rmeddis@0
|
197 ylim(method.zValuesRange)
|
rmeddis@0
|
198 end
|
rmeddis@0
|
199 if isfield(method,'yLabel') && ~isempty(method.yLabel)
|
rmeddis@0
|
200 ylabel(method.yLabel, 'color', defaultTextColor)
|
rmeddis@0
|
201 end
|
rmeddis@0
|
202
|
rmeddis@0
|
203 otherwise % >3 channels: surface plot
|
rmeddis@38
|
204 % add line to separate HSR and LSR
|
rmeddis@0
|
205 if method.plotDivider && size(toPlot,1) > 2
|
rmeddis@0
|
206 [r c]=size(toPlot);
|
rmeddis@0
|
207 emptyLine=max(max(toPlot))*ones(2,c);
|
rmeddis@0
|
208 halfway=round(r/2);
|
rmeddis@0
|
209 toPlot=[toPlot(1:halfway,:); emptyLine; toPlot(halfway+1:end,:)];
|
rmeddis@0
|
210 end
|
rmeddis@0
|
211
|
rmeddis@0
|
212 % invert data for black on white matrix plotting
|
rmeddis@0
|
213 if method.blackOnWhite
|
rmeddis@0
|
214 toPlot=-toPlot;
|
rmeddis@0
|
215 end
|
rmeddis@0
|
216
|
rmeddis@0
|
217 % matrix (analogue) plot
|
rmeddis@0
|
218 if isfield(method,'forceLog') && ~isempty(method.forceLog)
|
rmeddis@0
|
219 % positive values are put on log z-scale
|
rmeddis@0
|
220 toPlot=toPlot+min(min(toPlot))+1;
|
rmeddis@0
|
221 toPlot=log(toPlot);
|
rmeddis@0
|
222 if isfield(method,'title')
|
rmeddis@0
|
223 method.title=[method.title ' (log scale)'];
|
rmeddis@0
|
224 else
|
rmeddis@0
|
225 method.title= '(log scale)';
|
rmeddis@0
|
226 end
|
rmeddis@0
|
227 end
|
rmeddis@0
|
228
|
rmeddis@0
|
229 % zValuesRange
|
rmeddis@0
|
230 if isfield(method,'zValuesRange') ...
|
rmeddis@0
|
231 && ~isempty(method.zValuesRange)
|
rmeddis@0
|
232 clims=(method.zValuesRange);
|
rmeddis@0
|
233 imagesc(xValues, yValues, toPlot, clims), axis xy; %NB assumes equally spaced y-values
|
rmeddis@0
|
234 else
|
rmeddis@0
|
235 % automatically scaled
|
rmeddis@0
|
236 imagesc(xValues, yValues, toPlot), axis xy; %NB assumes equally spaced y-values
|
rmeddis@0
|
237
|
rmeddis@0
|
238 if ~isfield(method,'zValuesRange')...
|
rmeddis@0
|
239 || isempty(method.zValuesRange)
|
rmeddis@0
|
240 method.zValuesRange=[-inf inf];
|
rmeddis@0
|
241 end
|
rmeddis@0
|
242
|
rmeddis@0
|
243 if method.blackOnWhite
|
rmeddis@0
|
244 % NB plotted values have negative sign for black on white
|
rmeddis@0
|
245 caxis([-method.zValuesRange(2) -method.zValuesRange(1)])
|
rmeddis@0
|
246 else
|
rmeddis@0
|
247 caxis(method.zValuesRange)
|
rmeddis@0
|
248 end
|
rmeddis@0
|
249 end
|
rmeddis@0
|
250
|
rmeddis@0
|
251 % xaxis
|
rmeddis@0
|
252 % NB segmentation may shorten signal duration
|
rmeddis@0
|
253 [r c]=size(toPlot);
|
rmeddis@0
|
254 imageDuration=c*method.displaydt;
|
rmeddis@38
|
255 xlim([0 imageDuration])
|
rmeddis@38
|
256
|
rmeddis@0
|
257 % yaxis
|
rmeddis@0
|
258 if isfield(method,'minyMaxy') && ~isempty(method.minyMaxy)
|
rmeddis@0
|
259 ylim(method.minyMaxy)
|
rmeddis@0
|
260 else
|
rmeddis@0
|
261 if max(yValues)>min(yValues)
|
rmeddis@0
|
262 ylim([min(yValues) max(yValues)])
|
rmeddis@0
|
263 end
|
rmeddis@0
|
264 end
|
rmeddis@38
|
265
|
rmeddis@38
|
266 % y-axis design yTickLabels
|
rmeddis@38
|
267 if min(yValues)>1
|
rmeddis@0
|
268 tickValues=[min(yValues) max(yValues)];
|
rmeddis@38
|
269 tickLabels=num2str(tickValues');
|
rmeddis@38
|
270 if method.plotDivider && size(toPlot,1) > 2
|
rmeddis@38
|
271 % show min/max yvalues with slight shift
|
rmeddis@38
|
272 yList=yValues;
|
rmeddis@38
|
273 yValues=1:length(yValues);
|
rmeddis@38
|
274 tickValues=[1 halfway-1 halfway+2 length(yValues)];
|
rmeddis@38
|
275 idx=[1 halfway halfway+1 length(yValues)];
|
rmeddis@38
|
276 tickLabels=num2str(yList(idx)');
|
rmeddis@38
|
277 imagesc(xValues, yValues, toPlot), axis xy;
|
rmeddis@38
|
278 end
|
rmeddis@38
|
279
|
rmeddis@0
|
280 set(gca,'ytick',tickValues)
|
rmeddis@38
|
281 set(gca,'ytickLabel', strvcat(tickLabels))
|
rmeddis@0
|
282 set(gca,'FontSize', method.defaultFontSize)
|
rmeddis@0
|
283 end
|
rmeddis@0
|
284
|
rmeddis@0
|
285 end
|
rmeddis@0
|
286
|
rmeddis@38
|
287 else % is logical
|
rmeddis@0
|
288 % logical implies spike array. Use raster plot
|
rmeddis@0
|
289 [y,x]=find(toPlot); %locate all spikes: y is fiber number ie row
|
rmeddis@0
|
290 x=x*dt+method.timeStart; % x is time
|
rmeddis@0
|
291 plot(x,y, 'o', 'MarkerSize', rasterDotSize, 'color', 'k')
|
rmeddis@0
|
292 if numYvalues>1
|
rmeddis@0
|
293 set(gca,'yScale','linear')
|
rmeddis@0
|
294 set(gca,'ytick', [1 numYvalues],'FontSize', method.defaultFontSize)
|
rmeddis@0
|
295 % show lowest and highest BF value only
|
rmeddis@0
|
296 set(gca,'ytickLabel', [min(yValues) max(yValues) ],'FontSize', method.defaultFontSize)
|
rmeddis@0
|
297 if method.plotDivider
|
rmeddis@0
|
298 % or use labels to identify fiber type
|
rmeddis@0
|
299 set(gca,'ytickLabel', {'LSR', 'HSR'},'FontSize', method.defaultFontSize)
|
rmeddis@0
|
300 end
|
rmeddis@0
|
301 ylim([0 numYvalues+1])
|
rmeddis@0
|
302 end
|
rmeddis@0
|
303 xlim([0 method.objectDuration])
|
rmeddis@0
|
304 if isfield(method,'yLabel') && ~isempty(method.yLabel)
|
rmeddis@0
|
305 ylabel(method.yLabel,'FontSize', method.defaultFontSize, 'color', defaultTextColor)
|
rmeddis@0
|
306 end
|
rmeddis@0
|
307
|
rmeddis@0
|
308 % add line to separate HSR and LSR
|
rmeddis@0
|
309 if method.plotDivider
|
rmeddis@0
|
310 [r c]=size(toPlot);
|
rmeddis@0
|
311 halfWayUp=round(r/2);
|
rmeddis@0
|
312 hold on
|
rmeddis@0
|
313 plot([0 c*method.displaydt],[halfWayUp halfWayUp], 'b')
|
rmeddis@0
|
314 hold off
|
rmeddis@0
|
315 end
|
rmeddis@38
|
316
|
rmeddis@0
|
317 end
|
rmeddis@0
|
318
|
rmeddis@0
|
319 set(gca, 'xcolor', defaultAxesColor)
|
rmeddis@0
|
320 set(gca, 'ycolor', defaultAxesColor)
|
rmeddis@0
|
321
|
rmeddis@0
|
322 % add title
|
rmeddis@0
|
323 if isfield(method,'title') && ~isempty(method.title)
|
rmeddis@0
|
324 title(method.title, 'FontSize', method.defaultFontSize, 'color', defaultTextColor)
|
rmeddis@0
|
325 end
|
rmeddis@0
|
326
|
rmeddis@0
|
327 % label axes
|
rmeddis@0
|
328 if ~isfield(method,'axes') || isempty(method.axes)
|
rmeddis@0
|
329 % annotate the x-axis only if it is the last plot on a figure created by this utility
|
rmeddis@0
|
330 set(gca,'xtick',[],'FontSize', method.defaultFontSize)
|
rmeddis@0
|
331 if method.subPlotNo==method.numPlots
|
rmeddis@0
|
332 if isfield(method,'xLabel') && ~isempty(method.xLabel)
|
rmeddis@38
|
333 % set(gca,'ActivePositionProperty','outerposition')
|
rmeddis@0
|
334 % xlabel(method.xLabel)
|
rmeddis@0
|
335 xlabel(method.xLabel, 'FontSize', method.defaultFontSize, 'color', defaultTextColor)
|
rmeddis@0
|
336 end
|
rmeddis@0
|
337 set(gca,'xtickmode','auto') % add timescale to the lowest graph
|
rmeddis@0
|
338 end
|
rmeddis@0
|
339 end
|
rmeddis@0
|
340
|
rmeddis@0
|
341 % add user labels to the y-axis if requested
|
rmeddis@0
|
342 if isfield(method,'yLabel') && ~isempty(method.yLabel)
|
rmeddis@0
|
343 ylabel(method.yLabel, 'color', defaultTextColor)
|
rmeddis@0
|
344 end
|
rmeddis@0
|
345
|
rmeddis@0
|
346 % define color
|
rmeddis@0
|
347 if method.blackOnWhite, colormap bone, else colormap jet
|
rmeddis@0
|
348 end
|
rmeddis@0
|
349
|
rmeddis@0
|
350 % drawnow
|