Метка подзаговора в цифрах Matlab

Я хотел бы дать подсюжеты я делаю простой ярлык. К сожалению, я получаю уродливое поведение. Рассмотрим следующую функцию:

function h = set_label1(label)
tlh = get(gca, 'Title');
if strcmp(get(tlh, 'String'), '')
    title(' ');
end
ylh = get(gca, 'YLabel');
if strcmp(get(ylh, 'String'), '')
    ylabel(' ');
end

ylp = get(ylh, 'Position');
x = ylp(1);

tlp = get(tlh, 'Position');
y = tlp(2);

h = text('String', label, ...
        'HorizontalAlignment', 'right',...
        'VerticalAlignment', 'Baseline', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Position', [x y 0]);
end

Вот простой тестовый запуск:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
set_label1('A');  

axes(h2);
plot([0 1], [4 5]);
set_label1('B');

Картинка, которую я получаю:

введите здесь описание изображения

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

Проблема, с которой я столкнулся, заключается в том, что я не хочу указывать положение метки в единицах «данных». Вместо этого я хочу использовать нормализованные единицы измерения. Поэтому я использовал модифицированную форму функции. Теперь воспользуемся этим:

function h = set_label2(label)
tlh = get(gca, 'Title');
if strcmp(get(tlh, 'String'), '')
    title(' ');
end
ylh = get(gca, 'YLabel');
if strcmp(get(ylh, 'String'), '')
    ylabel(' ');
end

oldUnits = replace_prop(ylh, 'Units', 'normalized');
ylp = get(ylh, 'Position');
x = ylp(1);
set(ylh, 'Units', oldUnits);

oldUnits = replace_prop(tlh, 'Units', 'normalized');
tlp = get(tlh, 'Position');
y = tlp(2);
set(ylh, 'Units', oldUnits);

h = text('String', label, ...
        'HorizontalAlignment', 'right',...
        'VerticalAlignment', 'Baseline', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Units', 'normalized',...
        'Position', [x y 0]);
end

function oldvalue = replace_prop(handle, propName, newvalue)
oldvalue = get(handle, propName);
set(handle, propName, newvalue);
end

Запуск того же теста:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
set_label2('A');  

axes(h2);
plot([0 1], [4 5]);
set_label2('B');

Получаем точно такую ​​же картину, как и раньше. Единственная проблема в том, что когда мы изменяем его размер, происходит что-то плохое:

введите здесь описание изображения

На самом деле метки находятся в правильном положении. Но кажется, что свойства 'LooseInset' и 'TightInset', которые я использовал, заставляют оси вести себя так, как будто меток нет. Есть ли какое-нибудь решение для этого? На самом деле все, что я делаю, это получаю положение заголовка и ylabel в нормализованных единицах, а не в единицах данных, и это, кажется, все испортило.

Причина, по которой мне нужно получить его в нормализованных единицах, заключается в том, что когда мы получаем трехмерный график, я могу расположить метку относительно заголовка и zlabel.


person jmlopez    schedule 22.06.2012    source источник
comment
Даже если мы удалим код об изменении LooseInset в тестовом коде, мы все равно получим такое же поведение с set_label2.   -  person jmlopez    schedule 22.06.2012
comment
кстати, LooseInset является недокументированным свойством.   -  person Amro    schedule 23.06.2012


Ответы (2)


Во-первых, мне нравится ваша идея использовать title/y-метку для размещения текста в верхнем левом углу, умно :)

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

Поэтому добавьте следующее в конец вашей функции set_label1:

addlistener(ylh, 'Position', 'PostSet', @(o,e) posChanged(o,e,h,1))
addlistener(tlh, 'Position', 'PostSet', @(o,e) posChanged(o,e,h,2))

и вот функция обратного вызова, используемая для обоих случаев (мы используем последний аргумент idx, чтобы контролировать, установить ли координату x или y):

function posChanged(src,evt,hTxt,idx)
    posLabel = evt.NewValue;          %# new position of either title/y-label
    posText = get(hTxt, 'Position');  %# current text position
    posText(idx) = posLabel(idx);     %# update x or y position (based on idx)
    set(hTxt, 'Position',posText)     %# adjust the text position
end
person Amro    schedule 22.06.2012
comment
Спасибо, что показали мне, как добавить слушателя. В конце концов я решил заставить его работать с нормализованными единицами измерения. Но на этот раз я получаю «Положение» и «Внешнее положение» осей. Используя эту информацию, я могу указать расположение метки относительно левого верхнего угла. Таким образом, он также будет работать в 3D. - person jmlopez; 23.06.2012
comment
@jmlopez: ради потомков вы также должны рассмотреть возможность публикации своего нового кода. - person Amro; 23.06.2012
comment
Подойдет, я просто пытаюсь решить одну проблему с прослушивателями событий. - person jmlopez; 23.06.2012
comment
Вопрос... Вы добавляете прослушиватель событий к ylh и tlh. Есть ли способ обратиться к этому прослушивателю событий с учетом ylh объявления tlh. Обратите внимание, что мы не сохраняем его, но я хочу иметь возможность получить такой прослушиватель позже, чтобы я мог его удалить. - person jmlopez; 23.06.2012
comment
@jmlopez: да, просто сохраните возвращаемое значение: lh = addlistener(..);, затем вызовите delete(lh), когда захотите его удалить. - person Amro; 23.06.2012
comment
Это то, чего я не хотел делать... В любом случае, я вернул прослушиватель событий и дескриптор метки в ячейке. - person jmlopez; 23.06.2012
comment
Я разместил свой код. Есть еще некоторые проблемы. Может быть, вы можете улучшить его и исправить то, что я сделал неправильно. Я предпочитаю эту версию, потому что в этом случае все относится к верхнему левому углу исходящих сообщений. Таким образом, это также будет работать, когда мы используем 3D-графику. - person jmlopez; 23.06.2012

Для потомков вот версия, которую я решил использовать. Он делает то, что я от него ожидаю, но теперь у меня есть проблема, которую я не знаю, как решить. Хорошо, сначала хорошие новости, вот функция с именем axes_label.

function c = axes_label(varargin)

if isa(varargin{1}, 'char')
    axesHandle = gca;
else
    axesHandle = get(varargin{1}{1}, 'Parent');
end

if strcmp(get(get(axesHandle, 'Title'), 'String'), '')
    title(axesHandle, ' ');
end
if strcmp(get(get(axesHandle, 'YLabel'), 'String'), '')
    ylabel(axesHandle, ' ');
end
if strcmp(get(get(axesHandle, 'ZLabel'), 'String'), '')
    zlabel(axesHandle, ' ');
end

if isa(varargin{1}, 'char')    
    label = varargin{1};
    if nargin >=2
        dx = varargin{2};
        if nargin >= 3
            dy = varargin{3};
        else
            dy = 0;
        end
    else
        dx = 3;
        dy = 3;
    end
    h = text('String', label, ...
        'HorizontalAlignment', 'left',...
        'VerticalAlignment', 'top', ...
        'FontUnits', 'pixels', ...
        'FontSize', 16, ...
        'FontWeight', 'bold', ...
        'FontName', 'Arial', ...
        'Units', 'normalized');
    el = addlistener(axesHandle, 'Position', 'PostSet', @(o, e) posChanged(o, e, h, dx, dy));
    c = {h, el};
else
    h = varargin{1}{1};
    delete(varargin{1}{2});
    if nargin >= 2    
        if isa(varargin{2}, 'char')
            set(h, 'String', varargin{2});
            if nargin >=3
                dx = varargin{3};
                dy = varargin{4};
            else
                dx = 3;
                dy = 3;
            end
        else
            dx = varargin{2};
            dy = varargin{3};
        end
    else
       error('Needs more arguments. Type help axes_label'); 
    end
    el = addlistener(axesHandle, 'Position', 'PostSet', @(o, e) posChanged(o, e, h, dx, dy));
    c = {h, el};
end
posChanged(0, 0, h, dx, dy);
end

function posChanged(~, ~, h, dx, dy)
    axh = get(h, 'Parent');
    p = get(axh, 'Position');
    o = get(axh, 'OuterPosition');
    xp = (o(1)-p(1))/p(3);
    yp = (o(2)-p(2)+o(4))/p(4);
    set(h, 'Units', get(axh, 'Units'),'Position', [xp yp]);
    set(h, 'Units', 'pixels');
    p = get(h, 'Position');
    set(h, 'Position', [p(1)+dx, p(2)+5-dy]);
    set(h, 'Units', 'normalized');
end

Итак, как нам использовать эту дерьмовую функцию? Я сделал это так, чтобы мы могли использовать это:

%   c = axes_label('label')
%      Places the text object with the string 'label' on the upper-left 
%      corner of the current axes and returns a cell containing the handle
%      of the text and an event listener.
%
%   c = axes_label('label', dx, dy)
%      Places the text object dx pixels from the left side of the axes
%      and dy pixels from the top. These values are set to 3 by default.
%
%   c = axes_label(c, ...)
%      Peforms the operations mentioned above on cell c containing the
%      handle of the text and the event listener.
%
%   c = axes_label(c, dx, dy)
%      Adjusts the current label to the specifed distance from the
%      upper-left corner of the current axes.

Если мы выполним тот же тест, что и раньше:

figure;
h1 = axes('OuterPosition', [0,0,.5 1]);
set(h1,'LooseInset',get(h1,'TightInset'));
h2 = axes('OuterPosition', [.5,0,.5 1]);
set(h2,'LooseInset',get(h2,'TightInset'));

axes(h1);
plot([0 1], [4 5]);
axes_label('A');  

axes(h2);
plot([0 1], [4 5]);
axes_label('B', 250, 250);

Теперь мы получаем то, что я хотел. Метка «A» устанавливается в верхнем левом углу внешнего блока осей. И метку B я явно установил на расстоянии 250 пикселей от верхнего левого угла. Вот сюжет:

введите здесь описание изображения

Что мне нравится в этой функции, так это то, что если бы я сохранил ячейку, возвращенную из нее, а затем вернул ее, я мог бы изменить положение. Например, если label = axes_label('A');, то в командной строке я могу выполнить label = axes_label(label, 10, 20);, и я увижу, как перемещается моя метка.

Проблема, с которой я столкнулся сейчас, связана с функцией export_fig

Если я попытаюсь использовать это:

export_fig('testing.png', '-nocrop', '-painters');

Тогда это цифра, которую я получаю.

введите здесь описание изображения

Вот почему я переборщил с меткой B. До того, как я добавил обработчики событий, export_fig нормально печатал метки там, где я их расположил. Но почему-то теперь export_fig не делает того, о чем заявляет. В основном экспорт изображения с

Фигура/оси воспроизводятся так, как они появляются на экране

Если вместо этого мы удалим опцию -painters, то получим следующее:

введите здесь описание изображения

Вероятно, в коде есть ошибка, поскольку у меня нет опыта работы со слушателями, поэтому, если кто-то может исправить это поведение и/или улучшить этот код, не стесняйтесь делать это и делиться им в качестве ответа.

person jmlopez    schedule 23.06.2012