Добавить несуществующую запись в легенду

Я хочу вручную добавить запись в легенду MATLAB. Эта легенда может быть уже существующей и содержать записи других графических элементов, но не обязательно.

Я делаю точечную диаграмму, но вместо использования, например. scatter(x,y), я рисую с помощью

for n = 1:numel(x)
    text(x(n),y(n),num2str(n), ...
    'HorizontalAlignment','center','color',[1 0 0])
end

Это приводит к точечной диаграмме чисел от единицы до количества элементов в xy, поскольку они имеют одинаковый размер). Я хочу добавить легенду для этих чисел.

Я пытался добавить или отредактировать легенду с помощью

[h,icons,plots,s] = legend(___)

как описано на legend странице документации. Я не могу понять, как я могу добавить запись легенды без необходимости что-то строить (например, фактический точечный график или обычный график). Я хочу, чтобы обычный символ линии или маркера в легенде был числом или символом, таким как 'n', указывающим числа на графике. Возможно ли это и как этого добиться?


person Erik    schedule 09.11.2015    source источник
comment
Не могли бы вы подделать его с помощью annotation?   -  person Steve    schedule 10.11.2015
comment
@Steve - Да, но тогда это не сработало бы, если бы на графике уже была легенда для любых других графических элементов. В этом случае я хотел бы добавить свою пользовательскую запись в эту легенду.   -  person Erik    schedule 10.11.2015
comment
Возможно, можно было бы создать скрытые (белые) точки (используя код, аналогичный этому ответу), а затем добавить число в текст легенды, например 1: foo, 2: bar. Таким же образом можно добавить заполнитель в легенду, а затем сымитировать его, добавив текст в качестве аннотации сверху (хотя легенда может его скрывать).   -  person zelanix    schedule 10.11.2015
comment
@zelanix - спасибо за ссылку и предложения. Я подумал о следующем: я мог бы сделать строку легенды по умолчанию или маркер невидимыми (это можно сделать с помощью icons, вывода legend в вопросе). Затем я мог бы изменить положение текста легенды (также в icons). Затем текстовая строка может стать «n␣␣␣(с пробелами, необходимыми для нормального вида)␣␣␣текст записи легенды». Тогда это будет весь черный текст, что нормально для черных чисел. Однако, если бы я хотел добавить еще один разброс чисел другого цвета, буква «n» не могла бы быть этого цвета.   -  person Erik    schedule 10.11.2015
comment
Разве легенды MATLAB не просто оси, только завернутые в некоторые из более современных оболочек графического движка и довольно жестко запрограммированные и недоступные по сравнению с обычными осями? Я мог бы создать свою функцию, которая вместо добавления обычной легенды добавляет оси, которые выглядят точно так же, как настоящая легенда, в т.ч. любые текущие записи в легенде. Однако для этого потребуется довольно много программирования, на которое у меня нет времени.   -  person Erik    schedule 10.11.2015
comment
На заметку: ручка легенды довольно странная. Например. его дочерние элементы: у него есть пустой графический заполнитель. Однако icons содержит дескрипторы, которые в конечном итоге все имеют саму легенду в качестве родителя... Технически для дочернего элемента невозможно иметь родителя, но родитель не может иметь дочернего элемента!   -  person Erik    schedule 10.11.2015
comment
Я думаю, что раньше было так, что легенда была просто осями с дочерними элементами, но теперь нельзя добавлять в легенду новые дочерние элементы. Интересно, что элементы icons действительно показывают родителя как легенду, но они должны быть каким-то особенным. Я опубликовал возможное решение. Ваша идея сдвинуть текст влево и заполнить его тоже сработает, хотя и с упомянутыми вами оговорками.   -  person zelanix    schedule 10.11.2015


Ответы (1)


РЕДАКТИРОВАТЬ Эрика

Мой ответ идет ниже ответа zelanix, потому что мой основан на нем.


Оригинальный ответ

Вполне работоспособным решением может быть следующее:

x = rand(10, 1);
y = rand(10, 1);

figure;

text(x,y,num2str(transpose(1:numel(x))),'HorizontalAlignment','center')

% Create dummy legend entries, with white symbols.
hold on;
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
plot(0, 0, 'o', 'color', [1 1 1], 'visible', 'off');
hold off;

% Create legend with placeholder entries.
[h_leg, icons] = legend('foo', 'bar');

% Create new (invisible) axes on top of the legend so that we can draw
% text on top.
ax2 = axes('position', get(h_leg, 'position'));
set(ax2, 'Color', 'none', 'Box', 'off')
set(ax2, 'xtick', [], 'ytick', []);

% Draw the numbers on the legend, positioned as per the original markers.
text(get(icons(4), 'XData'), get(icons(4), 'YData'), '1', 'HorizontalAlignment', 'center')
text(get(icons(6), 'XData'), get(icons(6), 'YData'), '2', 'HorizontalAlignment', 'center')

axes(ax1);

Выход:

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

Хитрость заключается в том, что новые оси создаются точно в том же месте, что и легенда, а координаты элементов icons имеют нормализованные координаты, которые теперь можно использовать непосредственно внутри новых осей. Конечно, теперь вы можете использовать любой размер / цвет шрифта / все, что вам нужно.

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


Эрик ответ

Основываясь на ответе zelanix выше. Это незавершенный ответ, я пытаюсь сделать из этого довольно гибкую функцию. В настоящее время это просто сценарий, который вам нужно адаптировать к вашей ситуации.

% plot some lines and some text numbers
f = figure;
plot([0 1],[0 1],[0 1],[1 0])
x = rand(25,1);
y = rand(25,1);
for n = 1:numel(x)
    text(x(n),y(n),num2str(n), ...
    'HorizontalAlignment','center','color',[1 0 0])
end
hold on
% scatter(x,y) % used to test the number positions
scatter(x,y,'Visible','off') % moves the legend location to best position

% create the dummy legend using some dummy plots
plot(0,0,'o','Visible','off')
[l,i] = legend('some line','some other line','some numbers','location','best');
l.Visible = 'off';

% create empty axes to mimick legend
oa = gca; % the original current axes handle
a = axes;
axis manual
a.Box = 'on';
a.XTick = [];
a.YTick = [];

% copy the legend's properties and contents to the new axes
a.Units = l.Units; % just in case
a.Position = l.Position;
i = copyobj(i,a);

% replace the marker with a red 'n'
s = findobj(i,'string','some numbers');
% m = findobj(i(i~=s),'-property','YData','marker','o');
m = findobj(i(i~=s),'-property','YData');
sy = s.Position(2);
if numel(m)>1
    dy = abs(m(1).YData - sy);
    for k = 2:numel(m)
        h = m(k);
        dy2 = abs(h.YData - sy);
        if dy2<dy
            kbest = k;
            dy = dy2;
        end
    end
    m = m(kbest);
end
m.Visible = 'off';
mx = m.XData;
text(mx,sy,'n','HorizontalAlignment','center','color',[1 0 0])

% reset current axes to main axes
f.CurrentAxes = oa;

Результат:

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

person zelanix    schedule 10.11.2015
comment
Очень хорошо. Я бы добавил строку, чтобы сделать оригинальную легенду невидимой, на всякий случай. Кроме того, можно скопировать все элементы icons в новые оси, используя copyobj: это приведет к очень хорошему наложению новых осей со всеми текущими записями легенды. Наибольшая проблема будет заключаться в том, чтобы настроить положение и размер новых осей, чтобы они соответствовали всем существующим и новым записям. Самый простой способ сделать это — использовать обычную функцию legend, которая сделает всю работу за вас, а затем использовать свое решение для создания новых осей на ее основе и скопировать весь объект, который вы хотите (и оставить или отредактировать то, что не нужно). т нужно). - person Erik; 10.11.2015
comment
@Erik Интересная идея, так что вы бы воссоздали всю легенду в новых осях. Это также дало бы некоторые приятные функции, такие как возможность перетаскивания с помощью ручного инструмента и т. д. Пока вы копируете все после создания исходной легенды (с фиктивными записями), у вас не должно быть любые проблемы с позиционированием, поскольку оси используют нормализованные координаты. Я думаю, это зависит от того, насколько общим вы должны быть в своем приложении. - person zelanix; 10.11.2015
comment
Я изучаю это прямо сейчас и пытаюсь создать сценарий, который будет делать именно это. Я опубликую его здесь, если он сработает и добавит к вашему решению. Спасибо за помощь! - person Erik; 10.11.2015
comment
Без проблем! Удачи. Пожалуйста, отпишитесь, если получится - мне было бы очень интересно на это посмотреть. - person zelanix; 10.11.2015
comment
Я отредактировал ваш ответ, включив в него свой собственный, основанный на вашем. - person Erik; 11.11.2015