【问题标题】:How to position an axes in a figure relative to another axes?如何相对于另一个轴定位图中的轴?
【发布时间】:2011-10-30 03:22:51
【问题描述】:

在 MATLAB 中布置图形时,键入 axis equal 可确保无论 图形 尺寸如何, 始终是正方形:

我目前的问题是我想在这个图中添加第二个轴。通常,这没问题。我只需输入axes([x1 y1 x2 y2]),然后会添加一个新的正方形图形,并在(x1, y1), (x2, y2) 处添加角,这是相对于图形的固定位置。问题是,我希望这个新轴位于相对于 第一个轴的固定位置。

所以,我的问题是:

  1. 有谁知道如何通过指定相对于其他轴的位置来定位图中的轴?
  2. 假设我可以做到 1,即使我调整了图形大小,如何让这个新轴保持在同一个位置?

【问题讨论】:

  • 问题不是很清楚,你到底是怎么产生上图的?您是否为每个小图像添加axes,并设置其position 属性?关于axis image 的部分也令人困惑,它是应用于每个小轴,还是适用于包含所有其他轴的大轴?您绝对应该发布您的代码以获得更好的帮助..
  • @amro - :) 我实际上用提供的代码明确回答了你的问题; image 函数比大多数人熟悉的要复杂。不过,我同意你的看法,这个问题写得不好。我要完全重写它。
  • @amro - 我改变了很多东西,请再检查一遍,如果需要进一步澄清,请告诉我。
  • 谢谢它现在更清楚了。无论哪种方式,我都尝试在下面的帖子中回答两个版本的问题。

标签: image matlab figure


【解决方案1】:

position property 相对于其父容器。因此,一种可能性是创建一个与第一个轴大小相同的透明panel,然后在其中创建第二个轴,并根据需要设置其位置和大小。指定的位置就好像它是相对于第一个轴一样。

现在我们需要始终保持面板与第一个轴的大小/位置相同。通常这可以使用LINKPROP 来完成,它将多个图形对象(面板和轴)的属性链接为相同,即'Position' 属性。

但是,这在您的情况下会失败:当调用 axis image 时,它会通过设置像 'PlotBoxAspectRatio''DataAspectRatio' 这样的纵横比属性来将数据单元固定为在每个方向上都相同。不幸的是,'Position' 属性不会反映大小的变化,从而破坏了上述解决方案。这是一个说明问题的示例:如果您在发出axis image 调用之前/之后查询位置属性,它将是相同的:

figure, plot(1:10,1:10)
get(gca,'Position')
pause(1)
axis image
get(gca,'Position')

对我们来说幸运的是,在 FEX (plotboxpos) 上有一个提交解决了这个确切的问题,并返回了轴绘图区域的实际位置。一旦我们有了它,这就是将面板位置与轴位置同步的问题。一个技巧是为轴改变大小时创建一个事件侦听器(it appears'TightInset' 属性与'Position' 属性不同,因此在我们的例子中这可能是触发器)。

为了方便起见,我将上面的内容包装在一个函数 AXESRELATIVE 中:您可以像调用内置函数 AXES 一样调用它。唯一的区别是你给它作为第一个参数你想要相对定位新创建的轴的轴的句柄。它返回新轴及其包含面板的句柄。

这是一个示例用法:

%# automatic resize only works for normalized units
figure
hParentAx = axes('Units','normalized');
axis(hParentAx, 'image')

%# create a new axis positioned at normalized units with w.r.t the previous axis
%# the axis should maintain its relative position on resizing the figure
[hAx hPan] = axesRelative(hParentAx, ...
    'Units','normalized', 'Position',[0.7 0.1 0.1 0.1]);
set(hAx, 'Color','r')

以及功能实现:

function [hAx hPan] = axesRelative(hParentAx, varargin)
    %# create panel exactly on top of parent axis
    s = warning('off', 'MATLAB:hg:ColorSpec_None');
    hPan = uipanel('Parent',get(hParentAx, 'Parent'), ...
        'BorderType','none', 'BackgroundColor','none', ...
        'Units',get(hParentAx,'Units'), 'Position',plotboxpos(hParentAx));
    warning(s)

    %# sync panel to always match parent axis position
    addlistener(handle(hParentAx), ...
        {'TightInset' 'Position' 'PlotBoxAspectRatio' 'DataAspectRatio'}, ...
        'PostSet',@(src,ev) set(hPan, 'Position',plotboxpos(hParentAx)) );

    %# create new axis under the newly created panel
    hAx = axes('Parent',hPan, varargin{:});
end


在完全不同的情况下:在您最近编辑之前,我的印象是您正在尝试生成图像散点图(即像通常的散点图,但使用完整图像而不是点)。

您的建议(据我了解)是为每个图像创建一个轴,并将其位置设置为与该点的 x/y 坐标相对应。

我的解决方案是使用IMAGE/IMAGESC 函数并通过显式设置'XData''YData' 属性来适当地移动和缩放图像来绘制小图像。这样做的好处是它需要一个单轴,并且不必处理调整大小的问题..

这是一个示例实现:

%# create fan-shaped coordinates
[R,PHI] = meshgrid(linspace(1,2,5), linspace(0,pi/2,10));
X = R.*cos(PHI); Y = R.*sin(PHI);
X = X(:); Y = Y(:);
num = numel(X);

%# images at each point (they don't have to be the same)
img = imread('coins.png');
img = repmat({img}, [num 1]);

%# plot scatter of images
SCALE = 0.2;             %# image size along the biggest dimension
figure
for i=1:num
    %# compute XData/YData vectors of each image
    [h w] = size(img{i});
    if h>w
        scaleY = SCALE;
        scaleX = SCALE * w/h;
    else
        scaleX = SCALE; 
        scaleY = SCALE * h/w;
    end
    xx = linspace(-scaleX/2, scaleX/2, h) + X(i);
    yy = linspace(-scaleY/2, scaleY/2, w) + Y(i);

    %# note: we are using the low-level syntax of the function
    image('XData',xx, 'YData',yy, 'CData',img{i}, 'CDataMapping','scaled')
end
axis image, axis ij
colormap gray, colorbar
set(gca, 'CLimMode','auto')

【讨论】:

  • 感谢您指出 FEx 上的文件。回复:第二点,我们实际上是在做你发布的事情;在一个轴上绘制多个图像。但是,确实需要一个不使用主轴的图,这就是我在这个问题中所指的那个。谢谢!
【解决方案2】:

这通常是您可以使用自定义'ResizeFcn' 为您的图形处理的事情,它将调整较小轴相对于较大轴的位置和大小。这是一个调整大小函数的示例,它保持子轴的大小,使其始终为较大方轴大小的 15%,并位于右下角:

function resizeFcn(src,event,hAxes,hSubAxes)

  figurePosition = get(get(hAxes,'Parent'),'Position');
  axesPosition = get(hAxes,'Position').*figurePosition([3 4 3 4]);
  width = axesPosition(3);
  height = axesPosition(4);
  minExtent = min(width,height);
  newPosition = [axesPosition(1)+(width-minExtent)/2+0.8*minExtent ...
                 axesPosition(2)+(height-minExtent)/2+0.05*minExtent ...
                 0.15*minExtent ...
                 0.15*minExtent];
  set(hSubAxes,'Units','pixels','Position',newPosition);

end

下面是它的使用示例:

hFigure = figure('Units','pixels');  %# Use pixel units for figure
hAxes = axes('Units','normalized');  %# Normalized axes units so it auto-resizes
axis(hAxes,'image');                 %# Make the axes square
hSubAxes = axes('Units','pixels');   %# Use pixel units for subaxes
set(hFigure,'ResizeFcn',{@resizeFcn,hAxes,hSubAxes});  %# Set resize function

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-07-03
    • 1970-01-01
    • 2014-06-07
    • 2013-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多