看到阿昆的科研日常
写了一篇如何将轴线隐藏而不隐藏刻度的推送,使用了XRuler中的Axle对象来实现,但我试了一下R2023A版本中不太能直接用,解决了一下,同时讲一下这些有趣的隐藏对象及其其他的用法。
1 隐藏轴框线
假设我们编写了如下代码:
rng(12)
% 生成随机点
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));
% 绘制散点图
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{:});
% 增添图例
lgd=legend('scatter1','scatter2','scatter3');
lgd.Location='northwest';
lgd.FontSize=14;
% 半透明图例
pause(1e-6)
lgd.BoxFace.ColorType='truecoloralpha';
lgd.BoxFace.ColorData=uint8(255*[1;1;1;.8]);
% 坐标区域基础修饰
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];
在代码最后加入以下代码即可隐藏轴线:
% 隐藏轴线
ax=gca;
pause(1e-6)
ax.XRuler.Axle.LineStyle='none';
ax.YRuler.Axle.LineStyle='none';
注意对于比较新的版本,Axle不会直接被显示为XRuler的子对象,需要pause一下过段时间才会生成对象并被添加为XRuler的子对象,这是与老版本不同的地方。当然不设置线条格式,直接将其可见性调成否也是一种方法:
% 隐藏轴线
ax=gca;
pause(1e-6)
ax.XRuler.Axle.Visible='off';
ax.YRuler.Axle.Visible='off';
而如果设置线条格式,不仅仅可以设置为’none’还可以设置为’solid’ | ‘dashed’ | ‘dotted’ | ‘dashdot’ | 'none’等类型(注意观察下图x 轴)
2 对数坐标轴
一般绘制对数坐标轴图可以使用下面几个函数,但是绘制出来的都是线图:
- loglog 双对数刻度图
- semilogx 半对数图(x 轴有对数刻度)
- semilogy 半对数图(y 轴有对数刻度)
怎么样其他绘图类型也使用对数刻度呢??还是使用上面那段代码,比如我们在最后加上如下代码即可将x轴变成对数刻度(y 轴同理):
ax=gca;
ax.XRuler.Scale='log';
有个更简单的等价方法:
ax=gca;
ax.XScale='log';
再比如填充图的对数坐标轴:
x = logspace(-1,2,1000);
y = 5 + 3*sin(x);
fill([x x(end)],[y y(1)],[0.40 0.76 0.60],'FaceAlpha',.2,...
'LineWidth',1,'EdgeColor',[0.40 0.76 0.60])
% 坐标区域基础修饰
ax=gca; grid on;
ax.FontName = 'Cambria';
ax.TickDir = 'out';
ax.LineWidth = .8;
ax.Box = 'off';
% 对数坐标轴
ax=gca;
ax.XScale='log';
3 无刻度Box框
我们box on
操作后显示的框上也有刻度:
t = linspace(pi/100,4*pi,500);
y1 = cos(t).^2;
y2 = sin(t).^2./t;
% 基础绘图
hold on
area(y1,'LineWidth',.8,'FaceColor',[0,0,.9],'FaceAlpha',.2)
area(y2,'LineWidth',.8,'FaceColor',[.8,0,0],'FaceAlpha',.2)
% 坐标区域基础修饰
ax=gca; grid on; box on
ax.FontName = 'Cambria';
ax.TickDir = 'out';
ax.LineWidth = 1.2;
有没有啥办法不显示这个刻度呢??虽然我们能够获取BoxFrame但这玩意并没有刻度属性,因此我们想到了直接画直线,同时为了拖动图像时直线的位置依旧在边框应该待的地方,我们为当前坐标区域增添监听,大概这样:
function testBox
t = linspace(pi/100,4*pi,500);
y1 = cos(t).^2;
y2 = sin(t).^2./t;
% 基础绘图
hold on
area(y1,'LineWidth',.8,'FaceColor',[0,0,.9],'FaceAlpha',.2)
area(y2,'LineWidth',.8,'FaceColor',[.8,0,0],'FaceAlpha',.2)
% 坐标区域基础修饰
ax=gca; grid on; box on
ax.FontName = 'Cambria';
ax.TickDir = 'out';
ax.LineWidth = 1;
% 绘制可跟随移动的框线
ax=gca; box off
XLineHdl=plot(ax,ax.XLim([1,2]),ax.YLim([2,2]),'LineWidth',1,'Color',[0,0,0]);
YLineHdl=plot(ax,ax.XLim([2,2]),ax.YLim([1,2]),'LineWidth',1,'Color',[0,0,0]);
addlistener(ax,'MarkedClean',@changeLinePos)
function changeLinePos(~,~)
set(XLineHdl,'XData',ax.XLim([1,2]),'YData',ax.YLim([2,2]))
set(YLineHdl,'XData',ax.XLim([2,2]),'YData',ax.YLim([1,2]))
end
end
当然我们这么用不咋方便,我们可以将其封装为函数:
function addBox
ax=gca; box off
XLineHdl=plot(ax,ax.XLim([1,2]),ax.YLim([2,2]),'LineWidth',ax.LineWidth,'Color',ax.XColor);
YLineHdl=plot(ax,ax.XLim([2,2]),ax.YLim([1,2]),'LineWidth',ax.LineWidth,'Color',ax.YColor);
addlistener(ax,'MarkedClean',@changeLinePos)
function changeLinePos(~,~)
set(XLineHdl,'XData',ax.XLim([1,2]),'YData',ax.YLim([2,2]))
set(YLineHdl,'XData',ax.XLim([2,2]),'YData',ax.YLim([1,2]))
end
end
这样画完图之后在最后加一行addBox()即可,框的颜色及粗细会和轴的颜色相图:
t = linspace(pi/100,4*pi,500);
y1 = cos(t).^2;
y2 = sin(t).^2./t;
% 基础绘图
hold on
area(y1,'LineWidth',.8,'FaceColor',[0,0,.9],'FaceAlpha',.2)
area(y2,'LineWidth',.8,'FaceColor',[.8,0,0],'FaceAlpha',.2)
% 坐标区域基础修饰
ax=gca; grid on; box on
ax.FontName = 'Cambria';
ax.TickDir = 'out';
ax.LineWidth = 1;
ax.XColor = [0,0,.8];
ax.YColor = [.8,0,0];
addBox()
4 三维框的颜色
假设我们编写了如下代码:
% 获取数据
X1=normrnd(2,2,1,50);
X2=[normrnd(4,4,1,50),normrnd(5,2,1,50)];
X3=[normrnd(6,2,1,50),normrnd(8,4,1,50)];
X4=[normrnd(12,1,1,50),normrnd(12,4,1,50)];
X5=[normrnd(10,2,1,50),normrnd(10,4,1,50)];
X6=[normrnd(7,2,1,50),normrnd(7,4,1,50)];
X7=[normrnd(4,2,1,50),normrnd(4,4,1,50)];
Data={X1,X2,X3,X4,X5,X6,X7};
Y=zeros(7,500);
for i=1:length(Data)
tX=Data{i};tX=tX(:)';
[F,Xi]=ksdensity(tX,linspace(-5,10,500));
Y(i,:)=F;
end
X=Xi;
YLim=[min(min(Y)),max(max(Y))];
% 构造并绘制网格
[XMesh,YMesh]=meshgrid(X,linspace(YLim(1),YLim(2),1000));
hold on
for i=1:size(Y,1)
YMeshA=repmat(Y(i,:),[1000,1]);
CMesh=nan.*XMesh;
YMeshD=YMeshA-YLim(1);
CMesh(YMesh>=YLim(1)&YMesh<=YMeshA)=YMeshD(YMesh>=YLim(1)&YMesh<=YMeshA);
surf(XMesh,XMesh.*0+i,YMesh,'EdgeColor','none','CData',CMesh,'FaceColor','flat','FaceAlpha',.8)
end
% 绘制折线图
for i=1:size(Y,1)
plot3(X,X.*0+i,Y(i,:),'LineWidth',1,'Color',[0,0,0,.8])
end
% 设置配色
colorList=turbo(64);
% colorList=slanCM(110,64);
colormap(colorList)
colorbar
% 坐标区域修饰
ax=gca;hold on;box on
ax.XGrid='on';
ax.YGrid='on';
ax.XMinorTick='on';
ax.YMinorTick='on';
ax.LineWidth=.8;
ax.GridLineStyle='-.';
ax.FontName='Cambria';
ax.FontSize=12;
ax.GridAlpha=.03;
ax.Projection='perspective';
ax.GridAlpha=.05;
ax.BoxStyle='full';
view(16,36)
可以通过boxFrame属性设置每个框线的颜色:
% 设置框线颜色
ax=gca;
pause(1e-6);
ax.BoxFrame.XColor=[1,0,0];
ax.BoxFrame.YColor=[0,1,0];
ax.BoxFrame.ZColor=[0,0,1];
可以看到仅仅框线变色,轴线不变色,此属性仅仅为显示属性,保存时无法保留颜色,因此建议绘制折线硬画:
把之前写的一小部分东西拿过来再提一下:
5 更改3D图轴位置
对于hAxes=gca
- hAxes.XRuler.FirstCrossoverValue
X轴在Y轴上的位置 - hAxes.XRuler.SecondCrossoverValue
X轴在Z轴上的位置 - hAxes.YRuler.FirstCrossoverValue
Y轴在X轴上的位置 - hAxes.YRuler.SecondCrossoverValue
Y轴在Z轴上的位置 - hAxes.ZRuler.FirstCrossoverValue
Z轴在X轴上的位置 - hAxes.ZRuler.SecondCrossoverValue
Z轴在Y轴上的位置
一个实例:
N = 49;
X = linspace(-10,10,N);
Z = peaks(N);
mesh(X,X,Z);
hAxes=gca;
hAxes.LineWidth=1.5;
hAxes.XRuler.FirstCrossoverValue = 0; % X轴在Y轴上的位置
hAxes.YRuler.FirstCrossoverValue = 0; % Y轴在X轴上的位置
hAxes.ZRuler.FirstCrossoverValue = 0; % Z轴在X轴上的位置
hAxes.ZRuler.SecondCrossoverValue = 0; % Z轴在Y轴上的位置
6 修改坐标区域背景
我们知道可以通过设置
set(gca,'Color',[1,0,0])
类似的形式设置背景颜色,但这只是纯色,那么有啥办法把背景色换成渐变色?
t=0.2:0.01:3*pi;
hold on
plot(t,cos(t)./(1+t),'LineWidth',4)
plot(t,sin(t)./(1+t),'LineWidth',4)
plot(t,cos(t+pi/2)./(1+t+pi/2),'LineWidth',4)
plot(t,cos(t+pi)./(1+t+pi),'LineWidth',4)
legend
ax=gca;pause(1e-16);% Backdrop建立需要一定时间因此pause一下很重要
% 四列分别为四个角的颜色
% 使用4xN大小颜色矩阵
% 四行分别是R,G,B,和透明度
colorData = uint8([255, 150, 200, 100; ...
255, 100, 50, 200; ...
0, 50, 100, 150; ...
102, 150, 200, 50]);
set(ax.Backdrop.Face, 'ColorBinding','interpolated','ColorData',colorData);
7 半透明及渐变图例
t=0.2:0.01:3*pi;
hold on
plot(t,cos(t)./(1+t),'LineWidth',4)
plot(t,sin(t)./(1+t),'LineWidth',4)
plot(t,cos(t+pi/2)./(1+t+pi/2),'LineWidth',4)
plot(t,cos(t+pi)./(1+t+pi),'LineWidth',4)
hLegend=legend();
% 设置图例为半透明
pause(1e-16)
set(hLegend.BoxFace,'ColorType','truecoloralpha','ColorData',uint8(255*[1;1;1;.5]));
set(gca,'Color',[0,0,.18]);
当然也可以花里胡哨:
t=0.2:0.01:3*pi;
hold on
plot(t,cos(t)./(1+t),'LineWidth',4)
plot(t,sin(t)./(1+t),'LineWidth',4)
plot(t,cos(t+pi/2)./(1+t+pi/2),'LineWidth',4)
plot(t,cos(t+pi)./(1+t+pi),'LineWidth',4)
hLegend=legend();
% 设置图例为渐变色
pause(1e-16)
colorData = uint8([255, 150, 200, 100; ...
255, 100, 50, 200; ...
0, 50, 100, 150; ...
102, 150, 200, 50]);
set(hLegend.BoxFace,'ColorBinding','interpolated','ColorData',colorData)
8 轴标签的科学计数法
我们想将刻度值用科学计数法表示咋办,假如编写了如下代码:
rng(5)
% 随机生成数据
X=1.5+rand(4,4);
% 基础绘图
ax=gca;hold on;
bHdl=bar(X,'LineWidth',.8);
% 修改配色
CList=[0.4078 0.5647 0.8157
0.9098 0.7843 0.6588
0.9725 0.8784 0.7216
0.9725 0.9725 0.9725];
bHdl(1).FaceColor=CList(1,:);
bHdl(2).FaceColor=CList(2,:);
bHdl(3).FaceColor=CList(3,:);
bHdl(4).FaceColor=CList(4,:);
% 坐标区域修饰
ax.FontName='Times New Roman';
ax.LineWidth=.8;
ax.FontSize=12;
ax.YGrid='on';
ax.GridLineStyle='-.';
ax.XTick=1:4;
在最后编写如下代码使用科学计数法:
ax=gca;
ax.XRuler.Exponent=-5;
ax=gca;
ax.XRuler.Exponent=5;
9 更复杂的标签公式
刻度标签也可以改成支持latex,还是上面的绘图函数,在最后加上:
ax.XRuler.TickLabelInterpreter='latex';
ax.XTickLabel={'$\Delta A B C$','$\frac{n!}{r!(n-r)!} $','$\left(\begin{array}{cc}A& B\\C& D\end{array}\right)$','$E = n{{ \Delta \Phi } \over {\Delta {t} }} $'}
10 显示次标签
最后讲一下如何显示X轴及Y轴次标签:
x = linspace(0,100,1000);
y = 5 + 3*sin(x./2);
fill([x x(end)],[y y(1)],[0.40 0.76 0.60],'FaceAlpha',.2,...
'LineWidth',1,'EdgeColor',[0.40 0.76 0.60])
% 坐标区域基础修饰
ax=gca; grid on;
ax.FontName = 'Cambria';
ax.TickDir = 'out';
ax.LineWidth = .8;
ax.Box = 'off';
% 显示次标签
ax=gca;
% X轴主次标签
xlabel('XXXX1111')
ax.XRuler.SecondaryLabel.String='XXXX2222';
ax.XRuler.SecondaryLabel.Visible='on';
% Y轴主次标签
ylabel('YYYY1111')
ax.YRuler.SecondaryLabel.String='YYYY2222';
ax.YRuler.SecondaryLabel.Visible='on';
完
本期已经足够长了,等有下期可能会补充其他的MATLAB中的离谱操作!!!