2 votes

Comment mettre à jour une figure interactive en boucle avec JupyterLab

J'essaie de mettre à jour une figure interactive matplotlib tout en étant dans une boucle utilisant JupyterLab. Je peux le faire si je crée la figure dans une cellule différente de la boucle, mais je préférerais créer la figure et exécuter la boucle dans la même cellule.

Exemple de code simple :

import matplotlib.pyplot as plt
import time

%matplotlib widget

fig = plt.figure()

for i in range(5):
    x = list(range(i+2))
    xx = [x**2 for x in x]
    plt.clf()
    plt.plot(x, xx)
    fig.canvas.draw()

    time.sleep(1)

Si fig = plt.figure() se trouve dans la même cellule que la boucle, la figure n'est pas mise à jour tant que la boucle n'est pas terminée :

Not Dynamically Updating

Si je crée la figure dans une autre cellule, j'obtiens la mise à jour dynamique, mais j'aimerais pouvoir créer la figure dans la même cellule si possible afin que la sortie soit en dessous de la boucle :

Requires extra cell

J'ai essayé plusieurs réponses dans d'autres questions ( aquí , aquí et aquí ), mais elles ne semblent pas fonctionner avec les figures interactives de JupyterLab. J'utilise l'option jupyter/scipy-notebook docker image comme mon environnement, donc je crois que tout est configuré correctement.

Existe-t-il un moyen d'obtenir la mise à jour dynamique dans la même cellule que celle où la figure est créée ?

2voto

krassowski Points 1021

Vous pouvez utiliser asyncio, en tirant parti de la boucle événementielle d'IPython :

import matplotlib.pyplot as plt
import asyncio
%matplotlib widget
fig = plt.figure()

async def update():
    for i in range(5):
        print(i)
        x = list(range(i + 2))
        xx = [x**2 for x in x]
        plt.clf()
        plt.plot(x, xx)
        fig.canvas.draw()
        await asyncio.sleep(1)

loop = asyncio.get_event_loop()
loop.create_task(update());

gif with a notebook with single cell being run and the animation progressing as expected

0voto

BlackHC Points 98

Si vous ne souhaitez pas utiliser asyncio vous pouvez utiliser display(..., display_id=True) pour obtenir une poignée et utiliser .update() sur celui-ci :

import matplotlib.pyplot as plt
import time
%matplotlib widget
fig = plt.figure()

hfig = display(fig, display_id=True)

def update():
    for i in range(5):
        print(i)
        x = list(range(i + 2))
        xx = [x**2 for x in x]
        plt.clf()
        plt.plot(x, xx)
        fig.canvas.draw()
        hfig.update(fig)
        time.sleep(1)

update()

plt.close(fig)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X