# How to draw 3d vector field on a line?

How to draw 3d vector field on a line?

I want to visualize the vector field $( m_x(x), m_y(x), m_z(x) )$. After searching "visualize vector field", I find that most plotting software either plotting 2d vector fields on the plane, like the velocity field, or the 3d vector field in 3d space, like $( u(x,y,z), v(x,y,z), w(x,y,z))$.

I have tried the MATLAB function quiver3 to plot my test data,

quiver3( x, zeros(1,N), zeros(1,N), mx, my, mz );


Here is what I get, quite unsatisfactory.

It would be better to replace by the ones in the following figure(some simple 3d rendering would be enough, don't need to exactly the same as the following),

[Credit: MPQ, Quantum Many Body Systems Division ]

So I want to ask, is it possible to produce such a demonstration, using say, asympotote/tikz/matlab/mathematica ? This vector field is a function of time, so I will generate a movie of those plots.

I don't require it be generated within TeX, as long as it can be finally incorporated in my TeX file. Strictly speaking, it is not a TeX-question; please migrate it to the appropriate StackExchange site if necessary.

• pgfplots supports a quiver plot handler as well. It uses TikZ instructs to draw the lines, so one would need to find a tikz way for the advanced arrows. Or you can use a loop together with tikz drawing instructions (same approach as the one of @troy. – Christian Feuersänger Nov 15 '14 at 20:00

With Asymptote it is possible to draw a 3D vector field along a surface (not a path). It is not difficult to adapt this routine to draw a 3D vector field along a path. However the sophisticated arrow is not availabe and needs more work. Please find a example

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));}
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);
}

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);


And the result

At last, what about a Python/Matplotlib/Numpy/Scipy solution (which can generate a movie) ?

Edit 11/17/2014. I tried to modify the vectorfield function of Asymptote and included special arrow. Because I do not know how depend your path and your vector field, the following routine draws a vector field along a curve, the vector field drawn on f(t) depends on the (f(x),f(y)). For the special arrow I do not create a new Arrow3 in the Asymptote sense, the sphere is added in the vectorfield routine

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);
} 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))));}

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);
}

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);


Use pst-solides3d. Start from my code to work out your example. Be warned that it takes really a long time to compile.

\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}


• Thanks. I have tried to compile your code with latex, it generates dvi file instantly, but there is nothing in that dvi file. – anecdote Nov 15 '14 at 1:33
• @anecdote You should do dvi2ps too. – Troy Woo Nov 15 '14 at 1:46
• That works. Pst-solides3d could be my choice. Thank you. – anecdote Nov 15 '14 at 1:58
• @anecdote You are welcome. Note that the arrow is laid out by multiple geometries, kinda stupid. I don't think fusion did a good job either. That is something the authors should work on next, along with a gradient mesh support (hopefully). But you can always import your own geometry using 3rd party CAD software. – Troy Woo Nov 15 '14 at 8:56