samedi 27 novembre 2021

Matplotlib animation patch not redrawing patch

I'm trying to run a matplotlib.pyplot simulation which creates a figure in a 10x10 grid with a large circular outline of radius 10 (the container). Inside this container, a ball (and later multiple balls) is drawn, with its position given in initialisation. Then, when I run a method, next_collision(), it will apply other methods, and calculate a new position for the ball. The patch should then be redrawn at this new position.

class Simulation():
    def __init__(self, container = Container()):
        self._container = container
        self._balls = [Ball(np.array([i+1, i+1]), np.random.normal(0, 5, 2)) for i in range(num_particles)]
        print(self._balls)

                
    def next_collision(self):
        for i in range(0, num_particles):
            self.oldpos = self._balls[i].pos.copy()
            self.oldvel = self._balls[i].vel.copy()
            t = self._balls[i].time_to_collision(self._container)
            self._balls[i].pos = self._balls[i].move(t)
            self._balls[i].vel = self._balls[i].collide(self._container)

    def run(self, num_frames, animate=False):
        if animate == True:
            f = pl.figure()
            ax = pl.axes(xlim=(-10, 10), ylim=(-10, 10))
        for i in range(0, num_particles):
            for frame in range(num_frames):
                self.next_collision()
                if animate == True:
                    ax.add_artist(self._container.get_patch())
                    ax.add_patch(self._balls[i].get_patch())
                    pl.pause(0.1)
                    self._balls[i].patch.center = self._balls[i].pos
                    pl.pause(0.1)
                    pl.show()
        
sim = Simulation(con)        

the get_patch() methods in the final if statement is from two earlier classes, Ball and Container (respectively), as follows:

    def get_patch(self):
        self.patch = pl.Circle(self.oldpos, 1, fc = 'r')
        ax = pl.axes(xlim=(-10, 10), ylim=(-10, 10))
        ax.add_patch(self.patch)
        return self.patch
        #pl.pause(1) 
        #self.patch.center = [self.pos[0], self.pos[1]]
        #print('new patch center', self.patch.center)
        #pl.pause(1)
        #pl.show()

#rest of ball class code
#starts container class

    def get_patch(self):
        return pl.Circle([0., 0.], 10, ec='b', fill=False, ls='solid')

when I run the simulation object in the console, sim as follows:

 sim.run(2, True)

it should perform the next_collision() method twice (num_frames determines how many times next collision should be run), and so it should show the patch appearing in its first position, then appearing in its next position, then appearing in its next position. However instead of removing the old patch, and drawing the new patch, it instead keeps the old patches, whilst drawing a new patch in the new position, e.g:

enter image description here

which is not what I am looking for. I have noticed that if I do

sim.run(1, True)

i.e. doing one collision at a time and closing the pop up window that has the figure on it after each collision, it does update the patch position without having the old position also on the figure.

As a slight aside, and this is not as important, is there any way to make my animation more smoother, rather than just having a patch disappear from its old position and appearing at its new position without any motion of the ball between the positions?

Thanks

Aucun commentaire:

Enregistrer un commentaire