【问题标题】:3D histogram with gnuplot or octave带有 gnuplot 或 octave 的 3D 直方图
【发布时间】:2014-08-02 13:42:27
【问题描述】:

我想绘制一个 3D 直方图(使用 gnuplot 或 octave)来表示我的数据。 假设我有一个格式如下的数据文件:

2 3 4    
8 4 10    
5 6 7

我想在集合 [1,3]x[1,3] 中绘制九个彩色条(矩阵的大小),这样条的颜色与条的高度成正比。我该怎么做?

【问题讨论】:

  • 如何使用interp2 和最近邻插值将数据从 3×3 重新采样为 300×300,然后只使用 surf
  • @Dan 你为什么要添加 matlab 标签?
  • @TomFenech Matlab 和 Octave 共享相同的语法和功能,并且 Matlab 拥有更大的 SO 社区,因此它应该会增加获得好的解决方案的机会
  • @Dan 我没有意识到他们是如此相似。我想如果确定一个有效的 MATLAB 答案也可以在 Octave 上工作,那么这很公平。
  • @TomFenech 不确定,但极有可能

标签: matlab gnuplot histogram octave


【解决方案1】:

你看过this tutorial on bar3吗?

稍微调整一下:

Z=[2 3 4
   8 4 10
   5 6 7]; % input data
figure; 
h = bar3(Z); % get handle to graphics
for k=1:numel(h), 
    z=get(h(k),'ZData'); % old data - need for its NaN pattern
    nn = isnan(z); 
    nz = kron( Z(:,k),ones(6,4) ); % map color to height 6 faces per data point 
    nz(nn) = NaN; % used saved NaN pattern for transparent faces 
    set(h(k),'CData', nz); % set the new colors
end
colorbar;

这就是你最后得到的:

【讨论】:

  • Matlab 的绝佳解决方案 - 但看起来 bar3 不存在 Octave :(
【解决方案2】:

我无法访问 Octave,但我相信这应该可以解决问题:

Z = [2 3 4
     8 4 10
     5 6 7];

[H W] = size(Z);

h = zeros( 1, numel(Z) ); 
ih = 1;
for ix = 1:W
    fx = ix-.45;
    tx = ix+.45;
    for iy = 1:W
        fy = iy-.45;
        ty = iy+.45;      

        vert = [ fx fy 0;...
            fx ty 0;...
            tx fy 0;...
            tx ty 0;...
            fx fy Z(iy,ix);...
            fx ty Z(iy,ix);...
            tx fy Z(iy,ix);...
            tx ty Z(iy,ix)];
        faces = [ 1 3 5;...
            5 3 7;...
            7 3 4;...
            7 8 4;...
            5 6 7;...
            6 7 8;...
            1 2 5;...
            5 6 2;...
            2 4 8;...
            2 6 8];

        h(ih) = patch( 'faces', faces, 'vertices', vert, 'FaceVertexCData', Z(iy,ix),...
            'FaceColor', 'flat', 'EdgeColor','none' );
        ih = ih+1;
    end
end
view( 60, 45 );
colorbar;

【讨论】:

  • @Dan - 你能在 Octave 上查看这个吗?
  • 我也没有安装 Octave。我通常会在这里查看:compileonline.com/execute_matlab_online.php,但它并不总是绘制图表。它不会出错,所以很有希望。
  • 你能解释一下你的faces矩阵吗?
  • @Dan a face 是一个顶点列表,我怀疑 octave 不支持非平面的面,因此这里的所有面都是三角形(3 个顶点)。每个三角形面(faces 的行)索引vert 中的三行。因此,面[1 3 5] 是连接第一个、第三个和第五个顶点的三角形。
  • 我没有 Octave 可以检查。好的,我明白了,每个条形图有 10 个三角形 - 谢谢。
【解决方案3】:

我认为以下应该可以解决问题。我没有使用比colormapsurfpatch 更复杂的东西,据我所知,它们在 Octave 中应该都可以正常工作。

代码:

%# Your data
Z = [2 3 4
    8 4 10
    5 6 7];


%# the "nominal" bar (adjusted from cylinder())
n = 4;
r = [0.5; 0.5];
m = length(r);
theta = (0:n)/n*2*pi + pi/4;

sintheta = sin(theta); sintheta(end) = sqrt(2)/2;

x0 = r * cos(theta);
y0 = r * sintheta;
z0 = (0:m-1)'/(m-1) * ones(1,n+1);

%# get data for current colormap
map = colormap;
Mz = max(Z(:));
mz = min(Z(:));

% Each "bar" is 1 surf and 1 patch
for ii = 1:size(Z,1)
    for jj = 1:size(Z,2)

        % Get color (linear interpolation through current colormap)
        cI = (Z(ii,jj)-mz)*(size(map,1)-1)/(Mz-mz) + 1;
        fC = floor(cI);
        cC = ceil(cI);
        color = map(fC,:) + (map(cC,:) - map(fC,:)) * (cI-fC);

        % Translate and rescale the nominal bar
        x = x0+ii;
        y = y0+jj;
        z = z0*Z(ii,jj);

        % Draw the bar
        surf(x,y,z, 'Facecolor', color)
        patch(x(end,:), y(end,:), z(end,:), color)

    end
end

结果:

我如何生成“标称条”是基于 MATLAB 的 cylinder() 中的代码。一件很酷的事情是你可以很容易地制作出更时髦的酒吧:

这是通过更改生成的

n = 4;
r = [0.5; 0.5];

进入

n = 8;
r = [0.5; 0.45; 0.2; 0.1; 0.2; 0.45; 0.5];

【讨论】:

  • @Dan:你能验证这在 Octave(或其在线版本)上是否正常工作吗?
  • 在线版本没有错误,但不幸的是我无法检查它是否制作了正确的情节。我会怀疑,如果它没有出错,那么它确实可以工作,但恐怕我无法真正检查。不过看起来是个不错的解决方案!
  • fwiw,我得到了一个带有此代码的黄色大框。
  • @StevenLu 你有什么 MATLAB 版本?
  • 我没有。使用八度。我希望它能在 MATLAB 上完美运行。
【解决方案4】:

仅使用 OCTAVE 中可用功能的解决方案,已使用 octave-online 进行测试

此解决方案以类似于 Matlabs hist3d 函数内部的方式生成表面。

简而言之:

  • 创建一个具有 4 个点的曲面,每个点的“高度” 值,绘制在每个 bin 边缘。
  • 每个都被零包围,它们也在每个 bin 边缘绘制。
  • 颜色设置为基于 bin 值并应用于 4 个点和周围的零点。 (以便“条”的边缘和顶部的颜色与“高度”相匹配。)

对于以包含 bin 高度的矩阵形式给出的数据(代码中的 bin_values):

代码

bin_values=rand(5,4); %some random data

bin_edges_x=[0:size(bin_values,2)]; 
x=kron(bin_edges_x,ones(1,5));
x=x(4:end-2);

bin_edges_y=[0:size(bin_values,1)]; 
y=kron(bin_edges_y,ones(1,5));
y=y(4:end-2);

mask_z=[0,0,0,0,0;0,1,1,0,0;0,1,1,0,0;0,0,0,0,0;0,0,0,0,0];
mask_c=ones(5);
z=kron(bin_values,mask_z);
c=kron(bin_values,mask_c);

surf(x,y,z,c)

输出

【讨论】:

  • 太棒了。条形之间可以添加任何空间/填充吗? (不过没什么大不了的)
【解决方案5】:

下面是我实现的一个函数,它充当bar3 替换(部分)。

在我的版本中,条形图通过创建patch graphics object 来呈现:我们构建了vertex coordinates and a list of faces connecting those vertices 的矩阵。

我们的想法是首先构建一个“3d 立方体”作为模板,然后将其复制到尽可能多的条形图上。每个条都根据其位置和高度进行移动和缩放。

顶点/面矩阵以矢量化方式构造(看,没有循环!),结果是为所有条绘制单个patch object,而不是每个条绘制多个补丁(这更有效就graphics performance而言)。

该函数可以通过使用XDataYDataZDataCData 属性而不是VerticesFaces 属性来指定形成多边形的连接顶点的坐标来实现。事实上,这就是bar3 内部所做的。这种方法通常需要更大的数据来定义补丁(因为我们不能在补丁面上共享点,尽管在我的实现中我不太关心这一点)。这是related post,我试图解释bar3构造的数据的结构。

my_bar3.m

function pp = my_bar3(M, width)
    % MY_BAR3  3D bar graph.
    %
    % M     - 2D matrix
    % width - bar width (1 means no separation between bars)
    %
    % See also: bar3, hist3

    %% construct patch
    if nargin < 2, width = 0.8; end
    assert(ismatrix(M), 'Matrix expected.')

    % size of matrix
    [ny,nx] = size(M);

    % first we build a "template" column-bar (8 vertices and 6 faces)
    % (bar is initially centered at position (1,1) with width=? and height=1)
    hw = width / 2;    % half width
    [X,Y,Z] = ndgrid([1-hw 1+hw], [1-hw 1+hw], [0 1]);
    v = [X(:) Y(:) Z(:)];
    f = [
        1 2 4 3 ; % bottom
        5 6 8 7 ; % top
        1 2 6 5 ; % front
        3 4 8 7 ; % back
        1 5 7 3 ; % left
        2 6 8 4   % right
    ];

    % replicate vertices of "template" to form nx*ny bars
    [offsetX,offsetY] = meshgrid(0:nx-1,0:ny-1);
    offset = [offsetX(:) offsetY(:)]; offset(:,3) = 0;
    v = bsxfun(@plus, v, permute(offset,[3 2 1]));
    v = reshape(permute(v,[2 1 3]), 3,[]).';

    % adjust bar heights to be equal to matrix values
    v(:,3) = v(:,3) .* kron(M(:), ones(8,1));

    % replicate faces of "template" to form nx*ny bars
    increments = 0:8:8*(nx*ny-1);
    f = bsxfun(@plus, f, permute(increments,[1 3 2]));
    f = reshape(permute(f,[2 1 3]), 4,[]).';

    %% plot
    % prepare plot
    if exist('OCTAVE_VERSION','builtin') > 0
        % If running Octave, select OpenGL backend, gnuplot wont work
        graphics_toolkit('fltk');
        hax = gca;
    else
        hax = newplot();
        set(ancestor(hax,'figure'), 'Renderer','opengl')
    end


    % draw patch specified by faces/vertices
    % (we use a solid color for all faces)
    p = patch('Faces',f, 'Vertices',v, ...
        'FaceColor',[0.75 0.85 0.95], 'EdgeColor','k', 'Parent',hax);
    view(hax,3); grid(hax,'on');
    set(hax, 'XTick',1:nx, 'YTick',1:ny, 'Box','off', 'YDir','reverse', ...
        'PlotBoxAspectRatio',[1 1 (sqrt(5)-1)/2]) % 1/GR (GR: golden ratio)

    % return handle to patch object if requested
    if nargout > 0
        pp = p;
    end
end

这是一个与 MATLAB 中的内置 bar3 函数进行比较的示例:

subplot(121), bar3(magic(7)), axis tight
subplot(122), my_bar3(magic(7)), axis tight

请注意,我选择用单一纯色着色所有条形(类似于 hist3 函数的输出),而 MATLAB 用匹配的颜色强调矩阵的列。

虽然customize the patch 很容易;这是一个使用 indexed color mapping (scaled) 匹配 bar3 coloring mode 的示例:

M = membrane(1); M = M(1:3:end,1:3:end);
h = my_bar3(M, 1.0);

% 6 faces per bar
fvcd = kron((1:numel(M))', ones(6,1));
set(h, 'FaceVertexCData',fvcd, 'FaceColor','flat', 'CDataMapping','scaled')

colormap hsv; axis tight; view(50,25)
set(h, 'FaceAlpha',0.85)   % semi-transparent bars

或者说您想使用gradient according to their heights 为条形着色:

M = 9^2 - spiral(9);
h = my_bar3(M, 0.8);

% use Z-coordinates as vertex colors (indexed color mapping)
v = get(h, 'Vertices');
fvcd = v(:,3);
set(h, 'FaceVertexCData',fvcd, 'FaceColor','interp')

axis tight vis3d; daspect([1 1 10]); view(-40,20)
set(h, 'EdgeColor','k', 'EdgeAlpha',0.1)

请注意,在最后一个示例中,"Renderer" property of the figure 会影响渐变的外观。在 MATLAB 中,“OpenGL”渲染器将沿 RGB 颜色空间插入颜色,而其他两个渲染器(“Painters”和“ZBuffer”)将插入当前使用的颜色图的颜色(因此直方图条看起来像 mini @ 987654358@s 穿过jet 调色板,而不是从底部的蓝色渐变到定义高度的任何颜色,如上所示)。详情请见this post


我已经在 Windows 上运行的 Octave 3.6.43.8.1 中测试了该函数,并且运行良好。如果您运行我上面展示的示例,您会发现一些高级 3D 功能尚未在 Octave 中正确实现(包括透明度、照明等)。此外,我还使用了 Octave 中不可用的函数,例如 membranespiral 来构建示例矩阵,但这些对代码来说不是必需的,只需将它们替换为您自己的数据即可 :)

【讨论】:

  • 太棒了。但是为什么不将高度着色条作为 C 数据的额外参数合并到函数中呢?
  • @Dan:你的意思是你想调用函数为my_bar3(Z,C),其中C(一个与Z相同大小的矩阵)用于给条形着色?我想它可以做到,但bar3(我试图复制)不提供这样的语法。另外,我不想处理所有可能的调用选项,因为它会使代码太长(我们必须检查 C 是否通过,我们假设 C=Z 是否丢失或者我们应该使用单一颜色对于所有条形?另外决定是否应该使用C 来指定渐变,或者用于具有纯色的条形).. 至少我在示例中展示了如何做一些:)
  • 我想的更像my_bar3(Z, width, C),所以它仍然可以像bar3一样使用。我认为默认的C 可以是您的函数现在创建的一种纯色。我并没有真正考虑渐变与实体的问题......
  • @Dan:好的,这是合并颜色参数的一种可能方法:pastebin.com/HL9UtY2N(差异/补丁文件)。现在您可以通过以下方式调用该函数:my_bar3(M,w)(默认纯色)、my_bar3(M,w,rand(1,3))my_bar3(M,w,'red')(用户提供的纯色)、my_bar3(M,w,rand(size(M)))(使用索引映射作为渐变的每条颜色)当前颜色图)或my_bar3(M,w,rand(numel(M),3))(纯色,每条一行,由真彩色矩阵表示)。
猜你喜欢
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-04
  • 1970-01-01
  • 2014-08-04
  • 1970-01-01
相关资源
最近更新 更多