优化MATLAB中quiver函数绘制箭头图或矢量图(1)-MATLAB开发

利用MATLAB绘制更好看的向量图

Matlab的基本数据单位是矩阵,利用Matlab可以较方便得绘制向量分布图,比如空气流的采样数据;函数的梯度;曲面的法线向量等等。Matlab自带的quiver和quiver3函数可以满足这一需求,但是箭头的箭型较为简单,这里主要目的即是进一步绘制更好看的矢量图。

MATLAB向量图函数quiver

Matlab中自带的quiver和quiver3函数能够绘制简单的向量图,基本语法为quiver(X,Y,U,V),quiver3(X,Y,Z,U,V,W), 在由 X 和 Y 指定的笛卡尔坐标上绘制具有定向分量 U 和 V 的箭头。调整箭头的长度,设置线型、标记和颜色等语法参考MATLAB帮助中心.
示例1.(来源MATLAB帮助中心)
绘制函数 z = x e − x 2 − y 2 z=xe^{-x^2-y^2} z=xex2y2的梯度和等高线。
首先,创建一个由等间距的 x x x y y y 值组成的网格。使用它们来计算 z z z。然后,通过指定点之间的间距,求得 z z z 的梯度。
代码片

spacing = 0.2;
[X,Y] = meshgrid(-2:spacing:2);
Z = X.*exp(-X.^2 - Y.^2);
[DX,DY] = gradient(Z,spacing);

将梯度向量显示为一个箭头图。然后,在相同的坐标区中显示等高线。通过调用 axis equal,调整显示以使梯度向量垂直于等高线。
代码片

quiver(X,Y,DX,DY)
hold on
contour(X,Y,Z)
axis equal
hold off

示例2.(来源MATLAB帮助中心)
绘制垂直于由函数 z = x e − x 2 − y 2 z=xe^{-x^2-y^2} z=xex2y2 定义的曲面的向量。
首先,创建一个由等间距的 x x x y y y 值组成的网格。使用它们来计算 z z z。然后,求法向量。
代码片

[X,Y] = meshgrid(-2:0.25:2,-1:0.2:1);
Z = X.*exp(-X.^2 - Y.^2);
[U,V,W] = surfnorm(X,Y,Z);

将向量显示为一个三维箭头图。然后,在相同的坐标区中显示曲面。通过调用 axis equal,调整显示,使向量显示为垂直于曲面。
代码片

quiver3(X,Y,Z,U,V,W)
hold on
surf(X,Y,Z)
axis equal

MATLAB绘制3D箭头

这里我们首先写一个简单的绘制3D箭头的函数,输入箭头的位置(a,b,c)与朝向(alpha,beta,gamma),在坐标区中返回三维箭头,内部且可控制箭头的大小形状颜色等参数。箭头由四部分组成:圆锥侧面+圆柱侧面+圆锥底面+圆锥底面。因此输出我们设置四部分s1,s2,s3,s4。
函数表达式如下
代码片

function [s1,s2,s3,s4] = quiver_Refine(a,b,c,alpha,beta,gamma)
...
end

MATLAB绘制圆锤

首先绘制圆锥侧面以及圆锥底面:
代码片

% Cone
r1 = 0:0.01:0.25; % The cone radius
h1 = 0.5;         % The cone height
% The cone top position
a1 = a;    
b1 = b;
c1 = 0.5;
% Generate cone data
[u,v,w] = cylinder(r1,50);
u = u+a1;
v = v+b1;
w = -w*h1+c1+c;
% Cone botton
t1 = (0:0.04:2)*pi;
r = max(r1(:));
xc = a1;
yc = b1;
zc = c1-h1+c;
% Generate cone botton data
x1 = xc + cos(t1)*r;
y1 = yc + sin(t1)*r;
[m,n] = size(x1);
z1 = repmat(zc,m,n);

后边利用surf函数绘制圆锤侧面;利用fill3绘制圆锥底面

MATLAB绘制圆柱

然后绘制圆柱侧面以及圆柱底面,且圆柱顶部位置连接在圆锥底部:
代码片

% Cylinder
r2 = 0.1; % The cylinder radius
h2 = 0.5; % The cylinder height
% The cylinder top position
a2 = a1;
b2 = b1;
c2 = c1-h1;
% Generate cylinder data
[x,y,z] = cylinder(r2,50);
x = x+a2;
y = y+b2;
z = -z*h2+c2+c;
% Cylinder botton
t2 = (0:0.04:2)*pi;
r = r2;
xc = a2;
yc = b2;
zc = c2-h2+c;
% Generate cylinder botton data
x2 = xc + cos(t2)*r;
y2 = yc + sin(t2)*r;
[m,n] = size(x2);
z2 = repmat(zc,m,n);

利用利用surf函数绘制圆锤圆柱侧面;利用fill3绘制圆锥圆柱底面
代码片

%plot
s1 = surf(u,v,w,'Facecolor',color,'Edgecolor','none');
s2 = surf(x,y,z,'Facecolor',color,'Edgecolor','none');
s3 = fill3(x1,y1,z1,color,'Edgecolor','none');
s4 = fill3(x2,y2,z2,color,'Edgecolor','none');

这里已经可以画出来一个完整的箭头了,位置由(a,b,c)决定,此时方向默认沿 + z +z +z方向即(0,0,1)方向,颜色由color变量决定。

箭头的方向与颜色控制

箭头的方向控制利用rotate函数实现。
代码片

% Rotate arrow
zc = (c1+zc)/2;
hold on
origin = [xc,yc,zc];
theta2 = acos(gamma./sqrt(alpha.^2 + beta.^2 + gamma.^2));
if beta^2 + alpha^2 == 0
    direct = [0 1 0];
else
    direct = [-beta,alpha,0];
end

然后对之前的箭头的四部分分量分别进行坐标变换即可
代码片

if theta2 ~= 0
rotate(s1,direct,rad2deg(theta2),origin);
rotate(s2,direct,rad2deg(theta2),origin);
rotate(s3,direct,rad2deg(theta2),origin);
rotate(s4,direct,rad2deg(theta2),origin);
end

箭头的颜色控制可以自定义color变量的构成,比如这里将箭头在 x y xy xy面内的方位角 ϕ \phi ϕ与色环colorwheel绑定,极角 θ \theta θ与亮度intensity绑定。即颜色HSL空间中 H S L HSL HSL三分量与 α \alpha α, β \beta β, γ \gamma γ对应
XYZ to HSL

代码片

% control quiver color using HSL
H = atan2(beta,alpha);
% Get the atan2 space in 0 ~ 2*pi
if H < 0
    H = 2*pi+H;
end

% rotate clockwisely
H = H + theta/180*pi;
if H < 0
    H = H + 2*pi;
elseif H >2*pi
    H = H - 2*pi;
end

S = sqrt(1-gamma^2);
I = (gamma+1)/2;

% change HSL to RGB 
idx = find((0 <= H)&(H < 2*pi/3));
B(idx) = I(idx).*(1-S(idx));
R(idx) = I(idx).*(1+S(idx).*cos(H(idx))./cos(pi/3-H(idx)));
G(idx) = 3*I(idx)-(B(idx)+R(idx));

idx = find((2*pi/3 <= H)&(H < 4*pi/3));
R(idx) = I(idx).*(1-S(idx));
G(idx) = I(idx).*(1+S(idx).*cos(H(idx)-2*pi/3)./cos(pi-H(idx)));
B(idx) = 3*I(idx)-(G(idx)+R(idx));

idx = find((4*pi/3 <= H)&(H <= 2*pi));
G(idx) = I(idx).*(1-S(idx));
B(idx) = I(idx).*(1+S(idx).*cos(H(idx)-4*pi/3)./cos(5*pi/3-H(idx)));
R(idx) = 3*I(idx)-(G(idx)+B(idx));

color = [R G B];
color(isnan(color)) = 0;
% Get color in the right range
for i=1:3
    color(i)=max(min(color(i),1),0);
end

这里由于MATLAB中颜色解释为RGB,需要额外从HSL空间变换至RGB空间。其实也可以通过hsv2rgb函数实现。

光照参数调节

MATLAB具有完整的一套光照参数设置,图形提供的功能类似于带变焦镜头的相机,可控制由 MATLAB创建的场景视图,详情请参阅相机图形术语。MATLAB图形环境提供的命令允许放置光源并调整反射光线的对象的特性,详情请参阅光照概述。这里我们可以控制光照来使得箭头看起来更立体些。
代码片

% lighting settings
axis equal 
camlight('left');
lighting phong 
view(3)

新quiver效果展示

有了以上设置后我们可以来调试下自己的quiver_Refine函数:
quiver_Refine(0,0,0,1,0,0);quiver_Refine(0,0,0,-1,0,0);
quiver_Refine(0,0,0,0,1,0);quiver_Refine(0,0,0,0,-1,0);
quiver_Refine

位置/方向矩阵输入后效果展示

目前的quiver_Refine版本只支持输入单个位置的数据,需要利用for循环不断调用,运行速度较慢,不过最后结果看上去比原quiver函数要更好看一点。这里以Bloch-Skyrmion为例,把Colorwheel顺时针旋转120°后将quiver染上色,嗯还挺好看的。
BlochSkyrmion

  • 21
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

NBb-666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值