2
votes

Simplified Problem

I'm plotting 10 items.

To generate my plot I am creating 10 independent Line objects in a for loop

x=1:10;y=1;10;names = num2str((1:10)');
for i = 1:10
    my_plots(i) = plot(x(i),y(i),'.','Color',rgb(i,:),'MarkerSize',14); 
end
legend(my_plots,names);

Simple

When I click on an item in the legend it toggles visibility of the corresponding line

(legHandle.ItemHitFcn = toggleLegendItem).

function toggleLegendItem(src,evnt)

    if strcmp(evnt.Peer.Visible,'on')
        evnt.Peer.Visible = 'off';
    else 
       evnt.Peer.Visible= 'on';
    end

end

This works fine


I run into issues when some of my plots are actually the same category. Complex

In this simple example, I could combine lines 1:5 into one object in a number of different ways, and pass the combined object to the legend as a single item in my_plots.

Actual problem

All of my line objects are distributed between several independent axes/subplots. Each axis has to remain independent because I need to be able to freely rotate each subplot without disturbing the other plots.

Progress so far

I've been able to build a shared legend between axes (because same class items share the same color, I only need to link the first line for each class), but I cannot figure out how to link multiple line objects to a single legend item, so that I am able to properly all lines across axes on each legend item callback.

I have an array of lines.

  {{Line Line Line}}
  {{Line Line Line}} 
  {{Line Line Line}}
  ...
  {{Line Line Line}}

Basically what I need to do is set multiple Peer objects to a single legend item, but I am not sure if that is possible.

If someone has another solution that allows for combing multiple line handles across axes that would be helpful too.

1

1 Answers

0
votes

So looking at the legend() function, I found that it's not possible to instantiate a legend with multiple Peer objects per item. There may be a way to go back and add multiple references via some sort of "combined object" but I'm not sure if a "combined object" exists that can handle objects with different Parent handles.

A quick fix to my problem (which was attributing a callback to the same item in multiple axes) was to use the shared properties within each class and across axes to get the handles for all items within each class. In this case I already assigned color to be distinctive between categories but a more objective property like Tag could also be used.

function toggleLegendItem(src,evnt)
    % Find all items in this category
    obj = findobj(findall(gcf,'type','Scatter'),'CData',evnt.Peer.CData);

    for oid = 1:length(obj) 
        if strcmp(obj(oid).Visible,'on')
            obj(oid).Visible = 'off';
        else 
           obj(oid).Visible= 'on';
        end
    end
end

The one nuisance that this solution leaves is that the legend is a child of only one axis. If each category is not present in all axes, then the color for those missing categories may not show up. Luckily when you toggle each item's visibility the color appears and functions as normal. I would guess some other errors like this could occur.