Как позиционировать оси на фигуре относительно других осей? - PullRequest
8 голосов
/ 19 августа 2011

При размещении фигуры в MATLAB ввод axis equal гарантирует, что независимо от размеров фигуры оси всегда будут квадратными:

enter image description here

Моя текущая проблема заключается в том, что я хочу добавить вторые оси к этому графику. Обычно это не проблема; Я просто набрал бы axes([x1 y1 x2 y2]), и была бы добавлена ​​новая квадратная фигура с углами в (x1, y1), (x2, y2), которая является фиксированным местоположением относительно фигуры . Проблема в том, что я хочу, чтобы эти новые оси располагались в фиксированном месте относительно по отношению к первым осям .

Итак, мои вопросы:

  1. Кто-нибудь знает, как я могу расположить оси на фигуре, указав расположение относительно других осей?
  2. Предполагая, что я могу сделать 1, как я могу, чтобы эти новые оси оставались в том же месте, даже если я изменяю размер фигуры?

Ответы [ 2 ]

13 голосов
/ 24 августа 2011

Ось свойство позиции относительно его родительского контейнера.Следовательно, одна из возможностей - создать прозрачную панель того же размера, что и первая ось, затем внутри нее создать вторую ось и при необходимости установить ее местоположение и размер.Указанная позиция будет выглядеть так, как если бы она была относительно первой оси.

Теперь нам нужно всегда поддерживать размер панели / тот же размер / расположение, что и у первой оси.Обычно это можно сделать с помощью LINKPROP , который связывает свойство нескольких графических объектов (панель и ось) как одно и то же, а именно свойство 'Position'.

Однако это может произойти сбой вВаш случай: при вызове axis image он фиксирует одинаковые единицы измерения в каждом направлении, устанавливая свойства формата изображения, такие как 'PlotBoxAspectRatio' и 'DataAspectRatio'.Печальная новость заключается в том, что свойство 'Position' не будет отражать изменение размера, что нарушит вышеуказанное решение.Вот пример, иллюстрирующий проблему: если вы запросите свойство position до / после вызова axis image, оно будет таким же:

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

К счастью для нас, на FEX есть представление( plotboxpos ), которая решает эту точную проблему и возвращает фактическое положение области построения оси.Как только мы это получим, нужно синхронизировать положение панели с положением оси.Одна хитрость заключается в создании прослушивателя событий, когда ось меняет размер ( кажется, , что свойство '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

axesRelative


На совершенно другом замечании: перед вашим недавним редактированием у меня сложилось впечатление, что вы пытались создать точечный график изображений (то есть, как обычный точечный график, но с полными изображениями вместоточек).

То, что вы предложили (насколько я понимаю), создает одну ось для каждого изображения и устанавливает ее положение, соответствующее координатам 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')

image_scatter

4 голосов
/ 23 августа 2011

Это обычно то, о чем вы можете позаботиться с помощью пользовательской '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
...