error bars in bar plot with categories

200 Ansichten (letzte 30 Tage)
Paul Himsl
Paul Himsl am 12 Dez. 2019
Bearbeitet: dpb am 13 Dez. 2019
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]);

Akzeptierte Antwort

Star Strider
Star Strider am 12 Dez. 2019
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

Weitere Antworten (3)

Paul Himsl
Paul Himsl am 12 Dez. 2019
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 Kommentare
dpb
dpb am 12 Dez. 2019
"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 am 12 Dez. 2019
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.

Melden Sie sich an, um zu kommentieren.


dpb
dpb am 12 Dez. 2019
Bearbeitet: dpb am 12 Dez. 2019
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 Kommentare
dpb
dpb am 12 Dez. 2019
Bearbeitet: dpb am 12 Dez. 2019
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 am 12 Dez. 2019
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.

Melden Sie sich an, um zu kommentieren.


Paul Himsl
Paul Himsl am 13 Dez. 2019
Thank you all very much for your help!
  1 Kommentar
dpb
dpb am 13 Dez. 2019
Bearbeitet: dpb am 13 Dez. 2019
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...

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Data Distribution Plots finden Sie in Help Center und File Exchange

Community Treasure Hunt

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

Start Hunting!

Translated by