This documentation page applies to an outdated major AMT version. We show it for archival purposes only.
Click here for the documentation menu and here to download the latest AMT (1.6.0).
function varargout = data_baumgartner2017looming( varargin )
%data_baumgartner2017looming - Results from Baumgartner et al. (2017)
%
% Usage: data = data_baumgartner2017looming(dataFlag,measure)
% data = data_baumgartner2017looming(fig)
%
% DATA_BAUMGARTNER2017LOOMING provides individually measured HRTFs and
% experimental results from Baumgartner et al. (2017). Use the fig
% flag to obtain data shown in figures from Baumgartner et al. (2017).
%
% The dataFlag flag may be used to choose between HRTFs and various
% experimental results:
%
% 'hrtf' HRTFs used in all experiments.
% 'pretest' Behavioral results of pre-test.
% 'exp1' Behavioral or ERP results of Exp. I. Default.
% 'exp2' Behavioral results of Exp. II.
%
% The measure flag may be one of:
%
% 'judgment' Judgment of relative distance change (motion direction).
% Default.
% 'rt' Response time.
% 'erp' ERP magnitude measures.
%
% The fig flag may be one of:
%
% 'fig1b' Effect of spectral contrast manipulation according to
% factor C on magnitude responses of listener-specific
% stimuli of Exp. I (B, Top) as well as their frequency-specific
% and overall loudness changes relative to C = 1. Shaded
% areas denote ??1 standard error of the mean (SEM; N = 15).
% Note that changes in overall loudness oppose the intended
% effect of contrast switch.
% 'fig2' Behavioral responses were more consistent for sounds
% perceived as approaching compared to sounds perceived as
% receding if instantaneous spectral changes were presented
% in continuous stimuli. Mean behavioral responses in the
% 3?AFC motion discrimination task of Exp. I (fist figure; N = 15)
% and the 2?AFC motion discrimination task of Exp. II
% (second figure; N = 13). Results of Exp. II are separated
% between trials presenting instantaneous but continuous
% (Left; as in Exp. I) and discontinuous (Right) spectral
% contrast switches. Decreasing spectral contrast switches
% (orange lines) were predominantly perceived as approaching
% (orange triangles), increasing spectral contrast switches
% (green lines) as receding (green triangles), and constant
% spectral contrasts (no lines) as static (gray squares).
% Statistical analyses focused on these predominant response
% associations. Values reflect mean ??1 SEM.
% 'fig3a' Extracted N1 and P2 amplitudes evoked by stimulus onset.
% Error bars reflect SEM.
% 'fig3b' Extracted N1 and P2 amplitudes evoked by stimulus switch.
% Error bars reflect SEM.
% 'fig3c' Significant cluster in time and space that is distinctive
% between decreasing and increasing spectral contrasts. (no
% plotting)
%
% Additional flags may be:
%
% 'plot' Plot results as published.
% 'noplot' No plots. Default.
% 'stat' Analyze and display inferential statistics.
% 'nostat' No statistics. Default.
% 'onset' To use onset ERPs.
% 'switch' To use switch-ERPs. Default.
%
% Output parameters:
% data : structure that contains either HRTFs (id, and Obj) or
% experimental results including raw and averaged data
% (rawData,data, opional meta information).
% Statisitcs (stat) and figure handles (fig) are
% provided if requested.
%
% Requirements:
% -------------
%
% 1) SOFA API v0.4.3 or higher from http://sourceforge.net/projects/sofacoustics for Matlab (in e.g. thirdparty/SOFA)
%
% 2) Data in hrtf/baumgartner2017looming and auxdata/baumgartner2017looming (downloaded on the fly)
%
% 3) Statistics Toolbox for Matlab (for some fig)
%
% Examples:
% ---------
%
% To display results of Fig.1B :
%
% data_baumgartner2017looming('fig1b','plot');
%
% To display results of Fig.2 :
%
% data_baumgartner2017looming('fig2','plot');
%
% To display results of Fig.3A :
%
% data_baumgartner2017looming('fig3a','plot');
%
% To display results of Fig.3B :
%
% data_baumgartner2017looming('fig3b','plot');
%
% References:
% R. Baumgartner, D. K. Reed, B. Tóth, V. Best, P. Majdak, H. S. Colburn,
% and B. Shinn-Cunningham. Asymmetries in behavioral and neural responses
% to spectral cues demonstrate the generality of auditory looming bias.
% Proceedings of the National Academy of Sciences, 2017. [1]arXiv |
% [2]http ]
%
% References
%
% 1. http://arxiv.org/abs/http://www.pnas.org/content/early/2017/08/16/1703247114.full.pdf
% 2. http://www.pnas.org/content/early/2017/08/16/1703247114.abstract
%
%
% Url: http://amtoolbox.sourceforge.net/amt-0.10.0/doc/data/data_baumgartner2017looming.php
% Copyright (C) 2009-2020 Piotr Majdak and the AMT team.
% This file is part of Auditory Modeling Toolbox (AMT) version 0.10.0
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program. If not, see <http://www.gnu.org/licenses/>.
% AUTHOR: Robert Baumgartner, Acoustics Research Institute, Vienna, Austria
% definput.import={'amt_cache'};
definput.flags.expirement = {'exp1','exp2','pretest','hrtf'};
definput.flags.measure = {'judgment','rt','erp'};
definput.flags.erp = {'switch','onset'};
definput.flags.plot = {'noplot','plot'};
definput.flags.stat = {'nostat','stat'};
definput.flags.fig = {'nofig','fig1b','fig2','fig3a','fig3b','fig3c'};
[flags]=ltfatarghelper({},definput,lower(varargin));
if flags.do_nofig
%% HRTFs
if flags.do_hrtf
id = amt_load('baumgartner2017looming','subjects.mat');
out = struct('id',{},'Obj',{});
for ii = 1:length(id.subjects)
out(ii).id = id.subjects{ii};
out(ii).Obj = SOFAload(fullfile(SOFAdbPath,'baumgartner2017looming',...
[id.subjects{ii},'_eq.sofa']));
end
varargout{1} = out;
return
end
%% Behavioral Results
if flags.do_judgment || flags.do_rt
raw=amt_load('baumgartner2017looming',[flags.expirement,'.mat']);
Nsubj = length(raw.data);
ISI = unique(raw.data(1).ISI);
nISI = length(ISI);
ISIlbl = {'continuous','discont.'};
RTprctile = 25;
conditions = {[0,1];[0,0.5];[0.5,1];[1,0];[0.5,0];[1,0.5];[0,0];[0.5,0.5];[1,1]};
condLabelPlot = { '0\leftrightarrow1';'0\leftrightarrow.5';'.5\leftrightarrow1';...
'C_1=C_2'};
response = {'receding','approaching','constant'};
%% Evaluate Data
pResp = nan(Nsubj,length(conditions),length(response),nISI);
RTall = pResp;
for ss = 1:Nsubj
E = raw.data(ss).judgment;
C12 = raw.data(ss).C12;
sISI = raw.data(ss).ISI;
RT = raw.data(ss).RT;
for iISI = 1:nISI
for cc = 1:length(conditions)
idc = C12(:,1) == conditions{cc}(1) & C12(:,2) == conditions{cc}(2) & sISI(:) == ISI(iISI);
N = sum(idc);
Irecede = E(idc) > 0;
pResp(ss,cc,1,iISI) = sum(Irecede) / N;
RTall(ss,cc,1,iISI) = percentile(RT(Irecede),RTprctile);
Iappr = E(idc) < 0;
pResp(ss,cc,2,iISI) = sum(Iappr) / N;
RTall(ss,cc,2,iISI) = percentile(RT(Iappr),RTprctile);
Iconst = E(idc) == 0;
pResp(ss,cc,3,iISI) = sum(Iconst) / N;
RTall(ss,cc,3,iISI) = percentile(RT(Iconst),RTprctile);
end
end
end
if flags.do_judgment
meas = 100*pResp; % responses in percent
YLabel = 'Response (%)';
if flags.do_exp2
YLim = [43,105];
else
YLim = [-5,105];
end
elseif flags.do_rt
meas = 1e3*RTall; % response times in ms
YLabel = 'Response time (ms)';
YLim = 1e3*[0.451,1.149];
end
% outlier removal
rawData = struct2cell(raw.data);
ID = rawData(1,:);
if flags.do_exp2
pc = reshape(cat(2,pResp(:,1:3,1,:),pResp(:,4:6,2,:)),[Nsubj,6,nISI]); % percent correct
bias = squeeze(mean(pc(:,4:6,:) - pc(:,1:3,:),2));
[~,outlier] = max(bias(:,2)); % 1 listener showed a markedly larger looming bias for discontinuous stimuli compared with continuous stimuli (data provided in Outlier Evaluation for Experiment II and Fig. S3)
amt_disp(['Subject ' raw.data(outlier).ID ' identified as outlier and removed from further analyses.'])
iNew = (1:Nsubj)~=outlier;
ID = ID(iNew);
meas = meas(iNew,:,:,:);
Nsubj = Nsubj-1;
end
% Average constant conditions
meas = cat(2,meas(:,1:6,:,:),nan_mean(meas(:,7:9,:,:),2));
conditions = [conditions(1:6);'constant'];
% Standard errors of the means
sem = nan_std(meas)/sqrt(Nsubj);
% Output
out.data = meas;
out.rawData = raw.data;
out.meta.dim = 'subject_C_response_ISI';
out.meta.subject = ID;
out.meta.C = conditions;
out.meta.response = response;
out.meta.ISI = ISI;
if flags.do_stat && ~verLessThan('matlab','8.2')
% ANOVA
pc = reshape(cat(2,meas(:,1:3,1,:),meas(:,4:6,2,:)),Nsubj,[]); % percent correct
out.pcorrect.data = pc;
DV = array2table(pc);
contrast = strrep(condLabelPlot(1:3),'\leftrightarrow','-');
contrast = repmat(contrast,[2*nISI,1]);
out.pcorrect.contrast = contrast;
direction = cell(6,1);
direction(1:3) = {'receding'};
direction(4:6) = {'approaching'};
direction = repmat(direction,[nISI,1]);
out.pcorrect.direction = direction;
idISI = ceil((1:6*nISI)/6);
ISInom = nominal(ISI(idISI))';
IVs = table(contrast,direction,ISInom);
rm = fitrm(DV,['pc1-pc',num2str(length(contrast)),' ~ 1'],'WithinDesign',IVs);
if length(ISI) == 1
[ranovaResult,~,C,~] = ranova(rm,'WithinModel','direction*contrast');
else
[ranovaResult,~,C,~] = ranova(rm,'WithinModel','direction*contrast*ISInom');
end
ranovaResult.Properties.RowNames = strrep(ranovaResult.Properties.RowNames,'(Intercept):','');
% Sphericity corrections
spherCorr = epsilon(rm,C);
% Add corrected DFs to ranova table
idrep = round(0.5:0.5:length(spherCorr.GreenhouseGeisser)); % repeat iteratively
ranovaResult.DFGG = ranovaResult.DF .* ...
reshape(spherCorr.GreenhouseGeisser(idrep),size(ranovaResult.DF));
% Add effect sizes to ranova table
SSeffect = ranovaResult.SumSq(1:2:end);
SSerror = ranovaResult.SumSq(2:2:end);
eta_pSq = nan(2*length(SSerror),1);
eta_pSq(1:2:end) = SSeffect./(SSeffect+SSerror); % effect size per (eta_partial)^2
ranovaResult.eta_pSq = eta_pSq;
amt_disp(ranovaResult(:,[4,6,9,10]))
mc = multcompare(rm,'contrast');
amt_disp(mc)
out.stat = ranovaResult;
end
%% Plot
if flags.do_plot
out.fig = figure;
x = [1:3,1:3,4];
XTick = [x(1:3),x(end)];
if flags.do_exp2
x = x(1:6);
XTick = x(1:3);
response = response(1:2);
end
XLim = [XTick(1)-.6,XTick(end)+.6];
dx2 = .05*[-1,0,1]; % between responses
symb = '^vs';
lineStyle = {':';'-';'-.'}; % increase, decrease
colorR = [5,120,100;250,30,0;149,123,109]/255;
colorC = [5,120,100;250,30,0;255,255,255]/255;
for iisi = 1:nISI
subplot(1,nISI,iisi)
for rr = 1:length(response)
y = nan_mean(meas(:,:,rr,iisi));
l = sem(1,:,rr,iisi);
u = sem(1,:,rr,iisi);
idx = {1:3;4:6;7};
if flags.do_exp2
idx = idx(1:2);
end
for ii = 1:length(idx)
hC(rr,ii) = plot(x(idx{ii})+dx2(rr),y(idx{ii}),lineStyle{ii});
hold on
hR(rr,ii) = errorbar(x(idx{ii})+dx2(rr),y(idx{ii}),l(idx{ii}),u(idx{ii}),symb(rr));
set(hC(rr,ii),'Color',colorC(ii,:))
end
set(hR(rr,:),'MarkerFaceColor',colorR(rr,:),'Color',colorR(rr,:))
end
set(hR(1:2:size(hR,1),:),'MarkerFaceColor','w')
if flags.do_exp2
set([hC(2:3),hR(2:3)],'Visible','off')
end
set(gca,'XTick',XTick,'XTickLabel',condLabelPlot(1:length(XTick)))
axis([XLim,YLim])
ylabel(YLabel)
xlabel('Spectral contrast pair')
if flags.do_exp2
title(['Exp. II: ',ISIlbl{iisi}])
end
end
stimulus = {'C increase','C decrease','C constat'};
legend([hC(1,:)';hR(:,1)],[stimulus(1:size(hC,2)),response],'Location','eastoutside')
end
end
%% Physiological Results
if flags.do_erp
if not(flags.do_exp1)
error('ERPs only available for exp1.')
end
if flags.do_onset % onset
erp = amt_load('baumgartner2017looming','onsetERP.mat');
else % flags.do_switch
erp = amt_load('baumgartner2017looming','switchERP.mat');
end
erp.compLbl = {'N1','P2'};
out.rawData = erp;
if flags.do_stat
for rr = 1:length(erp.compLbl)
amt_disp(erp.compLbl{rr})
amt_disp(erp.compStats{rr}.ranova(:,[4,6,9,10]))
if isfield(erp.compStats{rr},'posthoc')
if isfield(erp.compStats{rr}.posthoc,'combination')
amt_disp(erp.compStats{rr}.posthoc.combination)
else
amt_disp(erp.compStats{rr}.posthoc)
end
end
end
end
if flags.do_plot
if flags.do_onset % onset
condLabelData = {'0','0.5','1'};
condLabel = condLabelData;
legLbl = erp.compLbl;
XLabel = 'Spectral contrast';
YLim = [-3.8,4.9];
condOrder = [1,3,2]; % to reorder erp.condLbl acc. to condLabel
resp = permute(erp.compAmp(condOrder,:,:),[2,1,3]); % subjects in first dimension
idx = {1:3};
dx = 0;
else % flags.do_switch
condLabel = { '0\leftrightarrow1';'0\leftrightarrow.5';'.5\leftrightarrow1'};
legLbl = {[erp.compLbl{1},', C increase'],[erp.compLbl{1},', C decrease'],...
[erp.compLbl{2},', C increase'],[erp.compLbl{2},', C decrease']};
XLabel = 'Spectral contrast pair';
YLim = [-3.5,3.5];
condOrder = [5,6,4,2,3,1]; % to reorder erp.condLbl acc. to condLabel
resp = permute(erp.compAmp(condOrder,:,:),[2,1,3]);
idx = {1:3;4:6};
dx = .1*[-1,1];
end
% Standard errors
seResp = std(resp)/sqrt(size(erp.compAmp,2));
out.fig = figure;
x = 1:3;
symb = 'oo';
lineStyle = {':','-'};
color = 0.8*[.65,.35,1;1,.5,0];
for rr = 1:length(erp.compLbl)
y = mean(resp(:,:,rr));
l = seResp(1,:,rr);
u = seResp(1,:,rr);
for ii = 1:length(idx)
h(rr,ii) = errorbar(x+dx(ii),y(idx{ii}),l(idx{ii}),u(idx{ii}),...
[symb(rr),lineStyle{ii}]);
hold on
end
set(h(rr,1),'MarkerFaceColor','w','Color',color(rr,:))
set(h(rr,length(idx)),'MarkerFaceColor',color(rr,:),'Color',color(rr,:))
set(gca,'XTick',x,'XLim',x([1,3])+[-1,1])
set(gca,'XTickLabel',condLabel)
ylabel('Cz potential (uV)')
xlabel(XLabel)
end
set(gca,'YLim',YLim,'YMinorTick','on')
legend(legLbl,'Location','eastoutside')
end
end
end
%% Fig. 1B
if flags.do_fig1b
stim = sig_baumgartner2017looming( 'exp1');
%% Top panel: Transfer characterisitcs
fs = stim(1).fs;
Nfft = 2^10;
freq = 0:fs/Nfft:fs/2; % frequency vector
mag = nan(length(freq),length(stim(1).C_IR),2,length(stim));
for ss = 1:length(stim)
if stim(ss).azi == -90
ipsiContra = [2,1];
else
ipsiContra = [1,2];
end
for cc = 1:length(stim(1).C_IR)
Sig = stim(ss).IR{cc};
for ich = 1:2
ch = ipsiContra(ich);
mag(:,cc,ich,ss) = db(abs(fftreal(Sig(:,ch),Nfft)));
end
end
end
mag = mag-3; % arbitrary adjustment to set ipsi. C=0 at 0 dB
if flags.do_plot
XLim = [800,17e3];
YLim = [-34,12];
blue = [0,0,0.7];
green = [0,0.7,0];
red = [0.7,0,0];
color = {blue,1.4*blue;green,1.4*green;red,1.4*red};
lineStyle = {'-','--'};
out.fig(1) = figure;
ii = 1;
for cc = 1:3
for ch = 1:2
lMEAN = mean(mag(:,cc,ch,:),4);
lSEM = std(mag(:,cc,ch,:),0,4)/sqrt(15);
h(ii) = shadedErrorBar(freq,lMEAN,lSEM,{'LineStyle',lineStyle{ch},'Color',color{cc,ch}},1);
hold on
ii = ii+1;
end
end
set(gca,'XScale','log','XLim',XLim,'YLim',YLim)
leg = legend([h.mainLine],'C=0 (ipsi)','C=0 (contra)','C=0.5 (ipsi)','C=0.5 (contra)','C=1 (ipsi)','C=1 (contra)');
set(leg,'Location','eastoutside','box','off')
ylabel('Magnitude (dB)')
xlabel('Frequency (Hz)')
end
out.magnitudeResponse.data = permute(mag,[1,3,4,2]);
out.magnitudeResponse.meta.dim = 'freq_channel_subject_C';
out.magnitudeResponse.meta.freq = freq;
out.magnitudeResponse.meta.channel = {'ipsi','contra'};
out.magnitudeResponse.meta.subject = cat(1,stim.ID);
out.magnitudeResponse.meta.C = 0:0.5:1;
%% Bottom panels: Loudness predictions
% The following loudness predictions were performed with the
% LoudnessToolbox 1.2 provided by Genesis (http://genesis-acoustics.com);
% models used:
% M1: Loudness_ISO532B_from_sound (calculated but not shown)
% M2: Loudness_ANSI_S34_2007 (used for publication);
% Data dimensions:
% subject (1:15) x C (0:.5:1) x model (M1,M2) [x channel (ipsi,contra)];
% frequency (M1:BarkAxis; M2:fc) x channel (ipsi,contra)
L = amt_load('baumgartner2017looming','specificLoudness.mat');
% Difference to reference
dLL_specif = cell(3,1);
for ss = 1:length(stim)
LLC1 = L.loudnessLevel_specif{ss,3,2};
for m = 1:3
dLL_specif{m}(:,:,ss) = L.loudnessLevel_specif{ss,m,2} - LLC1;
end
end
dLoudnessLevel = L.loudnessLevel(:,1:2,:,:) - repmat(L.loudnessLevel(:,3,:,:),[1,2,1,1]);
if flags.do_plot
out.fig(2) = figure;
YLim = [-9,13];
ii = 1;
for m = 1:3
for ch = 1:2
lMEAN = mean(dLL_specif{m}(:,ch,:),3);
lSEM = std(dLL_specif{m}(:,ch,:),0,3)/sqrt(15);
h(ii) = shadedErrorBar(L.fc,lMEAN,lSEM,{'LineStyle',lineStyle{ch},'Color',color{m,ch}},1);
hold on
ii = ii+1;
end
end
set(gca,'XScale','log','XLim',XLim,'YLim',YLim)
leg = legend([h.mainLine],'C=0 (ipsi)','C=0 (contra)','C=.5 (ipsi)','C=.5 (contra)');
set(leg,'Location','northwest','box','off')
ylabel('Loudness level difference to C=1 (phon)')
xlabel('Frequency (Hz)')
end
out.specificLoudnessLevelDiff.data = cat(4,dLL_specif{:});
out.specificLoudnessLevelDiff.meta.dim = 'freq_channel_subject_C';
out.specificLoudnessLevelDiff.meta.freq = L.fc;
out.specificLoudnessLevelDiff.meta.channel = {'ipsi','contra'};
out.specificLoudnessLevelDiff.meta.subject = cat(1,stim.ID);
out.specificLoudnessLevelDiff.meta.C = 0:0.5:1;
% overall loudness level
dLoudnessLevelP = dLoudnessLevel(:,:,2,:);
if flags.do_plot
try
out.fig(3) = figure;
boxplot(dLoudnessLevelP(:,:),... %,{{'M1';'M1';'M2';'M2'},[0;0.5;0;.5]}
'Factorgap',10,'FactorSeparator',1,'Whisker',Inf,...
'Colors',cat(1,color{[1,2,4,5]}))
set(gca,'YLim',YLim)
ylabel('Loudness level difference to C=1 (phon)')
xlabel('Spectral contrast (C)')
catch
warning('Statistics Toolbox not available, omitting figure 3.')
end
end
out.loudnessLevelDiff.data = permute(dLoudnessLevelP,[4,1,2,3]);
out.loudnessLevelDiff.meta.dim = 'channel_subject_C';
out.loudnessLevelDiff.meta.channel = {'ipsi','contra'};
out.loudnessLevelDiff.meta.subject = cat(1,stim.ID);
out.loudnessLevelDiff.meta.C = [0,0.5];
end
%% Fig. 2
if flags.do_fig2
amt_disp('Exp. I:')
out.exp1 = data_baumgartner2017looming('exp1',flags.plot,'stat');
title('Exp. I')
amt_disp('Exp. II:')
out.exp2 = data_baumgartner2017looming('exp2',flags.plot,'stat');
legend off
end
%% Fig. 3A
if flags.do_fig3a
out = data_baumgartner2017looming('erp','onset',flags.plot,flags.stat);
end
%% Fig. 3B
if flags.do_fig3b
out = data_baumgartner2017looming('erp','switch',flags.plot,flags.stat);
end
%% Fig. 3C
if flags.do_fig3c
out = amt_load('baumgartner2017looming','ERPclusterAnalysis.mat');
end
%% Output
if nargout == 1
varargout{1} = out;
end
end
%% Internal plotting functions
function varargout=shadedErrorBar(x,y,errBar,lineProps,transparent)
% function H=shadedErrorBar(x,y,errBar,lineProps,transparent)
%
% Purpose
% Makes a 2-d line plot with a pretty shaded error bar made
% using patch. Error bar color is chosen automatically.
%
% Inputs
% x - vector of x values [optional, can be left empty]
% y - vector of y values or a matrix of n observations by m cases
% where m has length(x);
% errBar - if a vector we draw symmetric errorbars. If it has a size
% of [2,length(x)] then we draw asymmetric error bars with
% row 1 being the upper bar and row 2 being the lower bar
% (with respect to y). ** alternatively ** errBar can be a
% cellArray of two function handles. The first defines which
% statistic the line should be and the second defines the
% error bar.
% lineProps - [optional,'-k' by default] defines the properties of
% the data line. e.g.:
% 'or-', or {'-or','markerfacecolor',[1,0.2,0.2]}
% transparent - [optional, 0 by default] if ==1 the shaded error
% bar is made transparent, which forces the renderer
% to be openGl. However, if this is saved as .eps the
% resulting file will contain a raster not a vector
% image.
%
% Outputs
% H - a structure of handles to the generated plot objects.
%
%
% Examples
% y=randn(30,80); x=1:size(y,2);
% shadedErrorBar(x,mean(y,1),std(y),'g');
% shadedErrorBar(x,y,{@median,@std},{'r-o','markerfacecolor','r'});
% shadedErrorBar([],y,{@median,@std},{'r-o','markerfacecolor','r'});
%
% Overlay two transparent lines
% y=randn(30,80)*10; x=(1:size(y,2))-40;
% shadedErrorBar(x,y,{@mean,@std},'-r',1);
% hold on
% y=ones(30,1)*x; y=y+0.06*y.^2+randn(size(y))*10;
% shadedErrorBar(x,y,{@mean,@std},'-b',1);
% hold off
%
%
% Rob Campbell - November 2009
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Error checking
narginchk(3,5)
%Process y using function handles if needed to make the error bar
%dynamically
if iscell(errBar)
fun1=errBar{1};
fun2=errBar{2};
errBar=fun2(y);
y=fun1(y);
else
y=y(:)';
end
if isempty(x)
x=1:length(y);
else
x=x(:)';
end
%Make upper and lower error bars if only one was specified
if length(errBar)==length(errBar(:))
errBar=repmat(errBar(:)',2,1);
else
s=size(errBar);
f=find(s==2);
if isempty(f), error('errBar has the wrong size'), end
if f==2, errBar=errBar'; end
end
if length(x) ~= length(errBar)
error('length(x) must equal length(errBar)')
end
%Set default options
defaultProps={'-k'};
if nargin<4, lineProps=defaultProps; end
if isempty(lineProps), lineProps=defaultProps; end
if ~iscell(lineProps), lineProps={lineProps}; end
if nargin<5, transparent=0; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Plot to get the parameters of the line
H.mainLine=plot(x,y,lineProps{:});
% Work out the color of the shaded region and associated lines
% Using alpha requires the render to be openGL and so you can't
% save a vector image. On the other hand, you need alpha if you're
% overlaying lines. There we have the option of choosing alpha or a
% de-saturated solid colour for the patch surface .
col=get(H.mainLine,'color');
edgeColor=col+(1-col)*0.55;
patchSaturation=0.15; %How de-saturated or transparent to make patch
if transparent
faceAlpha=patchSaturation;
patchColor=col;
set(gcf,'renderer','openGL')
else
faceAlpha=1;
patchColor=col+(1-col)*(1-patchSaturation);
set(gcf,'renderer','painters')
end
%Calculate the error bars
uE=y+errBar(1,:);
lE=y-errBar(2,:);
%Add the patch error bar
holdStatus=ishold;
if ~holdStatus, hold on, end
%Make the patch
yP=[lE,fliplr(uE)];
xP=[x,fliplr(x)];
%remove nans otherwise patch won't work
xP(isnan(yP))=[];
yP(isnan(yP))=[];
H.patch=patch(xP,yP,1,'facecolor',patchColor,...
'edgecolor','none',...
'facealpha',faceAlpha);
%Make pretty edges around the patch.
H.edge(1)=plot(x,lE,'-','color',edgeColor);
H.edge(2)=plot(x,uE,'-','color',edgeColor);
%Now replace the line (this avoids having to bugger about with z coordinates)
uistack(H.mainLine,'top')
if ~holdStatus, hold off, end
if nargout==1
varargout{1}=H;
end
end
function prc = percentile(x,k)
% percentile function to replace prctile in statistics toolbox
% x .. data vector
% k .. percentage in % (k >= 1)
% if k is outside the range the min or max value of x gets assigned
len = length(x);
if isempty(x)
prc = NaN;
return
end
if len == 1
prc = x; return
end
y = sort(x);
z = 100*(0.5:1:(len-0.5))/len;
if k<z(1)
prc=k(1); return
end
if k>z(end)
prc=z(end); return
end
if isempty(find(z==k, 1))
prc = interp1(z,y,k);
else
prc = y(find(z==k, 1));
end
end
function y = nan_mean(x,dim)
% FORMAT: Y = NANMEAN(X,DIM)
%
% Average or mean value ignoring NaNs
%
% This function enhances the functionality of NANMEAN as distributed in
% the MATLAB Statistics Toolbox and is meant as a replacement (hence the
% identical name).
%
% NANMEAN(X,DIM) calculates the mean along any dimension of the N-D
% array X ignoring NaNs. If DIM is omitted NANMEAN averages along the
% first non-singleton dimension of X.
%
% Similar replacements exist for NANSTD, NANMEDIAN, NANMIN, NANMAX, and
% NANSUM which are all part of the NaN-suite.
%
% See also MEAN
if isempty(x)
y = NaN;
return
end
if nargin < 2
dim = min(find(size(x)~=1));
if isempty(dim)
dim = 1;
end
end
% Replace NaNs with zeros.
nans = isnan(x);
x(isnan(x)) = 0;
% denominator
count = size(x,dim) - sum(nans,dim);
% Protect against a all NaNs in one dimension
i = find(count==0);
count(i) = ones(size(i));
y = sum(x,dim)./count;
y(i) = i + NaN;
end
function y = nan_std(x,dim,flag)
% FORMAT: Y = NANSTD(X,DIM,FLAG)
%
% Standard deviation ignoring NaNs
%
% This function enhances the functionality of NANSTD as distributed in
% the MATLAB Statistics Toolbox and is meant as a replacement (hence the
% identical name).
%
% NANSTD(X,DIM) calculates the standard deviation along any dimension of
% the N-D array X ignoring NaNs.
%
% NANSTD(X,DIM,0) normalizes by (N-1) where N is SIZE(X,DIM). This make
% NANSTD(X,DIM).^2 the best unbiased estimate of the variance if X is
% a sample of a normal distribution. If omitted FLAG is set to zero.
%
% NANSTD(X,DIM,1) normalizes by N and produces the square root of the
% second moment of the sample about the mean.
%
% If DIM is omitted NANSTD calculates the standard deviation along first
% non-singleton dimension of X.
%
% Similar replacements exist for NANMEAN, NANMEDIAN, NANMIN, NANMAX, and
% NANSUM which are all part of the NaN-suite.
%
% See also STD
if isempty(x)
y = NaN;
return
end
if nargin < 3
flag = 0;
end
if nargin < 2
dim = min(find(size(x)~=1));
if isempty(dim)
dim = 1;
end
end
% Find NaNs in x and nanmean(x)
nans = isnan(x);
avg = nan_mean(x,dim);
% create array indicating number of element
% of x in dimension DIM (needed for subtraction of mean)
tile = ones(1,max(ndims(x),dim));
tile(dim) = size(x,dim);
% remove mean
x = x - repmat(avg,tile);
count = size(x,dim) - sum(nans,dim);
% Replace NaNs with zeros.
x(isnan(x)) = 0;
% Protect against a all NaNs in one dimension
i = find(count==0);
if flag == 0
y = sqrt(sum(x.*x,dim)./max(count-1,1));
else
y = sqrt(sum(x.*x,dim)./max(count,1));
end
y(i) = i + NaN;
end