Search code examples
pythonvisual-studio-codejupyter-lab

Python Particle simulator in Quan Nguyen's book: Python advanced programming. The code not working for me


I have started reading "Advanced Python Programming", 2nd ed of Quan Nguyen. The code to simulate particles' circular motion is not working for me. But according to the book, it should work: I wonder if I am missing something. I run it on Windows 11, Python 3.8.12 and VScode or JupyterLab. Nothing seems to happen (in vscode) and a warning in JupyterLab.

Here is the code:

# %load simul.py
from matplotlib import pyplot as plt
from matplotlib import animation
from random import uniform
import timeit
import os

os.system('cls' if os.name == 'nt' else 'clear')


class Particle:

    __slots__ = ("x", "y", "ang_speed")

    def __init__(self, x, y, ang_speed):
        self.x = x
        self.y = y
        self.ang_speed = ang_speed


class ParticleSimulator:
    def __init__(self, particles):
        self.particles = particles

    def evolve(self, dt):
        timestep = 0.00001
        nsteps = int(dt / timestep)

        for i in range(nsteps):
            for p in self.particles:

                norm = (p.x ** 2 + p.y ** 2) ** 0.5
                v_x = (-p.y) / norm
                v_y = p.x / norm

                d_x = timestep * p.ang_speed * v_x
                d_y = timestep * p.ang_speed * v_y

                p.x += d_x
                p.y += d_y


def visualize(simulator):

    X = [p.x for p in simulator.particles]
    Y = [p.y for p in simulator.particles]

    fig = plt.figure()
    ax = plt.subplot(111, aspect="equal")
    (line,) = ax.plot(X, Y, "ro")

    # Axis limits
    plt.xlim(-1, 1)
    plt.ylim(-1, 1)

    # It will be run when the animation starts
    def init():
        line.set_data([], [])
        return (line,)

    def animate(i):
        # We let the particle evolve for 0.1 time units
        simulator.evolve(0.01)
        X = [p.x for p in simulator.particles]
        Y = [p.y for p in simulator.particles]

        line.set_data(X, Y)
        return (line,)

    # Call the animate function each 10 ms
    anim = animation.FuncAnimation(fig, animate, init_func=init, blit=True, interval=10)
    plt.show()


def test_visualize():
    particles = [
        Particle(0.3, 0.5, +1),
        Particle(0.0, -0.5, -1),
        Particle(-0.1, -0.4, +3),
    ]

    simulator = ParticleSimulator(particles)
    visualize(simulator)

if __name__ == "__main__":
    test_visualize()

The code can also be found here.

When run with JupyterLab, I get the following warning:

C:\Users\ephra\AppData\Local\Temp\ipykernel_18360\3786700959.py:71: UserWarning: frames=None which we can infer the length of, did not pass an explicit *save_count* and passed cache_frame_data=True.  To avoid a possibly unbounded cache, frame data caching has been disabled. To suppress this warning either pass `cache_frame_data=False` or `save_count=MAX_FRAMES`.
  anim = animation.FuncAnimation(fig, animate, init_func=init, blit=True, interval=10)

Am I running it in a wrong way?


Solution

  • that's probably the reason why an explicit value isn't passed. To avoid infinite caching, frame data caching has been disabled. You can turn off cached frame data by passing cache_frame_data=False or pass a numeric value using save_count=MAX_FRAMES to prevent this warning from appearing.