欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 养生 > 【MATLAB学习笔记】绘图——自定义标记(Marker)形状,实现与MATLAB自带标记基本一致的功能(自适应缩放、自适应裁剪)

【MATLAB学习笔记】绘图——自定义标记(Marker)形状,实现与MATLAB自带标记基本一致的功能(自适应缩放、自适应裁剪)

2024/10/24 14:20:40 来源:https://blog.csdn.net/qq_53350487/article/details/141609816  浏览:    关键词:【MATLAB学习笔记】绘图——自定义标记(Marker)形状,实现与MATLAB自带标记基本一致的功能(自适应缩放、自适应裁剪)

目录

  • 前言
  • 自定义标记函数
  • 自定义标记函数的说明
    • 纵横比调整
    • 将图形大小按磅数设置
    • 平移标记点
    • 绘制标记点
    • 边界标记点不裁剪
  • 拓展功能——标记点自适应绘图区的缩放
    • 绘图区缩放回调函数
    • 标记点大小自适应
    • 标记点裁剪自适应
  • 示例
    • 基本绘图
    • 自定义标记函数的使用
  • 总代码
    • 主函数
    • 自定义标记函数
    • 回调函数
    • 其他函数
  • 总结

前言

  在MATLAB中,使用plot、scatter和patch等函数进行绘图时,很多时候都需要使用标记(Marker)对数据点进行标记,以便更清晰地展示数据。在MATLAB只能使用默认的标记形状(如下图),但有时觉得MATLAB自带的标记不好看或者不够用时就需要自定义标记形状,而MATLAB中并没有提供自定义标记这样一个功能或者函数。
在这里插入图片描述

  本文章提供了一个可以自定义标记形状的函数,只需要输入标记形状的点坐标和连接方式即可绘制出与MATLAB自带标记基本一致的自定义标记,包括随着绘图区的缩放,标记在屏幕上的大小不会改变,以及绘图区边缘的标记可以超出绘图区等功能,同时可以设置该标记的颜色、磅数、线宽等基本属性。

自定义标记函数

  自定义标记的主函数如下,该函数目前只能绘制没有交叉线的图形。前5个参数为必须输入,包括ax绘图区对象,曲线的x和y坐标,标记形状的点坐标GPoints(第一列为x坐标,第二列为y坐标),形状点的连接顺序(不需要首尾相连)GSeq。
  其他可设置参数为填充的面颜色faceColor,填充的线颜色edgeColor,形状的大小pounds,形状的线宽度lineWidth,形状的数量NMarker(近似数量, 采用等间距, 如不能整除则四舍五入,输入0则表示绘制所有点的标记)。同时,若不需要则以空数组[ ]代替, 如不需要形状磅数pounds, 则pounds = [ ]。

function setMarker(ax, x, y, GPoints, GSeq, faceColor, edgeColor, pounds, lineWidth, NMarker)
% 自定义设置标记形状(目前只能绘制没有交叉线的图形), 前5个参数为必须输入, 其他参数为可选参数
% 若不需要则以空数组[]代替, 如不需要形状磅数pounds, 则pounds = []
%
% ax        绘图区
% x,y       绘图的数据点
% GPoints   形状的点坐标
% GSeq      形状点的连接顺序(不需要首尾相连)
% faceColor 填充的面颜色  默认:none
% edgeColor 填充的线颜色  默认:k
% pounds    形状的大小(磅数)  默认:6
% lineWidth 形状的线宽度  % 默认:0.5
% NMarker   形状的数量(近似数量, 采用等间距, 如不能整除则四舍五入)  
%           默认:0, 0则代表全部点都绘制if nargin < 6, faceColor = 'none'; end
if nargin < 7, edgeColor = 'k'; end
if nargin < 8, pounds = 6; end
if nargin < 9, lineWidth = 0.5; end
if nargin < 10, NMarker = 0; endif isempty(faceColor), faceColor = 'none'; end
if isempty(edgeColor), edgeColor = 'k'; end
if isempty(pounds), pounds = 6; end
if isempty(lineWidth), lineWidth = 0.5; end
if isempty(NMarker), NMarker = 0; endif NMarker == 0, NMarker = length(x); endhold(ax,"on") NG = length(GSeq);  % 点数量% 将图形的比例拉正
xl = xlim;
yl = ylim;
lenx = xl(2)-xl(1); % x轴的长度
leny = yl(2)-yl(1); % y轴的长度
yRatio = leny/lenx; % 纵横比比例
GPoints(:,2) = GPoints(:,2)*yRatio; % 修正坐标 % 获取绘图区的每单位在屏幕上的长度(磅)
unitLength = getUnitLength();% 计算水平距离矩阵
W = zeros(NG);
for i = 1:NGfor j = 1:NGif i ~= jW(i,j) = sqrt((GPoints(i,1)-GPoints(j,1))^2);endend
end% 缩放比例
scale = 2*pounds/(max(max(W))*unitLength);
% 缩放
GPoints = GPoints*scale;PM = 1:round(length(x)/NMarker):length(x);   % 需要绘制的点位置
NMarker = length(PM);                        % 绘制标记的真实数量% 重心坐标
[Cx, Cy] = polygon_centroid(GPoints);% 初始化所有标记的坐标和连接顺序
GPointsAll = zeros(NMarker*NG,2);
GSeqAll = zeros(NMarker,NG);
% 边界点判断初始化
BJudge = false(NMarker,1);
for k = 1:NMarker% 取出当前点坐标xk = x(PM(k));yk = y(PM(k));% 平移displacement = [xk-Cx,yk-Cy];% 更新坐标GPointsNew = GPoints;GPointsNew = GPointsNew + repmat(displacement,size(GPoints,1),1);% 保存所有标记点的坐标和连接顺序GPointsAll(NG*(k-1)+1:NG*k,:) = GPointsNew;GSeqAll(k,:) =  GSeq + NG*(k-1);%%% 判断当前标记点是否处于边界 %%%xkk = GPointsNew(:, 1);  % 当前标记点的x坐标ykk = GPointsNew(:, 2);  % 当前标记点的y坐标% 标记形状坐标判断BLeft = xkk - xl(1);    % 左边界BRight = xkk - xl(2);   % 右边界BDown = ykk - yl(1);    % 下边界BUp = ykk - yl(2);      % 上边界% 标记中心坐标判断BLeft2 = xk - xl(1);    % 左边界BRight2 = xl(2)-xk;     % 右边界BDown2 = yk - yl(1);    % 下边界BUp2 = yl(2) - yk;      % 上边界% 判断形状坐标是否同号以及中心点是否在绘图区if (~judgeSign(BLeft) || ~judgeSign(BRight) || ~judgeSign(BDown) || ~judgeSign(BUp)) && ...all([BLeft2,BRight2,BDown2,BUp2]>=0)BJudge(k) = true;  % 记录处于边界的标记点endend
% 绘制标记点
pa = patch('Faces', GSeqAll, 'Vertices', GPointsAll, 'FaceColor', faceColor,...'EdgeColor', edgeColor,'lineWidth',lineWidth);% 设置绘图区边缘图形不裁剪
pa2 = patch('Faces', GSeqAll(BJudge,:), 'Vertices', GPointsAll, 'FaceColor', faceColor,...'EdgeColor', edgeColor,'LineWidth',lineWidth, 'Clip', 'off');%%%% 控制图形放大缩小 %%%%
zm = zoom(ax);
zm.Enable = 'on'; % 启用缩放% 初始化xy轴范围
xl = xlim;
yl = ylim;
setappdata(ax,'lxl',xl) 
setappdata(ax,'lyl',yl) % 绘图区缩放回调函数
set(zm, 'ActionPostCallback', @(src, event) updateZoomInfo(ax,x,y,PM,NG,NMarker,pa,pa2)); end

自定义标记函数的说明

纵横比调整

  在自定义形状时,如果x轴和y轴的刻度一致,则绘制出来的图形与实际一致。大多数情况下,MATLAB绘制图形时一般x轴和y轴的刻度并不一致,比如x轴一格长度为2,y轴一格长度为500,这时绘制出来的图形看起来会呈现上下被压扁的性质。比如,原本需要绘制的形状是下图这个四边形,但是因为x轴和y轴的刻度不一致,会出现绘制出来的形状只呈现出一条线(下面第二张图)。
在这里插入图片描述
在这里插入图片描述
  为了避免这种情况,首先就要对图形比例进行修正,即获取x轴和y轴刻度之间的比例,对标记图形的x或者y坐标进行拉伸或者收缩。

% 将图形的比例拉正
xl = xlim;
yl = ylim;
lenx = xl(2)-xl(1); % x轴的长度
leny = yl(2)-yl(1); % y轴的长度
yRatio = leny/lenx; % 纵横比比例
GPoints(:,2) = GPoints(:,2)*yRatio; % 修正坐标 

下面是调整后的效果图。
在这里插入图片描述

将图形大小按磅数设置

  放缩了x轴或者y轴的比例后,会出现标记图形过大或者过小的情况,这时就需要对标记的坐标进行放缩。在MATLAB中,标记的大小(MarkerSize)通常以磅数为单位,默认大小为6磅。同样参考MATLAB的方式,我们绘制图形也可以用磅数设置图形大小,但并不知道绘图区单位长度对应的磅数大小是多少。因此,首先要计算绘图区中的单位磅数。
  下面的函数中,Position(3)对应的就是x轴的总磅数,除x轴的总长度即可得到绘图区中的单位磅数。在上图中,绘图区中的单位磅数为50.9091磅。

function unitLength = getUnitLength()
% 获取绘图区的每单位在屏幕上的长度(磅)% 获取图形窗口的大小和位置  
Po = get(gcf, 'Position'); % 返回的单位是点 (points),每个点约为 1/72 英寸  
figWidth = Po(3); % 图形的宽度 % X轴范围  
xl = xlim;
rangeX = xl(2) - xl(1); % 绘图区的每单位在屏幕上的长度(磅)
unitLength = figWidth/rangeX;end

  得到了绘图区中的单位磅数后就可以以某一个标准(比如图形的水平长度、竖直长度和最长边的长度等)对图形的坐标进行放缩。本文采用图形的水平长度L为标准,将长度L乘单位长度unitLength可以得到图形当前的磅数,由于MATLAB中图形的大小是以半径为参考的,故需要在前面乘2。

% 获取绘图区的每单位在屏幕上的长度(磅)
unitLength = getUnitLength();% 水平长度矩阵
L = max(GPoints(:,1)) - min(GPoints(:,1));% 缩放比例
scale = 2*pounds/(L*unitLength);% 缩放
GPoints = GPoints*scale;

  设置磅数pounds = 6,可以得到下面的效果图(红色为自定义标记,黑色为MATLAB自带的三角形标记),可以看到,自定义标记与MATLAB自带标记的大小一致。
在这里插入图片描述

平移标记点

  已知标记点初始的点坐标和连接顺序后,还需要将标记点平移到相应的位置。
  NMarker为需要绘制的标记点数量,为得到标记点的位置,需要将整个数据区间均分成NMarker份。但是,输入的NMarker并不一定能均分,因此文章采用一种四舍五入的方法,即下面的round(length(x)/NMarker),以及更新NMarker的数量。

% 计算绘制的点位置
PM = 1:round(length(x)/NMarker):length(x);   % 需要绘制的点位置
NMarker = length(PM);                        % 绘制标记的真实数量

  得到了绘制标记点的位置后,需要将标记平移到该位置。本文以标记图形的重心作为参考,计算重心到该位置的位移,再到坐标进行更新。
  计算多边形的重心方法如下:

  1. 计算面积 A A A
      假设一个多边形的顶点坐标为 ( x 1 , y 1 ) , ( x 2 , y 2 ) , … , ( x n , y n ) (x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n) (x1,y1),(x2,y2),,(xn,yn),连接顺序为 1 − n − 1 1-n-1 1n1,则该多边形的面积 A

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com