error bars in bar plot with categories

조회 수: 177 (최근 30일)
Paul Himsl
Paul Himsl 2019년 12월 12일
편집: dpb 2019년 12월 13일
Hello
I have a bar plot with 3 categories where I want to insert error bars.
I've been trying it for a long time, but I can't find the solution.
x are the categories
y the values
errorplus and errorminus the errors values.
Can someone hel me?
Thank you very much!
x=categorical({'Hip';'Knee';'Ankle'});
y=[21.0416,19.5461,50;30.003601074218750,24.056737899780273,50;22.604316711425780,26.007211685180664,35];
errorplus=[0.434635639190674,1.783290743827820,0;1.722714424133301,1.000267505645752,0;0.471254885196686,2.722285032272339,0];
errorminus=errorplus;
figure;
bar(x,y);
title('Range of Motion','FontSize',18)
ylabel('Angle Values [°]','FontSize',18)
set(gca,'linewidth',2,'FontSize',14)
ylim([0 60]);

채택된 답변

Star Strider
Star Strider 2019년 12월 12일
This seems to be an XOR situation. Apparently, it is possible to have categorical x-values or errorbar bars but not both.
This requires non-categorical x-values, although it produces the appropriate final result:
x=categorical({'Hip';'Knee';'Ankle'});
y=[21.0416,19.5461,50;30.003601074218750,24.056737899780273,50;22.604316711425780,26.007211685180664,35];
errorplus=[0.434635639190674,1.783290743827820,0;1.722714424133301,1.000267505645752,0;0.471254885196686,2.722285032272339,0];
errorminus=errorplus;
figure;
bar(x,y);
hBar = bar(y, 0.8); % Return ‘bar’ Handle
for k1 = 1:size(y,2)
ctr(k1,:) = bsxfun(@plus, hBar(k1).XData, hBar(k1).XOffset'); % Note: ‘XOffset’ Is An Undocumented Feature, This Selects The ‘bar’ Centres
ydt(k1,:) = hBar(k1).YData; % Individual Bar Heights
end
hold on
errorbar(ctr, ydt, errorplus, '.r') % Plot Error Bars
hold off
title('Range of Motion','FontSize',18)
ylabel('Angle Values [°]','FontSize',18)
set(gca,'linewidth',2,'FontSize',14)
ylim([0 60]);
set(gca,'XTickLabel',x)
producing this plot:
1error bars in bar plot with categories - 2019 12 12.png

추가 답변 (3개)

Paul Himsl
Paul Himsl 2019년 12월 12일
WOW .. thank you yery much!
Is it possible to "write" the values of each bar on the top of the bar when there are error bars already?
  댓글 수: 3
dpb
dpb 2019년 12월 12일
"Is it possible to "write" the values of each bar on the top of the bar when there are error bars already?"
Showing how to write text is the link I posted; to add them as well as the error bars just adjust the y position to add the error value to the y value (for above) or subtract for below.
Star Strider
Star Strider 2019년 12월 12일
Finally ... reinstalled and updated!
To add the values of each bar at the top, the loop changes to:
for k1 = 1:size(y,2)
ctr(k1,:) = bsxfun(@plus, hBar(k1).XData, hBar(k1).XOffset'); % Note: ‘XOffset’ Is An Undocumented Feature, This Selects The ‘bar’ Centres
ydt(k1,:) = hBar(k1).YData; % Individual Bar Heights
for k2 = 1:size(ydt,2)
text(ctr(k1,k2), ydt(k1,k2)+errorplus(k1,k2), sprintf('%.1f', ydt(k1,k2)), 'HorizontalAlignment','center','VerticalAlignment','bottom');
end
end
The inner loop is necessary in order to plot the values correctly.
1error bars in bar plot with categories (2) - 2019 12 12.png
Make appropriate changes to get the result you want.

댓글을 달려면 로그인하십시오.


dpb
dpb 2019년 12월 12일
편집: dpb 2019년 12월 12일
This is a royal pain for even numeric axes; even worse for categorical. Complain to TMW about the sorry quality of implementation for bar to not provide the necessary tools <See LINK for example w/ numeric axis> and then errorbar hasn't been enhanced to allow categorical variables on x-axis...besides, there's no concept of a fractional value for a categorical variable to let you move to the right bar position for the grouped bars. All in all, it's a royal mess of not being a complete packaged solution. Disgraceful in my opinion.
Anyway, only practical way I see is to actually plot the figure as numeric underlying data and then label the result as desired...
... % your preliminaries here...
figure;
hB=bar(double(x),y); % create the bar as numeric instead of categorical x axis
title('Range of Motion','FontSize',18)
ylabel('Angle Values [°]','FontSize',18)
set(gca,'linewidth',2,'FontSize',14)
ylim([0 60]);
hold on
% get ready to put the errorbar() on top...
err=errorplus; % all errors were same +/- so use symmetric
hEB=[]; % placeholder of the errorbar object handles
hT=[]; % ditto text handles
for i=1:numel(hB) % put the errorbar on each bar
hEB=[hEB; errorbar(hB(i).XData+hB(i).XOffset,hB(i).YData, err(:,i),'.k')];
hT=[hT text(hB(i).XData+hB(i).XOffset, ...
hB(i).YData+err(:,i).', ...
num2str(hB(i).YData.','%.2f'), ...
'VerticalAlignment','bottom','horizontalalign','center','fontsize',9)];
end
xticklabels(categories(x)) % label the ticks by categorical names
There really should be built in facilities inside bar for adding annotations w/o relying on hidden properties and so much coding.
Hadn't previously thought of the limitation in errorbar, but it should be enhanced, too, and then the dificulties in mixing the internals of a categorical axis with positions other than exactly at the category values should be addressed as well. So much work to do that TMW never seems to want to address but that would be major boosts in overall productivity to quit having to spend hours trying to find workarounds. :(
  댓글 수: 5
dpb
dpb 2019년 12월 12일
편집: dpb 2019년 12월 12일
Above looks ok w/o double loop to me???
HMMM...yours is Hip/Knee/Ankle whereas default order is Ankle/Hip/Knee, the order of categories of x in alphabetic order. Mayhaps there's the difference.
The data are the same for both, however, just the order of them on the x axis.
>> figure
>> bar(x,y)
results in
which is order in which OP defined the arrays. Not sure what changed the axis order in yours.
Could it be version, perhaps? Mayhaps the newer release honors the array order instead of the alphabetic of R2017b as categories here shows? What does the following return on your system (R2019 I think?)
>> x
x =
3×1 categorical array
Hip
Knee
Ankle
>> categories(x)
ans =
3×1 cell array
{'Ankle'}
{'Hip' }
{'Knee' }
>> double(x)
ans =
2
3
1
>>
dpb
dpb 2019년 12월 12일
Ah-so! I hadn't seen you threw away the bar(x,y) call by the subsequent hBar=bar(y,0.8) so the x values weren't provided to the bar object explicitly. That 'splains it all and why it took the second level addressing.

댓글을 달려면 로그인하십시오.


Paul Himsl
Paul Himsl 2019년 12월 13일
Thank you all very much for your help!
  댓글 수: 1
dpb
dpb 2019년 12월 13일
편집: dpb 2019년 12월 13일
Glad to help where TMW falls short...
BTW, the route S-S took can also be done w/o the double loop; just have to recognize the order is different as noted in previous comment--the following generates identical plot.
hB=bar(y); % the y data versus column number instead of ordered categorical x
ylim([0 60]);
hold on
hEB=[]; % placeholder of the errorbar object handles
hT=[]; % ditto text handles
for i=1:numel(hB)
hEB=[hEB; errorbar(hB(i).XData+hB(i).XOffset,hB(i).YData, err(:,i),'.k')];
hT=[hT text(hB(i).XData+hB(i).XOffset, ...
hB(i).YData+err(:,i).', ...
num2str(hB(i).YData.','%.2f'), ...
'VerticalAlignment','bottom','horizontalalign','center','fontsize',9)];
end
xticklabels(cellstr(x)) % label in numeric, not alphabetic order
BTW, hEB, hT are the handles to the errorbar and text objects saved so can make additional tweaks on their properties should such be desired...

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Data Distribution Plots에 대해 자세히 알아보기

Community Treasure Hunt

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

Start Hunting!

Translated by