Traçage en temps réel avec pyplot

王林
Libérer: 2024-09-03 17:17:02
original
668 Les gens l'ont consulté

Real-time plotting with pyplot

Je voulais représenter graphiquement certaines données que je générais à partir d'une simple application de sondage. J'ai bricolé pyplot dans le passé, mais je n'ai pas essayé de créer quoi que ce soit à partir de zéro. Heureusement, c'est très populaire et il existe des tonnes d'exemples sur StackOverflow et ailleurs.

J'ai fait une recherche et j'ai commencé avec cette réponse SO liée à la mise à jour d'un graphique au fil du temps.

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()
Copier après la connexion

Ce code anime une phase de changement d'onde sinusoïdale.

Les deux premières lignes importent les bibliothèques que je souhaite utiliser : matplotlib.pyplot s'occupe du traçage et de la gestion de l'interface graphique.

La méthode ion(), si je comprends bien (même si je ne peux pas le faire), permet à pyplot de piloter l'interface graphique. Vous pouvez également l'utiliser dans un programme tkinter, ou l'utiliser pour générer des images statiques, mais dans notre cas, il est logique de le laisser gérer l'interface graphique de l'intrigue pour nous. (C'est ce que fait l'appel flush_events() plus tard : permettre l'interactivité avec la fenêtre de la figure.)

Cet exemple utilise la méthode numpy linspace() pour créer les valeurs x. Il renvoie un tableau numpy, qui est une liste Python sophistiquée.

La raison d'utiliser np.sin au lieu de math.sin est la diffusion. C'est le terme numpy pour appliquer la fonction à chaque élément d'une liste. En fait, il me vient à l'esprit que la même chose pourrait être réalisée sans numpy en utilisant map :

map(lambda n: math.sin(n), x)
Copier après la connexion

Mais la diffusion numpy est pratique et simple à utiliser.

Vient maintenant la configuration de pyplot. Tout d'abord, créez une nouvelle "figure" (fig). Dans cette figure, ajoutez une sous-intrigue (hache) – il pourrait y en avoir plusieurs. 111 a une interprétation plutôt ésotérique : "créez une grille 1x1 et placez cette sous-intrigue dans la première cellule."

Dans ce sous-tracé (ou ensemble d'axes), une ligne est tracée en utilisant les valeurs x et y transmises. (Les points sont reliés par des lignes droites et tracés en continu.) « r- » est la manière abrégée de spécifier une ligne rouge continue. Nous pourrions spécifier plusieurs lignes, donc plot() renvoie un tuple ; le code ci-dessus utilise le déballage de tuple pour extraire la valeur souhaitée.

C'est un bon début, mais je dois étendre l'axe des x au fil du temps. Ce code ne met pas non plus à jour les limites de l'axe y si nécessaire : il est verrouillé dans les limites qu'il calcule pour le premier tracé. Un peu plus de recherche m'amène à cette réponse SO. Pour les citer :

Vous devrez mettre à jour le dataLim des axes, puis mettre à jour ensuite le viewLim des axes en fonction du dataLim. Les méthodes appropriées sont les méthodes axes.relim() et ax.autoscale_view().

Bien sûr, ça a l'air bien. Sur la base de leur exemple, j'ai créé un graphique de démonstration qui grandit à la fois en x et en 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)
Copier après la connexion

Maintenant, j'arrive à quelque chose. Mais il s’agit d’une boucle de blocage et j’ai besoin que mes données soient occasionnellement mises à jour. Si j'avais plusieurs threads, je devrais m'inquiéter d'être sûr des threads lors de la mise à jour de mes variables. Dans ce cas, je peux être paresseux car je sais que la variable n'est mise à jour qu'une fois toutes les 5 minutes (ou quelle que soit la fréquence d'exécution de la fonction d'interrogation) ; il n'y a aucun risque que la variable soit écrasée au milieu d'une ligne de code.

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)
Copier après la connexion

Le graphique n'est mis à jour que lorsque le thread de croissance attribue une valeur à new_x. Notez que l'appel flush_events() se trouve en dehors de l'instruction "if", de sorte qu'il est appelé fréquemment.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!