How to Animate Matplotlib 3D Plots in Python

In this tutorial, you’ll learn various methods to animate different types of 3D plots using Matplotlib and Python.

To get started, you’ll need to import the necessary libraries:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from mpl_toolkits.mplot3d import Axes3D

This code imports NumPy for numerical operations, Matplotlib for plotting, FuncAnimation for creating animations, and Axes3D for 3D plotting capabilities.

 

 

Rotate 3D surface plot

You can create a rotating 3D surface plot to showcase different angles of your data:

def generate_surface(x, y):
    return np.sin(np.sqrt(x**2 + y**2))
x = np.linspace(-6, 6, 30)
y = np.linspace(-6, 6, 30)
X, Y = np.meshgrid(x, y)
Z = generate_surface(X, Y)
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
surf = ax.plot_surface(X, Y, Z, cmap='viridis')
def rotate(frame):
    ax.view_init(elev=10, azim=frame)
    return surf,
ani = FuncAnimation(fig, rotate, frames=np.linspace(0, 360, 100), interval=50, blit=False)
plt.show()

This code creates a 3D surface plot of a sine function and animates it by rotating the view around the z-axis.

The rotate function updates the viewing angle for each frame, creating a smooth rotation effect.

You can also create a video from the animated plot and this goes for any of the coming examples.

 

Update 3D scatter plot data

You can animate a 3D scatter plot by updating the data points in each frame:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
n_points = 100
scatter = ax.scatter([], [], [])
def update_scatter(frame):
    x = np.random.normal(0, 1, n_points)
    y = np.random.normal(0, 1, n_points)
    z = np.random.normal(0, 1, n_points)
    scatter._offsets3d = (x, y, z)
    return scatter,
ani = FuncAnimation(fig, update_scatter, frames=100, interval=50, blit=False)
plt.show()

The update_scatter function updates the positions of the scatter points, giving the illusion of movement.

 

Animate 3D line plot

To create an animated 3D line plot, you can update the line data in each frame:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
line, = ax.plot([], [], [])
def update_line(frame):
    t = np.linspace(0, 10, 1000)
    x = np.sin(t + frame/10)
    y = np.cos(t + frame/10)
    z = t
    line.set_data(x, y)
    line.set_3d_properties(z)
    return line,
ani = FuncAnimation(fig, update_line, frames=100, interval=50, blit=False)
plt.show()

The update_line function calculates new x, y, and z coordinates for each frame, updating the line’s position.

 

Animate 3D bar chart

You can create an animated 3D bar chart by updating the heights of the bars in each frame:

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x = np.arange(5)
y = np.arange(5)
x, y = np.meshgrid(x, y)
x = x.flatten()
y = y.flatten()
z = np.zeros_like(x)
dx = dy = 0.8
dz = np.random.rand(25)
bars = ax.bar3d(x, y, z, dx, dy, dz, shade=True)

# Function to update the bars
def update_bars(frame):
    new_dz = np.random.rand(25)
    ax.clear()
    ax.bar3d(x, y, z, dx, dy, new_dz, shade=True)
ani = FuncAnimation(fig, update_bars, frames=100, interval=100)
plt.show()

The update_bars function generates new heights for each bar and redraws the entire chart in each frame.

 

Evolving 3D contour plot

To create an evolving 3D contour plot, you can update the contour data in each frame:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
contour = ax.contour3D(X, Y, np.zeros_like(X))
def update_contour(frame):
    Z = np.sin(np.sqrt(X**2 + Y**2) - frame/10)
    ax.clear()
    ax.contour3D(X, Y, Z, 50, cmap='viridis')
    ax.set_zlim(-1, 1)
ani = FuncAnimation(fig, update_contour, frames=100, interval=50)
plt.show()

The update_contour function calculates new Z values for each frame and redraws the contour plot.

 

Animated 3D Vector Field

You can create an animated 3D vector field by updating the vectors in each frame:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
x, y, z = np.meshgrid(np.arange(-2, 3),
                      np.arange(-2, 3),
                      np.arange(-2, 3))

quiver = ax.quiver(x, y, z, np.zeros_like(x), np.zeros_like(y), np.zeros_like(z), length=0.5, normalize=True)
def update_quiver(frame):
    global quiver
    # Remove the old quiver
    quiver.remove()
    # Calculate new vector components
    u = np.sin(x + frame / 10)
    v = np.cos(y + frame / 10)
    w = np.sin(z + frame / 10)
    # Create a new quiver
    quiver = ax.quiver(x, y, z, u, v, w, length=0.5, normalize=True)
    return quiver,
ani = FuncAnimation(fig, update_quiver, frames=100, interval=50, blit=False)
plt.show()

The update_quiver function calculates new vector components for each frame and redraws the entire vector field.

 

Growing 3D Network Graph

To create a growing 3D network graph, you can add nodes and edges in each frame:

import networkx as nx
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
G = nx.Graph()
num_nodes = 20
for i in range(num_nodes):
  G.add_node(i)
def update_graph(num):
  ax.clear()
  ax.set_title('3D Growing Network Graph')
  
  # Add edges randomly
  if num > 0:
      for _ in range(2):  # Add two edges per frame
          n1, n2 = np.random.choice(num_nodes, 2, replace=False)
          G.add_edge(n1, n2)
  
  # Get node positions
  pos = {i: (np.random.rand(), np.random.rand(), np.random.rand()) for i in range(num_nodes)}
  xs, ys, zs = zip(*pos.values())
  ax.scatter(xs, ys, zs, s=50, c='blue', alpha=0.6)
  for edge in G.edges():
      x = [pos[edge[0]][0], pos[edge[1]][0]]
      y = [pos[edge[0]][1], pos[edge[1]][1]]
      z = [pos[edge[0]][2], pos[edge[1]][2]]
      ax.plot(x, y, z, c='black', alpha=0.4)  
  ax.set_xlim([0, 1])
  ax.set_ylim([0, 1])
  ax.set_zlim([0, 1])
ani = FuncAnimation(fig, update_graph, frames=range(num_nodes), interval=500, repeat=False)
plt.show()

The update_graph function adds new nodes and edges in each frame and puts them randomly in 3D space.

 

Animate Highlighting Certain Points

You can create an animation that highlights specific points or regions in a 3D plot:

fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
x = np.random.rand(100) * 4 - 2
y = np.random.rand(100) * 4 - 2
z = np.random.rand(100) * 4 - 2
scatter = ax.scatter(x, y, z, c='blue', s=50)
highlight = ax.scatter([], [], [], c='red', s=100)
def update_highlight(frame):
    center = np.array([np.sin(frame/10), np.cos(frame/10), np.sin(frame/5)])
    distances = np.sqrt(np.sum((np.array([x, y, z]).T - center)**2, axis=1))
    highlighted = distances < 0.5
    highlight._offsets3d = (x[highlighted], y[highlighted], z[highlighted])
    return highlight,
ani = FuncAnimation(fig, update_highlight, frames=100, interval=50, blit=False)
plt.show()

The update_highlight function calculates the distance of each point from a moving center and highlights points within a certain radius.

Leave a Reply

Your email address will not be published. Required fields are marked *