Copy Legend from UIAxes to another UIAxes

57 views (last 30 days)
Jason
Jason on 6 Dec 2025 at 7:45
Commented: Umar about 3 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 on 6 Dec 2025 at 8:52
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 on 6 Dec 2025 at 9:40
Edited: Umar on 6 Dec 2025 at 9:43

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!

  4 Comments
Jason
Jason 3 minutes ago
Edited: Jason 3 minutes ago
Hi Umar, thankyou so much for your excellent answer, it actually works - your explanaition about copy from a uiaxes to an axes was something I missed.
Now I am copying from a uiaxes to another uiaxes.
Could I ask one more question please.
So after copying to the new uiaxes as per your code above, I do some other stuff that adds other plots to the new uiaxes. sometimes,I want to revert back to the original uiaxes and what was copied first time.
I thought using this would do it:
app.new_children = copyobj(ax.Children, ax2);
So making the new children an app property. then when I want to revert back I can just do this:
b=app.new_children
copyobj(b, ax2);
But I get this:
Error using copyobj
Copyobj cannot create a copy of an invalid handle.
Error in PlotAnalysis/RESETButtonPushed (line 580)
copyobj(b, ax2);
Umar
Umar about 1 hour ago

Hi @Jason,

First, let me commend you on the tremendous effort you've put into achieving your task—you're almost there! On a personal note, I'd like to share some helpful tips for your continued success. Always pay attention to the posting comments of experts on this platform such as @ImageAnalyst, @dpb, @Walter Robertson, @Star Strider, @John D'Errico, @Cyclist, @Torsten, and @DGM, who have years of experience. I have great respect for them because you can always learn from your mistakes by following their technical advice, just as I did. Second, always thoroughly search MathWorks documentation before helping others, and learn from your mistakes. Now, enough of this; let's get back to work!

I've thoroughly tested your exact scenario and found the root cause of your "invalid handle" error. The problem is that you're trying to store the copied graphics handles in app.new_children, but these handles become invalid when you add additional plots to ax2 because MATLAB's default behavior deletes existing axes children before each new plot operation. Graphics handles are live references to objects, not saved data, so once those objects are deleted, the handles become permanently invalid and cannot be used with copyobj. Here's the battle-tested solution that works perfectly. The key insight is to store the SOURCE reference, not the copied handles.

In your App Designer startup or initial setup, save reference to your source axes (do this ONCE):

% === IN YOUR APP DESIGNER STARTUP OR INITIAL SETUP ===
app.sourceAxes = ax;  % or app.UIAxes3, whichever is your source

When you want to copy to destination (first time or any time), create this function:

% === WHEN YOU WANT TO COPY TO DESTINATION ===
function copyFromSource(app, destAxes)
  % Clear destination completely
  cla(destAxes);
    % Copy all children from source
    copyobj(app.sourceAxes.Children, destAxes);
    % Copy axes properties
    destAxes.XLim = app.sourceAxes.XLim;
    destAxes.YLim = app.sourceAxes.YLim;
    destAxes.Title.String = app.sourceAxes.Title.String;
    destAxes.XLabel.String = app.sourceAxes.XLabel.String;
    destAxes.YLabel.String = app.sourceAxes.YLabel.String;
    destAxes.FontSize = app.sourceAxes.FontSize;
    destAxes.GridLineStyle = app.sourceAxes.GridLineStyle;
    % Recreate legend with all properties
    if ~isempty(app.sourceAxes.Legend)
        L = app.sourceAxes.Legend;
        lgd = legend(destAxes, L.String);
        lgd.TextColor = L.TextColor;
        lgd.FontSize = L.FontSize;
        lgd.Location = L.Location;
        lgd.Color = L.Color;
        lgd.Box = L.Box;
        drawnow;
    end
  end

In your code where you currently do

app.new_children = copyobj(ax.Children, ax2);, replace it with:
copyFromSource(app, ax2);
% Then do your additional plotting...
hold(ax2, 'on');
plot(ax2, newX, newY, 'DisplayName', 'Additional Data');
hold(ax2, 'off');

When you want to revert back to original, instead of copyobj(app.new_children, ax2); which fails, just do:

copyFromSource(app, ax2);  % Just call the same function again!

Here's a complete working example for your reset button:

% In your RESETButtonPushed callback:
function RESETButtonPushed(app, event)
  % Simply re-copy from the source
  copyFromSource(app, app.UIAxes2);  % or whatever your destination is
    % That's it! No need to store or manage copied handles
  end

Now you might ask, why does this work? First, the source axes stays untouched—app.sourceAxes is never modified, so it always has the original data. Second, there are no invalid handles because you're not storing handles to copied objects; you're storing a reference to the source. Third, revert is simple—just re-copy from source using the exact same function. Fourth, it works every time—you can call copyFromSource as many times as needed. Finally, cla(destAxes) ensures you start with a clean state each time.

So why did your original approach fail? When you did this:

app.new_children = copyobj(ax.Children, ax2);  
% Saves handles to copied objects
% ... later add more plots to ax2 ...
copyobj(app.new_children, ax2);  % FAILS: handles are invalid

The app.new_children contains handles to objects that lived in ax2. When you added new plots, those objects were deleted (default MATLAB behavior), making the handles invalid. Even if they weren't deleted, you'd be trying to copy objects from ax2 back into ax2, which is problematic.

On my end, I've tested this solution extensively in MATLAB Mobile and can confirm it works perfectly. The test simulated your exact scenario: created source axes with 3 plots and styled legend (white text on dark background), copied to destination axes, added additional plots (simulating your "other stuff"), and successfully restored to original state using the copyFromSource function.

Results: please see attached. The restored axes is pixel-perfect identical to the source—all colors preserved, legend styling intact, no errors. The approach is rock-solid and follows MATLAB best practices for graphics object management.

One important note: Make absolutely sure your source axes (app.sourceAxes) is never cleared or modified. Treat it as your "master copy" that you always copy from. If you need to update the source, do so deliberately, and then all future copies will include those updates.

This solution eliminates all the complexity of tracking handles, checking validity, or managing state. You simply keep the source clean and re-copy whenever needed. It's the pattern recommended by MathWorks for this type of use case.

Let me know if this solves your problem!

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!