tqdm w Jupyter Notebook wielokrotnie drukuje nowe paski postępu


138

Używam tqdmdo drukowania postępu w skrypcie, który uruchamiam w notatniku Jupyter. Drukuję wszystkie wiadomości do konsoli za pośrednictwem tqdm.write(). Jednak nadal daje mi to wypaczony wynik:

wprowadź opis obrazu tutaj

Oznacza to, że za każdym razem, gdy ma być wydrukowany nowy wiersz, nowy pasek postępu jest drukowany w następnym wierszu. Nie dzieje się tak, gdy uruchamiam skrypt przez terminal. Jak mogę to rozwiązać?


Właściwie, kiedy używam tqdm_notebook, mogę nawet normalnie robić printi nie ma to wpływu na pasek postępu.
Tomasz Gandor

Odpowiedzi:


216

Spróbuj użyć tqdm.notebook.tqdmzamiast tqdm, jak opisano tutaj .

Może to być tak proste, jak zmiana importu na:

from tqdm.notebook import tqdm

Powodzenia!

EDYCJA: Po testach wydaje się, że tqdmfaktycznie działa dobrze w „trybie tekstowym” w notatniku Jupyter. Trudno to stwierdzić, ponieważ nie podano minimalnego przykładu , ale wygląda na to, że problem jest spowodowany instrukcją print w każdej iteracji. Instrukcja print umieszcza liczbę (~ 0,89) pomiędzy każdą aktualizacją paska stanu, co psuje wynik. Spróbuj usunąć instrukcję print.


2
Nie użyłem print()oświadczenia, użyłem tqdm.write(). Jednak tqdm_notebookdaje dobre efekty. Dzięki
:)

Czy wiesz, czy obsługuje Python 3.6? Nie miałem z tym szczęścia
Jon

1
Jaki błąd otrzymujesz? U mnie działa dobrze. Nie można pomóc przy tak małej ilości informacji ... Czy włączyłeś ipywidgets w jupyer ? Czy masz po prostu zwyczajne tqdm, a nie tqdm_notebook? Działa to dobrze z Pythonem 3.6 i Jupyter 1.0.0.
oscarbranson

tqdm_notebook z tqdm 4.19.4 działa dla mnie na Pythonie 3.6, Jupyter notebook 5.0.0 i ipywidgets 7.0.3.
Matt Kleinsmith

2
@ bugmenot123 Dobry chwyt, naprawiony.
Czyżby

39

To jest alternatywna odpowiedź w przypadku, gdy tqdm_notebook nie działa dla Ciebie.

Biorąc pod uwagę następujący przykład:

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)

Wynik będzie wyglądał mniej więcej tak (postęp byłby czerwony):

  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

Problem polega na tym, że dane wyjściowe do stdout i stderr są przetwarzane asynchronicznie i osobno pod względem nowych wierszy.

Jeśli powiedzmy, że Jupyter odbiera na stderr pierwszą linię, a następnie „przetworzone” wyjście na standardowe wyjście. Następnie, gdy otrzyma wyjście na stderr, aby zaktualizować postęp, nie wróci i nie zaktualizuje pierwszej linii, ponieważ zaktualizuje tylko ostatnią linię. Zamiast tego będzie musiał napisać nową linię.

Obejście 1, zapisywanie na standardowe wyjście

Jednym obejściem byłoby wyprowadzenie obu na standardowe wyjście:

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)

Wynik zmieni się na (nie będzie już czerwony):

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]

Tutaj widzimy, że Jupyter nie wydaje się oczyścić do końca linii. Moglibyśmy dodać inne obejście tego problemu, dodając spacje. Jak na przykład:

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)

Co daje nam:

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

Obejście 2, zamiast tego ustaw opis

Ogólnie rzecz biorąc, prostsze może być nie posiadanie dwóch wyjść, ale zamiast tego zaktualizowanie opisu, np .:

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)

Z wyjściem (opis aktualizowany podczas przetwarzania):

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

Wniosek

W większości przypadków można go sprawić, aby działał dobrze za pomocą zwykłego tqdm. Ale jeśli tqdm_notebook działa dla ciebie, po prostu go użyj (ale wtedy prawdopodobnie nie przeczytałeś aż tak daleko).


alternatywą jest użycie tego progressbar stackoverflow.com/a/34482761/1207193
eusoubrasileiro

To zdecydowanie najlepsza odpowiedź.
Rafay,

18

Większość odpowiedzi jest teraz nieaktualna. Lepiej, jeśli poprawnie zaimportujesz tqdm .

from tqdm import tqdm_notebook as tqdm

wprowadź opis obrazu tutaj


7
Znowu się zmieniło:TqdmDeprecationWarning: This function will be removed in tqdm==5.0.0 Please use tqdm.notebook.tqdm instead of tqdm.tqdm_notebook
stason

10

Jeśli inne wskazówki nie działają i - tak jak ja - korzystasz z pandasintegracji progress_apply, możesz tqdmsobie z tym poradzić:

from tqdm.autonotebook import tqdm
tqdm.pandas()

df.progress_apply(row_function, axis=1)

Główny punkt leży w tqdm.autonotebookmodule. Jak stwierdzono w ich instrukcjach dotyczących używania w notatnikach IPython , powoduje to tqdmwybór między formatami paska postępu używanymi w notebookach Jupyter i konsolach Jupyter - z powodu, dla którego wciąż brakuje dalszych badań z mojej strony, określony format wybrany przez tqdm.autonotebookdziała płynnie pandas, podczas gdy wszystkie inne nie. „t, o progress_applyspecjalnie.


9

Aby zakończyć odpowiedź oscarbranson: możliwe jest automatyczne wybranie wersji paska postępu na konsole lub notebooka w zależności od tego, skąd jest uruchamiany:

from tqdm.autonotebook import tqdm

Więcej informacji można znaleźć tutaj


8

Żadne z powyższych nie działa dla mnie. Uważam, że uruchomienie do następujących rozwiązuje ten problem po błędzie (po prostu usuwa wszystkie wystąpienia pasków postępu w tle):

from tqdm import tqdm

# blah blah your code errored

tqdm._instances.clear()

1
Dziękuję Ci! Jednak zgłasza i błąd, jeśli nie ma żadnych instancji. Nadal chcę go używać ze skryptami i Hydrogen IDE. Oto mój kod. try: # Avoids problem on notebooks / Hydrogen IDE tqdm.tqdm._instances.clear() except Exception: pass
Jacques Peeters

Tak, zgłosi wyjątek, jeśli nie istnieje żadna instancja. Czy istnieje problem z Twoją próbą oprócz podejścia?
James Owers


0

Dla każdego, kto korzysta z systemu Windows i nie mógł rozwiązać problemu z powielaniem pasków za pomocą żadnego z wymienionych tutaj rozwiązań. Musiałem zainstalować coloramapakiet zgodnie ze znanymi problemami tqdm, które go naprawiły.

pip install colorama

Wypróbuj na tym przykładzie:

from tqdm import tqdm
from time import sleep

for _ in tqdm(range(5), "All", ncols = 80, position = 0):
    for _ in tqdm(range(100), "Sub", ncols = 80, position = 1, leave = False):
        sleep(0.01)

Który da coś takiego:

All:  60%|████████████████████████                | 3/5 [00:03<00:02,  1.02s/it]
Sub:  50%|██████████████████▌                  | 50/100 [00:00<00:00, 97.88it/s]
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.