rmeddis@0: function UTIL_plotMatrix(toPlot, method) rmeddis@0: % UTIL_plotMatrix general purpose plotting utility for plotting the results rmeddis@0: % of the MAP auditory model. rmeddis@0: % All plots are placed in subplots of a figure (default figure 1). rmeddis@38: % rmeddis@0: % Input arguments: rmeddis@0: % 'toPlot' is matrix (either numeric or logical) rmeddis@0: % 'method' is a structure containing plot instructions rmeddis@0: % rmeddis@0: % mandatory parameters: rmeddis@38: % method.displaydt xValues spacing between data points rmeddis@38: % method.yValues yaxis labels mandatory only for 3D plots rmeddis@0: % rmeddis@0: % optional rmeddis@38: % method.figureNo default figure(1) rmeddis@38: % method.numPlots number of subPlots in the figure (default=1) rmeddis@38: % method.subPlotNo number of this plot (default=1) rmeddis@38: % method.zValuesRange [min max] value pair to define yaxis limits rmeddis@38: % method.zValuesRange [min max] CLIMS for 3-D plot rmeddis@38: % method.yLabel (string) y-axis label rmeddis@38: % method.minyMaxy y-axis limits rmeddis@38: % method.xLabel (string) x-axis label rmeddis@38: % method.title (string) subplot title rmeddis@0: % method.bar =1, to force bar histogram (single channel only) rmeddis@38: % method.view 3D plot 'view' settings e.g. [-6 40] rmeddis@38: % method.axes (handle) where to plot (overules all others) rmeddis@38: % method.maxPixels maximum number of pixels (used to speed plotting) rmeddis@38: % method.blackOnWhite =1; inverts display for 2D plots rmeddis@38: % method.forceLog positive values are put on log z-scale rmeddis@38: % method.rasterDotSize min value is 1 rmeddis@38: % method.defaultFontSize deafult= 12 rmeddis@38: % method.timeStart default= dt rmeddis@38: % method.defaultTextColor default ='k' rmeddis@38: % method.defaultAxesColor default ='k' rmeddis@38: % method.nCols default = 1 (layout for subplots) rmeddis@38: % method.nRows default=method.numPlots (layout for subplots rmeddis@38: % method.segmentNumber plot only this segment while 'hold on' rmeddis@0: % rmeddis@38: % e.g. rmeddis@0: % UTIL_plotMatrix(toPlot, method) rmeddis@0: rmeddis@0: dt=method.displaydt; rmeddis@38: [r cols]=size(toPlot); rmeddis@38: if cols==1 rmeddis@38: % toPlot should be a wide matrix or a long vector rmeddis@38: toPlot=toPlot'; rmeddis@38: end rmeddis@38: rmeddis@38: if ~isfield(method,'numPlots') || isempty(method.numPlots) rmeddis@38: method.numPlots =1; rmeddis@38: method.subPlotNo =1; rmeddis@38: end rmeddis@38: rmeddis@0: if ~isfield(method,'figureNo') || isempty(method.figureNo) rmeddis@0: method.figureNo=99; rmeddis@0: end rmeddis@38: rmeddis@0: % if ~isfield(method,'zValuesRange') || isempty(method.zValuesRange) rmeddis@0: % method.zValuesRange=[-inf inf]; rmeddis@0: % end rmeddis@0: rmeddis@0: % set some defaults rmeddis@0: if ~isfield( method,'blackOnWhite') || isempty(method.blackOnWhite) rmeddis@38: method.blackOnWhite=0; rmeddis@0: end rmeddis@0: if ~isfield(method,'timeStart')|| isempty(method.timeStart) rmeddis@38: method.timeStart=dt; rmeddis@0: end rmeddis@0: if ~isfield(method,'objectDuration') || isempty(method.objectDuration) rmeddis@0: [nRows nCols]=size(toPlot); method.objectDuration=dt*nCols; rmeddis@0: end rmeddis@0: if ~isfield(method,'defaultFontSize') || isempty(method.defaultFontSize) rmeddis@38: method.defaultFontSize=12; rmeddis@0: end rmeddis@0: if ~isfield(method,'defaultTextColor') || isempty(method.defaultTextColor) rmeddis@0: method.defaultTextColor='k'; rmeddis@0: defaultTextColor=method.defaultTextColor; rmeddis@0: else rmeddis@0: defaultTextColor='k'; rmeddis@0: end rmeddis@0: if ~isfield( method,'defaultAxesColor') || isempty(method.defaultAxesColor) rmeddis@38: method.defaultAxesColor=defaultTextColor; rmeddis@0: end rmeddis@0: defaultAxesColor=method.defaultAxesColor; rmeddis@0: rmeddis@0: % arrangement of plots in rows and columns rmeddis@0: if ~isfield(method,'nCols') || isempty(method.nRows) rmeddis@0: method.nCols=1; rmeddis@0: end rmeddis@0: if ~isfield(method,'nRows') || isempty(method.nRows) rmeddis@0: method.nRows= method.numPlots; rmeddis@0: end rmeddis@0: rmeddis@0: if ~isfield(method,'rasterDotSize') || isempty(method.rasterDotSize) rmeddis@0: rasterDotSize=1; rmeddis@0: else rmeddis@0: rasterDotSize=method.rasterDotSize; rmeddis@0: end rmeddis@0: rmeddis@0: % user can specify either an independent axis rmeddis@0: % or a subplot of the current figure rmeddis@0: % if both are specified, 'axes' takes priority rmeddis@0: figure(method.figureNo) rmeddis@0: if isfield(method,'axes') && ~isempty(method.axes) rmeddis@38: % user defines where to plot it rmeddis@38: axes(method.axes); rmeddis@38: method.numPlots =1; rmeddis@38: method.subPlotNo =1; rmeddis@38: rmeddis@0: else rmeddis@0: % now using a regular figure rmeddis@0: if method.subPlotNo>method.numPlots; rmeddis@0: error('UTIL_plotMatrix: not enough subplots allocated in figure 1. Check method.numPlots') rmeddis@0: end rmeddis@0: % choose subplot rmeddis@0: subplot(method.nRows,method.nCols,method.subPlotNo), % cla rmeddis@0: rmeddis@0: if isfield(method,'segmentNumber') && ~isempty(method.segmentNumber)... rmeddis@0: && method.segmentNumber>1 rmeddis@38: % in multi-segment mode do not clear the image rmeddis@0: % from the previous segment rmeddis@0: hold on rmeddis@0: else rmeddis@0: % otherwise a fresh image will be plotted rmeddis@0: hold off rmeddis@0: cla rmeddis@0: end rmeddis@0: end rmeddis@0: rmeddis@0: [numYvalues numXvalues]=size(toPlot); rmeddis@0: xValues=method.timeStart:dt:method.timeStart+dt*(numXvalues-1); rmeddis@0: rmeddis@0: if isfield(method,'yValues') && ~isempty(method.yValues) rmeddis@0: % yValues is normally a vector specifying channel BF rmeddis@0: yValues=method.yValues; rmeddis@0: else rmeddis@0: yValues=1:numYvalues; rmeddis@0: end rmeddis@0: rmeddis@38: if round(numYvalues/length(yValues))>1 rmeddis@38: % case where the plot matrix is double height (e.g. LSR+HSR) rmeddis@38: yValues=[yValues yValues]; rmeddis@38: method.plotDivider=1; rmeddis@38: else rmeddis@38: method.plotDivider=0; rmeddis@38: end rmeddis@38: rmeddis@0: % Now start the plot. rmeddis@0: % 3D plotting for 4 or more channels rmeddis@0: % otherwise special cases for fewer channels rmeddis@0: rmeddis@0: if ~islogical(toPlot) rmeddis@0: % continuous variables rmeddis@0: switch numYvalues rmeddis@0: case 1 % single vector (black) rmeddis@0: if isfield(method,'bar') && ~isempty(method.bar) rmeddis@0: % histogram rmeddis@0: bar(xValues, toPlot,'k') rmeddis@0: method.bar=[]; % avoid carry over between modules rmeddis@0: else rmeddis@0: % waveform rmeddis@0: plot(xValues, toPlot,'k') rmeddis@0: end rmeddis@0: xlim([0 method.objectDuration]) rmeddis@0: if isfield(method,'zValuesRange') ... rmeddis@0: && ~isempty(method.zValuesRange) rmeddis@0: ylim(method.zValuesRange) rmeddis@0: method.zValuesRange=[]; % avoid carry over between modules rmeddis@0: end rmeddis@0: if isfield(method,'yLabel') && ~isempty(method.yLabel) rmeddis@0: ylabel(method.yLabel, 'color', defaultTextColor) rmeddis@0: method.yLabel=[]; % avoid carry over between modules rmeddis@0: end rmeddis@0: rmeddis@0: case 2 % 2 x N vector (black and red) rmeddis@0: plot(xValues, toPlot(1,:),'k'), % hold on rmeddis@0: plot(xValues, toPlot(2,:),'r'), % hold off rmeddis@0: xlim([0 method.objectDuration]) rmeddis@0: if isfield(method,'zValuesRange') ... rmeddis@0: && ~isempty(method.zValuesRange) rmeddis@0: ylim(method.zValuesRange) rmeddis@0: method.zValuesRange=[]; % avoid carry over between modules rmeddis@0: end rmeddis@0: if isfield(method,'yLabel')&& ~isempty(method.yLabel) rmeddis@0: ylabel(method.yLabel, 'color', defaultTextColor) rmeddis@0: method.yLabel=[]; % avoid carry over between modules rmeddis@0: end rmeddis@0: rmeddis@0: case 3 % 3 x N vector (black red and green) rmeddis@0: % this is used for 1 channel DRNL output rmeddis@0: plot(xValues, toPlot(1,:),'k'), hold on rmeddis@0: plot(xValues, toPlot(2,:),'r'), hold on rmeddis@0: plot(xValues, toPlot(3,:),'g'), hold off rmeddis@0: xlim([0 method.objectDuration]) rmeddis@0: if isfield(method,'zValuesRange') ... rmeddis@0: && ~isempty(method.zValuesRange) rmeddis@0: ylim(method.zValuesRange) rmeddis@0: end rmeddis@0: if isfield(method,'yLabel') && ~isempty(method.yLabel) rmeddis@0: ylabel(method.yLabel, 'color', defaultTextColor) rmeddis@0: end rmeddis@0: rmeddis@0: otherwise % >3 channels: surface plot rmeddis@38: % add line to separate HSR and LSR rmeddis@0: if method.plotDivider && size(toPlot,1) > 2 rmeddis@0: [r c]=size(toPlot); rmeddis@0: emptyLine=max(max(toPlot))*ones(2,c); rmeddis@0: halfway=round(r/2); rmeddis@0: toPlot=[toPlot(1:halfway,:); emptyLine; toPlot(halfway+1:end,:)]; rmeddis@0: end rmeddis@0: rmeddis@0: % invert data for black on white matrix plotting rmeddis@0: if method.blackOnWhite rmeddis@0: toPlot=-toPlot; rmeddis@0: end rmeddis@0: rmeddis@0: % matrix (analogue) plot rmeddis@0: if isfield(method,'forceLog') && ~isempty(method.forceLog) rmeddis@0: % positive values are put on log z-scale rmeddis@0: toPlot=toPlot+min(min(toPlot))+1; rmeddis@0: toPlot=log(toPlot); rmeddis@0: if isfield(method,'title') rmeddis@0: method.title=[method.title ' (log scale)']; rmeddis@0: else rmeddis@0: method.title= '(log scale)'; rmeddis@0: end rmeddis@0: end rmeddis@0: rmeddis@0: % zValuesRange rmeddis@0: if isfield(method,'zValuesRange') ... rmeddis@0: && ~isempty(method.zValuesRange) rmeddis@0: clims=(method.zValuesRange); rmeddis@0: imagesc(xValues, yValues, toPlot, clims), axis xy; %NB assumes equally spaced y-values rmeddis@0: else rmeddis@0: % automatically scaled rmeddis@0: imagesc(xValues, yValues, toPlot), axis xy; %NB assumes equally spaced y-values rmeddis@0: rmeddis@0: if ~isfield(method,'zValuesRange')... rmeddis@0: || isempty(method.zValuesRange) rmeddis@0: method.zValuesRange=[-inf inf]; rmeddis@0: end rmeddis@0: rmeddis@0: if method.blackOnWhite rmeddis@0: % NB plotted values have negative sign for black on white rmeddis@0: caxis([-method.zValuesRange(2) -method.zValuesRange(1)]) rmeddis@0: else rmeddis@0: caxis(method.zValuesRange) rmeddis@0: end rmeddis@0: end rmeddis@0: rmeddis@0: % xaxis rmeddis@0: % NB segmentation may shorten signal duration rmeddis@0: [r c]=size(toPlot); rmeddis@0: imageDuration=c*method.displaydt; rmeddis@38: xlim([0 imageDuration]) rmeddis@38: rmeddis@0: % yaxis rmeddis@0: if isfield(method,'minyMaxy') && ~isempty(method.minyMaxy) rmeddis@0: ylim(method.minyMaxy) rmeddis@0: else rmeddis@0: if max(yValues)>min(yValues) rmeddis@0: ylim([min(yValues) max(yValues)]) rmeddis@0: end rmeddis@0: end rmeddis@38: rmeddis@38: % y-axis design yTickLabels rmeddis@38: if min(yValues)>1 rmeddis@0: tickValues=[min(yValues) max(yValues)]; rmeddis@38: tickLabels=num2str(tickValues'); rmeddis@38: if method.plotDivider && size(toPlot,1) > 2 rmeddis@38: % show min/max yvalues with slight shift rmeddis@38: yList=yValues; rmeddis@38: yValues=1:length(yValues); rmeddis@38: tickValues=[1 halfway-1 halfway+2 length(yValues)]; rmeddis@38: idx=[1 halfway halfway+1 length(yValues)]; rmeddis@38: tickLabels=num2str(yList(idx)'); rmeddis@38: imagesc(xValues, yValues, toPlot), axis xy; rmeddis@38: end rmeddis@38: rmeddis@0: set(gca,'ytick',tickValues) rmeddis@38: set(gca,'ytickLabel', strvcat(tickLabels)) rmeddis@0: set(gca,'FontSize', method.defaultFontSize) rmeddis@0: end rmeddis@0: rmeddis@0: end rmeddis@0: rmeddis@38: else % is logical rmeddis@0: % logical implies spike array. Use raster plot rmeddis@0: [y,x]=find(toPlot); %locate all spikes: y is fiber number ie row rmeddis@0: x=x*dt+method.timeStart; % x is time rmeddis@0: plot(x,y, 'o', 'MarkerSize', rasterDotSize, 'color', 'k') rmeddis@0: if numYvalues>1 rmeddis@0: set(gca,'yScale','linear') rmeddis@0: set(gca,'ytick', [1 numYvalues],'FontSize', method.defaultFontSize) rmeddis@0: % show lowest and highest BF value only rmeddis@0: set(gca,'ytickLabel', [min(yValues) max(yValues) ],'FontSize', method.defaultFontSize) rmeddis@0: if method.plotDivider rmeddis@0: % or use labels to identify fiber type rmeddis@0: set(gca,'ytickLabel', {'LSR', 'HSR'},'FontSize', method.defaultFontSize) rmeddis@0: end rmeddis@0: ylim([0 numYvalues+1]) rmeddis@0: end rmeddis@0: xlim([0 method.objectDuration]) rmeddis@0: if isfield(method,'yLabel') && ~isempty(method.yLabel) rmeddis@0: ylabel(method.yLabel,'FontSize', method.defaultFontSize, 'color', defaultTextColor) rmeddis@0: end rmeddis@0: rmeddis@0: % add line to separate HSR and LSR rmeddis@0: if method.plotDivider rmeddis@0: [r c]=size(toPlot); rmeddis@0: halfWayUp=round(r/2); rmeddis@0: hold on rmeddis@0: plot([0 c*method.displaydt],[halfWayUp halfWayUp], 'b') rmeddis@0: hold off rmeddis@0: end rmeddis@38: rmeddis@0: end rmeddis@0: rmeddis@0: set(gca, 'xcolor', defaultAxesColor) rmeddis@0: set(gca, 'ycolor', defaultAxesColor) rmeddis@0: rmeddis@0: % add title rmeddis@0: if isfield(method,'title') && ~isempty(method.title) rmeddis@0: title(method.title, 'FontSize', method.defaultFontSize, 'color', defaultTextColor) rmeddis@0: end rmeddis@0: rmeddis@0: % label axes rmeddis@0: if ~isfield(method,'axes') || isempty(method.axes) rmeddis@0: % annotate the x-axis only if it is the last plot on a figure created by this utility rmeddis@0: set(gca,'xtick',[],'FontSize', method.defaultFontSize) rmeddis@0: if method.subPlotNo==method.numPlots rmeddis@0: if isfield(method,'xLabel') && ~isempty(method.xLabel) rmeddis@38: % set(gca,'ActivePositionProperty','outerposition') rmeddis@0: % xlabel(method.xLabel) rmeddis@0: xlabel(method.xLabel, 'FontSize', method.defaultFontSize, 'color', defaultTextColor) rmeddis@0: end rmeddis@0: set(gca,'xtickmode','auto') % add timescale to the lowest graph rmeddis@0: end rmeddis@0: end rmeddis@0: rmeddis@0: % add user labels to the y-axis if requested rmeddis@0: if isfield(method,'yLabel') && ~isempty(method.yLabel) rmeddis@0: ylabel(method.yLabel, 'color', defaultTextColor) rmeddis@0: end rmeddis@0: rmeddis@0: % define color rmeddis@0: if method.blackOnWhite, colormap bone, else colormap jet rmeddis@0: end rmeddis@0: rmeddis@0: % drawnow