Search code examples
pythonplot3d

Plotting a 3D vector field on 2D plane in Python


I would like to plot a 3D vector field on a 2D plane.

an example data i tried plotting but not able to get a 3D view of the vector fields

any help would be highly appreciated and thankful

tried plotting using matplotlib 3d but with no success


Solution

  • Here's a version inspired by this post that gives a much cleaner picture.

    import numpy as np
    from matplotlib import pyplot as plt
    from mpl_toolkits.mplot3d import Axes3D
    from matplotlib.patches import FancyArrowPatch
    from mpl_toolkits.mplot3d import proj3d
    
    class Arrow3D(FancyArrowPatch):
        def __init__(self, xs, ys, zs, *args, **kwargs):
            FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs)
            self._verts3d = xs, ys, zs
            
        def do_3d_projection(self, renderer=None):
            xs3d, ys3d, zs3d = self._verts3d
            xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.M)
            self.set_positions((xs[0],ys[0]),(xs[1],ys[1]))
    
            return np.min(zs)
            
    coords_y = np.arange(-4,5)
    coords_z = np.arange(-4,5)
    coords = np.vstack([[0,y,z] for y in coords_y for z in coords_z])
    
    angle = pi/4
    R_mat = np.array([[cos(angle),-sin(angle)],[sin(angle),cos(angle)]])
    vel_yz = coords[:,1:]@R_mat.T
    vel = np.hstack([.1*np.ones([len(coords),1]),vel_yz])
    
    fig,ax = plt.subplots(figsize = (10,10),subplot_kw = {"projection":"3d"})
    ax.view_init(vertical_axis = 'x')
    ax.plot3D(*coords.T, 'ro')
    
    for p,v in zip(coords,.2*vel):
        a = Arrow3D(*zip(p,p+v), mutation_scale=20, 
                    lw=2, arrowstyle="-|>", color="b")
        ax.add_artist(a)
    

    Result:

    enter image description here


    Here's something that gets pretty close to what you're looking for, using that 3D quiver method and setting the x-axis to be the vertical axis.

    I'm still looking into how we could get the arrows to look a little nicer.

    import numpy as np
    import matplotlib.pyplot as plt
    from numpy.random import randn
    from numpy import sin, cos, pi
    
    coords_y = np.arange(-4,5)
    coords_z = np.arange(-4,5)
    coords = np.vstack([[0,y,z] for y in coords_y for z in coords_z])
    
    R_mat = np.array([[cos(pi/4),-sin(pi/4)],[sin(pi/4),cos(pi/4)]])
    vel_yz = coords[:,1:]@R_mat.T
    vel = np.hstack([.1*np.ones([len(coords),1]),vel_yz])
    
    fig,ax = plt.subplots(figsize = (10,10),subplot_kw = {"projection":"3d"})
    ax.view_init(vertical_axis = 'x')
    ax.plot3D(*coords.T, 'ro')
    ax.quiver(*coords.T, *vel.T, length = .1)
    

    Sample result:

    enter image description here