如何为3D条形图中的条形设置任意颜色?

时间:2017-07-31 18:58:49

标签: matlab 3d bar-chart matlab-figure colormap

假设我有一个带有一些值的矩阵Z,我希望通过以Z高度绘制值来说明它。我想到的第一个解决方案是表面,但使用surf和类似的函数与小矩阵看起来并不好。

所以我想到使用bar3这样的3D条形图。但问题是这个功能总是按组而不是按高度设置颜色,我不能这样做。

以下是一个例子:

Z = peaks(5);
subplot 121
surf(Z)
title('Surface look bad')
subplot 122
bar3(Z)
title('The color is not by height')

enter image description here

我试图在bar3返回的句柄中查找颜色属性(例如CDataFaceColor)但是丢失了所有值以及它们与条形本身的关系

最终,我希望有一个通用的解决方案,对于2个矩阵ZC,我可以创建一个3D条形图,其高度由Z给出,并由C

我该怎么办?

3 个答案:

答案 0 :(得分:4)

函数bar3返回一个 surface 对象,每个对应一个(即每种颜色一个),因此一组中的所有条形图基本上都被绘制为一个“破碎”曲面。这在this answer中解释得非常好,所以我在此不再重复。

相反,我会针对这个特定问题找到解决方案。表面的相关属性为CData。当我们创建条形图时,每个曲面的CData都会被赋予一个大小相同的矩阵(我们将得到它),它们都等于一个值。每个表面的值不同。这就是图形整体将其颜色图转换为组颜色的方式。

如上所述(并在linked answer中详细说明),每个组由一个曲面表示,因此需要一个完整的矩阵来定义曲面每个点的颜色。我们要做的第一件事是获得这个矩阵大小:

Z = peaks(5);
bar_h = bar3(Z);
% we take only the first one, but they are all the same size:
cdata_sz = size(bar_h(1).CData) 

cdata_sz =
    30     4

CData始终有4列(请参阅here why),行数始终为6 *组数。这是因为它需要5个顶点来创建一个带有区域对象的闭合矩形(最后一个顶点就像第一个顶点),一条线用于带有NaN的条形之间的间距,因此它们看起来是分开的。

接下来,我们需要以正确的方式放大原始色彩图(大小与Z相同)以适合CData。基本上,我们只想为属于同一个条的所有顶点重复相同的值。假设Z也是我们的颜色数据(即我们按高度颜色),我们会这样做:

z_color = repelem(Z,6,4)

现在我们需要将z_color拆分为我们组中不同的单元格。每个单元格将包含一个表面对象的着色数据:

z_color = mat2cell(z_color,cdata_sz(1),ones(1,size(Z,2))*cdata_sz(2));

最后,我们将新的颜色数据应用于条形图:

set(bar_h,{'CData'},z_color.')

作为奖励,如果我们想从我们的栏中删除所有零值,可以通过将它们设置为NaN来轻松完成:

Z(abs(Z)<eps) = nan;
C(isnan(Z)) = nan; % if we use a colormap C different from Z

demo2

以上所有内容都可以归结为这个方便的功能:

function bar_h = Cbar3(Z,C,b,y)
% Z - The data
% C - CData (if other then Z values)
% b - Minimum absolute value to keep colored
% y - y-axis values to order the data by

if nargin<2, C = Z; end
if nargin<3 || isempty(b), b = 0; end
Z(abs(Z)<b) = nan;
C(isnan(Z)) = nan;
if nargin<4 
    bar_h = bar3(Z);
else
    bar_h = bar3(y,Z);
end
cdata_sz = size(bar_h(1).CData);
z_color = repelem(C,6,4);
z_color = mat2cell(z_color,...
    cdata_sz(1),ones(1,size(Z,2))*cdata_sz(2));
set(bar_h,{'CData'},z_color.')
end

使用示例:

subplot 121
Z = peaks(30);
Cbar3(Z,Z,0.5);
pbaspect auto
shading flat % just to get a cleaner look
title('Cbar3 using height as color')

subplot 122
Cbar3(Z,rand(size(Z)),0.5);
pbaspect auto
shading flat % just to get a cleaner look
title('Cbar3 using random as color')

结果:

enter image description here

答案 1 :(得分:2)

这是部分答案。

使用条形高度作为颜色的情况由官方MATLAB documentation涵盖。基本上,示例代码归结为:

function q45423394
hB = bar3(peaks(25)); colorbar;
for indE = 1:numel(hB)
  hB(indE).CData = hB(indE).ZData;
end

之后您需要做的就是确保colormap是您想要的。

enter image description here

答案 2 :(得分:0)

虽然我发现EBH的解决方案在美学上更令人愉悦,但这里有一个更简单的解决方案:插值

z = peaks(5);
[x,y]=meshgrid(1:0.1:size(z,1),1:0.1:size(z,2));
zn=interp2(z,x,y,'nearest');
% plot it
surf(zn,'edgecolor','none','facecolor','interp')

enter image description here