2012-06-22 2 views
3

Я хотел бы дать подзаголовки, которые я делаю простой ярлык. К сожалению, я получаю уродливое поведение. Рассмотрят следующую функцию:Маркировка подзаголовка в цифрах 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'); 

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

enter image description here

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

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

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'); 

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

enter image description here

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

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

+0

Даже если мы удалим код об изменении 'LooseInset' в тестовом коде, мы по-прежнему получаем такое же поведение с' set_label2'. – jmlopez

+0

, кстати, 'LooseInset' является [недокументированным] (http://undocumentedmatlab.com/blog/axes-looseinset-property/) свойством – Amro

ответ

1

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

Теперь, вместо того, чтобы использовать нормализованные единицы, продолжайте использовать блоки данных и создайте прослушиватель событий, когда заголовок или 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 контролировать ли устанавливать х или координату) :

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 
+0

Спасибо, что показали мне, как добавить слушателя. В конце концов я решил заставить его работать с использованием нормализованных единиц. Но на этот раз я получаю «Положение» и «OuterPosition» осей. Используя эту информацию, я могу указать расположение метки относительно левого верхнего угла. Таким образом, он также будет работать в 3D. – jmlopez

+0

@jmlopez: для потомков вам следует рассмотреть возможность размещения вашего нового кода. – Amro

+0

Сделаю, я просто пытаюсь исправить одну проблему с прослушивателями событий. – jmlopez

2

Для потомства здесь версия, с которой я решил пойти. Он делает то, что я ожидаю от этого, но теперь у меня есть проблема, о которой я не знаю, как ее решить. Хорошо, сначала хорошие новости, вот функция под названием 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» установлен в верхнем левом углу Outerbox осей. И ярлык B я явно установил его в 250 пикселей из его верхнего левого угла. Вот сюжет:

enter image description here

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

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

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

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

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

enter image description here

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

Рисунок/осей воспроизведенных как он появляется на экране

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

enter image description here

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

Смежные вопросы