我想绘制3D直方图(使用gnuplot或倍频程)以表示我的数据。
可以说我有以下格式的数据文件:

2 3 4
8 4 10
5 6 7

我想在集合[1,3] x [1,3]中绘制九个彩色条(矩阵的大小),以使条的颜色与条的高度成比例。我怎样才能做到这一点?

最佳答案

下面是我实现的函数,该函数充当 bar3 的替代品(部分)。

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

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

顶点/面矩阵以矢量化方式构建(看起来像ma,没有循环!),结果是为所有条形绘制了一个 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很容易;这是一个使用coloring mode匹配bar3 indexed color mapping (scaled)的示例:
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 colorbar穿过jet调色板,而不是从底部的蓝色到上面定义的高度的任何颜色的渐变。有关更多详细信息,请参见this post

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

10-08 17:40