Search code examples
matlabbar-chartfigure

Having groups of the same color in a bar graph and having the legend elements in the bars


I have a bar graph as given below and x is a 8x3 matrix. My codes are as

x=[0.2193   0.2281  0;
0.193   0.1404  0;
0.2045  0.1875  0.159;
0.0625  0.0568  0;
0.1993  0.1554  0.1318;
0.0878  0.0034  0;
0.1369  0.1103  0.1027;
0.0951  0.076   0];

x0=10;
y0=10;
width=1200;
height=500;
set(gcf,'position',[x0,y0,width,height])

a=bar(x,'BarWidth',0.9);
a(1).FaceColor=[0.9290, 0.6940, 0.1250];
a(2).FaceColor=[0, 0.4470, 0.7410];
a(3).FaceColor=[0.4660, 0.6740, 0.1880];


lgd=legend('Method 1','Method 2','Method 3');
title('False Negative Rates')
xlabel('Clusters')
ylabel('False Negative Rate')
xticklabels({'Cl1 - PRed','Cl1 - PYellow','Cl2 - PRed','Cl2 - PYellow', 'Cl3 - PRed','Cl3 - PYellow', 'Cl4 - PRed','Cl4 - PYellow'})
saveas(gcf,'False Negatives.png')

As you can see there are 8 groups in the chart. enter image description here I need to do three things with this graph:

  1. 1st, 3rd, 5th and 7th groups should be colored red, and others yellow.
  2. I need to write the legend elements inside every bar. If it doesn't fit inside, then above it in a vertical fashion. Red bars will have white font, yellow bars will have black font.
  3. If the value is 0, then show it by a line on the horizontal axis.

I went through this but couldn't apply similarly. How to make groups of horizontal bars have the same color?

How can I achieve any or all of these?


Solution

  • You need to follow the following algorithm to correctly get the graph as per requirements.

    1. Loop for each element individually in the x matrix.
    2. And for each element plot the respective bar graph and hold on.
    3. Check each column number in a switch-case and accordingly put the legends vertically above the bars.
    4. Next, check if the row number is odd, if yes then change the bar color to red and legend color to white. Within this step fix the position of legends inside/outside the bars, based on the bar length.
    5. If, row is an even number then change the bar color to yellow and change the legend color to black and fix the legend position accordingly as per bar length.
    6. Finally, check whether the x bar length is 0, if yes then increase the Line-Width and slide up the bar's legend.
    7. Increment the bar's gap variable and close the inner loop.
    8. Increment again the bar's gap variable and close the outer loop.
    9. Hold off and Put the title, ticks and labels.

    The code to do is given below.

    clc
    close all
    
    % declare the points, for the bars
    x=[0.2193   0.2281  0;
    0.193   0.1404  0;
    0.2045  0.1875  0.159;
    0.0625  0.0568  0;
    0.1993  0.1554  0.1318;
    0.0878  0.0034  0;
    0.1369  0.1103  0.1027;
    0.0951  0.076   0];
    
    % declare the figure width and height
    x0=10;
    y0=10;
    width=1200;
    height=500;
    % create the figure
    set(gcf,'position',[x0,y0,width,height]);
    % get the number of rows and column in x points
    [row, col] = size(x);
    % variable to decide the gap between the bars
    p = 1;
    
    %%%%%%  Loop for Rows %%%%%%%%
    for r = 1:row
    
        %%%%%%%%%% loop for each elements in each row %%%%%%%
        % loop for columns %
        for c = 1:col
            % draw the individual bar
            a = bar(p, x(r,c), 'BarWidth',0.9); hold on
            % switch the column value
            switch(c)
                % if column is 1 then create bar legend as "Method 1"
                % vertically just above the bar
                case 1 
                    t1 = text(p,x(r,c),'Method 1','rotation',90);
                % if column is 2 then create bar legend as "Method 2"
                % vertically just above the bar
                case 2
                    t1 = text(p,x(r,c),'Method 2','rotation',90);
                % if column is 3 then create bar legend as "Method 3"
                % vertically just above the bar
                case 3
                    t1 = text(p,x(r,c),'Method 3','rotation',90);
            end
    
            % Now check whether the row is odd
            % if yes then change the bar color to Red
            if(rem(r, 2) ~= 0)
                set(a, 'FaceColor', 'r')
                % Change the legend color to white in red bars
                t1.Color = 'White';
                % check if x value is equals or greaten than 
                % 0.05, it means the legend fit inside the bars
                if(x(r,c) >= 0.05)
                    % slide down the legend into the bars
                    t1.Position = [p, x(r,c)-0.04];
                else
                    % else change the color of the 
                    % legend to black and keep the
                    % position unchanged, because if the 
                    % position remains outside the red bars
                    % then the legend would not be visible due 
                    % to the color white and hence change it to black
                    t1.Color = 'black';
                end
            else
               % else, it means row is even then
               % change the bar color to yellow
               set(a, 'FaceColor', 'y')
               % if bar color is yellow then change the legend
               % color to black
                t1.Color = 'black';
                % check if length of bar is greater than 0.05
                % if yes slide the legend position inside the bar
                  if(x(r,c) >= 0.05)
                    t1.Position = [p, x(r,c)-0.04];
                  end
            end
    
            % finally, check if x is equal to 0
            % then make the line width of bar to
            % 2 points, to make it more visible
            % and slide up the legend above the bar
            % to few fractional points to make it more ligible
            if(x(r,c) == 0)
                a.LineWidth = 2;
                t1.Position = [p, x(r,c)+0.002];
            end
    
            % increment the legend gap as y-axis
            p = p+1;
    
        end
        %%%%% END the Column loop %%%%%%%%%
    
        % on each row end increment the gap of bars to
        % make it categorized as each row.
        p = p+1;
    end
    %%%%%%%%% END the Row loop %%%%%%%%%%%
    
    hold off
    % set the title
    title('False Negative Rates')
    % set the labels
    xlabel('Clusters')
    ylabel('False Negative Rate')
    % mark the xticks to put the xticklables
    % in next line
    xticks([2:4:32])
    % change the xtick labels at corresponding xticks
    xticklabels({'Cl1 - PRed','Cl1 - PYellow','Cl2 - PRed','Cl2 - PYellow', 'Cl3 - PRed','Cl3 - PYellow', 'Cl4 - PRed','Cl4 - PYellow'})
    saveas(gcf,'False Negatives.png')
    

    OUTPUT

    enter image description here