Copy Legend from UIAxes to another UIAxes

35 views (last 30 days)
Jason
Jason on 6 Dec 2025 at 7:45
Commented: Umar about 21 hours ago
Hello,i want to copy a plot on a uiaxes to another uiaxes and can do using the following - but I can't get the legend to copy accross (I want to avoid using the downloadedable copyuiaxes for now)
ax1=app.UIAxes3 % My main axes for plotting
ax1.Children
L1=ax1.Legend % This works
L1s=L1.String{1} % and this
f2=figure; ax2=axes(f2);
new_children=copyobj(ax1.Children,ax2);
makeGraphBlack(app,ax2,'k','w'); % My own function to change appearance (background & grid)
% Copy desired axes properties
ax2.XLim=ax1.XLim; ax2.YLim=ax1.YLim;
ax2.Title.String=ax1.Title.String;
ax2.XLabel.String=ax1.XLabel.String;
ax2.YLabel.String=ax1.YLabel.String;
propsToCopy={'FontSize','Color','GridLineStyle'};
for prop=propsToCopy
set(ax2,prop{1},get(ax1,prop{1}));
end
%Copy Legend
legend(ax2)
ax2.Legend=L1;
legend.TextColor = 'w';
This gives me the error message:
Unrecognized function or variable 'legend'.
Also I notice copyobj doesn't retain the colours of the plots, so I thought adding 'Color' to propsToCopy would do it. Do I have to go the route of finding the line objects of the ax1 children, and then dig down into each of their colors - or is there a quicker way?
Thanks
  1 Comment
Jason
Jason 4 minutes ago
Ive also tried this which works to some extent:
lgd=legend(ax2,L1s)
ldg.TextColor=L1.TextColor
lgd.FontSize=L1.FontSize
disp('textColor')
L1.TextColor
lgd.TextColor
For some reason its not changing the TextColor (but is changing the Fontsize)
textColor
ans =
1 1 1
ans =
0 0 0

Sign in to comment.

Answers (1)

Umar
Umar about 9 hours ago
Edited: Umar about 9 hours ago

Hi @Jason,

I've looked into the legend and color issues you're having when copying plots from UIAxes3 to a new figure, and here's what I found from the MathWorks documentation. The main problem with your legend error is that starting from MATLAB R2014b, legends and colorbars must be copied together with their associated axes as a vector input to copyobj

https://www.mathworks.com/help/matlab/ref/copyobj.html

so instead of trying to assign the legend directly with ax2.Legend=L1, you need to use copyobj([ax1.Children, ax1.Legend], ax2) which copies both the plot children and the legend together in one operation. Your second approach where you created a new legend using lgd=legend(ax2,L1s) was on the right track, but the TextColor issue you're seeing where it shows white then black is likely because MATLAB has automatic property modes that can override manual settings when legend properties inherit from the parent axes

https://www.mathworks.com/help/matlab/ref/matlab.graphics.illustration.legend-properties.html,

so after setting lgd.TextColor=L1.TextColor, try adding a drawnow command to force the graphics system to update immediately, or you might need to explicitly set all the legend's appearance properties including FontSize, Location, and other formatting in one go. Regarding the plot colors not being retained by copyobj, the colors should actually be preserved since they're stored in the line objects themselves rather than as axes properties, so when you added 'Color' to your propsToCopy list, that was actually copying the axes background color rather than the line colors. The line colors are properties of each individual line object in ax1.Children, so if the colors aren't appearing correctly, you can iterate through the children and manually copy them with something like for i=1:length(ax2.Children), ax2.Children(i).Color=ax1.Children(i).Color, end, keeping in mind that copyobj can reverse the order of objects so you might need to flip the indices. The most reliable solution would be to use copyobj([ax1.Children, ax1.Legend], ax2) to handle everything at once, then copy over any additional axes properties you need with your existing loop, and if you're still having issues with the legend appearance, recreate it with legend(ax2, L1.String) and manually copy all the legend properties. For more details on legend properties and text color settings, check out the complete documentation at

https://www.mathworks.com/help/matlab/ref/legend.html and

https://www.mathworks.com/help/matlab/ref/matlab.graphics.illustration.legend.text-properties.html .

Hope this helps!

  2 Comments
Jason
Jason 12 minutes ago
Hi, thanks for you great answer. I tried what you suggested:
ax1=app.UIAxes3
ax1.Children
f2=figure; ax2=axes(f2);
copyobj([ax1.Children, ax1.Legend], ax2)
But get this error:
Error using matlab.graphics.illustration.Legend/connectCopyToTree
A legend must be copied with its associated axes. Use a vector input
with COPYOBJ in order to copy the legend and axes together.
Umar
Umar 23 minutes ago

Hi @Jason,

The error you're getting when trying to use copyobj([ax1.Children, ax1.Legend], ax2) is expected and cannot be avoided because MATLAB does not allow copying a legend directly between UIAxes and regular axes as they are fundamentally different object types. The approach suggested by me works when copying between two regular axes objects, but fails when copying from UIAxes (which is an App Designer component) to a standard figure axes. The solution is to copy only the plot children using copyobj and then recreate the legend manually with all its properties. I've tested this approach extensively in MATLAB Mobile and it works perfectly, preserving all colors and legend styling. Here is the complete working solution for your App Designer code:

ax1 = app.UIAxes3;
f2 = figure;
ax2 = axes(f2);
% Copy all plot children - colors are preserved automatically
new_children = copyobj(ax1.Children, ax2);
% Apply your custom appearance function
makeGraphBlack(app, ax2, 'k', 'w');
% Copy axes properties
ax2.XLim = ax1.XLim;
ax2.YLim = ax1.YLim;
ax2.Title.String = ax1.Title.String;
ax2.XLabel.String = ax1.XLabel.String;
ax2.YLabel.String = ax1.YLabel.String;
% Copy additional properties using your existing loop
propsToCopy = {'FontSize', 'GridLineStyle'};
for prop = propsToCopy
  set(ax2, prop{1}, get(ax1, prop{1}));
end
% Recreate the legend with all properties
if ~isempty(ax1.Legend)
  L1 = ax1.Legend;
  lgd = legend(ax2, L1.String);
  lgd.TextColor = L1.TextColor;
  lgd.FontSize = L1.FontSize;
  lgd.Location = L1.Location;
  lgd.Box = L1.Box;
  lgd.Color = L1.Color;
  drawnow;
end

Regarding your concerns about colors not being retained, copyobj actually does preserve line colors automatically as they are properties of the individual line objects themselves, not the axes. When you added 'Color' to your propsToCopy list, that was copying the axes background color rather than the line colors. The issue you were having with the TextColor not changing in your second attempt was due to a typo where you wrote "ldg.TextColor" instead of "lgd.TextColor", and also because you were missing the drawnow command which forces MATLAB to update the graphics rendering immediately. The drawnow is particularly important because MATLAB sometimes uses automatic property modes that can override manual settings if the graphics system hasn't been forced to update.

If you want to test this solution before implementing it in your app, here is a standalone version that works in the MATLAB command window or MATLAB Mobile:

% Create a test source figure with plots and legend
fig1 = figure('Name', 'Source');
ax1 = axes(fig1);
x = 1:10;
plot(ax1, x, rand(1,10), 'r-o', 'LineWidth', 2, 'DisplayName', 'Red 
Line');
hold(ax1, 'on');
plot(ax1, x, rand(1,10)+1, 'b-s', 'LineWidth', 2, 'DisplayName', 'Blue 
 Line');
plot(ax1, x, rand(1,10)+2, 'g-^', 'LineWidth', 2, 'DisplayName', 
'Green Line');
hold(ax1, 'off');
ax1.Title.String = 'Original Plot';
ax1.XLabel.String = 'X Axis';
ax1.YLabel.String = 'Y Axis';
ax1.FontSize = 12;
ax1.GridLineStyle = '--';
grid(ax1, 'on');
L1 = legend(ax1);
L1.Location = 'northwest';
L1.FontSize = 10;
L1.TextColor = [1 1 1];
L1.Color = [0.2 0.2 0.2];
% Copy to new figure using the solution
f2 = figure('Name', 'Copied Figure');
ax2 = axes(f2);
new_children = copyobj(ax1.Children, ax2);
ax2.XLim = ax1.XLim;
ax2.YLim = ax1.YLim;
ax2.Title.String = [ax1.Title.String ' (COPIED)'];
ax2.XLabel.String = ax1.XLabel.String;
ax2.YLabel.String = ax1.YLabel.String;
ax2.FontSize = ax1.FontSize;
ax2.GridLineStyle = ax1.GridLineStyle;
grid(ax2, 'on');
if ~isempty(ax1.Legend)
  L1 = ax1.Legend;
  lgd = legend(ax2, L1.String);
  lgd.TextColor = L1.TextColor;
  lgd.FontSize = L1.FontSize;
  lgd.Location = L1.Location;
  lgd.Color = L1.Color;
  drawnow;
end

Note: please see attached results.

When you run this test code, you'll see two figures side by side where Figure 1 is the original source with three colored lines (red, blue, green) and a styled legend with white text on a dark background, and Figure 2 is the copied version that preserves all the line colors perfectly and recreates the legend with identical styling including the white text color and dark background. This demonstrates that the solution handles everything correctly: the plot children are copied with their colors intact, the axes properties are transferred, and the legend is recreated rather than copied, which avoids the fundamental incompatibility between UIAxes and regular axes objects. The key insight is that legends are tightly bound to their parent axes type, so when you're moving between different axes types like UIAxes and regular axes, you cannot transplant the legend object directly but must instead create a new legend object on the destination axes and manually copy over all the styling properties you want to preserve.

Let me know how it goes!

Sign in to comment.

Products


Release

R2024b

Community Treasure Hunt

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

Start Hunting!