how to merge two legend in one?
113 次查看(过去 30 天)
显示 更早的评论
Hello every one,
i have three plots and i want to have just one legend for plot p1 and p2 ,for example for the following code:
x=0:0.25:2*pi;
y=sin(x);
p1=plot(x,y);
hold on
p2=plot(x,y,'o','MarkerSize',12,'MarkerFaceColor','b','MarkerEdgeColor','b');
p3=plot(x+0.02,y+0.02,'o','MarkerSize',4,'MarkerFaceColor','w','MarkerEdgeColor','w');
as you see i have merged two markers(a big blue circle and a small white circle ) and i want two show these two circles together as same legend.is there any way to do it?
3 个评论
dpb
2020-3-8
I tried
hL(2)=plot(x+dxy,y+dxy,'or','MarkerSize',4);
also and thought kinda' cute...
采纳的回答
Walter Roberson
2020-3-7
Yes, there is a way to do it.
[h, icons] = legend([p2, p3], {'whatever the legend should say', 'unused'});
%p2_text = icons(1);
p3_text = icons(2);
p2_line = icons(3);
%p2_marker = icons(4);
p3_line = icons(5);
p3_marker = icons(6);
p2_line.Color = p1.Color;
p2_line.LineStyle = p1.LineStyle; %it is missing the solid line of p1
p3_text.Visible = 'off'; %turn off what you do not need
p3_line.Visible = 'off';
p3_marker.XData = p2_marker.XData + 0.02; %move the small white circle
p3_marker.YData = p2_marker.YData + 0.02;
This is a bit clunky.
You have to use a backwards compatibility of legend() that will probably go away and might not work for uifigures. You must have two or more outputs on the legend() call: the backwards compatibility is triggered by that. If you only have one output on the legend call, then it does not create the objects that you need to have created.
You cannot just pass a single graphics object as the first parameter to legend and add-on the additional graphics within the legend, as you are not permitted to add additional graphics objects inside a legend. Instead you have to create as many graphics objects as you need at the start, and then turn off the legend portions of them that you do not need. But you can move the objects that are already inside the legend.
2 个评论
dpb
2020-3-7
编辑:dpb
2020-3-7
"have to use a backwards compatibility of legend() that will probably go away..."
Indeed, legend was klunky before and now, while TMW has added some features, their recent penchant for hiding needed/useful properties from the user and not only making them invisible but to actually make the object almost totally opaque is a real kick in the teeth for such user niceties.
Dunno that users have the power to change the mindset that seems to have developed that we are children that must be protected from ourselves, but it is surely disheartening.
A quick look-thru using Yair's undocumented function makes it appear that even by getting to what is exposed but hidden isn't enough to be able to get to the actual objects; TMW has appears to have completely made them inaccessible.
I guess I now recall having been thru the exercise earlier that one cannot even use those hidden properties to get the children of the axes buried in the new legend object. If TMW does choose to actually remove the backwards compatibility feature, one will be hosed entirely other than by completely reinventing the wheel.
"Ease of use and rapid development" as long as willing to live with what is deemed allowable...
更多回答(2 个)
Nathan Miller
2021-10-19
编辑:Walter Roberson
2023-5-13
If you dig in deep enough you absolutely can customize the legend icons to whatever you want programatically, but it's quite messy and 'undocumented'.
I came up with my solution below after looking through Yair's https://undocumentedmatlab.com/blog_old/plot-legend-customization and thinking outside the box a bit with a colleague. The key was doing the copy of the node object to create a new Marker primitive and then updating the Parent property that loads it into the legend handle to be drawn.
% Plot OP's code
figure; hold all; % new fig, enable hold/add
x=0:0.25:2*pi;
y=sin(x);
hL(1)=plot(x,y,'o-','MarkerSize',12,'MarkerFaceColor','b','MarkerEdgeColor','b');
hL(2)=plot(x+0.02,y+0.02,'o','MarkerSize',4,'MarkerFaceColor','w','MarkerEdgeColor','w');
% Add legend for the first/main plot handle
hLegend = legend(hL(1),'location','best');
drawnow(); % have to render the internal nodes before accessing them
% Extract legend nodes/primitives
hLegendEntry = hLegend.EntryContainer.NodeChildren(1); % first/bottom row of legend
iconSet = hLegendEntry.Icon.Transform.Children.Children; % array of first/bottom row's icons (marker+line)
% Create a new icon marker to add to the icon set
newLegendIcon = copy(iconSet(1)); % copy the object (or look into making a matlab.graphics.primitive.world.Marker)
newLegendIcon.get % list all properties
newLegendIcon.Parent = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
% Mess with the new icon's properties to show how you want
newLegendIcon.FaceColorData = uint8([255;255;255;255]); % rgba uint8
newLegendIcon.VertexData(1) = 0.53; % [0-1] within the icon's boundaries (not the +0.02)
newLegendIcon.VertexData(2) = 0.65; % [0-1] within the icon's boundaries (not the +0.02)
newLegendIcon.Size = 4; % a little different from MarkerSize it seems
Output image if the auto-run figure from the above code doesn't generate correctly:
Bonus extra figure/example showing how you can separate the icon markers to show multiple of them on the same line:
2 个评论
Nathan Miller
2023-5-15
Here, something to this effect:
% Plot OP's code
figure; hold all; % new fig, enable hold/add
x=1:5;
y=x;
hL(1)=plot(x,y,'ob');
hL(2)=plot(x,y+1,'r-s');
% Add legend for the first/main plot handle
hLegend = legend(hL,'location','best');
drawnow(); % have to render the internal nodes before accessing them
%%% Update top row legened (blue circle)
% Extract legend nodes/primitives
hLegendEntryTop = hLegend.EntryContainer.NodeChildren(end); % top row of legend
iconSet = hLegendEntryTop.Icon.Transform.Children.Children; % array of first/bottom row's icons (marker+line)
% Move primary marker over to the edge
iconSet(1).VertexData(1) = 0.90;
% Create a new icon marker to add to the icon set
newLegendIcon1 = copy(iconSet(1)); % copy the object (or look into making a matlab.graphics.primitive.world.Marker)
newLegendIcon1.Parent = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
newLegendIcon1.Style = 'plus';
newLegendIcon1.VertexData(1) = 0.10;
% Create a new icon marker to add to the icon set
newLegendIcon2 = copy(iconSet(1)); % copy the object (or look into making a matlab.graphics.primitive.world.Marker)
newLegendIcon2.Parent = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
newLegendIcon2.Style = 'asterisk';
newLegendIcon2.VertexData(1) = 0.50;
%%% Update bottom row legend (red square + line)
% Extract legend nodes/primitives
hLegendEntryBtm = hLegend.EntryContainer.NodeChildren(1); % bottom row of legend
iconSet = hLegendEntryBtm.Icon.Transform.Children.Children; % array of first/bottom row's icons (marker+line)
% Move primary marker over
iconSet(1).VertexData(1) = 0.25;
% Create a new icon marker to add to the icon set
newLegendIcon = copy(iconSet(1)); % copy the object (or look into making a matlab.graphics.primitive.world.Marker)
newLegendIcon.Parent = iconSet(1).Parent; % set the parent, adding to the legend's icon draw set
newLegendIcon.Style = 'pentagram';
newLegendIcon.VertexData(1) = 0.75;
newLegendIcon.Size = 8;
Hakan Caldag
2023-3-28
编辑:Hakan Caldag
2023-11-7
For anyone who is happy to keep the legend somewhere outside the axes, I ended up with another solution that looks simpler to me: Copying the axes object to have a new one right on top, having two legends for each and setting the top legend color to 'none' so it becomes transparent and both icons become visible:
x=0:0.25:2*pi;
y=sin(x);
subplot(121);
p1=plot(x,y);
hold on
p2=plot(x,y,'o','MarkerSize',12,'MarkerFaceColor','b','MarkerEdgeColor','b');
p3=plot(x+0.02,y+0.02,'o','MarkerSize',4,'MarkerFaceColor','w','MarkerEdgeColor','w');
legend('','Anything here','Position',[0.6 0.6 0.1 0.1])
axhand=gca; %axes handle
duplicateplot=copyobj(axhand,1); % the duplicate
axes(duplicateplot);
% Removing the additional labels/ticks of the second axes object
xticks([]);yticks([]);xlabel('');ylabel('');
legend('','',' ','Position',[0.52 0.6036 0.135 0.1],'Color','none','EdgeColor','none')
% Setting the colors to none is what makes the icons overlap
% Adjust the position any way you would like here, I tried to match the
% shape in the plot.
% Notice that the ' ' label is set for the plot object with the white icons
0 个评论
另请参阅
类别
在 Help Center 和 File Exchange 中查找有关 Legend 的更多信息
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!