Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match legend to axes objects

Context:

I have a (programmatic) GUI which contains several axes objects inside some uipanel parenting structure. Some of these axes have legend objects associated, some don't.
I want to include a button in my GUI which copies the currently visible plot into a new figure including its legend if it has one.

I know how to get the handles to the currently visible uipanel and all axes objects inside it. I also know how to tell the axes apart from the legends.

Question:

How can I match the legends to the axes?

For example, in one case my GUI shows 2 axes with some plots, each of which has its own legend. When I click the 'export' button, I want 2 new figures to be created, each containing one axes with its corresponding legend.
What I'm currently able to do is

  1. put everything in one figure (they overlap in that case because their positions in the original uipanels are the same),
  2. put each axes and each legend into their own respective figures,
  3. put all axes in one and all legends in another figure and
  4. put all axes in their own figure with all legends within the same panel.
  5. split it up by panel, that is, put all subplots into the same figure and each group of plots in their own figure.

Problem:

The problem is, I don't have the handles to either of those objects. I only have the handles to the uipanel objects. The graphics inside the panels are built by another function which contains all sorts of tricky stuff, but doesn't return handles. Also the parenting structure of said panels makes it rather hard to do this with tricks like get(handles.panels{1},'Children') because it will work in some, but not all cases.
I thought about simply exporting the panels (and have actually a working version which does this), but this has several problems, mainly related to figure tools and resizing. I want to get rid of the panels when I use the "Export" button.

Code Snippet / Example:

The following code snippet will create an example GUI with access to all handles I have access to in my complete GUI. Clicking the buttons will show the different versions I got to "work". What I want is one figure for each axes including its legend, if it has one. the 4th version (same parent) comes close, but breaks if it encounters subplots, the 5th version (by panel) simply puts entire subplot groups into one window (in which case, at least, they don't overlap). Copy the code into a new .mfile to try it.

function test
    figure(1)
    clf
    t=(0:0.1:10)'; %'// dummy comment
    p2 = uipanel('Visible','off','Position',[0 0 1 1]);
    p1 = uipanel('position',[0 0 1 1]);
    p11 = uipanel('Parent',p1,'Position',[0 0 0.5 0.9]);
    p12 = uipanel('Parent',p1,'Position',[0.5 0 0.5 0.9]);
    uicontrol('Style','push','String','all in one','Units','norm',...
        'Position',[0.05 0.91 0.14 0.06],'Callback',@export1);
    uicontrol('Style','push','String','all in own','Units','norm',...
        'Position',[0.24 0.91 0.14 0.06],'Callback',@export2);
    uicontrol('Style','push','String','by type','Units','norm',...
        'Position',[0.43 0.91 0.14 0.06],'Callback',@export3);
    uicontrol('Style','push','String','same parent','Units','norm',...
        'Position',[0.62 0.91 0.14 0.06],'Callback',@export4);
    uicontrol('Style','push','String','same panel','Units','norm',...
        'Position',[0.81 0.91 0.14 0.06],'Callback',@export5);
    subplot(1,1,1,'Parent',p11)
    plot(t,[sin(t) cos(t)])
    legend('Sine','Cosine')
    subplot(2,1,1,'Parent',p12)
    plot(t,[polyval([0.05 -1 2],t) exp(-t) abs(t-3)])
    subplot(2,1,2,'Parent',p12)
    plot(t,erf(t))
    legend('Error function')

    function export1(~,~)
        current = findobj('Type','uipanel','Parent',1,'Visible','on');
        visible_axes = findobj(current,'Type','axes');
        copyobj(visible_axes,figure);
    end

    function export2(~,~)
        current = findobj('Type','uipanel','Parent',1,'Visible','on');
        visible_axes = findobj(current,'Type','axes');
        for i=1:length(visible_axes)
            copyobj(visible_axes(i),figure);
        end
    end

    function export3(~,~)
        current = findobj('Type','uipanel','Parent',1,'Visible','on');
        visible_axes = findobj(current,'Type','axes','Tag','');
        visible_legends = findobj(current,'Tag','legend');
        copyobj(visible_axes,figure);
        copyobj(visible_legends,figure);
    end

    function export4(~,~)
        current = findobj('Type','uipanel','Parent',1,'Visible','on');
        visible_axes = findobj(current,'Type','axes','Tag','');
        visible_legends = findobj(current,'Tag','legend');
        for i=1:length(visible_axes)
            par = get(visible_axes(i),'Parent');
            same = findobj(visible_legends,'Parent',par);
            h=figure;
            copyobj(visible_axes(i),h)
            copyobj(same,h)
        end
    end

    function export5(~,~)
        current = findobj('Type','uipanel','Parent',1,'Visible','on');
        visible_axes = findobj(current,'Type','axes');
        parents = cell2mat(get(visible_axes,'Parent'));
        uparents = unique(parents);
        for i=1:length(uparents)
            copyobj(visible_axes(parents==uparents(i)),figure)
        end
    end
end
like image 793
scenia Avatar asked Feb 14 '14 12:02

scenia


2 Answers

In a figure, graphical objects are organized hierarchically and can all be handled individually. For instance, axes is a child of a figure, plot is a child of an axes, and legends are build as axes.

The following example plots 2 lines (red and blue, with legends), then mixes plots and legends using copyobj.

figure;
subplot(1,2,1)
hp1 = plot(1:10,'r')
hl1 = legend('red')

subplot(1,2,2)
hp2 = plot(1:10,'b')
hl2 = legend('blue')

hf = figure;
hax = axes;
copyobj(hp1, hax);    %copy plot to axes
copyobj(hl2, hf);     %copy legend to figure

enter image description here

enter image description here

Not tested with a GUI though.

like image 70
marsei Avatar answered Sep 20 '22 01:09

marsei


I think the simpler solution is to save the axes of the figure you're about to save as a fig file.

h = figure(1);

x = linspace(1,100);
y = 2*x;

ax = findall(h,'type','axes');
plot(x,y);

save('youraxes', 'ax');
hgsave(h, 'yourfig.fig');

I'm using Matlab R2012a, alternatively in R2013a or b the function to save the fig is now savefig.

like image 22
SamuelNLP Avatar answered Sep 20 '22 01:09

SamuelNLP