10

我有一个使用 bar3 plot 命令生成的二维直方图(图是 3D - 几个并排绘制的直方图)。但是,所有零值在 xy 平面中都显示为扁平正方形。有没有办法阻止 MATLAB 显示这些值?我已经尝试用 NaN 替换所有零,但它并没有改变情节的任何内容。这是我一直在尝试的代码:

x1=normrnd(50,15,100,1); %generate random data to test code
x2=normrnd(40,13,100,1);
x3=normrnd(65,12,100,1);

low=min([x1;x2;x3]);
high=max([x1;x2;x3]);
y=linspace(low,high,(high-low)/4); %establish consistent bins for histogram
z1=hist(x1,y);
z2=hist(x2,y);
z3=hist(x3,y);
z=[z1;z2;z3]';
bar3(z)

如您所见,图中有很多零值。在用 NaN 替换零后关闭图形并重新绘制似乎没有任何改变:

close
z(z==0)=NaN;
bar3(z)
4

3 回答 3

13

一种解决方案是修改由bar3. 首先,您必须获取从以下位置返回的句柄bar3

h = bar3(z);

在您的情况下,h将是一个 3 元素的句柄向量,每组彩色条一个。然后,以下代码应使计数为零的 bin 不可见:

for i = 1:numel(h)
  index = logical(kron(z(:, i) == 0, ones(6, 1)));
  zData = get(h(i), 'ZData');
  zData(index, :) = nan;
  set(h(i), 'ZData', zData);
end

这是一个插图(带有强制性的徒手圆圈):

在此处输入图像描述

这个怎么运作...

如果您的 bin 计数向量是N-by-1bar3则将绘制6*N矩形块(即每个 bin 的长方体的 6 个面)。'ZData'因此,每组补丁对象的属性h将是(6*N)-by-4,因为每个矩形面有 4 个角。因此,每个属性的 6 行集群'ZData'是一组 z 坐标,用于一个 bin 的 6 个面。

kron上面的代码首先创建一个逻辑向量,其中 bin 计数等于 0 的所有地方都是一个,然后使用该函数将该向量的每个元素复制 6 次。这成为'ZData'属性行的索引,并且该索引用于将 z 坐标设置nan为空箱的补丁。这将导致补丁不被渲染。


编辑:

'ZData'这是代码的略微修改版本,它通过从绘制的条形的属性中获取条形高度使其更通用,因此它工作所需的只是从bar3. 我还将代码包装在一个函数中(没有错误和输入检查):

function remove_empty_bars(hBars)
  for iSeries = 1:numel(hBars)
    zData = get(hBars(iSeries), 'ZData');  % Get the z data
    index = logical(kron(zData(2:6:end, 2) == 0, ones(6, 1)));  % Find empty bars
    zData(index, :) = nan;                 % Set the z data for empty bars to nan
    set(hBars(iSeries), 'ZData', zData);   % Update the graphics objects
  end
end
于 2010-01-12T16:51:58.070 回答
7

这是一个示例,显示如何隐藏零值条。我们从一个正常的BAR3图开始:

x = 1:7;
Y = jet(numel(x));
h = bar3(x,Y,'detached');
xlabel x; ylabel y; zlabel z; box on;

前

请注意,该变量h包含一个句柄数组surface(在这种情况下为 3 个,每个“组”条对应一个。这些组对应于Y矩阵的列,每个由不同的颜色表示)。

现在隐藏零值的代码:

for i=1:numel(h)
    %# get the ZData matrix of the current group
    Z = get(h(i), 'ZData');

    %# row-indices of Z matrix. Columns correspond to each rectangular bar
    rowsInd = reshape(1:size(Z,1), 6,[]);

    %# find bars with zero height
    barsIdx = all([Z(2:6:end,2:3) Z(3:6:end,2:3)]==0, 2);

    %# replace their values with NaN for those bars
    Z(rowsInd(:,barsIdx),:) = NaN;

    %# update the ZData
    set(h(i), 'ZData',Z)
end

后

解释:

对于每组条形图,surface都会创建一个图形对象(句柄存储在 中h(i))。它的 Z 坐标矩阵ZData表示为一个6*N-by-4矩阵(对于XDataYDataCData矩阵也是一样的),其中 N 是每组中矩形条的数量,或者在上面的示例中为 7。

这样,每个矩形都用 6x4 矩阵表示(每个 X/Y/Z 坐标一个)。例如,一个这样的矩形的坐标如下所示:

>> xx = get(h(3),'XData'); yy = get(h(3),'YData'); zz = get(h(3),'ZData');

>> xx(1:6,:)
ans =
          NaN          2.6          3.4          NaN
          2.6          2.6          3.4          3.4
          2.6          2.6          3.4          3.4
          NaN          2.6          3.4          NaN
          NaN          2.6          3.4          NaN
          NaN          NaN          NaN          NaN

>> yy(1:6,:)
ans =
          NaN          0.6          0.6          NaN
          0.6          0.6          0.6          0.6
          1.4          1.4          1.4          1.4
          NaN          1.4          1.4          NaN
          NaN          0.6          0.6          NaN
          NaN          NaN          NaN          NaN

>> zz(1:6,:)
ans =
          NaN            0            0          NaN
            0            1            1            0
            0            1            1            0
          NaN            0            0          NaN
          NaN            0            0          NaN
          NaN          NaN          NaN          NaN

每一列的第二列沿着左面追踪点,第三列沿着右面追踪点,当两者连接时,将绘制矩形的 4 个面:

>> surface(xx(1:6,2:3), yy(1:6,2:3), zz(1:6,2:3), cc(1:6,2:3))
>> view(3)

矩形表面

第一列和最后一列将通过闭合矩形的边来绘制剩余的两个面。

所有这些矩阵都连接为一个高矩阵,并且所有矩形都是使用单个表面对象绘制的。这是通过使用NaN值来分隔不同部分来实现的,既在同一矩形的点内,也在不同的矩形之间。

因此,上面的代码所做的是寻找 Z 高度为零的矩形,并将其所有值替换NaN为有效地告诉 MATLAB 不要绘制由这些点形成的表面的值。

于 2013-07-04T19:52:48.313 回答
1

我的问题不是零值,而是 NaN 值(在 bar3 内转换为零值)。我想继续显示值为 0 的元素,而不是值为 nan 的元素。我稍微调整了代码,效果很好:

for i = 1:numel(h)
  index = logical(kron(isnan(z(:,i)),ones(6,1)));
  zData = get(h(i),'ZData');
  zData(index,:) = nan;
  set(h(i),'ZData',zData);
end

谢谢!

于 2011-04-29T09:51:16.560 回答