我想绘制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而言,效率更高) 。
该功能可以通过使用XData
,YData
,ZData
和CData
属性而不是Vertices
和Faces
属性指定形成多边形的连接顶点的坐标来实现。实际上,这就是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.4和3.8.1中测试了该功能,并且工作正常。如果运行上面显示的示例,您会发现某些高级3D功能尚未在Octave中正确实现(这包括透明度,照明等)。我还使用了Octave中不可用的函数(例如
membrane
和spiral
)来构建示例矩阵,但是这些对代码不是必不可少的,只需将它们替换为您自己的数据即可:)