【问题标题】:How to make groups of horizontal bars have the same color?如何使多组水平条具有相同的颜色?
【发布时间】:2018-06-07 06:41:42
【问题描述】:

我需要使用grouped 样式绘制水平条,这样属于每个组的所有条具有相同的颜色但与其他组不同(即顶部组的所有条都是红色,它下面的组 - 绿色, 等等...)。

另外,如何将值水平放置在每个条的顶部?如何控制这些值的位置?

这是我的代码:

y = [91.9 8.1 94.4 5.6; 84.9 15.1 90.12 9.88; 89.4 10.6 91.2 8.8; 72 28 50.9 49.1];

h = barh(y,'grouped'); 
job = {'group1','group2 ','group 3','group4'};
legend(job,'location','northeast');

这是我现在的图:

【问题讨论】:

  • @Tommaso 编辑时请尝试更彻底。尽管您删除了一些错别字,但仍有一些地方需要改进,例如:标题、代码和更多错别字。

标签: matlab plot colors label bar-chart


【解决方案1】:

这两个请求重叠使得一切都变得有点复杂,因为为每个组使用统一的颜色意味着使用需要另一种解决方法来处理男性栏文本工作的解决方法。代码如下:

y = [
  91.90  8.10 94.40  5.60;
  84.90 15.10 90.12  9.88;
  89.40 10.60 91.20  8.80;
  72.00 28.00 50.90 49.10
];

[rows,cols] = size(y);
n = NaN(rows,cols);

c = {'r' 'g' 'b' 'y'};

bh = cell(rows,1);
lh = cell(rows,1);

hold on;

for k = 1:rows
    curr = n;
    curr(k,:) = y(k,:);

    bar = barh(curr,'FaceColor',c{k});

    bh{k} = bar;
    lh{k} = bar(1);
end

hold off;

legend([lh{:}],{'G1','G2','G3','G4'},'Location','southoutside');

yl = get(gca,'XLim');
yl_up = yl(2);
xoff = yl_up * 0.01;
set(gca,'XLim',[yl(1) (yl_up + (yl_up * 0.1))]);

set(gcf,'Units','normalized','Position',[0.1 0.1 0.8 0.8]);

for i = 1:numel(bh)
    bh_i = bh{i};

    for j = 1:numel(bh_i)
        bh_ij = bh_i(j);
        hx = bh_ij.YData + xoff;
        hy = bh_ij.XData + bh_ij.XOffset;

        text(hx,hy,num2str(hx.','%.2f'), ...
             'FontSize',10, ...
             'HorizontalAlignment','left', ...
             'VerticalAlignment','middle');
    end
end

这是输出:

【讨论】:

  • 请告诉我如何从这个自定义图形中删除 Y 轴的数字(1,1.5,2,2.5,....ect)?我尝试使用 % 清除 X 轴数据 %set(gcf,'XTick',[]);但不工作!
  • @MohsenAli 1. 它是您要更改的轴,而不是图;所以你会使用gca,而不是gcf2. 此外,您希望在 y 轴而不是 x 轴上进行更改。因此它将是:set(gca,'YTick',[])。祝你好运!
【解决方案2】:

这是一个技巧:
一次绘制 1 行的条形图并用 NaNs 填充空间,同时为所有行指定单一颜色。绘制NaNs 不会绘制任何内容。

[ry, cy] = size(y);   %Number of rows and columns of y
hold on;
for k = 1:ry
    tmp = [NaN(k-1,cy); y(k,:); NaN(4-k,cy)];   %Filling with NaNs
    h{k} = barh(tmp, 'FaceColor', rand(1,3));   %Plotting bar graph in random color
    h{k} = h{k}(1);   %Store handle of any of the rows (Required for legend)
end
job = {'group1', 'group2', 'group3', 'group4'}; %Required legend entries
legend([h{:}], job);  %Default location is already 'northeast' (so can be skipped)

输出:

【讨论】:

    【解决方案3】:

    这是另一种黑客攻击;在 R2017b 上测试。

    您所问的问题之所以难以做到,是因为条形图中的每个组实际上都是一个 Quadrilateral 对象(即多边形)。例如,我们以 1stBar 对象为例:

    >> h(1).Face.VertexData
    
    ans =
    
      3×16 single matrix
    
      Columns 1 through 9
    
             0   91.9000   91.9000         0         0   84.9000   84.9000         0         0
        0.6545    0.6545    0.8000    0.8000    1.6545    1.6545    1.8000    1.8000    2.6545
             0         0         0         0         0         0         0         0         0
    
      Columns 10 through 16
    
       89.4000   89.4000         0         0   72.0000   72.0000         0
        2.6545    2.8000    2.8000    3.6545    3.6545    3.8000    3.8000
             0         0         0         0         0         0         0
    

    如果我们将这一行添加到代码中:

    drawnow; hold on; scatter(h(1).Face.VertexData(1,:), h(1).Face.VertexData(2,:));
    

    我们得到(注意绿色圆圈):

    有趣的是VertexData 中的点不是只读的,这意味着我们可以智能地“重新排列”N 条组的VertexData 矩阵以获得所需的结果。这是一种方法(注意我将h重命名为hBar):

    % Obtain the old VertexData:
    vd_old = cell2mat(reshape(get([hBar.Face],'VertexData'),1,1,[]));
    % Rearrange VertexData:
    nB = numel(hBar);
    vd_new = cell2mat(permute(mat2cell(vd_old,3,repelem(4,nB),repelem(1,nB)),[1,3,2]));
    % Assign the new VertexData back into the Bar objects' Edge and Face fields:
    for indB = 1:nB
      hBar(indB).Edge.VertexData = vd_new(:,:,indB);
      hBar(indB).Face.VertexData = vd_new(:,:,indB);
    end
    

    最后,我们使用text 命令手动添加标签:

    xOffset = 1;
    
    for indB = 1:nB
      text(double(vd_new(1,2:4:end,indB)) + xOffset, double(tmpY(2:4:end)), ...
        string(vd_new(1,2:4:end,indB)),'VerticalAlignment','middle');
    end
    

    最终结果:

    最终代码:

    function q47978293
    close all force;
    
    y = [91.9 8.1 94.4 5.6; 84.9 15.1 90.12 9.88; 89.4 10.6 91.2 8.8; 72 28 50.9 49.1];
    
    figure(47978293); set(gcf,'Position',[786,556,887,420]); hBar = barh(y,'grouped');
    legend("group" + (1:4),'location','northeast');
    drawnow;
    % hold on; scatter(h(1).Face.VertexData(1,:), h(1).Face.VertexData(2,:));
    
    % Obtain the old VertexData:
    vd_old = cell2mat(reshape(get([hBar.Face],'VertexData'),1,1,[]));
    % Rearrange VertexData:
    nB = numel(hBar);
    vd_new = cell2mat(permute(mat2cell(vd_old,3,repelem(4,nB),repelem(1,nB)),[1,3,2]));
    % Assign the new VertexData back into the Bar objects' Edge and Face fields:
    xOffset = 1; % < Adjust as you see fit
    for indB = 1:nB
      hBar(indB).Edge.VertexData = vd_new(:,:,indB);
      hBar(indB).Face.VertexData = vd_new(:,:,indB);
      try
        text( y(indB,:) + xOffset, mean(reshape(vd_new(2,1:2:end,indB),2,[]),1,'double'), ...
          string(vd_new(1,2:4:end,indB)),'VerticalAlignment','middle');
      catch % Compatibility fix for R2016b & R2017a. Credit @SardarUsama
        text( y(indB,:) + xOffset, mean(reshape(vd_new(2,1:2:end,indB),2,[]),1,'double'), ...
          split(num2str(vd_new(1,2:4:end,indB))),'VerticalAlignment','middle');
      end
    end
    
    end
    

    注意:由于此解决方案的 hacky 特性,如果重新绘制图形(例如由于调整大小),条形颜色将恢复到其原始状态 -所以要确保改变颜色的部分是你做的最后一件事。


    附言
    R2017b release notes 声明现在应该正式支持此自定义(通过 Bar 对象的 CData 属性),但我无法让图例显示正确的颜色。如果您想尝试一下,只需使用以下命令 (R2017b+) 进行绘图:

    barh(y,'grouped','FaceColor','flat','CData',lines(size(y,1)));
    

    【讨论】:

    • @Tommaso 谢谢!我只希望我能让它以“官方方式”工作(我最近在最后添加了它的开头)......
    猜你喜欢
    • 1970-01-01
    • 2016-11-24
    • 2020-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-27
    相关资源
    最近更新 更多