Search code examples
pythonmatplotlibanimationmatplotlib-animation

Moving sphere animation


I want to create an animation of a moving sphere in matplotlib. For some reason it isnt working:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib import cm
from matplotlib import animation
import pandas as pd


fig = plt.figure(facecolor='black')
ax = plt.axes(projection = "3d")

u = np.linspace(0, 2*np.pi, 100)
v = np.linspace(0, np.pi, 100)
r = 4

ax.set_xlim(0, 60)
ax.set_ylim(0, 60)
ax.set_zlim(0, 60)

x0 = r * np.outer(np.cos(u), np.sin(v)) + 10
y0 = r * np.outer(np.sin(u), np.sin(v)) + 10
z0 = r * np.outer(np.ones(np.size(u)), np.cos(v)) + 50

def init():
    ax.plot_surface(x0,y0,z0)
    return fig,

def animate(i):
    ax.plot_surface(x0 + 1, y0 + 1, z0 + 1)
    return fig,

ani = animation. FuncAnimation(fig, animate, init_func = init, frames = 90, interval = 300)


plt.show()

Here, I have attempted to move the sphere by (1,1,1) in each new iteration, but it fails to do so.


Solution

  • There are a couple of mistakes with your approach:

    1. In your animate function you are adding a sphere at each iteration. Unfortunately, Poly3DCollection objects (created by ax.plot_surface) cannot be modified after they have been created, hence to animate a surface we need to remove the surface of the previous iteration and add a new one.
    2. In your animation the sphere didn't move because at each iteration you were adding a new sphere at the same location as the previous one.
    import numpy as np
    import matplotlib.pyplot as plt
    from mpl_toolkits import mplot3d
    from matplotlib import cm
    from matplotlib import animation
    import pandas as pd
    
    
    fig = plt.figure(facecolor='black')
    ax = plt.axes(projection = "3d")
    
    u = np.linspace(0, 2*np.pi, 100)
    v = np.linspace(0, np.pi, 100)
    r = 4
    
    ax.set_xlim(0, 60)
    ax.set_ylim(0, 60)
    ax.set_zlim(0, 60)
    
    x0 = r * np.outer(np.cos(u), np.sin(v)) + 10
    y0 = r * np.outer(np.sin(u), np.sin(v)) + 10
    z0 = r * np.outer(np.ones(np.size(u)), np.cos(v)) + 50
    
    surface_color = "tab:blue"
    
    def init():
        ax.plot_surface(x0, y0, z0, color=surface_color)
        return fig,
    
    def animate(i):
        # remove previous collections
        ax.collections.clear()
        # add the new sphere
        ax.plot_surface(x0 + i, y0 + i, z0 + i, color=surface_color)
        return fig,
    
    ani = animation. FuncAnimation(fig, animate, init_func = init, frames = 90, interval = 300)
    
    
    plt.show()