How to add error bars to multiple axes-plots?

69 vues (au cours des 30 derniers jours)
Dinuka Kankanige
Dinuka Kankanige le 4 Jan 2023
Commenté : Voss le 21 Jan 2023
I've produced a plot with 3 y-axes (for y1,y2,y3) and trying to add errorbars to the 3 line graphs. Initially I used 'plot' function as below (only to plot the data without error bars) and it went alright.
y1plot=plot(x,y1,'color',[0.8500,0.3250,0.0980]);
y2plot=plot(x,y2,'-b');
y3plot=plot(ax2,x,y3,'-k');
But when I replace 'plot' with 'errorbar' function as below, the graphs won't show up.
y1plot=errorbar(x,y1,y1_err,'color',[0.8500,0.3250,0.0980]);
y2plot=errorbar(x,y2,y2_err,'-b');
y3plot=errorbar(ax2,x,y3,y3_err,'-k');
Using 'plot' first, and then 'errorbar' as below also mess up the entire plot.
y1plot=plot(x,y1,'color',[0.8500,0.3250,0.0980]);
errorbar(y1,y1_err);
Maybe as it's being plotted on multiple axes, there's something going wrong which I find difficult to figure out. Any suggestions please! (The code is provided below for reference)
(R2020b)
-Thank you-
%reshape 4D arrays of data to 2D arrays
y1=reshape(A,1,12);
y2=reshape(B,1,12);
y3=reshape(C,1,12);
%reshape 4D arrays of error to 2D arrays
y1_err=reshape(A_err,1,12); %y1
y2_err=reshape(B_err,1,12); %y2
y3_err=reshape(C_err,1,12); %y3
%set x axis
x=datetime(2002,1:(16*12),1,'Format','MMM-yyyy');
%plot y1,y2
figure
ax1=axes;
yyaxis left;
y1plot=errorbar(x,y1,y1_err,'color',[0.8500,0.3250,0.0980]); %y1 on left
ax1.YColor=[0.8500,0.3250,0.0980];
ylabel('y1');
ax1.XTickMode='manual';
ax1.YTickMode='manual';
ax1.YLim=[min(ax1.YTick), max(ax1.YTick)];
ax1.XLimMode='manual';
grid(ax1,'on')
ytick=ax1.YTick;
yyaxis right
y2plot=errorbar(x,y2,y2_err,'-b'); %y2 on right
ax1.YColor='b';
ylabel('y2');
%create 2nd transparent axes & plot y3
ax2 = axes('position',ax1.Position);
y3plot=errorbar(ax2,x,y3,y3_err,'-k'); %y3 on left
ylabel('y3');
ax2.Color='none';
grid(ax2,'on');
ax2.YAxis.TickLabelFormat='%.2f';
%horizontally scale the y axis to align the grid
ax2.XLim=ax1.XLim;
ax2.XTick=ax1.XTick;
ax2.YLimMode='manual';
y1=ax2.YLim;
ax2.YTick=linspace(y1(1),y1(2),length(ytick));
%horzontally offset y tick labels
ax2.YTickLabel=strcat(ax2.YTickLabel,{' '});

Réponse acceptée

Voss
Voss le 8 Jan 2023
One problem is that setting XLimMode to 'manual' can have the effect of changing the XLim.
Example:
% create a figure, axes, and plot:
figure()
ax = axes();
plot(ax,0:10,0:10)
% at this point XLim *should be* [0 10], and setting XLimMode to manual
% *should* not change them ...
ax.XLimMode = 'manual';
get(ax,'XLim') % ... but in fact the XLim are [0 1] now
ans = 1×2
0 1
Obviously you could set the XLim before setting XLimMode, but I assume you want to let MATLAB pick the XLim for you (and then you're setting XLimMode to 'manual' to have them be fixed in place).
Interestingly, merely querying the XLim (not setting them) before setting XLimMode to 'manual' seems to give the expected behavior:
figure
ax = axes();
plot(ax,0:10,0:10)
get(ax,'XLim') % now XLim are [0 10]
ans = 1×2
0 10
ax.XLimMode = 'manual';
get(ax,'XLim') % and XLim remain [0 10] after setting XLimMode
ans = 1×2
0 10
You could also insert a drawnow before setting XLimMode:
figure
ax = axes();
plot(ax,0:10,0:10)
drawnow();
ax.XLimMode = 'manual';
get(ax,'XLim') % and XLim remain [0 10] after setting XLimMode
ans = 1×2
0 10
With that observation in mind, including a few drawnow() commands at strategic points in the code seems to fix all the problems. See explanations in the comments in the code below:
% %reshape 4D arrays of data to 2D arrays
% y1=reshape(A,1,12);
% y2=reshape(B,1,12);
% y3=reshape(C,1,12);
%
% %reshape 4D arrays of error to 2D arrays
% y1_err=reshape(A_err,1,12); %y1
% y2_err=reshape(B_err,1,12); %y2
% y3_err=reshape(C_err,1,12); %y3
% some data, since I don't have your data:
y1 = randi(100,1,12);
y2 = randi(20,1,12);
y3 = randi(70,1,12);
y1_err = 10*rand(1,12);
y2_err = 2*rand(1,12);
y3_err = 7*rand(1,12);
% %set x axis
% x = datetime(2002,1:(16*12),1,'Format','MMM-yyyy');
% set x-coordinate of lines (I'm not sure how your x was 1-by-192
% when your y1, y2, etc., were all 1-by-12):
x = datetime(2002,1:12,1,'Format','MMM-yyyy');
%plot y1,y2
figure
ax1=axes;
yyaxis left;
y1plot=errorbar(x,y1,y1_err,'color',[0.8500,0.3250,0.0980]); %y1 on left
ax1.YColor=[0.8500,0.3250,0.0980];
ylabel('y1');
% this drawnow() allows ax1 properties to update before
% setting their modes to manual:
drawnow();
ax1.XTickMode='manual';
ax1.YTickMode='manual';
ax1.YLim=[min(ax1.YTick), max(ax1.YTick)];
ax1.XLimMode='manual';
grid(ax1,'on')
ytick=ax1.YTick;
yyaxis right
y2plot=errorbar(x,y2,y2_err,'-b'); %y2 on right
ax1.YColor='b';
ylabel('y2');
% this drawnow() allows ax1.Position to update before using it for
% ax2.Position, so that the axes overlap properly
drawnow();
%create 2nd transparent axes & plot y3
ax2 = axes('position',ax1.Position);
y3plot=errorbar(ax2,x,y3,y3_err,'-k'); %y3 on left
ylabel('y3');
ax2.Color='none';
% grid(ax2,'on'); % Note: ax2 grid is not necessary, because ax1 has the same grid
% (the x-limits of ax1 and ax2 are the same, and ax2.YTick
% is set below to correspond to ax1.YTick)
ax2.YAxis.TickLabelFormat='%.2f';
%horizontally scale the y axis to align the grid
ax2.XLim=ax1.XLim;
ax2.XTick=[];%ax1.XTick; % Note: I set ax2.XTick to [] (no ticks) to avoid duplicating
% the xticklabels that already exist in ax1
% this drawnow() allows ax2.YLim to update before setting ax2.YLimMode
drawnow();
ax2.YLimMode='manual';
% Note: I'm calling this variable "y_limits" instead of "y1" because I
% don't want to overwrite the data variable "y1". (I could use "yl",
% with a lower-case L, but that's difficult to distinguish from "y1"):
y_limits=ax2.YLim;
ax2.YTick=linspace(y_limits(1),y_limits(2),length(ytick));
%horzontally offset y tick labels
% ax2.YTickLabel=strcat(ax2.YTickLabel,{' '});
% Note: I removed a few spaces to be able to see the
% YTickLabels of ax2 here in the forum environment
ax2.YTickLabel=strcat(ax2.YTickLabel,{' '});
As an alternative to placing several drawnow commands in code, you could rearrange the code so that all the plotting and axes creation is done first, and then all the axes appearance modification (setting labels, ticks, limits, etc.) is done afterward, but that's a little tricky because of the use of yyaxis.
  2 commentaires
Dinuka Kankanige
Dinuka Kankanige le 20 Jan 2023
Thank you very much! This helps indeed.
Voss
Voss le 21 Jan 2023
You're welcome!

Connectez-vous pour commenter.

Plus de réponses (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by