Prevent Matlab from updating the legend when saving a figure

16 visualizaciones (últimos 30 días)
Christopher Taube
Christopher Taube el 13 de Jul. de 2024
Editada: Benjamin Kraus el 15 de Jul. de 2024
I have a figure with a tiled layout and some plots which - because they are partly related - I don't want to give them all their own legend entry, but rather summarise several plots with one entry. I do this by subsequently changing the legend entries to display several line types, like in this example:
leg = legend([plot1, plot2], {'Plot1', 'Plot2'});
drawnow();
% Update legend
hLegendEntryTop = leg.EntryContainer.NodeChildren(end); % top row of legend
iconSet = hLegendEntryTop.Icon.Transform.Children.Children; % array of icons
% Move primary line up
iconSet(1).VertexData(2,1) = 0.65;
iconSet(1).VertexData(2,2) = 0.65;
% Create a new line
iconSet(2) = copy(iconSet(1)); % copy the object
iconSet(2) = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
% Move primary line down
iconSet(2).VertexData(2,1) = 0.35;
iconSet(2).VertexData(2,2) = 0.35;
iconSet(2).LineStyle = 'dashed';
...... % Do the same with other plot lines
saveas(gcf,'figure','epsc')
Interestingly, it works when exporting as PNG, but not when exporting as eps or pdf (vector graphics). The image is then updated and all additional lines inserted disappear again. I have absolutely no idea how I can prevent Matlab from updating the legend again when saving.
  1 comentario
dpb
dpb el 13 de Jul. de 2024
Editada: dpb el 13 de Jul. de 2024
leg = legend([plot1, plot2], {'Plot1', 'Plot2'});
Unrecognized function or variable 'plot1'.
drawnow();
% Update legend
hLegendEntryTop = leg.EntryContainer.NodeChildren(end); % top row of legend
iconSet = hLegendEntryTop.Icon.Transform.Children.Children; % array of icons
% Move primary line up
iconSet(1).VertexData(2,1) = 0.65;
iconSet(1).VertexData(2,2) = 0.65;
% Create a new line
iconSet(2) = copy(iconSet(1)); % copy the object
iconSet(2) = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
% Move primary line down
iconSet(2).VertexData(2,1) = 0.35;
iconSet(2).VertexData(2,2) = 0.35;
iconSet(2).LineStyle = 'dashed';
...... % Do the same with other plot lines
saveas(gcf,'figure','epsc')
  1. Format your code
  2. Provide complete Minimum Working Example
Such shenanigans are generally more successfully obtained by creating dummy lines of the desired characteristcs and then using the legend() function for those and not displaying the legends for the other lines at all.
But we need MWE code and an illustration of what effect(s) you're trying to achieve would never hurt...

Iniciar sesión para comentar.

Respuestas (1)

Benjamin Kraus
Benjamin Kraus el 15 de Jul. de 2024
By using the EntryContainer and NodeChildren properties, you are accessing the undocumented internal implementation details of the Legend. One aspect of being undocumented internal implementation details is that MATLAB is free to change the values of those properties whenever it wants, so this approach is not going to be reliable, and could break any time.
  • When you export to a PNG you are lucky that MATLAB doesn't redraw the scene, so it doesn't update those properties.
  • But, when you export to a PDF or EPS, MATLAB needs to change the internal layout and rendering a bit, so it does a graphics update, and during that graphics update all those properties you set are going to be restored to their original values.
The recommended way to create entries in the legend that don't match items you can see are you create entries with NaN data.
Something like this:
hold on
solidLines = plot(magic(4));
dashedLines = plot(magic(4)+2,'--');
invisibleSolid = plot(NaN, 'k', 'DisplayName', 'Solid lines');
invisibleDashed = plot(NaN, 'k--', 'DisplayName', 'Dashed lines');
legend([invisibleSolid invisibleDashed])
  1 comentario
Benjamin Kraus
Benjamin Kraus el 15 de Jul. de 2024
Editada: Benjamin Kraus el 15 de Jul. de 2024
You can still use this approach if you have several axes in a tiledlayout.
t = tiledlayout(2,2);
y = [sin(1:10)' cos(1:10)'];
for ii = 1:4
ax(ii) = nexttile(t);
p(ii*2-[1 0]) = plot(y);
p(ii*2).LineStyle = '--';
end
h = legend(ax(ii),p(1:2));
h.Layout.Tile = 'east';

Iniciar sesión para comentar.

Etiquetas

Productos


Versión

R2021a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by