Edvard Fagerholm
Edvard Fagerholm

Reputation: 862

Trying to get matplotlib to display images as an animation

I have a class that imports matplotlib when needed and functions as a callback that receives a NumPy array, which should be shown in the next rendered frame. I need to dump this in a window as an animation on the screen. The current code is:

import matplotlib.pyplot as plt
import numpy as np

class Renderer(object):
    def __init__(self):
        self._image = None

    def __call__(self, buffer):
        if not self._image:
            self._image = plt.imshow(buffer, animated=True)
        else:
            self._image.set_data(buffer)
        plt.draw()

renderer = Renderer()
for _ in range(100):
    renderer(
        np.random.randint(low=0, high=255, size=(240, 320, 3), dtype=np.uint8))

There's some pretty heavy computation doing simulations that are generating each frame, so I don't worry that the frame rate will be too high.

Currently, the code does absolutely nothing, i.e. nothing appears on screen. Does anyone have an idea how to do an animation with the library?

UPDATE: Regarding context, so in my use case an instance of Renderer gets passed down to a layer of code that generates pixels and draws them on the screen by calling the Renderer object. In other words, when something should be drawn is out of my control, I also can't control the frame rate and don't know the time interval between the frames. For this reason what I really need from an API point-of-view is just a way to dump a bunch of pixels on the screen right now.

The FuncAnimation approach has the problem that getting the frames to it would require changing the Renderer callback to put frames on a queue from where the generator generating frames would pull them. FuncAnimation also seems to require me to know the time interval between frames a priori, which I don't know and isn't necessarily constant.

Upvotes: 0

Views: 504

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339340

Just as usual for animations, use interactive mode (plt.ion()) or a FuncAnimation.

Interactive mode (plt.ion())

import matplotlib.pyplot as plt
import numpy as np

class Renderer(object):
    def __init__(self):
        self._image = None

    def __call__(self, buffer):
        if not self._image:
            self._image = plt.imshow(buffer, animated=True)
        else:
            self._image.set_data(buffer)
        plt.pause(0.01)
        plt.draw()

renderer = Renderer()
plt.ion()
for _ in range(100):
    renderer(
        np.random.randint(low=0, high=255, size=(240, 320, 3), dtype=np.uint8))
plt.ioff()
plt.show()

Animation with FuncAnimaton

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np

class Renderer(object):
    def __init__(self):
        self._image = None

    def __call__(self, buffer):
        if not self._image:
            self._image = plt.imshow(buffer, animated=True)
        else:
            self._image.set_data(buffer)


renderer = Renderer()

fig, ax = plt.subplots()
def update(i):
    renderer(
        np.random.randint(low=0, high=255, size=(240, 320, 3), dtype=np.uint8))
ani = FuncAnimation(fig, update, frames=100, interval=10)

plt.show()

Upvotes: 1

Related Questions