tqdm в ноутбуке Jupyter

Я использую tqdm для печати прогресса в сценарии, который я запускаю в ноутбуке Jupyter. Я печатаю все сообщения на консоль через tqdm.write(). Тем не менее, это все еще дает мне перекошенный вывод, например:

enter image description here

То есть, каждый раз, когда должна печататься новая строка, на следующей строке печатается новый индикатор выполнения. Этого не происходит, когда я запускаю скрипт через терминал. Как я могу это решить?

Ответы

Ответ 1

Попробуйте использовать tqdm_notebook вместо tqdm, как описано здесь. Он экспериментальный на этом этапе, но в большинстве случаев работает очень хорошо.

Это может быть так же просто, как изменить импорт:

from tqdm import tqdm_notebook as tqdm

Удачи!

EDIT: после тестирования кажется, что tqdm действительно отлично работает в текстовом режиме в ноутбуке Jupyter. Трудно сказать, потому что вы не представили минимальный пример, но похоже, что ваша проблема вызвана операцией печати на каждой итерации. Оператор печати выводит число (~ 0,89) между каждым обновлением строки состояния, которое испортит вывод. Попробуйте удалить инструкцию печати.

Ответ 2

Это альтернативный ответ для случая, когда tqdm_notebook не работает для вас.

В следующем примере:

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)

Результат будет выглядеть примерно так (прогресс будет красным):

  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

Проблема в том, что вывод в stdout и stderr обрабатывается асинхронно и отдельно в терминах новых строк.

Если говорят, что Jupyter получает на stderr первую строку, а затем "обработанный" вывод на stdout. Затем, как только он получает вывод на stderr для обновления прогресса, он не возвращается и не обновляет первую строку, поскольку он обновляет только последнюю строку. Вместо этого ему придется написать новую строку.

Обходной путь 1, запись в stdout

Одним из способов решения этой проблемы было бы вывести на stdout:

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)

Выход будет изменен на (не более красным):

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]

Здесь мы видим, что Jupyter, похоже, не очищается до конца строки. Мы могли бы добавить еще одно обходное решение для этого путем добавления пробелов. Такие как:

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)

Что дает нам:

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

Обходной путь 2, вместо описания

В целом, возможно, более прямолинейно не иметь два выхода, но вместо этого обновить описание, например:

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)

С выходом (описание обновляется во время обработки):

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

Вывод

Вы можете в основном заставить его работать нормально с простым tqdm. Но если tqdm_notebook работает для вас, просто используйте это (но тогда вы, вероятно, не читали бы так далеко).

Ответ 3

Если другие советы здесь не работают и - как и я - вы используете интеграцию pandas через progress_apply, вы можете позволить tqdm справиться с этим:

from tqdm.auto import tqdm
tqdm.pandas()

df.progress_apply(row_function, axis=1)

Главное здесь заключается в модуле tqdm.auto. Как указано в их инструкциях по применению в IPython тетрадях, это делает tqdm выбор между штриховых форматов, используемых в ходе Jupyter ноутбуков и Jupyter консолей - по причине, по- прежнему не хватает дальнейших исследований на моей стороне, конкретный формат, выбранный tqdm.auto работает плавно pandas в то время как все остальные не, для progress_apply специально.