如何在一条线上绘制三维矢量场?
我想可视化矢量场 $( m_x(x), m_y(x), m_z(x) )$。搜索“可视化矢量场”后,我发现大多数绘图软件要么在平面上绘制二维矢量场,如速度场,要么在三维空间中绘制三维矢量场,如 $( u(x,y,z), v(x,y,z), w(x,y,z))$。
我尝试使用 MATLAB 函数 quiver3 来绘制我的测试数据,
quiver3( x, zeros(1,N), zeros(1,N), mx, my, mz );
这是我得到的结果,相当不令人满意。
最好用下图这样替换(简单的3d渲染就可以了,不需要和下图一模一样),
[来源:MPQ,量子多体系统部门]
所以我想问一下,是否可以使用 asympotote/tikz/matlab/mathematica 进行这样的演示?这个矢量场是时间的函数,所以我将生成这些图的电影。
我并不要求它在 TeX 中生成,只要它最终可以合并到我的 TeX 文件中即可。严格来说,它不是一个 TeX 问题;如有必要,请将其迁移到适当的 StackExchange 站点。
答案1
使用 Asymptote 可以沿表面(而不是路径)绘制 3D 矢量场。调整此例程以沿路径绘制 3D 矢量场并不困难。但是复杂的箭头不可用,需要更多工作。请查找示例
import graph3;
size(200,0);
currentprojection=perspective(10,8,4);
real f(pair z) {return 0.5+exp(-abs(z)^2);}
triple F(pair z){ return (z.x,z.y,f(z));}
path3 gradient(pair z) {
static real dx=sqrtEpsilon, dy=dx;
return O--(-(f(z+dx)-f(z-dx))/2dx,
-(f(z+I*dy)-f(z-I*dy))/2dy,
1);
}
add(vectorfield(gradient,F,(-1,-1),(1,1),red));
draw((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle);
surface s=surface(f,(-1,-1),(1,1),nx=5,Spline);
xaxis3(Label("$x$"),red,Arrow3);
yaxis3(Label("$y$"),red,Arrow3);
zaxis3(XYZero(extend=true),red,Arrow3);
draw(s,lightgray,meshpen=black+thick(),nolight,render(merge=true));
label("$O$",O,-Z+Y,red);
结果
最后,Python/Matplotlib/Numpy/Scipy 解决方案(可以生成电影)怎么样?
编辑于 2014 年 11 月 17 日。我尝试修改 Asymptote 的矢量场函数并包含特殊箭头。因为我不知道你的路径和矢量场如何依赖,所以以下例程沿曲线绘制矢量场,在 f(t) 上绘制的矢量场取决于 (f(x),f(y))。对于特殊箭头,我不会在 Asymptote 意义上创建新的 Arrow3,而是在矢量场例程中添加球体
import graph3;
real maxilength(triple f(real z), real a, real b, int nu)
{
real du=1/nu;
real maxi = abs(f(a+(b-a)/nu)-f(a));
for(int i=0; i < nu; ++i) {
real x=interp(a,b,i*du);
real y=interp(a,b,(i+1)*du);
maxi=min(maxi,abs(f(y)-f(x)));
}
return maxi;
}
// return a vector field on a parametric curve f defined on the interval
// [a,b].
// The vector field depends on the x and y coordinates of f. For example
// f is a curve lying on a surface and the vector field depends on the
// (x,y) point of the surface
picture vectorfield(path3 vector(pair v), triple f(real z), real a, real b,
int nu=nmesh, int nv=nu, bool truesize=false,
real maxlength=truesize ? 0 : maxilength(f,a,b,nu)
,
bool cond(real z)=null, pen p=currentpen,
arrowbar3 arrow=Arrow3, margin3 margin=PenMargin3,
string name="", render render=defaultrender)
{
picture pic;
real du=1/nu;
bool all=cond == null;
real scale;
if(maxlength > 0) {
real size(pair z) {
path3 g=vector(z);
return abs(point(g,size(g)-1)-point(g,0));
}
real maxi=size((0,0));
for(int i=0; i <= nu; ++i) {
real x=interp(a,b,i*du);
maxi=max(maxi,size((f(x).x,f(x).y)));
}
scale=maxi > 0 ? maxlength/maxi : 1;
} else scale=1;
bool group=name != "" || render.defaultnames;
if(group)
begingroup3(pic,name == "" ? "vectorfield" : name,render);
for(int i=0; i <= nu; ++i) {
real x=interp(a,b,i*du);
real z=x;
if(all || cond(z)) {
path3 g=scale3(scale)*vector((f(z).x,f(z).y));
string name="vector";
if(truesize) {
picture opic;
draw(opic,g,p,arrow,margin,name,render);
draw(opic,shift(point(g,.25))*scale3(abs(point(g,1)-point(g,0))/8)*unitsphere,p,name,render);
add(pic,opic,f(z));
} else
{
draw(pic,shift(f(z))*g,p,arrow,margin,name,render);
draw(pic,shift(f(z))*shift(point(g,.25))*scale3(abs(point(g,1)-point(g,0))/8)*unitsphere,p,name,render);
}
}
// }
}
if(group)
endgroup3(pic);
return pic;
}
import graph3;
size(200,0);
currentprojection=perspective(10,8,4);
real f(pair z) {return 0.5+exp(-abs(z)^2);}
//triple F(pair z){ return (z.x,z.y,f(z));}
triple FF(real x) {return (cos(x),sin(x),f((cos(x),sin(x))));}
path3 gradient(pair z) {
static real dx=sqrtEpsilon, dy=dx;
return O--(//(f(z+I*dy)-f(z-I*dy))/2dy,
-(f(z+dx)-f(z-dx))/2dx,
- (f(z+I*dy)-f(z-I*dy))/2dy,
1);
}
//add(vectorfield(gradient,F,(-1,-1),(1,1),red,Arrow3));
add(vectorfield(gradient,FF,-pi,pi-0.4,20,//maxlength=.2,
1.5bp+red,Arrow3(DefaultHead3)));
draw((-1,-1,0)--(1,-1,0),Arrow3(DefaultHead3));
draw((-1,-1,0)--(1,-1,0)--(1,1,0)--(-1,1,0)--cycle);
surface s=surface(f,(-1,-1),(1,1),nx=5,Spline);
xaxis3(Label("$x$"),red,Arrow3);
yaxis3(Label("$y$"),red,Arrow3);
zaxis3(XYZero(extend=true),red,Arrow3);
draw(s,lightgray+opacity(.5),meshpen=black+thick(),nolight,render(merge=true));
label("$O$",O,-Z+Y,red);
请查找结果
答案2
使用pst-solides3d
。从我的代码开始,完成您的示例。请注意,编译需要很长时间。
\documentclass{article}
\usepackage{etex}
\usepackage{pst-solides3d}
\newcommand\arrow[2]{
\psSolid[object=cylindre,h=.11,r=.04,
fillcolor=#2,linewidth=.25pt,
transform={0 0 -.2 translatepoint3d #1},ngrid=1 16]
\psSolid[object=sphere,r=.1,
fillcolor=#2,linewidth=.25pt,
transform={ #1},ngrid=16 16]%
\psSolid[object=cylindre,h=.11,r=.04,
fillcolor=#2,linewidth=.25pt,
transform={0 0 .09 translatepoint3d #1},ngrid=1 16]%
\psSolid[object=cone,h=.2,r=.075,
fillcolor=#2,mode=4,linewidth=.25pt,
transform={0 0 .2 translatepoint3d #1},ngrid=1 16]%
}
\begin{document}
\psset{unit=.1\textwidth,viewpoint=10 45 25 rtp2xyz,
Decran=10,lightsrc=10 10 10,lightintensity=2}
\begin{pspicture}(-5,-5)(5,5)
\multido{\iA=0+1,\iB=0+30}{20}{
\arrow{0 30 0 rotateOpoint3d
0 0 \iB\space rotateOpoint3d
0 \iA\space .6 mul 6 sub 0 translatepoint3d}{blue!50}
}
\end{pspicture}
\end{document}