The Python Oracle

Python Progress Bar

Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn

--

Music by Eric Matyas
https://www.soundimage.org
Track title: Puzzle Game 5 Looping

--

Chapters
00:00 Question
00:44 Accepted answer (Score 230)
01:23 Answer 2 (Score 677)
02:30 Answer 3 (Score 225)
04:04 Answer 4 (Score 150)
06:12 Thank you

--

Full question
https://stackoverflow.com/questions/3160...

Accepted answer links:
[like this one here]: http://pypi.python.org/pypi/progressbar2
[progressbar2]: https://pypi.org/project/progressbar2/
[progressbar]: https://pypi.python.org/pypi/progressbar

Answer 2 links:
[tqdm]: https://github.com/tqdm/tqdm
[notebook version]: https://github.com/tqdm/tqdm/#ipython-ju...
[tqdm.contrib]: https://tqdm.github.io/docs/contrib
[tqdm.contrib.concurrent]: https://tqdm.github.io/docs/contrib.conc...
[tqdm.contrib.telegram]: https://tqdm.github.io/docs/contrib.tele...
[tqdm.contrib.discord]: https://tqdm.github.io/docs/contrib.disc...

Answer 3 links:
[alive-progress]: https://github.com/rsalmei/alive-progres...
https://github.com/rsalmei/alive-progres...

Answer 4 links:
[image]: https://i.stack.imgur.com/wzjGN.gif

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #progressbar

#avk47



ANSWER 1

Score 775


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<00:12,  0.33 it/s]

Also, there is a notebook version:

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.

GIF showing an example of the output of using tqdm.contrib.telegram to display progress bar in Telegram mobile app




ACCEPTED ANSWER

Score 235


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.




ANSWER 3

Score 189


No external packages. A ready-made piece of code.

You can customize bar progress symbol "#", bar size, text prefix etc.

Python 3.6+ (f-string) with Time Remaining estimate

import sys
import time

def progressbar(it, prefix="", size=60, out=sys.stdout): # Python3.6+
    count = len(it)
    start = time.time() # time estimate start
    def show(j):
        x = int(size*j/count)
        # time estimate calculation and string
        remaining = ((time.time() - start) / j) * (count - j)        
        mins, sec = divmod(remaining, 60) # limited to minutes
        time_str = f"{int(mins):02}:{sec:03.1f}"
        print(f"{prefix}[{u'█'*x}{('.'*(size-x))}] {j}/{count} Est wait {time_str}", end='\r', file=out, flush=True)
    show(0.1) # avoid div/0 
    for i, item in enumerate(it):
        yield item
        show(i+1)
    print("\n", flush=True, file=out)
[████████████████████████████.........................] 24/50 Est wait 00:05.3

Usage:

import time    
for i in progressbar(range(15), "Computing: ", 40):
    time.sleep(0.1) # any code you need

enter image description here


  • 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.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)

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()



ANSWER 4

Score 109


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: [{0}] {1}% {2}".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