- Python Progress Bar
- 47 Answers 47
- No external packages. A ready-made piece of code.
- Python 3.3+
- Usage:
- Python 3.6+ (f-string)
- Python 2 (old-code)
- Отслеживаем прогресс выполнения в Python
- Используем Progress
- Используем tqdm
- Используем alive-progress
- GUI индикатор прогресса для скрипта
- Индикатор в приложении PySimpleGUI
- Заключение
Python Progress Bar
How do I use a progress bar when my script is doing some task that is likely to take time? For example, a function which takes some time to complete and returns True when done. How can I display a progress bar during the time the function is being executed? Note that I need this to be in real time, so I can’t figure out what to do about it. Do I need a thread for this? I have no idea. Right now I am not printing anything while the function is being executed, however a progress bar would be nice. Also I am more interested in how this can be done from a code point of view.
CLI. But I can use a third party library, that is no issue. With GUI I can do this, but I was interested in the CLI part.
Possible duplicate of Text Progress Bar in the Console Note that while this question was posted three days earlier, the linked question is more frequently viewed.
I’ve published a new kind of progress bar, which you can print, see throughput and eta, even pause it, besides the very cool animations! Please take a look: github.com/rsalmei/alive-progress !alive-progress
47 Answers 47
With tqdm ( conda install tqdm or pip install tqdm ) you can add a progress meter to your loops in a second:
from time import sleep from tqdm import tqdm for i in tqdm(range(10)): sleep(3) 60%|██████ | 6/10 [00:18
from tqdm.notebook import tqdm for i in tqdm(range(100)): sleep(3)
You can use tqdm.auto instead of tqdm.notebook to work in both a terminal and notebooks.
tqdm.contrib contains some helper functions to do things like enumerate , map , and zip . There are concurrent maps in tqdm.contrib.concurrent .
You can even get progress sent to your phone after disconnecting from a jupyter notebook using tqdm.contrib.telegram or tqdm.contrib.discord .
@JoshUsre Yes it should work with any iterable, for the moment I didn't see any iterable it choked on. However, the display of the ETA (remaining time) requires the iterable to have a __len__ property or the user must supply the total argument to tqdm . Else, the bar will work but with no ETA.
@gaborous: How come this isn't the top voted answer? This simple solution works both in terminal and in Jupyter notebook unlike the top answer.
for running in a jupyter notebook use from tqdm import tqdm_notebook as tqdm . Otherwise doesn't write it on one line.
Use alive-progress, the coolest progress bar ever! Just pip install alive-progress , and you can:
To use any progress bars and get a percentage of completion and an ETA, you need to be able to tell it how many things you're processing, and where you currently are.
Then, you can either drive the alive-bar within your code:
def compute(): with alive_bar(1000) as bar: # declare your expected total for item in items: #
Or just insert an yield in your code to mark that an item has been processed:
def compute(): for i in range(1000): print(item) # your actual processing here yield # just insert this :)
And drive the bar like this:
with alive_bar(1000) as bar: for i in compute(): bar()
Either way, you'll get an awesome and alive progress bar!
|█████████████▎ | ▅▃▁ 321/1000 [32%] in 8s (40.1/s, eta: 16s)
Disclosure: I'm the author of alive-progress , but it should solve your problem nicely! Read the documentation at https://github.com/rsalmei/alive-progress to know more. Now it works also on Jupyter Notebooks! Here are some more examples of what it can do:
I don't have a loop, it's a single write command. In that case is it possible? ` with open(path2file, 'wb+') as f: # with open(path2file, 'w+') as f: f.write(data.read())`
Thanks, @ruloweb. You advance it by whatever quantity you want, just call bar(size) at the end of the iteration.
There are specific libraries (like this one here) but maybe something very simple would do:
import time import sys toolbar_width = 40 # setup toolbar sys.stdout.write("[%s]" % (" " * toolbar_width)) sys.stdout.flush() sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '[' for i in range(toolbar_width): time.sleep(0.1) # do real work here # update the bar sys.stdout.write("-") sys.stdout.flush() sys.stdout.write("]\n") # this ends the progress bar
Note: progressbar2 is a fork of progressbar which hasn't been maintained in years.
I tried this code, and it threw a NameError: name 'xrange' is not defined error. Am I missing a module?
No external packages. A ready-made piece of code.
You can customize bar progress symbol "#" , bar size , text prefix etc.
Python 3.3+
import sys def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.3+ count = len(it) def show(j): x = int(size*j/count) print("<>[<><>] <>/<>".format(prefix, "#"*x, "."*(size-x), j, count), end='\r', file=out, flush=True) show(0) for i, item in enumerate(it): yield item show(i+1) print("\n", flush=True, file=out)
Usage:
import time for i in progressbar(range(15), "Computing: ", 40): time.sleep(0.1) # any code you need
To fill the whole character space use a unicode u"█" char replacing "#" . With for i in progressbar(range(100)): . you get :
- Doesn't require a second thread. Some solutions/packages above require.
- Works with any iterable it means anything that len() can be used on. A list , a dict of anything for example ['a', 'b', 'c' . 'g']
- Works with generators only have to wrap it with a list(). For example for i in progressbar(list(your_generator), "Computing: ", 40): Unless the work is done in the generator. In that case you need another solution (like tqdm).
You can also change output by changing out to sys.stderr for example.
Python 3.6+ (f-string)
def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.6+ count = len(it) def show(j): x = int(size*j/count) print(f"[] /", end='\r', file=out, flush=True) show(0) for i, item in enumerate(it): yield item show(i+1) print("\n", flush=True, file=out)
Python 2 (old-code)
import sys def progressbar(it, prefix="", size=60, out=sys.stdout): count = len(it) def show(j): x = int(size*j/count) out.write("%s[%s%s] %i/%i\r" % (prefix, u"#"*x, "."*(size-x), j, count)) out.flush() show(0) for i, item in enumerate(it): yield item show(i+1) out.write("\n") out.flush()
I like this solution, generators will throw the following error: TypeError: object of type 'generator' has no len()
Should have seen this comment before, wasted time to figure out on making it work with generator. I must say converting to list might not be helpful with large objects as the point of generator is lost. (In my case, I am reading pages from a PDF and I don't want to load all pages into memory). I appreciate the simplicity over adding a library for progress bar
Wrapping a generator as a list seem to indeed miss the point. If all the work is done in the generator, then the progress bar wouldn't show the progress. (tqdm handles that for example by then not showing a percentage unless you tell it the total) The comment regarding the thread issue may not be 100% accurate. A second thread wouldn't be an issue with jupyter notebook. Writing to two separate outputs is (stdout and stderr).
I made a "better" version which replaces the # character with a unicode character that fills a whole character space - █ . This is a gist I made: gist.github.com/ChesterChowWOV/2b35c551b339adbf459363322aac5b4b
The above suggestions are pretty good, but I think most people just want a ready made solution, with no dependencies on external packages, but is also reusable.
I got the best points of all the above, and made it into a function, along with a test cases.
To use it, just copy the lines under "def update_progress(progress)" but not the test script. Don't forget to import sys. Call this whenever you need to display or update the progress bar.
This works by directly sending the "\r" symbol to console to move cursor back to the start. "print" in python does not recongise the above symbol for this purpose, hence we need 'sys'
import time, sys # update_progress() : Displays or updates a console progress bar ## Accepts a float between 0 and 1. Any int will be converted to a float. ## A value under 0 represents a 'halt'. ## A value at 1 or bigger represents 100% def update_progress(progress): barLength = 10 # Modify this to change the length of the progress bar status = "" if isinstance(progress, int): progress = float(progress) if not isinstance(progress, float): progress = 0 status = "error: progress var must be float\r\n" if progress < 0: progress = 0 status = "Halt. \r\n" if progress >= 1: progress = 1 status = "Done. \r\n" block = int(round(barLength*progress)) text = "\rPercent: [] % ".format( "#"*block + "-"*(barLength-block), progress*100, status) sys.stdout.write(text) sys.stdout.flush() # update_progress test script print "progress : 'hello'" update_progress("hello") time.sleep(1) print "progress : 3" update_progress(3) time.sleep(1) print "progress : [23]" update_progress([23]) time.sleep(1) print "" print "progress : -10" update_progress(-10) time.sleep(2) print "" print "progress : 10" update_progress(10) time.sleep(2) print "" print "progress : 0->1" for i in range(101): time.sleep(0.1) update_progress(i/100.0) print "" print "Test completed" time.sleep(10)
This is what the result of the test script shows (The last progress bar animates):
progress : 'hello' Percent: [----------] 0% error: progress var must be float progress : 3 Percent: [##########] 100% Done. progress : [23] Percent: [----------] 0% error: progress var must be float progress : -10 Percent: [----------] 0% Halt. progress : 10 Percent: [##########] 100% Done. progress : 0->1 Percent: [##########] 100% Done. Test completed
Отслеживаем прогресс выполнения в Python
Индикаторы прогресса (progress bar) — визуальное отображение процесса работы. Они избавляют нас от необходимости беспокоиться о том, не завис ли скрипт, дают интуитивное представление о скорости его выполнения и подсказывают, сколько времени осталось до завершения.
Человек ранее не использовавший индикаторы прогресса может предположить, что их внедрение может сильно усложнить код. К счастью, это не так. Небольшие примеры ниже покажут, как быстро и просто начать отслеживать прогресс в консоли или в интерфейсе быстро набирающей популярность графической библиотеки PySimpleGUI.
Используем Progress
Всё, что от вас потребуется, это указать количество ожидаемых итераций, тип индикатора и вызывать функцию при каждой итерации:
import time from progress.bar import IncrementalBar mylist = [1,2,3,4,5,6,7,8] bar = IncrementalBar('Countdown', max = len(mylist)) for item in mylist: bar.next() time.sleep(1) bar.finish()
Есть индикаторы на любой вкус:
Используем tqdm
Следующей на очереди идёт библиотека tqdm.
Быстрый и расширяемый индикатор прогресса для Python и CLI
Всего один вызов функции понадобится для получения результата аналогичного предыдущему:
import time from tqdm import tqdm mylist = [1,2,3,4,5,6,7,8] for i in tqdm(mylist): time.sleep(1)
Само собой, в комплекте идёт куча настроек и опций.
Используем alive-progress
Ещё один вариант синтаксиса, побольше дефолтных анимаций, чем в предыдущих примерах:
from alive_progress import alive_bar import time mylist = [1,2,3,4,5,6,7,8] with alive_bar(len(mylist)) as bar: for i in mylist: bar() time.sleep(1)
GUI индикатор прогресса для скрипта
Иногда возникает необходимость предоставить конечному пользователю графический индикатор.
Сколько кода нужно, чтобы достигнуть такого результата? Немного:
import PySimpleGUI as sg import time mylist = [1,2,3,4,5,6,7,8] for i, item in enumerate(mylist): sg.one_line_progress_meter('This is my progress meter!', i+1, len(mylist), '-key-') time.sleep(1)
Индикатор в приложении PySimpleGUI
Рассмотрим реализацию индикатора в PySimpleGUI.
import PySimpleGUI as sg import time mylist = [1,2,3,4,5,6,7,8] progressbar = [ [sg.ProgressBar(len(mylist), orientation='h', size=(51, 10), key='progressbar')] ] outputwin = [ [sg.Output(size=(78,20))] ] layout = [ [sg.Frame('Progress',layout= progressbar)], [sg.Frame('Output', layout = outputwin)], [sg.Submit('Start'),sg.Cancel()] ] window = sg.Window('Custom Progress Meter', layout) progress_bar = window['progressbar'] while True: event, values = window.read(timeout=10) if event == 'Cancel' or event is None: break elif event == 'Start': for i,item in enumerate(mylist): print(item) time.sleep(1) progress_bar.UpdateBar(i + 1) window.close()
Заключение
Как видите, нет ничего сложного в добавлении информации о прогрессе выполнения: кода немного, а отзывчивость повышается очень сильно. Используйте индикаторы, чтобы больше никогда не гадать, завис ли процесс или нет!