在MATLAB中将坐标轴与绘图区分离

5
我发现坐标轴上或附近的数据点很难看到。当然,显而易见的修复方法是简单地使用axis([xmin xmax ymin ymax])更改绘图区域,但并非所有情况下都适用;例如,如果x轴代表时间,则将最小值x移动到-1以显示0处的活动是没有意义的。
相反,我希望能够简单地将x和y轴移离绘图区域,就像我在这里所做的一样:left: Matlab generated, right: desired (image editing software) 左:MATLAB生成,右:期望(图像处理软件)
有办法在MATLAB中自动执行此操作吗?我认为可以通过使用outerposition轴属性来实现(即将其设置为[0 0 0.9 0.9]并在原始位置绘制新的轴?),但我没有从那个策略中得到任何进展。

另一个选项可能是类似于 axis([minx-minx/10 maxx miny maxy]) 或者其他因素而不是1/10。 - shamalaia
4个回答

5
这里已经有一些回答向您展示了大部分方法 - 这是将x和y轴根据您提供的示例分离的最后一步。
f = figure ( 'color', 'white' );
% create the axes and set some properties
ax = axes ( 'parent', f, 'box', 'off', 'nextplot', 'add', 'XMinorTick', 'on', 'YMinorTick', 'on' );
% plot some data
plot ( ax, 0:10, [0:10].^2, 'rx-' )
% modify the x and y limits to below the data (by a small amount)
ax.XLim(1) = ax.XLim(1)-(ax.XTick(2)-ax.XTick(1))/4;
ax.YLim(1) = ax.YLim(1)-(ax.YTick(2)-ax.YTick(1))/4;
% Set the tick direction
ax.TickDir = 'out';
% draw the plot to generate the undocumented vertex data var
drawnow()

%% R2015a
% X, Y and Z row of the start and end of the individual axle.
ax.XRuler.Axle.VertexData(1,1) = 0;
ax.YRuler.Axle.VertexData(2,1) = 0;


%% R2015b
% extract the x axis vertext data
% X, Y and Z row of the start and end of the individual axle.
vd = get(ax.XAxis.Axle,'VertexData');
% reset the zero value
vd(1,1) = 0;
% Update the vertex data
set(ax.XAxis.Axle,'VertexData',vd);
% repeat for Y (set 2nd row)
vd = get(ax.YAxis.Axle,'VertexData');
vd(2,1) = 0;
set(ax.YAxis.Axle,'VertexData',vd);
编辑:每当坐标轴/图形更改大小或缩放或平移时,顶点是Matlab重新创建的内容。

你可以尝试通过添加监听器来捕捉这个变化(请记住,此处使用了不记录在案的功能)。我们可以使用MarkedClean事件,该事件被调用多次。

addlistener ( ax, 'MarkedClean', @(obj,event)resetVertex(ax) );

如果你的resetVertex函数类似于以下代码:(仅显示R2015b版本)

function resetVertex(ax)
    % ...
end

编辑2:添加了关闭小于0的次刻度线的代码。

function resetVertex ( ax )
  % extract the x axis vertext data
  % X, Y and Z row of the start and end of the individual axle.
  ax.XAxis.Axle.VertexData(1,1) = 0;
  % repeat for Y (set 2nd row)
  ax.YAxis.Axle.VertexData(2,1) = 0;

  % You can modify the minor Tick values by modifying the vertex data
  % for them, e.g. remove any minor ticks below 0 
  ax.XAxis.MinorTickChild.VertexData(:,ax.XAxis.MinorTickChild.VertexData(1,:)<0) = [];
  ax.YAxis.MinorTickChild.VertexData(:,ax.YAxis.MinorTickChild.VertexData(2,:)<0) = [];
end

在这里输入图片描述

注意:此方法使用了未经文档记录的功能,因此可能仅适用于某些版本的Matlab(我已添加了r2015a和r2015b的代码),并且根据您对绘图所做的操作,Matlab可能会重新创建顶点数据。


非常好!但是在2015a版本中无法运行,导致错误:No appropriate method, property, or field 'XAxis' for class 'matlab.graphics.axis.Axes'. - EBH
@matlabgui 首先 - 你是怎么找到这样的功能的?其次 - 我和 @sardar_Usama 有同样的问题,即使只是缩放或平移图形,轴也会重新连接,再运行 ax.XRuler.Axle.VertexData... 这一行代码并不能总是解决问题。 - EBH
无法停止MATLAB重新创建此property或者无法将此property关闭一段时间吗?最新的编辑解决了小图窗口的问题,但当图窗最大化时会出现一些刻度。 - Sardar Usama
1
你正在处理未记录的功能,它们可能会表现出你不希望发生的方式。我怀疑它们不能被关闭,但你可以“与它们共事”... - matlabgui
@matlabgui 我不能说它是完美的,但它是最接近最优的 +1。 - EBH
显示剩余5条评论

2
这里有一个简单的方法来实现这个目标:
% some data:
x = 1:100;
f=@(x) 5.*x;
y=f(x)+rand(1,length(x))*50;
close all
% plotting:
f1 = figure('Color','white');
ax = axes;
plot(ax,x,y,'o');
% 'clean' the data area a little bit:
box off
ax.TickDir = 'out';
% pushing the axis a bit forward:
lims = axis;
pos = ax.Position;
axis([lims(1)-ax.XTick(2)/5 lims(2)+0.1 lims(3)-ax.YTick(2)/5 lims(4)+0.1])
% Create lines
firstXtick = 0.013; %this value need to be adjusted only once per figure
firstYtick = 0.023; %this value need to be adjusted only once per figure
lx = annotation(f1,'line',[pos(1) pos(1)+firstXtick],...
     [pos(2) pos(2)],'Color',[1 1 1],'LineWidth',1);
ly = annotation(f1,'line',[pos(1) pos(1)],...
     [pos(2) pos(2)+firstYtick],'Color',[1 1 1],'LineWidth',1);

这将产生如下图所示的结果: enter image description here 唯一需要调整的是每种图形类型仅需进行一次的firstXtickfirstYtick值,必须对特定坐标轴进行精细调整。设置正确值后,可以轻松调整图形大小。缩放和平移需要进行少量修补。

@achilles和Sardar_Usama,我已经编辑了我的答案,以获得更接近问题中的图形的结果(与matlabgui不同的方式),请告诉我它是否适用于您。 - EBH
这也可以解决问题 -- 抱歉我不能接受两个答案 ... +1 - achilles
@EBH 很棒的注释技巧! 我已经给它投了赞! - Sardar Usama

1

您可以从小于零开始设置坐标轴,然后从图表中删除小于零的刻度。例如:

plot(0:3:30,0:3:30);     %Some random data for plotting
h = gca;
axis([-1 30 -1 30]);     %Setting the axis from less than zero
box off;                 %Removing box
h.TickDir = 'out';       %Setting Direction of ticks to outwards
h.XTickLabel(1)= {' '};  %Removing the first tick of X-axis
h.YTickLabel(1)= {' '};  %Removing the first tick of Y-axis

使用这段代码,您将获得以下结果:

zeromarkmaynotbeincluded

这可能有一个缺点,有时候零刻度也会被移除(如上图所示)。这是因为图表将轴的第一个刻度设置为零。可以通过使用 if 条件来避免这种情况。因此,代码可以修改为以下形式:
plot(0:3:30,0:3:30);
h = gca;
axis([-1 30 -1 30]);
box off;
h.TickDir = 'out';

if str2num(cell2mat(h.XTickLabel(1))) <0
    h.XTickLabel(1)= {' '};
end

if str2num(cell2mat(h.YTickLabel(1))) <0
    h.YTickLabel(1)= {' '};
end

上述代码将产生以下结果:-

zeromarkincluded

此外,请注意,对于您的情况,由于轴刻度非常少,-1 可能不太适合作为轴起始值,您可能需要使用 -0.1,即 axis([-0.1 30 -0.1 30]);

0

通过对@matlabgui的答案进行轻微修改,您可以跟踪(主要)刻度限制:

ax = gca();
% Set the tick direction
ax.TickDir = 'out';
% Make sure this stays when saving, zooming, etc
addlistener ( ax, 'MarkedClean', @(obj,event) change_ticks(ax) );
% Draw the plot to generate the undocumented vertex data variable
% and call callback for the first time
drawnow();

回调函数

function change_ticks( ax )       
    % Modify ruler
    ax.XRuler.Axle.VertexData(1,1) = ax.XTick(1);
    ax.XRuler.Axle.VertexData(1,2) = ax.XTick(end);
    ax.YRuler.Axle.VertexData(2,1) = ax.YTick(1);
    ax.YRuler.Axle.VertexData(2,2) = ax.YTick(end);
end

我没有进行详尽的测试,但似乎也适用于自定义刻度。这样可以很好地将标尺截断,不仅在零点处,而且在第一个和最后一个刻度之外。在Windows上测试过Matlab 2019a,ax.XRuler.Axle.VertexData运行正常。请注意,这仅适用于主要刻度!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接