Search code examples
matlab

reverse ordering of legend colors in matlab bar plot


Trying to change some of the properties associated with the bar plot in matlab is very confusing. I have found a number of solution to my problems here. However, there is one that I cannot find. Consider the following:

ax1 = subplot(121);
id2 = [8;2;3;5];
id2_t = sum(id2);
id3 = (id2/id2_t).*100; id3(:,2) = 0;
H1 = bar(id3','stacked','EdgeColor','none');
set(gca,'XTicklabel',[]);
xlim([0.75 1.25]);

% add legend
str = {'str1','str2','str3','str4'};
ll = legend(str);
legend('boxoff');
set(ll,'PlotBoxAspectRatio',[0.5 1 1]);
ll_i = get(ll,'position');
set(ll, 'Position', [0.25 ll_i(2)-0.1 ll_i(3) ll_i(4)]);

% change dimensions of plot
AX1 = get(ax1,'position');
set(ax1,'position',[AX1(1) AX1(2) AX1(3)/2.7 AX1(4)]);

This code was written to produce a single stacked bar in matlab, not the most sophisticated of solutions, but it works. The bar plot I get is below:

enter image description here

Now I am trying to reverse the order of my legend entries so that they match up with the plot. Some people have suggested flipud or fliplr on the strings, but this doesnt work. This changes the sequence of the strings but does not change the colors. Can anyone suggest a method that an match up the ordering of the colors between the legend and the plot? For example, str4 should be blue

Note that the flipud suggestion works for line plots, but not for a stacked bar plot like this. Example using line plot:

x = 1:10;
h = zeros(5, 1);
hold on;
cols = {'r', 'g', 'b', 'y', 'k'};
for k = 1:5
    h(k) = plot(x, k*x, cols{k});
end
legend({'one','two','three', 'four', 'five'}) % one way
legend(flipud(h), {'one', 'two', 'three', 'four', 'five'}) % another way

Solution

Here is the solution using the answer provided by Dan:

ax1 = subplot(121);
id2 = [8;2;3;5];
id2_t = sum(id2);
id3 = (id2/id2_t).*100; id3(:,2) = 0;
H1 = bar(id3','stacked','EdgeColor','none');
set(gca,'XTicklabel',[]);
xlim([0.75 1.25]);

% add legend
str = {'str1','str2','str3','str4'};
[ll ll2]= legend(str);
legend('boxoff');
set(ll,'PlotBoxAspectRatio',[0.5 1 1]);
ll_i = get(ll,'position');
set(ll, 'Position', [0.25 ll_i(2)-0.1 ll_i(3) ll_i(4)]);

% change dimensions of plot
AX1 = get(ax1,'position');
set(ax1,'position',[AX1(1) AX1(2) AX1(3)/2.7 AX1(4)]);

map = colormap;
n = size(ll2,1);
MAP = map(linspace(size(map,1),1,n/2),:); %// n is as my code above
for k = (n/2 + 1):n;
    a1 = get(ll2(k),'Children');
    set(a1,'FaceColor',MAP(k-n/2,:));
end

enter image description here


Solution

  • So you can control the colours of the legend independently of the colors of the bar chart like this (note that I got this idea based on this post and then by inspecting the object properties in the command line):

    [ll, ll2] = legend(str);
    
    n = size(ll2,1);
    for k = (n/2 + 1):n
        ll2(k).Children.FaceColor = RGBTriple;
    end
    

    So try setting RGBTriple to [1,0,0] and you should see all the legend boxes become red. So now it's just a case of getting the bar chart colors (probably in a very similar manner) and flipping them.

    OK so here is a hacky way to find the right colors:

    1. Get the current colormap:

      map  = colormap;
      
    2. Reduce the colormap to the size of your legend:

      MAP = map(linspace(size(map,1),1,n/2),:); %// n is as my code above
      
    3. Use it for RGBTriple:

      for k = (n/2 + 1):n
          ll2(k).Children.FaceColor = MAP(k-n/2,:);
      end