Let me talk a little bit about MATLAB bottoms. I wrote some drawing functions before, such as the shadow histogram. I want to modify the icons in the legend so that they also have shadows. I take the method of directly drawing some legends that will detect them. The shadow icon of the moving box is used to pretend to be the icon of the legend, so is there a way to really customize the legend?
I really found a way, let me tell you how to do it first, and then I may write some related functions specially:
Or the heart-shaped legend in the upper right corner:
Or change the square box directly:
Thanks to @左右通源
(https://www.zhihu.com/people/zuo-you-feng-yuan-4-38)
for the ideas and some codes! !
principle
First of all, as we all know, MATLAB legends have many hidden properties, roughly like this:
The first thing I think about is how to get out the object bound in the legend icon. Our research has found that there are still many ways, for example:
hLegend.EntryContainer.NodeChildren(n).Icon.Transform.Children.Children
Or with a little more trouble:
hLegend.EntryContainer.Children(n).Children(1).Transform.Children.Children
Or findobj
select the object directly after using:
objHdl=findobj(hLegend.EntryContainer)
objHdl(4).Transform.Children.Children
左右逢源
A piece of code for batch acquisition is given:
lgdEntryChild=hLegend.EntryContainer.NodeChildren;
iconSet=arrayfun(@(lgdEntryChild)lgdEntryChild.Icon.Transform.Children.Children,lgdEntryChild,UniformOutput=false)
After getting this object, you can actually modify it directly:
clc;clear;close all
hold on;
plot(1:5,'LineWidth',2);
plot(2:6,'LineWidth',2);
hLegend=legend();
hLegend.Title.String='MyLegend';
% 批量获取全部图标对象
pause(1e-6)
lgdEntryChild=hLegend.EntryContainer.NodeChildren;
iconSet=arrayfun(@(lgdEntryChild)lgdEntryChild.Icon.Transform.Children.Children,lgdEntryChild,UniformOutput=false);
% 换颜色+加粗
iconSet{
2}.ColorData=uint8([0;0;0;255]);
iconSet{
2}.LineWidth=10;
So is there a way to combine it? , this method is 左右逢源
thought of, generally just copy an object and modify the group (parent class) it belongs to:
% 复制并改父类
tempIcon=copy(iconSet{
1});
tempIcon.Parent=iconSet{
2}.Parent;
very amazing, so we started various attempts:
writing code for fun
circle+cross
The easiest way to create a new legend is to combine several old legends, so I first tried a combination of circle + cross:
clc;clear;close all
hold on
% 绘制等高线图为构造自定义图例提供素材
x=linspace(-2*pi,2*pi);
y=linspace(0,4*pi);
[X,Y]=meshgrid(x,y);
Z=sin(X)+cos(Y);
contour(X,Y,Z,'LineWidth',1);
% 绘制横线竖线为构造自定义图例提供素材
plot(1:5,'LineWidth',1);
scatter(1,1,'LineWidth',1,'Marker','|');
% 获取横线竖线素材,之所以分两次构建图例
% 且copy第一次构建图例的素材
% 是因为如果直接将图例素材移动再
% 删除无用素材的EntryContainer也依旧会保留空白
hLegend1=legend();
pause(1e-6)
lgdEntryChild=hLegend1.EntryContainer.NodeChildren;
iconSet=arrayfun(@(lgdEntryChild)copy(lgdEntryChild.Icon.Transform.Children.Children),lgdEntryChild,UniformOutput=false);
% 第二次构建图例且只保留等高线图的图例
cHdl=findobj(gca,'Type','Contour');
hLegend2=legend(cHdl,'Data');
pause(1e-6)
iconParent=hLegend2.EntryContainer.NodeChildren(1).Icon.Transform.Children;
icon=hLegend2.EntryContainer.NodeChildren(1).Icon.Transform.Children.Children;
% 简单修改素材组成(删除等高线图例的两个内圈环)
delete(icon(1))
delete(icon(2))
% 修改横线竖线素材的父类组
iconSet{
1}.Parent=iconParent;
iconSet{
2}.Parent=iconParent;
% 修饰素材颜色和大小利于拼接
iconSet{
1}.EdgeColorData=uint8([0;0;0;255]);
iconSet{
1}.Size=8;
iconSet{
2}.ColorData=uint8([0;0;0;255]);
icon(3).ColorData=uint8([0;0;0;255]);
Square contours?
At this time, it has been found that VertexData
the shape is controlled by the method, and I tried to copy and shrink the legend icon itself:
clc;clear;close all
hold on
% 绘制等高线图为构造自定义图例提供素材
fill([0,0,1,1],[1,0,0,1],[1,1,1],'LineWidth',.8)
hLegend=legend();
pause(1e-6)
icon=hLegend.EntryContainer.NodeChildren.Icon.Transform.Children.Children;
% 复制第一圈改颜色
LineIcon=copy(icon(1));
QuadIcon=copy(icon(2));
LineIcon.VertexData=(LineIcon.VertexData-.5).*.7+.5;
LineIcon.Parent=icon(1).Parent;
QuadIcon.VertexData=(QuadIcon.VertexData-.5).*.7+.5;
QuadIcon.ColorData=uint8([255;220;220;255]);
QuadIcon.Parent=icon(2).Parent;
% 复制第二圈改颜色
LineIcon=copy(icon(1));
QuadIcon=copy(icon(2));
LineIcon.VertexData=(LineIcon.VertexData-.5).*.4+.5;
LineIcon.Parent=icon(1).Parent;
QuadIcon.VertexData=(QuadIcon.VertexData-.5).*.4+.5;
QuadIcon.ColorData=uint8([210;220;225;255]);
QuadIcon.Parent=icon(2).Parent;
triangle
At this time, it is found that the points cannot be adjusted LineLoop
and Quadrilateral
the object can only be modified in a limited way:
clc;clear;close all
hold on
% 绘制等高线图为构造自定义图例提供素材
fill([0,0,1,1],[1,0,0,1],[1,1,1],'LineWidth',.8)
hLegend=legend();
pause(1e-6)
icon=hLegend.EntryContainer.NodeChildren.Icon.Transform.Children.Children;
icon(1).VertexData=single([0 1 1 1
0 1 1 0
0 0 0 0]);
love
After trying to find out LineStrip
that TriangleStrip
the object can adjust the number of points, I tried to construct a heart-shaped legend icon:
clc;clear;close all
x = -1:1/100:1;
y1 = 0.6 * abs(x) .^ 0.5 + ((1 - x .^ 2) / 2) .^ 0.5;
y2 = 0.6 * abs(x) .^ 0.5 - ((1 - x .^ 2) / 2) .^ 0.5;
plot([x, flip(x)], [y1, y2], 'r')
hLegend=legend();
pause(1e-6)
icon=hLegend.EntryContainer.NodeChildren.Icon.Transform.Children.Children;
XX=[x, flip(x),x(1)]./2+.5;
YY=([y1, y2,y1(1)]-.2)./2+.5;
XYZ=single([XX;YY;0.*XX]);
icon.VertexData=XYZ;
icon.LineWidth=2;
It seems that it supports horizontal and vertical legends.
Use of other hidden attributes
hide dividing line
Knowing that there are still many attempts to do what those hidden attributes can do, such as hiding the horizontal line between the title and the legend icon:
clc;clear;close all
hold on;
plot(1:5,'LineWidth',2);
plot(2:6,'LineWidth',2);
hLegend=legend();
hLegend.Title.String='MyLegend';
% 批量获取全部图标对象
pause(1e-6)
hLegend.TitleSeparator.Visible='off';
Could look better.
parallelogram box
clc;clear;close all
hold on;
plot(1:5,'LineWidth',2);
plot(2:6,'LineWidth',2);
hLegend=legend();
hLegend.Title.String='MyLegend';
pause(1e-6)
hLegend.BoxEdge.VertexData=single([0 -.5 1 1.5
0 1 1 0
0 0 0 0]);
over
The above are all the attempts we have made so far for its hidden attributes. I feel that we can make a lot of interesting things. In the future, it is possible to develop drawing functions that really use the legend icon designed by ourselves. The above code is not perfect and needs to be designed. All kinds of monitoring callbacks can reach the level of real use, but it is quite interesting to popularize these hidden things for everyone, see you in the next issue~