本文来讲一下如何自动标注超出坐标区域范围的点,例如这样:
如图右侧的红叉代表横坐标超过范围的点的纵坐标
,当然下方的红叉代表纵坐标超过范围点的横坐标。
本文使用的自己编写的工具函数scatterOOR
将被放在文末,先讲讲咋用哈,
基础使用
假设编写了如下绘制散点图的代码:
clc; clear; close all
rng(1)
% 生成随机点(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';
ax.XLim = [-2,10];
ax.YLim = [2,14];
我们直接在代码最后加上一行:
scatterOOR()
或者
scatterOOR(gca)
即第一个参数是坐标区域对象,可省略。直接简单的调用就能达到下面的效果:
若是想要超出范围的点画的花哨点呢?可通过自定义scatter
图形属性来实现,例如以下两种方法:
scatterOOR('filled','CData',[0,0,.8],'LineWidth',1.5,...
'MarkerEdgeColor',[.5,.5,.5],'SizeData',120,'Marker','s')
scatterOOR(gca,'filled','CData',[0,0,.8],'LineWidth',1.5,...
'MarkerEdgeColor',[.5,.5,.5],'SizeData',120,'Marker','s')
我们可以注意超出范围点默认图例名称为OOR,这个名称咋改呢?
也非常简单,例如将名称改为LALALA
,可在代码最后加上这样两行:
OORHdl = findobj(ax,'Tag','SLANOOR');
OORHdl.DisplayName = 'LALALA';
工具函数完整代码
非常短哈只有不到40行:
function scatterOOR(ax,varargin)
% Copyright (c) 2023, Zhaoxu Liu / slandarer
if nargin < 1
ax = gca;
end
if ~isa(ax,'matlab.graphics.axis.Axes')
varargin = [{ax}, varargin(:)'];
ax = gca;
end
ax.NextPlot = 'add';
if isempty(varargin)
varargin={'filled','CData',[.8,0,0],'LineWidth',1.5,...
'MarkerEdgeColor',[.8,0,0],'SizeData',120,'Marker','x'};
end
OORHdl = findobj(ax,'Tag','SLANOOR');
if isempty(OORHdl)
OORHdl = scatter([],[],varargin{:},'Tag','SLANOOR','DisplayName','OOR');
end
fullHdl = findobj(ax,'Type','scatter');
fullXData = [fullHdl(:).XData];
fullYData = [fullHdl(:).YData];
moveAxes();
addlistener(ax,'MarkedClean',@moveAxes);
function moveAxes(~,~)
tBool = fullXData >= ax.XLim(2) | fullXData <= ax.XLim(1)...
| fullYData >= ax.YLim(2) | fullYData <= ax.YLim(1);
tFullXData = fullXData;
tFullYData = fullYData;
tFullXData(tFullXData >= ax.XLim(2)) = ax.XLim(2);
tFullXData(tFullXData <= ax.XLim(1)) = ax.XLim(1);
tFullYData(tFullYData >= ax.YLim(2)) = ax.YLim(2);
tFullYData(tFullYData <= ax.YLim(1)) = ax.YLim(1);
tFullXData = tFullXData(tBool);
tFullYData = tFullYData(tBool);
OORHdl.XData = tFullXData;
OORHdl.YData = tFullYData;
end
end