Double Progress Bar в Python

Есть ли способ создать двойной индикатор выполнения в Python? Я хочу запустить две петли внутри друг друга. Для каждого цикла я хочу иметь индикатор выполнения. Моя программа выглядит так:

import time
for i1 in range(5):
    for i2 in range(300):
        # do something, e.g. sleep
        time.sleep(0.01)
        # update upper progress bar
    # update lower progress bar

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

50%|############################                                  |ETA: 0:00:02
80%|##################################################            |ETA: 0:00:04

Уже существующий действительно классный progressbar модуль, похоже, не поддерживает это.

Ответ 1

Используйте вложенные параметры выполнения tqdm, чрезвычайно низкую накладную, очень настраиваемую библиотеку индикаторов выполнения:

$ pip install -U tqdm

Тогда:

from tqdm import tqdm
import time
for i1 in tqdm(range(5)):
    for i2 in tqdm(range(300)):
        # do something, e.g. sleep
        time.sleep(0.01)

Вы также можете использовать from tqdm import trange, а затем заменить tqdm(range(...)) на trange(...). Вы также можете получить работу в ноутбуке.

Ответ 2

Вам потребуется переместить позицию курсора. Я написал вам хакерскую вещь, чтобы сделать это.

Этот script полагается на то, что модуль progressbar предполагает, что вы находитесь на новой строке, чтобы нарисовать индикатор выполнения. Просто перемещая курсор вверх (используя escape-код для "move cursor 1 row up" ) и вниз (просто используя новую строку. Я также мог бы использовать escape-код, но новая строка проще и быстрее), можно поддерживать многократный прогресс бары.

import progressbar, time, sys

def up():
    # My terminal breaks if we don't flush after the escape-code
    sys.stdout.write('\x1b[1A')
    sys.stdout.flush()

def down():
    # I could use '\x1b[1B' here, but newline is faster and easier
    sys.stdout.write('\n')
    sys.stdout.flush()

# Total bar is at the bottom. Move down to draw it
down()
total = progressbar.ProgressBar(maxval=50)
total.start()

for i in range(1,51):
    # Move back up to prepare for sub-bar
    up()

    # I make a new sub-bar for every iteration, thinking it could be things
    # like "File progress", with total being total file progress.
    sub = progressbar.ProgressBar(maxval=50)
    sub.start()
    for y in range(51):
        sub.update(y)
        time.sleep(0.005)
    sub.finish()

    # Update total - The sub-bar printed a newline on finish, so we already
    # have focus on it
    total.update(i)
total.finish()

Это, конечно, немного взломанный, но он выполняет свою работу. Надеюсь, что это полезно.

Ответ 3

Это можно легко сделать с помощью atpbar.

Например:

import time, random
from atpbar import atpbar

for i in atpbar(range(4), name='outer'):
    n = random.randint(1000, 10000)
    for j in atpbar(range(n), name='inner {}'.format(i)):
        time.sleep(0.0001)

Приведенный выше код вложен for циклы. Внешний цикл повторяется четыре раза. Для каждой итерации внешнего цикла внутренний цикл повторяет количество случайных выборок. Индикатор выполнения для внутреннего цикла перемещается вверх по завершении цикла. Активные индикаторы прогресса остаются внизу. Снимок индикаторов выполнения может выглядеть следующим образом

 100.00% :::::::::::::::::::::::::::::::::::::::: |     3287 /     3287 |:  inner 0
 100.00% :::::::::::::::::::::::::::::::::::::::: |     5850 /     5850 |:  inner 1
  50.00% ::::::::::::::::::::                     |        2 /        4 |:  outer  
  34.42% :::::::::::::                            |     1559 /     4529 |:  inner 2

Ответ 4

enter code here
from tqdm import tqdm_notebook as tqdm
import time
for i1 in tqdm(range(5)):
     for i2 in tqdm(range(300)):
         # do something, e.g. sleep
         time.sleep(0.01)