Search code examples
pythonmatplotlib3dangle

Control angle of image projection in 3D matplotlib graphs


I have a 3D graph plotted using matplotlib.

I would like to have the 3D plot projected at a specific angle, but using axis.view_init(elevation_angle, azimuthal_angle) does not cover the angle that I want, this is due to the 3 possible planes of rotation in 3 dimensions and only 2 angles that you can specify in matplotlib.

Here is a minimum working example.

import numpy,matplotlib,scipy
from matplotlib import pyplot
from scipy import constants
from mpl_toolkits.mplot3d.axes3d import Axes3D

pi=scipy.constants.pi

  w= numpy.arange(0,5000,1)


def lorentzian(x,center,width,time,tau):
    return 1.0/((1+((x-center)/width)**2)*width*pi)*numpy.exp(-time/tau)

centers= [1000.0,2000.0,4000.0]
widths = [100.0,300.0,50.0]

taus=numpy.zeros(len(widths))

for i in xrange(0,len(widths),1):
    taus[i] = 1.0/widths[i]

time = numpy.array([0,0.019,0.033])
B = numpy.zeros((3,len(w)))
for z in xrange(0,len(time),1):
    a= numpy.zeros(len(w))
    for i in xrange(0,len(centers),1):
        a = a + lorentzian(w,centers[i],widths[i],time[z],taus[i])

    B[z] = a

ThreeD_spectrum_figure = matplotlib.pyplot.figure()
ThreeD_spectrum_axis = ThreeD_spectrum_figure.add_subplot(111, projection="3d")

colour = ["purple","green","orange"]
for i in xrange(0,len(time),1):
    ThreeD_spectrum_axis.plot(w, B[i],time[i],color=colour[i],linewidth=3)

ThreeD_spectrum_axis.view_init( 135,-90)
matplotlib.pyplot.show()

This will generate the graph shown in the image below where I have, hastily in ms paint, added lines to show the rotation and the axis.

Red shows the angle control of the azimuth, rotating about the Y axis.

Blue shows the elevation angle, rotating about the X axis.

Black shows the rotation I need, which would be rotating about the Z axis, which is not possible using axis.view_init(elevation_angle, azimuth_angle). enter image description here

Can anyone offer any help or insight into how I can achieve this rotation? Thanks


Solution

  • Rotation about the z Axis can be achieved using the azimuthal angle alone.

    enter image description here

    import numpy as np
    import matplotlib.animation
    import matplotlib.pyplot as plt
    from mpl_toolkits.mplot3d.axes3d import Axes3D
    
    pi=np.pi
    w= np.arange(0,5000,1)
    
    def lorentzian(x,center,width,time,tau):
        return 1.0/((1+((x-center)/width)**2)*width*pi)*np.exp(-time/tau)
    
    centers= [1000.0,2000.0,4000.0]
    widths = [100.0,300.0,50.0]
    
    taus=np.zeros(len(widths))
    
    for i in xrange(0,len(widths),1):
        taus[i] = 1.0/widths[i]
    
    time = np.array([0,0.019,0.033])
    B = np.zeros((3,len(w)))
    for z in xrange(0,len(time),1):
        a= np.zeros(len(w))
        for i in xrange(0,len(centers),1):
            a = a + lorentzian(w,centers[i],widths[i],time[z],taus[i])
        B[z] = a
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection="3d")
    
    colour = ["purple","green","orange"]
    for i in xrange(len(time)-1,-1,-1):
        ax.plot(time[i]*np.ones_like(w), w ,B[i]*np.ones_like(w),color=colour[i],linewidth=3)
    
    ax.set_xlabel("x")
    ax.set_ylabel("y")
    ax.set_zlabel("z")
    
    #(elev, azim)
    ax.view_init(45,0)
    
    phi = np.linspace(0, 2*np.pi)
    
    def update(phi):
        ax.view_init(45, phi*180./np.pi)
    
    ani = matplotlib.animation.FuncAnimation(fig, update, frames=phi)
    ani.save(__file__+".gif", writer='imagemagick', fps=10)
    plt.show()