Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set different legends for MATLAB errorbar plot's dot and vertical line?

I have a errorbar plot showing mean and standard deviation. I wish to have a legend item for the circle, the mean, and a separate one for the bar. Something like,

--------------------------
| o mean                 |
| | standard deviation   |
--------------------------

MWE

errorbar([1 2], [2 3], [0.1 0.2], 'o');
legend('mean +- stddev', 'Location','north')

gives me this

enter image description here

like image 603
Sibbs Gambling Avatar asked Dec 24 '22 23:12

Sibbs Gambling


1 Answers

This builds on Jens Boldsen's answer, to which it adds the following:

  • The line representing the errorbar in the legend may be rotated to make it vertical, or be left at its default horizontal orientation;
  • The ends of that line are "closed" with short lines.

The method is quite general, as it supports:

  • Arbitrary color, linestyle and markers as arguments to errorbar. Note that the actual bars are always plotted as solid lines with no markers (using the specified color). This is as per errorbar behaviour.
  • The newly created short lines move with the legend.
  • The width of those lines is a configurable parameter. Also, the length of the errobar is a parameter in the vertical case. Both are defined in normalized units with respect to the legend.

The approach is slightly different depending on Matlab version, because of the changes in graphical objects introduced in R2014b. Also, the errobar line in the legend may be horizontal or vertical. So there are four cases.

Case I: Pre-R2014b, horizontal errorbar in legend

Once the data and legend have been plotted, the code follows these steps:

  1. Get legend's children
  2. Find, among those children, the appropriate line
  3. Get its x and y coordinates
  4. Making use of those coordinates, create two short lines at each end. Make those lines children of the legend, so that they move with it.

The code has been tested in Matlab R2010b.

%// Define graph aspect
color_spec = 'r';       %// color of data and bars.
linestyle_spec = '--';  %// linestyle for data. The bars are always solid
marker_spec = 'o';      %// marker for data
wid = .12;              %// width of bar in legend. Normalized units

%// Plot errobar
h_er = errorbar([1 2], [2 3], [0.1 0.2], [color_spec linestyle_spec marker_spec]); 

%// Add dummy line for legend (as per Jens Boldsen) and create legend
hold on;
plot(0,0,color_spec); %// linestyle is always solid with no marker
h_le = legend('Mean','Standard deviation','Location','north');

%// Add short lines at each end of line in the legend
c_le = get(h_le, 'Children');                                                %// step 1
h_li = findobj(c_le, 'linestyle','-', 'color',color_spec, 'marker','none');  %// step 2
h_li = h_li(1); %// in case there's more than one
li_x = get(h_li,'XData');                                                    %// step 3
li_y = get(h_li,'YData');
line(li_x([1 1]), li_y+wid*[-.5 .5], 'parent',h_le, 'color',color_spec);     %// step 4
line(li_x([2 2]), li_y+wid*[-.5 .5], 'parent',h_le, 'color',color_spec);

enter image description here

Case II: R2014b, horizontal errorbar in legend

In Matlab R2014b the legend is no longer an axes object, and has no children. So steps 1 and 2 have to be modified with respect to case I:

  1. Get legend's icons when creating the legend
  2. Find, among those icons, the appropriate line
  3. Get its x and y coordinates
  4. Making use of those coordinates, create two short lines at each end. Make those lines share the parent with the initial line, so that they move together with the legend.

Also, the new syntax in this Matlab version helps simplify the code a little.

%// Define graph aspect
color_spec = 'r';       %// color of data and bars.
linestyle_spec = '--';  %// linestyle for data. The bars are always solid
marker_spec = 'o';      %// marker for data
wid = .12;              %// width of bar in legend. Normalized units

%// Plot errobar
h_er = errorbar([1 2], [2 3], [0.1 0.2], [color_spec linestyle_spec marker_spec]); 

%// Add dummy line for legend (as per Jens Boldsen)
hold on;
plot(0,0,color_spec); %// linestyle is always solid with no marker

%// Create legend and add short lines at each end of line in the legend
[~, icons] = legend('Mean','Standard deviation','Location','north');           %// 1
li = findobj(icons, 'type','line', 'linestyle','-');                           %// 2
li = li(1); %// in case there's more than one
li_x = li.XData;                                                               %// 3
li_y = li.YData;
line(li_x([1 1]), li_y+wid*[-.5 .5], 'parent',li.Parent, 'color',color_spec);  %// 4
line(li_x([2 2]), li_y+wid*[-.5 .5], 'parent',li.Parent, 'color',color_spec);

enter image description here

Case III: Pre-R2014b, vertical errorbar in legend

This is similar to case I, but some fiddling with the lines' x and y coordinates is required. Also, a new parameter is introduced to control the length of the errorbar in the legend.

%// Define graph aspect
color_spec = 'r';       %// color of data and bars.
linestyle_spec = '--';  %// linestyle for data. The bars are always solid
marker_spec = 'o';      %// marker for data
wid = .04;              %// width of bar in legend. Normalized units
len = .45;              %// length of main bar in legend. Normalized units

%// Plot errobar
h_er = errorbar([1 2], [2 3], [0.1 0.2], [color_spec linestyle_spec marker_spec]); 

%// Add dummy line for legend (as per Jens Boldsen) and create legend
hold on;
plot(0,0,color_spec); %// linestyle is always solid with no marker
h_le = legend('Mean','Standard deviation','Location','north');

%// Add short lines at each end of line in the legend
c_le = get(h_le, 'Children');    
h_li = findobj(c_le, 'linestyle','-', 'color',color_spec, 'marker','none');
h_li = h_li(1); %// in case there's more than one
set(h_li,'XData', repmat(mean(get(h_li,'XData')),1,2));
set(h_li,'YData', mean(get(h_li,'YData'))+len*[-.5 .5]);
li_x = get(h_li,'XData');
li_y = get(h_li,'YData');
line(li_x+wid*[-.5 .5], li_y([1 1]), 'parent',h_le, 'color',color_spec);
line(li_x+wid*[-.5 .5], li_y([2 2]), 'parent',h_le, 'color',color_spec);

enter image description here

Case IV: R2014b, vertical errorbar in legend

Again, this is similar to case II but with some fiddling with the lines' coordinates.

%// Define graph aspect
color_spec = 'r';       %// color of data and bars.
linestyle_spec = '--';  %// linestyle for data. The bars are always solid
marker_spec = 'o';      %// marker for data
wid = .05;              %// width of small bars in legend. Normalized units
len = .45;              %// length of main bar in legend. Normalized units

%// Plot errobar
h_er = errorbar([1 2], [2 3], [0.1 0.2], [color_spec linestyle_spec marker_spec]); 

%// Add dummy line for legend (as per Jens Boldsen)
hold on;
plot(0,0,color_spec); %// linestyle is always solid with no marker

%// Create legend, modify line and add short lines
[~, icons] = legend('Mean','Standard deviation','Location','north');             
li = findobj(icons, 'type','line', 'linestyle','-');
li = li(1); %// in case there's more than one
li.XData = repmat(mean(li.XData),1,2);                                           
li.YData = mean(li.YData)+len*[-.5 .5];
li_x = li.XData;
li_y = li.YData;
line(li_x+wid*[-.5 .5], li_y([1 1]), 'parent',li.Parent, 'color',color_spec);
line(li_x+wid*[-.5 .5], li_y([2 2]), 'parent',li.Parent, 'color',color_spec);

enter image description here

like image 186
Luis Mendo Avatar answered May 12 '23 23:05

Luis Mendo