MATLAB | Love Legend and Exquisite Translucent Rounded Legend

All the diagrams in this article are self-made, please indicate the source when disseminating.

I wrote some small finished functions, such as how to turn the icon on the legend into a heart shape when drawing a pie chart:

For example, how to make a semi-transparent rounded legend:

Still talk about the principle first and then give these two codes:


1 Principle Explanation - Graphic Object

closed quadrilateral object

In the previous article we have already talked about the hidden properties of the legend component:

The outline and, in most cases, the legend are drawn LineLoopusing :Quadrilateral

These two basic graphics objects draw graphics in groups of four points, and the general principle is as follows:

VertexDataIt is the coordinates of the vertices. It is an array of size 3xn. The first row represents the x coordinates, and the 2nd and 3rd rows represent the y and z coordinates. The range is 0-1.

Every four points is a group, for example, if there are eight vertices, four four vertices will be grouped into a graph (1,2,3,4 a group, 5,6,7,8 a group):

Of course, you can arrange the points in order, or set VertexIndicesthe vertex order to get the desired quadrilateral shape:


other objects

Compared with the object that can only be a group of four points, we also introduce a more flexible object. First of all LineStrip, this graphics object will draw a line in groups of two points:

Instead TriangleStrip, a group of three points draws an object that fills a triangle, for example, a complex polygon can be filled with multiple triangles:


2 Principle Explanation - Creation and Replacement

Let me talk about how to construct basic graphics objects. These objects are constructed by undisclosed very low-level functions, for example LineStrip, not through:

  • LineStrip()

to build, but via:

  • matlab.graphics.primitive.world.LineStrip()

After constructing the object, the following properties must be set in order for the hidden object to be displayed:

  • Layer
  • ColorBinding
  • ColorData
  • VertexData
  • PickableParts

The setting of these properties can refer to the original legend to form the object, which will not be described in detail here, but also refer to the code I wrote.

Then set the newly constructed object parent class to the Group parent class of the original component, and then hide the original component:

newBoxEdgeHdl.Parent=oriBoxEdgeHdl.Parent;
oriBoxEdgeHdl.Visible='off';

The above is the whole process of component replacement, and I wrote two pieces of sample code:


3 sample code

translucent legend

function SPrettyLegend(lgd)
% Semitransparent rounded rectangle legend
% Copyright (c) 2023, Zhaoxu Liu / slandarer
% -------------------------------------------------------------------------
% Zhaoxu Liu / slandarer (2023). pretty legend 
% (https://www.mathworks.com/matlabcentral/fileexchange/132128-pretty-legend), 
% MATLAB Central File Exchange. 检索来源 2023/7/9.
% =========================================================================
if nargin<1
    ax = gca;
    lgd = get(ax,'Legend');
end
pause(1e-6)
Ratio = .1;
t1 = linspace(0,pi/2,4); t1 = t1([1,2,2,3,3,4]);
t2 = linspace(pi/2,pi,4); t2 = t2([1,2,2,3,3,4]);
t3 = linspace(pi,3*pi/2,4); t3 = t3([1,2,2,3,3,4]);
t4 = linspace(3*pi/2,2*pi,4); t4 = t4([1,2,2,3,3,4]);
XX = [1,1,1-Ratio+cos(t1).*Ratio,1-Ratio,Ratio,Ratio+cos(t2).*Ratio,...
    0,0,Ratio+cos(t3).*Ratio,Ratio,1-Ratio,1-Ratio+cos(t4).*Ratio];
YY = [Ratio,1-Ratio,1-Ratio+sin(t1).*Ratio,1,1,1-Ratio+sin(t2).*Ratio,...
    1-Ratio,Ratio,Ratio+sin(t3).*Ratio,0,0,Ratio+sin(t4).*Ratio];
% 圆角边框(border-radius)
oriBoxEdgeHdl = lgd.BoxEdge;
newBoxEdgeHdl = matlab.graphics.primitive.world.LineStrip();
newBoxEdgeHdl.AlignVertexCenters = 'off';
newBoxEdgeHdl.Layer = 'front';
newBoxEdgeHdl.ColorBinding = 'object';
newBoxEdgeHdl.LineWidth = 1;
newBoxEdgeHdl.LineJoin = 'miter';
newBoxEdgeHdl.WideLineRenderingHint = 'software';
newBoxEdgeHdl.ColorData = uint8([38;38;38;0]);
newBoxEdgeHdl.VertexData = single([XX;YY;XX.*0]);
newBoxEdgeHdl.Parent=oriBoxEdgeHdl.Parent;
oriBoxEdgeHdl.Visible='off';
% 半透明圆角背景(Semitransparent rounded background)
oriBoxFaceHdl = lgd.BoxFace;
newBoxFaceHdl = matlab.graphics.primitive.world.TriangleStrip();
Ind = [1:(length(XX)-1);ones(1,length(XX)-1).*(length(XX)+1);2:length(XX)];
Ind = Ind(:).';
newBoxFaceHdl.PickableParts = 'all';
newBoxFaceHdl.Layer = 'back';
newBoxFaceHdl.ColorBinding = 'object';
newBoxFaceHdl.ColorType = 'truecoloralpha';
newBoxFaceHdl.ColorData = uint8(255*[1;1;1;.6]);
newBoxFaceHdl.VertexData = single([XX,.5;YY,.5;XX.*0,0]);
newBoxFaceHdl.VertexIndices = uint32(Ind);
newBoxFaceHdl.Parent = oriBoxFaceHdl.Parent;
oriBoxFaceHdl.Visible = 'off';
end

Example of use

clc; clear; close all
rng(12)
% 生成随机点(Generate random points)
mu = [2 3; 6 7; 8 9];
S  = cat(3,[1 0; 0 2],[1 0; 0 2],[1 0; 0 1]);
r1 = abs(mvnrnd(mu(1,:),S(:,:,1),100));
r2 = abs(mvnrnd(mu(2,:),S(:,:,2),100));
r3 = abs(mvnrnd(mu(3,:),S(:,:,3),100));
% 绘制散点图(Draw scatter chart)
hold on
propCell = {
    
    'LineWidth',1.2,'MarkerEdgeColor',[.3,.3,.3],'SizeData',60};
scatter(r1(:,1),r1(:,2),'filled','CData',[0.40 0.76 0.60],propCell{
    
    :});
scatter(r2(:,1),r2(:,2),'filled','CData',[0.99 0.55 0.38],propCell{
    
    :});
scatter(r3(:,1),r3(:,2),'filled','CData',[0.55 0.63 0.80],propCell{
    
    :});
% 增添图例(Draw legend)
lgd = legend('scatter1','scatter2','scatter3');
lgd.Location = 'northwest';
lgd.FontSize = 14;
% 坐标区域基础修饰(Axes basic decoration)
ax=gca; grid on
ax.FontName   = 'Cambria';
ax.Color      = [0.9,0.9,0.9];
ax.Box        = 'off';
ax.TickDir    = 'out';
ax.GridColor  = [1 1 1];
ax.GridAlpha  = 1;
ax.LineWidth  = 1;
ax.XColor     = [0.2,0.2,0.2];
ax.YColor     = [0.2,0.2,0.2];
ax.TickLength = [0.015 0.025];
% 隐藏轴线(Hide XY-Ruler)
pause(1e-6)
ax.XRuler.Axle.LineStyle = 'none';
ax.YRuler.Axle.LineStyle = 'none';

SPrettyLegend(lgd)


Heart-shaped legend (exclusive to pie charts)

function pie2HeartLegend(lgd)
% Heart shaped legend for pie chart
% Copyright (c) 2023, Zhaoxu Liu / slandarer
% =========================================================================
if nargin<1
    ax = gca;
    lgd = get(ax,'Legend');
end
pause(1e-6)
% 心形曲线(Heart curve)
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;
XX = [x, flip(x),x(1)]./3.4+.5;
YY = ([y1, y2,y1(1)]-.2)./2+.5;
Ind = [1:(length(XX)-1);2:length(XX)];
Ind = Ind(:).';
% 获取图例图标(Get Legend Icon)
lgdEntryChild = lgd.EntryContainer.NodeChildren;
iconSet = arrayfun(@(lgdEntryChild)lgdEntryChild.Icon.Transform.Children.Children,lgdEntryChild,UniformOutput=false);
% 基础边框句柄(Base Border Handle)
newEdgeHdl = matlab.graphics.primitive.world.LineStrip();
newEdgeHdl.AlignVertexCenters = 'off';
newEdgeHdl.Layer = 'front';
newEdgeHdl.ColorBinding = 'object';
newEdgeHdl.LineWidth = .8;
newEdgeHdl.LineJoin = 'miter';
newEdgeHdl.WideLineRenderingHint = 'software';
newEdgeHdl.ColorData = uint8([38;38;38;0]);
newEdgeHdl.VertexData = single([XX;YY;XX.*0]);
newEdgeHdl.VertexIndices = uint32(Ind);
% 基础多边形面句柄(Base Patch Handle)
newFaceHdl = matlab.graphics.primitive.world.TriangleStrip();
Ind = [1:(length(XX)-1);ones(1,length(XX)-1).*(length(XX)+1);2:length(XX)];
Ind = Ind(:).';
newFaceHdl.PickableParts = 'all';
newFaceHdl.Layer = 'middle';
newFaceHdl.ColorBinding = 'object';
newFaceHdl.ColorType = 'truecoloralpha';
newFaceHdl.ColorData = uint8(255*[1;1;1;.6]);
newFaceHdl.VertexData = single([XX,.5;YY,.5;XX.*0,0]);
newFaceHdl.VertexIndices = uint32(Ind);
% 替换图例图标(Replace Legend Icon)
for i = 1:length(iconSet)
    oriEdgeHdl = iconSet{
    
    i}(1);
    tNewEdgeHdl = copy(newEdgeHdl);
    tNewEdgeHdl.ColorData = oriEdgeHdl.ColorData;
    tNewEdgeHdl.Parent = oriEdgeHdl.Parent;
    oriEdgeHdl.Visible = 'off';

    oriFaceHdl = iconSet{
    
    i}(2);
    tNewFaceHdl = copy(newFaceHdl);
    tNewFaceHdl.ColorData = oriFaceHdl.ColorData;
    tNewFaceHdl.Parent = oriFaceHdl.Parent;
    oriFaceHdl.Visible = 'off';
end
end

Example of use

clc; clear; close all
% 生成随机点(Generate random points)
X = [1 3 0.5 2.5 2];
pieHdl = pie(X);

% 修饰饼状图(Decorate pie chart)
colorList=[0.4941    0.5490    0.4118
    0.9059    0.6510    0.3333
    0.8980    0.6157    0.4980
    0.8902    0.5137    0.4667
    0.4275    0.2824    0.2784];
for i = 1:2:length(pieHdl)
    pieHdl(i).FaceColor=colorList((i+1)/2,:);
    pieHdl(i).EdgeColor=colorList((i+1)/2,:);
    pieHdl(i).LineWidth=1;
    pieHdl(i).FaceAlpha=.6;
end
for i = 2:2:length(pieHdl)
    pieHdl(i).FontSize=13;
    pieHdl(i).FontName='Times New Roman';
end
lgd=legend('FontSize',13,'FontName','Times New Roman','TextColor',[1,1,1].*.3);

pie2HeartLegend(lgd)


over

The above is all the exploration made in this article. I should be the first person on the whole network to give a feasible method to modify the legend. Through the above method, the drawing of special legends such as shadow histogram legends has also become possible. I look forward to your second. creative ha

Guess you like

Origin blog.csdn.net/slandarer/article/details/131628250