HOWTO · Matplotlib

Como plotar dados em tempo real usando o Matplotlib

Exiba dados em mudança em uma janela do Matplotlib com FuncAnimation(), redesenhos manuais da tela ou um elemento de dispersão que se atualiza.

Nesta página

Para exibir dados que mudam em uma janela do Matplotlib, atualize os dados dos elementos gráficos já plotados e deixe um backend com suporte a interface gráfica atualizar a exibição. Escolha FuncAnimation() quando as atualizações chegarem em quadros, canvas.draw() e canvas.flush_events() quando precisar controlar o loop diretamente, ou um elemento de dispersão quando cada atualização acrescentar um ponto. Estes exemplos geram valores localmente; ao adaptá-los, substitua a lógica de atualização pelos valores da sua própria fonte. Eles não se conectam a sensores nem a fontes de dados pela rede.

Anime um gráfico com FuncAnimation()

matplotlib.animation.FuncAnimation chama uma função de atualização para cada quadro e agenda os redesenhos. O callback recebe o valor do quadro atual, atualiza a linha existente e retorna os elementos gráficos que foram alterados. frames=10 fornece valores de 0 a 9, enquanto interval=50 solicita um intervalo de 50 milissegundos entre os quadros; o tempo real depende do loop de eventos da interface gráfica.

Mantenha uma referência ao objeto de animação enquanto a janela estiver aberta. O exemplo exibe a animação de forma interativa. Para salvá-la, chame ani.save("animation.gif", writer="pillow", fps=10) antes de plt.show() e instale um gravador de animação compatível, como o Pillow. Salvar é uma etapa de renderização separada e não cria uma fonte de dados ao vivo.

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

figure, ax = plt.subplots()
line, = ax.plot([], [])
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")

def update(frame):
    x = np.linspace(0, 2 * np.pi, 200)
    y = np.sin(x - frame / 5)
    line.set_data(x, y)
    return (line,)

ani = FuncAnimation(figure, update, frames=40, interval=50, blit=True)
plt.show()

Gráfico em tempo real com a função FuncAnimation

Use init_func se a animação precisar de um estado inicial separado e fargs para passar argumentos fixos adicionais ao callback. Se a janela abrir sem atualizar, confira se o backend selecionado do Matplotlib oferece suporte a um loop de eventos de interface gráfica e mantenha ani ativo enquanto a janela estiver aberta.

Atualize uma linha com canvas.draw() e canvas.flush_events()

Para controlar cada atualização em um loop, crie uma linha uma única vez e altere seus dados com set_ydata(). Em seguida, canvas.draw() renderiza a figura atualizada e canvas.flush_events() permite que a interface gráfica processe os eventos pendentes. Esses são métodos do canvas do Matplotlib; eles não limpam a figura. plt.ion() ativa o modo interativo, e uma breve pausa dá tempo para a interface responder.

import time
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 2 * np.pi, 200)
figure, ax = plt.subplots()
line, = ax.plot(x, np.sin(x))
ax.set(xlim=(0, 2 * np.pi), ylim=(-1, 1), xlabel="x", ylabel="sin(x)")

plt.ion()
for frame in range(40):
    line.set_ydata(np.sin(x - frame / 5))
    figure.canvas.draw()
    figure.canvas.flush_events()
    time.sleep(0.05)

plt.ioff()
plt.show()

Gráfico em tempo real no Matplotlib com canvas_draw

Essa abordagem é útil quando o loop também precisa coordenar outras tarefas. Mantenha cada atualização curta para que o loop de eventos possa processar entradas e solicitações de redesenho. Em um backend não interativo, essas chamadas podem renderizar uma figura, mas não oferecer uma janela responsiva; para atualizações interativas, selecione um backend com suporte a interface gráfica.

Crie um gráfico de dispersão em tempo real

Para um fluxo de pontos, crie um único elemento de dispersão e substitua suas coordenadas à medida que novos pontos chegam. Atualizar o mesmo elemento evita acumular um novo objeto gráfico a cada iteração. plt.pause() atualiza o loop de eventos da interface entre os quadros, e os limites dos eixos abaixo mantêm visíveis todos os pontos gerados.

import numpy as np
import matplotlib.pyplot as plt

figure, ax = plt.subplots()
points = ax.scatter([], [])
ax.set(xlim=(0, 4), ylim=(-1.1, 1.1), xlabel="x", ylabel="sin(x)")
x_values = []
y_values = []

for frame in range(100):
    x = frame * 0.04
    x_values.append(x)
    y_values.append(np.sin(x))
    points.set_offsets(np.column_stack((x_values, y_values)))
    plt.pause(0.05)

plt.show()

Gráfico de dispersão em tempo real

Se apenas o ponto mais recente for relevante, mantenha um único par de coordenadas em vez de guardar todo o histórico. Se quiser manter todos os pontos anteriores visíveis, amplie os limites dos eixos à medida que o fluxo cresce. Para dados em alta frequência, atualize com menos frequência do que os dados chegam ou mantenha apenas uma janela recente, para que o desenho não se torne um gargalo.