"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Plotagem em tempo real com pyplot

Plotagem em tempo real com pyplot

Publicado em 2024-11-08
Navegar:541

Real-time plotting with pyplot

Eu queria representar graficamente alguns dados que estava gerando a partir de um aplicativo de pesquisa simples. Já mexi no pyplot no passado, mas não tentei criar nada do zero. Felizmente, é muito popular e há muitos exemplos que podem ser encontrados no StackOverflow e em outros lugares.

Fiz uma pesquisa e comecei com esta resposta SO relacionada à atualização de um gráfico ao longo do tempo.

import matplotlib.pyplot as plt
import numpy as np

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)

fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma

for phase in np.linspace(0, 10*np.pi, 500):
    line1.set_ydata(np.sin(x   phase))
    fig.canvas.draw()
    fig.canvas.flush_events()

Este código anima uma fase de mudança de onda senoidal.

As primeiras duas linhas importam as bibliotecas que desejo usar: matplotlib.pyplot faz a plotagem e o manuseio da GUI.

O método ion(), se bem entendi (embora não), faz com que o pyplot conduza a GUI. Você também pode usá-lo dentro de um programa tkinter ou para gerar imagens estáticas, mas no nosso caso faz sentido deixá-lo lidar com a GUI do gráfico para nós. (Isso é o que a chamada flush_events() mais tarde está fazendo: permitindo a interatividade com a janela da figura.)

Este exemplo usa o método numpy linspace() para criar os valores x. Ele retorna um array numpy, que é uma lista sofisticada do Python.

O motivo para usar np.sin em vez de math.sin é a transmissão. Esse é o termo numpy para aplicar a função a cada item de uma lista. Na verdade, me ocorre que a mesma coisa poderia ser alcançada sem numpy usando map:

map(lambda n: math.sin(n), x)

Mas a transmissão numpy é conveniente e simples de usar.

Agora vem a configuração do pyplot. Primeiro, crie uma nova “figura” (fig). Nesta figura, adicione uma subtrama (ax) – pode haver muitas. 111 tem uma interpretação bastante esotérica, "crie uma grade 1x1 e coloque esta subtrama na primeira célula."

Nesta subtrama (ou conjunto de eixos), uma linha é traçada usando os valores x e y passados. (Os pontos são conectados com linhas retas e plotados continuamente.) "r-" é a forma abreviada de especificar uma linha vermelha sólida. Poderíamos especificar múltiplas linhas, então plot() retorna uma tupla; o código acima usa descompactação de tupla para extrair o valor que desejamos.

É um bom começo, mas preciso estender o eixo x ao longo do tempo. Este código também não atualiza os limites do eixo y, se necessário - ele fica bloqueado em quaisquer limites calculados para o primeiro gráfico. Um pouco mais de pesquisa me levou a esta resposta SO. Para citá-los:

Você precisará atualizar o dataLim dos eixos e, posteriormente, atualizar o viewLim dos eixos com base no dataLim. Os métodos apropriados são os métodos axes.relim() e ax.autoscale_view().

Claro, parece bom. Com base no exemplo deles, criei um gráfico de demonstração que cresce em x e em y.

import matplotlib.pyplot as plt
import numpy as np
from threading import Thread
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Returns a tuple of line objects

growth = 0

while True:
    x.append(x_next_max / 10)
    x_next_max  = 1
    line1.set_xdata(x)
    line1.set_ydata(np.sin(x)   np.sin(np.divide(x, 100))   np.divide(x, 100))
    ax.relim()
    ax.autoscale()
    fig.canvas.draw()
    fig.canvas.flush_events()

    sleep(0.1)

Agora estou chegando a algum lugar. Porém, este é um loop de bloqueio e preciso que meus dados sejam atualizados ocasionalmente. Se eu tivesse vários threads, teria que me preocupar em ser seguro para threads ao atualizar minhas variáveis. Nesse caso, posso ser preguiçoso porque sei que a variável só é atualizada uma vez a cada 5 minutos (ou com que frequência a função de pesquisa é executada); não há perigo de a variável ser substituída no meio de uma linha de código.

import matplotlib.pyplot as plt
import numpy as np
from threading import Timer
from time import sleep

x = list(map(lambda x: x / 10, range(-100, 100)))
x_next_max = 100
y = np.sin(x)

# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()

fig = plt.figure()
ax = fig.add_subplot(111)
line1 = ax.plot(x, y, 'r-')[0] # Plot returns a tuple of line objects

growth = 0
new_x = None

dT = 1

def grow():
    global new_x, x_next_max
    while True:
        new_x = x   [x_next_max / 10]
        x_next_max  = 1
        sleep(dT) # grow every dT seconds

t = Thread(target=grow)
t.start()

while True:

    if new_x:
        x = new_x
        new_x = None
        line1.set_xdata(x)
        line1.set_ydata(np.sin(x)   np.sin(np.divide(x, 100))   np.divide(x, 100))
        ax.relim()
        ax.autoscale()
        fig.canvas.draw()

    fig.canvas.flush_events()

    sleep(0.1)

O gráfico só é atualizado quando o thread de crescimento atribui um valor a new_x. Observe que a chamada flush_events() está fora da instrução "if", portanto é chamada com frequência.

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/paxfeline/real-time-plotting-with-pyplot-2b3g?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3