web-dev-qa-db-fra.com

tqdm dans Jupyter Notebook

J'utilise tqdm pour imprimer la progression dans un script exécuté dans un cahier Jupyter. J'imprime tous les messages sur la console via tqdm.write(). Cependant, cela me donne toujours une sortie biaisée comme ceci:

enter image description here

C'est-à-dire que chaque fois qu'une nouvelle ligne doit être imprimée, une nouvelle barre de progression est imprimée sur la ligne suivante. Cela ne se produit pas lorsque j'exécute le script via un terminal. Comment puis-je résoudre ça?

83
Rohan Saxena

Essayez d’utiliser tqdm_notebook au lieu de tqdm, comme indiqué ici . C'est expérimental à ce stade, mais fonctionne plutôt bien dans la plupart des cas.

Cela pourrait être aussi simple que de changer votre importation en:

from tqdm import tqdm_notebook as tqdm

Bonne chance!

EDIT: Après les tests, il semble que tqdm fonctionne correctement en "mode texte" dans le cahier Jupyter. C'est difficile à dire car vous n'avez pas fourni de exemple minimal , mais il semble que votre problème soit causé par une instruction print à chaque itération. L'instruction print génère un nombre (~ 0,89) entre chaque mise à jour de la barre d'état, ce qui perturbe la sortie. Essayez de supprimer la déclaration d'impression.

141
oscarbranson

C'est une réponse alternative pour le cas où tqdm_notebook ne fonctionne pas pour vous.

Étant donné l'exemple suivant:

from time import sleep
from tqdm import tqdm

values = range(3)
with tqdm(total=len(values)) as pbar:
    for i in values:
        pbar.write('processed: %d' %i)
        pbar.update(1)
        sleep(1)

La sortie ressemblerait à quelque chose comme ceci (les progrès seraient affichés en rouge):

  0%|          | 0/3 [00:00<?, ?it/s]
processed: 1
 67%|██████▋   | 2/3 [00:01<00:00,  1.99it/s]
processed: 2
100%|██████████| 3/3 [00:02<00:00,  1.53it/s]
processed: 3

Le problème est que la sortie de stdout et stderr est traitée de manière asynchrone et séparée en termes de nouvelles lignes.

Si Jupyter reçoit sur stderr la première ligne puis la sortie "traitée" sur stdout. Ensuite, une fois qu'il aura reçu une sortie sur stderr pour mettre à jour l'avancement, il ne reviendra pas en arrière et mettra à jour la première ligne car il ne mettrait à jour que la dernière ligne. Au lieu de cela, il devra écrire une nouvelle ligne.

Solution de contournement 1, écriture sur stdout

Une solution de contournement serait de sortir les deux sur stdout à la place:

import sys
from time import sleep
from tqdm import tqdm

values = range(3)
with tqdm(total=len(values), file=sys.stdout) as pbar:
    for i in values:
        pbar.write('processed: %d' % (1 + i))
        pbar.update(1)
        sleep(1)

La sortie passera à (plus de rouge):

processed: 1   | 0/3 [00:00<?, ?it/s]
processed: 2   | 0/3 [00:00<?, ?it/s]
processed: 3   | 2/3 [00:01<00:00,  1.99it/s]
100%|██████████| 3/3 [00:02<00:00,  1.53it/s]

Nous pouvons voir ici que Jupyter ne semble pas effacer avant la fin de la ligne. Nous pourrions ajouter une autre solution de contournement pour cela en ajoutant des espaces. Tel que:

import sys
from time import sleep
from tqdm import tqdm

values = range(3)
with tqdm(total=len(values), file=sys.stdout) as pbar:
    for i in values:
        pbar.write('processed: %d%s' % (1 + i, ' ' * 50))
        pbar.update(1)
        sleep(1)

Ce qui nous donne:

processed: 1                                                  
processed: 2                                                  
processed: 3                                                  
100%|██████████| 3/3 [00:02<00:00,  1.53it/s]

Solution 2, définissez la description à la place

En général, il peut être plus simple de ne pas avoir deux sorties mais de mettre à jour la description, par exemple:

import sys
from time import sleep
from tqdm import tqdm

values = range(3)
with tqdm(total=len(values), file=sys.stdout) as pbar:
    for i in values:
        pbar.set_description('processed: %d' % (1 + i))
        pbar.update(1)
        sleep(1)

Avec la sortie (description mise à jour pendant le traitement):

processed: 3: 100%|██████████| 3/3 [00:02<00:00,  1.53it/s]

Conclusion

Vous pouvez généralement le faire fonctionner correctement avec plain tqdm. Mais si tqdm_notebook fonctionne pour vous, utilisez-le (mais vous ne liriez probablement pas si loin).

25
de1

Si les autres astuces ne fonctionnent pas et que, comme moi, vous utilisez l'intégration pandas via progress_apply, vous pouvez laisser tqdm le gérer:

from tqdm.auto import tqdm
tqdm.pandas()

df.progress_apply(row_function, axis=1)

Le point principal ici réside dans le module tqdm.auto. Comme indiqué dans leurs instructions d'utilisation dans les ordinateurs portables IPython , cela fait tqdm choisir entre les formats de barre de progression utilisés dans les ordinateurs portables Jupyter et les consoles Jupyter - pour une raison qui manque toujours Le format spécifique choisi par tqdm.auto fonctionne sans problème dans pandas, contrairement à tous les autres, pour progress_apply en particulier.

3
Julio Cezar Silva