问题描述
以 SO的示例为例,我想根据当前视图调整轴刻度.这是默认行为,除非有人设置了自己定义的刻度数,
Taking an example from SO, I'd like to adapt the axis ticks dependent on the current view. This is the default behavior, unless one sets a self defined number of ticks,
结果显示在下面的图片中.左侧是默认行为,右侧是带有自定义刻度的图形.当使用自定义的Z
刻度旋转图时,其编号将不适应当前可用空间(请参见右下图).
The resulting behavior is demonstrated in the picture below. On the left side the default behavior, on the right side the figure with self defined ticks. When rotating the plot with the self defined Z
ticks, their number won't be adapted to the currently available space (see right bottom figure).
是否有一个简单,通用的解决方案,而没有像camva()
这样获得当前角度的奇特的东西?我不希望对数据本身进行缩放,因为它是一个很大的数据集,而是要使用自定义的刻度和刻度标签.它需要与MATLAB Version: 8.0.0.783 (R2012b)
一起使用.
Is there a simple, general solution for that without some fancy things like getting current angle by camva()
? I'd wish to not scale the data itself, since it's a big dataset, but to use self defined ticks and tick-labels. It needs to work with MATLAB Version: 8.0.0.783 (R2012b)
.
代码
%# sample graph vertices and edges (similar to your data)
[adj,XYZ] = bucky;
[r, c] = find(adj);
edges = [r c]; %# M-by-2 matrix holding the vertex indices
points = XYZ'; %# 3-by-N matrix of points X/Y/Z coordinates
%# build a list of separated lines
e = edges';
e(end+1,:) = 1;
e = e(:);
p = points(:,e);
p(:,3:3:end) = NaN;
figure
line(p(1,:), p(2,:), p(3,:));
view(3)
% Now the same with self defined ticks
figure
line(p(1,:), p(2,:), p(3,:));
view(3)
z = points(3, :);
fac = 3.14159265359;
tickstep = (max(z)-min(z))/9;
ticklabels_ = min(z):tickstep:max(z);
set(gca, 'ZTick', ticklabels_)
set(gca, 'ZTickLabel', sprintf('%.3f|',ticklabels_))
推荐答案
如注释中@bdecaf所示,您可以为z刻度变化时编写事件处理程序,以便相应地自定义刻度标签.这是使用未记录 .
As indicated by @bdecaf in the comments, you could write an event handler for when the z-ticks change, in order to customize the tick labels accordingly. This is using undocumented functionality.
这很方便,因为我们仍然让MATLAB根据轴的可用屏幕空间自动确定最佳的刻度数,我们只是自定义显示标签的格式.
This is convenient because we still let MATLAB automatically decide on the best number of ticks to use depending on the screen space available for the axis, we just customize the format of the labels displayed.
function customize_ticks_example()
% data
[adj,XYZ] = bucky;
[r,c] = find(adj);
edges = [r c];
points = XYZ';
e = edges';
e(end+1,:) = 1;
e = e(:);
p = points(:,e);
p(:,3:3:end) = NaN;
% plot
hFig = figure;
line(p(1,:), p(2,:), p(3,:), ...
'LineWidth',2, 'Marker','.', 'MarkerSize',20);
ax = handle(gca);
view(3), grid on, box on
xlabel x, ylabel y, zlabel z
rotate3d on
% listen to changes on ZTick property
ev = handle.listener(ax, findprop(ax,'ZTick'), ...
'PropertyPostSet', @onZTickChange);
setappdata(hFig, 'my_ztick_listener', ev);
end
function onZTickChange(~,e)
% get the new 'ZTick', and format them as needed
labels = num2str(e.NewValue(:),'%g $');
% update the 'ZTickLabel'
set(double(e.AffectedObject), 'ZTickLabel',labels)
end
当然标签不必一定是数字的,只要您具有某种比例尺,就可以使用自定义标签来插值以确定要使用的标签.
Of course the labels don't have to be numerical, you could use any custom labels as long as you have some kind of scale along which you can interpolate values to figure what label to use.
设置事件监听器的简便方法:
ev = addlistener(gca, 'ZTick', 'PostSet', @onZTickChange);
(在这种情况下,无需将ev
与setappdata
一起存储在GUI中.此语法将监听器绑定到GUI对象的生命周期.
(in this case, there is no need to store ev
inside the GUI with setappdata
. This syntax bind the listener to the lifecycle of the GUI object).
为回应评论,这是另一个示例:
In response to comments, here is another example:
function example_manual_ticks
%% some 3d plot
hFig = figure;
sphere
view(3), grid on, box on
xlabel x, ylabel y, zlabel z
%% create a hidden copy of the axis
hax1 = gca;
hax2 = copyobj(hax1, hFig);
set(hax2, 'Visible','off', 'Color','none', 'HitTest','off', ...
'XLimMode','manual', 'YLimMode','manual', 'ZLimMode','manual')
delete(get(hax2, 'Children'))
uistack(hax2, 'bottom')
% sync axes on 3d rotation
hlink = linkprop([hax1,hax2], {'CameraPosition','CameraUpVector'});
setappdata(hax1, 'my_axes_linkprop', hlink);
rotate3d on
% respnd to changes in ZTick axis property
ev = addlistener(hax2, 'ZTick', 'PostSet',@(o,e) onZTickChange(o,e,hax1));
%% animation
el = 90 .* sin(linspace(0,2*pi,100) + asin(1/3));
for n=1:numel(el)
view(-37.5, el(n))
drawnow
end
end
function onZTickChange(~,e,ax)
% determine number of ticks
num_ticks = numel(e.NewValue);
new_num_ticks = num_ticks - 1;
% interpolate new ticks along the axis limits
limits = get(ax, 'ZLim');
zticks = linspace(limits(1), limits(2), new_num_ticks);
zticks_labels = num2str(zticks(:), '%.2f ($)');
% update ticks
set(ax, 'ZTick',zticks, 'ZTickLabel',zticks_labels)
drawnow
end
该想法是创建轴的隐藏的副本 ,与原始对象保持3D旋转同步.第二个轴将具有自动刻度线,而我们可以根据需要自定义第一个轴的刻度线(类似于在刻度线更改时在隐藏轴上注册回调的情况).
The idea is to create a hidden copy of the axis, kept in sync with the original one on 3D rotation. This second axis will have automatic tick marks, while we customize the ticks of first axis as we wish (similar to before we register a callback on the hidden axis for when the ticks change).
再次,我使用此隐藏轴作为一种方法,让MATLAB处理确定给定视图的最佳刻度数的任务(这比弄乱相机角度和矩阵变换要容易得多,以便找出答案投影轴的长度(以像素为单位).
Again I'm using this hidden axis as a way to let MATLAB deal with the task of determining the best number of ticks given the view (this is a lot easier than messing with camera angles and matrix transformations in order to find out the length of the projected axis in pixels).
在上面的示例中,我只是将刻度数设置为比自动数({2,4,10}
而不是{3,5,11}
)少一个,但是您可以使用任何想要的映射.
In the example above, I'm simply setting the number of ticks one less than the automatic number ({2,4,10}
instead of {3,5,11}
), but you could use any kind of mapping you want.
这篇关于动态调整自定义刻度的数量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!