Text progress bar in terminal with block characters [closed]
Asked Answered
P

31

574

I wrote a simple console app to upload and download files from an FTP server using the ftplib.

I would like the app to show some visualization of its download/upload progress for the user; each time a data chunk is downloaded, I would like it to provide a progress update, even if it's just a numeric representation like a percentage.

Importantly, I want to avoid erasing all the text that's been printed to the console in previous lines (i.e. I don't want to "clear" the entire terminal while printing the updated progress).

This seems a fairly common task – how can I go about making a progress bar or similar visualization that outputs to my console while preserving prior program output?

Preservative answered 4/7, 2010 at 0:29 Comment(8)
Hmm, look like a duplicate of this question asked yesterday: https://mcmap.net/q/67443/-python-progress-bar/3162864 So, you should use fish pypi.python.org/pypi/fishTreasurehouse
"just use a GUI" misunderstands that GUIs are great in some situations (quick learning curve, ad-hoc exploratory or interactive or one-off activities) while command-line tools are great for others (expert users, composing ad-hoc applications on the fly to perform a carefully defined operation many times.)Cowardly
I voted to reopen. The question doesn't strike me as too broad.Almuce
I think what you're looking for is tqdm... though I also don't know why SO is prompting me to review reopen votes on year-old questions.Discontinuity
I think here is the best answer if you don't want a external package.Pretension
Why don't you just use a cool progress bar, which you can see the throughput and ETA, even pause it, all with very cool animations! Here: github.com/rsalmei/alive-progress !demoAbvolt
Also see the FiraCode progress bar support.Cephalometer
Also see another thread here on SO: #23113994Gavage
E
757

Python 3

A Simple, Customizable Progress Bar

Here's an aggregate of many of the answers below that I use regularly (no imports required).

Note: All code in this answer was created for Python 3; see end of answer to use this code with Python 2.

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
    # Print New Line on Complete
    if iteration == total: 
        print()

Sample Usage

import time

# A List of Items
items = list(range(0, 57))
l = len(items)

# Initial call to print 0% progress
printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
for i, item in enumerate(items):
    # Do stuff...
    time.sleep(0.1)
    # Update Progress Bar
    printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)

Sample Output

Progress: |█████████████████████████████████████████████-----| 90.0% Complete

Update

There was discussion in the comments regarding an option that allows the progress bar to adjust dynamically to the terminal window width. While I don't recommend this, here's a gist that implements this feature (and notes the caveats).

Single-Call Version of The Above

A comment below referenced a nice answer posted in response to a similar question. I liked the ease of use it demonstrated and wrote a similar one, but opted to leave out the import of the sys module while adding in some of the features of the original printProgressBar function above.

Some benefits of this approach over the original function above include the elimination of an initial call to the function to print the progress bar at 0% and the use of enumerate becoming optional (i.e. it is no longer explicitly required to make the function work).

def progressBar(iterable, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█', printEnd = "\r"):
    """
    Call in a loop to create terminal progress bar
    @params:
        iterable    - Required  : iterable object (Iterable)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
        printEnd    - Optional  : end character (e.g. "\r", "\r\n") (Str)
    """
    total = len(iterable)
    # Progress Bar Printing Function
    def printProgressBar (iteration):
        percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
        filledLength = int(length * iteration // total)
        bar = fill * filledLength + '-' * (length - filledLength)
        print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
    # Initial Call
    printProgressBar(0)
    # Update Progress Bar
    for i, item in enumerate(iterable):
        yield item
        printProgressBar(i + 1)
    # Print New Line on Complete
    print()

Sample Usage

import time

# A List of Items
items = list(range(0, 57))

# A Nicer, Single-Call Usage
for item in progressBar(items, prefix = 'Progress:', suffix = 'Complete', length = 50):
    # Do stuff...
    time.sleep(0.1)

Sample Output

Progress: |█████████████████████████████████████████████-----| 90.0% Complete

Python 2

To use the above functions in Python 2, set the encoding to UTF-8 at the top of your script:

# -*- coding: utf-8 -*-

And replace the Python 3 string formatting in this line:

print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)

With Python 2 string formatting:

print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = printEnd)
Exemplify answered 17/12, 2015 at 2:39 Comment(31)
This snippet works great! I did encounter a couple minor issues so I made some minor edits (PEP-8, default encoding for non-ascii character) and threw them in a gist here: gist.github.com/aubricus/f91fb55dc6ba5557fbab06119420dd6aTetrapody
Worth noting that the UTF-8 declaration is not necessary unless your using Python 2 @TetrapodyExemplify
SyntaxError: Non-ASCII character '\xe2' on line 5, but no encoding declaredGuarino
@MattClimbs This is written for Python 3 which uses UTF-8 encoding by default. You can either change the default fill parameter of the function, which is a UTF-8 character, or use the UTF-8 declaration. See the gist in the comment above for an example of what a UTF-8 declaration should look like.Exemplify
I have just done a simpler little progress bar solution on this question if anyone is interested in something easier with an explanation :). p.s good answer GreenstickBensky
Hi @Greenstick, I posted a follow up question to this one here. I'm trying to add a title above the progress bar. It would be great to get your input on this as you were the one that wrote the print_progress code I'm using. Much appreciated!Enthetic
I've just modified your code a little for this answer to herteladrian's question ; I hope you don't mind.Jeremiahjeremias
For Python 2, the required heading at top of file is # -*- coding: utf-8 -*- as per #3170711Pietra
I'm trying to use it, but i'm getting this error: overflowError: cannot fit 'int' into an index-sized integer does anyone know why?Rotatory
@roberto.sannazzaro It’s hard to know exactly what the error is without the code and trace, but the error is from a memory overflow. If you have any large numbers in your code or that you are passing as arguments into the function that would likely be the issue.Exemplify
Print on every iteration is extra-heavy operationBedwell
@YuriS.Cherkasov You can always place a conditional before calling the progress bar in the loop. Something like if i % n == 0: where n is the frequency at which you'd like to print (e.g. n = 10 for every 10 iterations). But that comes down to appropriate usage, which is at the users discretion.Exemplify
Is this even possible with the logging module instead of raw print statements?Longhair
Thanks @Aubricus, that worked for me on python 2.7 :-)Dante
Thanks, nice summary, also detection of terminal size could be useful for this function # Size of terminal rows, columns = [int(x) for x in os.popen('stty size', 'r').read().split()] columns should be passed to length to adjust progress bar size to terminal window. Though length of progressing part of bar should be decreased (by length of prefix, suffix, percent and additional characters in this string '\r%s |%s| %s%% %s'Skulduggery
@Exemplify I have slightly modified version with added sys.stdout.flush() which was necessary to make it work properly. Sorry for discrepancies with original one. Ohh, it doesn't fit in characters limt( How can I send it to you?Skulduggery
@Skulduggery Double-checked and it seems to work on my end. It may be that, to get a full progress bar 0 - 100%, you do have to call the initial 0% progress bar outside the iterations and then increment the index (if using a 0-based index) prior to passing it into the printProgressBar function. This ensures that the if iteration == total: conditional prints the last line.Exemplify
@Skulduggery I've decided against the autoresize option. It's very resource intensive – given we're spooling a subprocess to query the terminal window size on each call of the printProgressBar function. We could query the window size once and cache the width as an environment variable, but this isn't a good solution – if the terminal were resized during iteration the progress bar wouldn't resize accordingly. For future reference, here's a gist with the autoresize option.Exemplify
@Exemplify you are right, I've forgotten that infer terminal width outside the function) Sorry for disturbanceSkulduggery
Would you consider making this into a small Python module?Mcanally
@Mcanally Sure, I can do that. I've got some other similar functions (like loading ellipses, etc.) for the CLI that I can throw in. That said, there are great existing libraries out there – have you checked out tdqm?Exemplify
Yes, sorry, I read this reply before the ones below. Given tqdm exists please ignore my comment!Mcanally
To get this to work in some IDEs (e.g. PyCharm on Windows) you may need to change end = '\r' to end = ''.Discommon
I think this still a better answer 2020+Pretension
Right-aligning the percent number would prevent the layout shifts from 9 to 10 and 99 to 100. percent.rjust(4 + decimals if decimals > 0 else 3) could do the trick.Corriecorriedale
Very nice, but (for the updated version) it can throw a ZeroDivisionError in the calculation of the percentage if there is no element in the stream.Pulp
@Pulp could share a gist that reproduces the issue? Thanks.Exemplify
@Exemplify Of course: 1. Create empty list, 2. use this on progressBar() -> ZeroDivisionError in the first line of printProgressBar() -> you can fix this by doing percentage = 1 if total == 0 else (iteration / float(total)) followed by percent = ("{0:." + str(decimals) + "f}").format(100 * percentage) or something like this. (Note that filledLength migh also throw I changed it to filled_length = int(length if total == 0 else (length * iteration // total)) therefore)Pulp
this doesn't work when having threadsUrias
@Urias Is this while you are multiprocessing or using subprocesses? If so, it may have more to do with how you're handling that – I've used this in both cases and it works fine (although if you can reproduce it with a gist I'd take a look). Of course, this is after all a code snippet – if you're looking for a robust progress bar library, I'd recommend tdqm.Exemplify
I get this: ZeroDivisionError: float division by zero using first version, but the one-liner works!Smalt
O
341

Writing '\r' will move the cursor back to the beginning of the line.

This displays a percentage counter:

import time
import sys

for i in range(101):
    time.sleep(0.05)
    sys.stdout.write("\r%d%%" % i)
    sys.stdout.flush()
Oleomargarine answered 4/7, 2010 at 0:39 Comment(18)
Pasted that and ran. It prints to a new line each time. I want the number to be updated on the same line. :)Preservative
@Preservative : I just tried it on two different OS's (mac & linux), two different versions of python. It prints on one line. :) Are you sure you added ',' at the end of the print statement?Oleomargarine
I am using python 2.6 I tried in Aptana studio and on the command line. Prints on multiple lines. :(Preservative
@Preservative : Edited, try sys.stdout.writeOleomargarine
Some proof. :) twitpic.com/227xk2Preservative
Replaced 3rd line with yours. Same problem as the picture illustrates.Preservative
Hmm, proof proven :) I suspect that the "Aptana studio" doesn't support \r. I'm not familiar with Aptana, so I'm not sure what to tell you :(Oleomargarine
I get the exact same results in "cmd" on Windows 7. Oh well. :PPreservative
\r only works on unix (and even then, not necessarily in all shells). On windows you need to use the home key, which SHOULD be \x00\x71, but I didn't test it.Estey
@Nick \r works on all platforms.Satirist
@Aviral: It most certainly does not perform a traditional carriage return in powershell - it's not a platform thing, per se, it has to do with how your controlling shell treats control sequences (The POSIX shell definition doesn't actually require that carriage return reset the character position to the beginning of the line either).Estey
This example also produces an OBOB it ends loading at 99%Tortious
@GlennDayton What is an OBOB?Matthaeus
@moose It stands for "Off by one bug"Tortious
it's OBOB cuz of the range(100), should be range(101) to print until 100Swee
print has an end argument: https://mcmap.net/q/67448/-output-to-the-same-line-overwriting-previous-outputCouncilman
To add to what @IoannisFilippidis said, print also has a flush argument: docs.python.org/3/library/functions.html#printRhodos
liked it, further simplified with print(f"\r{i}%", end='')Adessive
E
250

tqdm: add a progress meter to your loops in a second:

>>> import time
>>> from tqdm import tqdm
>>> for i in tqdm(range(100)):
...     time.sleep(1)
... 
|###-------| 35/100  35% [elapsed: 00:35 left: 01:05,  1.00 iters/sec]

tqdm repl session

Emotional answered 16/10, 2014 at 1:8 Comment(8)
What the python shell do you use?Scrimpy
@xotonic the link says it is ptpythonEmotional
sure, pull a lib for 20 lines function :DEvelunn
@iperov: there are trade-offs, as usual. Unless you can list specific reasons not to, use the code that somebody else has to maintain. I can remember both: rolling out my own code (just a few lines to display progress) and using tqdm in various circumstances (there are 1k+ commits for a reason).Emotional
@Emotional sure. but I often find that library developers make mistakes, and my project that depends on them crashes. That's why I prefer to make my own function implementations, which have more predictable behavior.Evelunn
this is perfect, had to change my df.iterrows to range(len(df)) then call df.iloc[i].values[0] but this is exactly what I was looking for! Thank you jfs!Madelaine
@Evelunn Of course, because unlike library developers, you never make mistakes, and if you do, you catch them faster than all those library's incompetent users do.Potamic
@Michael Scheper exactly.Evelunn
S
130

Write a \r to the console. That is a "carriage return" which causes all text after it to be echoed at the beginning of the line. Something like:

def update_progress(progress):
    print '\r[{0}] {1}%'.format('#'*(progress/10), progress)

which will give you something like: [ ########## ] 100%

Satirist answered 4/7, 2010 at 0:35 Comment(13)
Do '\r' + myPercentage printout?Preservative
Do \r and then write the whole line out again. Basically: print("\rProgress: [{0:50s}] {1:.1f}%".format('#' * int(amtDone * 50), amtDone * 100)), where amtDone is a float between 0 and 1.Wheal
@MikeDeSimone, that looks like the best bar short of using curses.Rockel
I don't see what curses would buy you there. Seems like overkill. Besides, this should work in a curses window, too; I won't tell.Wheal
Better to use sys.stdout.write than print. With print I got newlines.Toughie
append a comma , at the end of the print works for me.Travesty
in python3 use print(...., end='') and you won't have any newlinesAleris
flushing the output buffer after the print finally got rid of my newlines. Try: sys.stdout.flush() (thanks to @ned-batchelder: https://mcmap.net/q/67449/-python-trailing-comma-after-print-executes-next-instruction)Minus
I use Python 2.7. This worked for me: print "\r{0}%".format(i+1),Coshow
You can use something like this to have a fixed width window that fills in at 10% increments: print '\r[%-10s] %0.2f%%' % ('#' * int(progress/10), progress),Devastation
Summarizing for Python3 former contribs: print("\rProgress: [{0:50s}] {1:.1f}%".format('#' * int(workdone * 50), workdone*100), end="", flush=True), where workdone is a float between 0 and 1, e.g., workdone = parsed_dirs/total_dirsBenefactor
print with , or end='\r' did not work for me in the Jupyter notebook. sys.stdout.write did.Unideaed
With fixed width: print('\r[ {0}{1} ] {2}%'.format('#' * progress, ' ' * int(100 - progress), progress))Centralism
K
85

It is less than 10 lines of code.

The gist here: https://gist.github.com/vladignatyev/06860ec2040cb497f0f3

import sys


def progress(count, total, suffix=''):
    bar_len = 60
    filled_len = int(round(bar_len * count / float(total)))

    percents = round(100.0 * count / float(total), 1)
    bar = '=' * filled_len + '-' * (bar_len - filled_len)

    sys.stdout.write('[%s] %s%s ...%s\r' % (bar, percents, '%', suffix))
    sys.stdout.flush()  # As suggested by Rom Ruben

enter image description here

Kinakinabalu answered 9/1, 2015 at 23:45 Comment(4)
adds "sys.stdout.flush()" to the end of function.Normative
for me it goes in a new lineSamekh
@GM what OS/platform do you use?Kinakinabalu
I don't know why if I run it from spyder ide it doesn't work but if I run it from ipython console it works!Samekh
H
75

Try the click library written by the Mozart of Python, Armin Ronacher.

$ pip install click # both 2 and 3 compatible

To create a simple progress bar:

import click

with click.progressbar(range(1000000)) as bar:
    for i in bar:
        pass 

This is what it looks like:

# [###-------------------------------]    9%  00:01:14

Customize to your hearts content:

import click, sys

with click.progressbar(range(100000), file=sys.stderr, show_pos=True, width=70, bar_template='(_(_)=%(bar)sD(_(_| %(info)s', fill_char='=', empty_char=' ') as bar:
    for i in bar:
        pass

Custom look:

(_(_)===================================D(_(_| 100000/100000 00:00:02

There are even more options, see the API docs:

 click.progressbar(iterable=None, length=None, label=None, show_eta=True, show_percent=None, show_pos=False, item_show_func=None, fill_char='#', empty_char='-', bar_template='%(label)s [%(bar)s] %(info)s', info_sep=' ', width=36, file=None, color=None)
Hypophyge answered 9/6, 2015 at 18:42 Comment(1)
This should be the accepted answer. It's sad to see so many devs reinventing the wheel.Potamic
T
36

I realize I'm late to the game, but here's a slightly Yum-style (Red Hat) one I wrote (not going for 100% accuracy here, but if you're using a progress bar for that level of accuracy, then you're WRONG anyway):

import sys

def cli_progress_test(end_val, bar_length=20):
    for i in xrange(0, end_val):
        percent = float(i) / end_val
        hashes = '#' * int(round(percent * bar_length))
        spaces = ' ' * (bar_length - len(hashes))
        sys.stdout.write("\rPercent: [{0}] {1}%".format(hashes + spaces, int(round(percent * 100))))
        sys.stdout.flush()

Should produce something looking like this:

Percent: [##############      ] 69%

... where the brackets stay stationary and only the hashes increase.

This might work better as a decorator. For another day...

Theodoretheodoric answered 3/12, 2012 at 14:11 Comment(0)
S
18

Check this library: clint

it has a lot of features including a progress bar:

from time import sleep  
from random import random  
from clint.textui import progress  
if __name__ == '__main__':
    for i in progress.bar(range(100)):
        sleep(random() * 0.2)

    for i in progress.dots(range(100)):
        sleep(random() * 0.2)

this link provides a quick overview of its features

Stout answered 16/1, 2012 at 12:25 Comment(0)
A
12

Here's a nice example of a progressbar written in Python: http://nadiana.com/animated-terminal-progress-bar-in-python

But if you want to write it yourself. You could use the curses module to make things easier :)

[edit] Perhaps easier is not the word for curses. But if you want to create a full-blown cui than curses takes care of a lot of stuff for you.

[edit] Since the old link is dead I have put up my own version of a Python Progressbar, get it here: https://github.com/WoLpH/python-progressbar

Ange answered 4/7, 2010 at 0:39 Comment(7)
curses? Easier? Hmmm....Satirist
An excellent article, I was going to give a link to it but couldn't find in my bookmarks :)Charity
@Aviral Dasgupta: fair enough, easier might not be the right word here. It can save you a lot of work though, but it really depends on what you're looking for.Ange
Not looking for anything near this involved, but thanks anyway. :)Preservative
Dead link, that's the price of not posting the link'ed content in your answer -__-Dampier
@ThorSummoner: have you seen the second link? As for not posting the content, it's quite a large script. Too much for a stackoverflow answer. The new script is available on both pypi and Github so it won't easily disappear.Ange
I feel it's worth amending the answer to not contain a dead link. I did check the github repo, I'm not settled on it yet.Dampier
A
12
import time,sys

for i in range(100+1):
    time.sleep(0.1)
    sys.stdout.write(('='*i)+(''*(100-i))+("\r [ %d"%i+"% ] "))
    sys.stdout.flush()

output

[ 29% ] ===================

Atypical answered 21/4, 2015 at 12:24 Comment(0)
M
11

Install tqdm.(pip install tqdm) and use it as follows:

import time
from tqdm import tqdm
for i in tqdm(range(1000)):
    time.sleep(0.01)

That's a 10 seconds progress bar that'll output something like this:

47%|██████████████████▊                     | 470/1000 [00:04<00:05, 98.61it/s]
Markos answered 25/11, 2017 at 13:11 Comment(0)
D
7

and, just to add to the pile, here's an object you can use:

Add the following to a new file progressbar.py

import sys

class ProgressBar(object):
    CHAR_ON  = '='
    CHAR_OFF = ' '

    def __init__(self, end=100, length=65):
        self._end = end
        self._length = length
        self._chars = None
        self._value = 0

    @property
    def value(self):
        return self._value
    
    @value.setter
    def value(self, value):
        self._value = max(0, min(value, self._end))
        if self._chars != (c := int(self._length * (self._value / self._end))):
            self._chars = c
            sys.stdout.write("\r  {:3n}% [{}{}]".format(
                int((self._value / self._end) * 100.0),
                self.CHAR_ON  * int(self._chars),
                self.CHAR_OFF * int(self._length - self._chars),
            ))
            sys.stdout.flush()

    def __enter__(self):
        self.value = 0
        return self

    def __exit__(self, *args, **kwargs):
        sys.stdout.write('\n')

Can be included in your program with:

import time
from progressbar import ProgressBar

count = 150
print("starting things:")

with ProgressBar(count) as bar:
    for i in range(count + 1):
        bar.value += 1
        time.sleep(0.01)

print("done")

Results in:

starting things:
  100% [=================================================================]
done

This may be "over the top", but is handy when used frequently.

Dipnoan answered 24/1, 2014 at 7:1 Comment(2)
Thanks for this. Small fix, the plotProgress method should use the line sys.stdout.flush() else the progress bar might not be drawn until the task has been completed (as occurs in the mac terminal).Anthocyanin
I love this!!! Fairly easy to use!!! ThankyouJimmiejimmy
P
6

Run this at the Python command line (not in any IDE or development environment):

>>> import threading
>>> for i in range(50+1):
...   threading._sleep(0.5)
...   print "\r%3d" % i, ('='*i)+('-'*(50-i)),

Works fine on my Windows system.

Paulettapaulette answered 4/7, 2010 at 17:50 Comment(0)
P
5

Try to install this package: pip install progressbar2 :

import time
import progressbar

for i in progressbar.progressbar(range(100)):
    time.sleep(0.02)

progresssbar github: https://github.com/WoLpH/python-progressbar

Perorate answered 25/5, 2018 at 23:11 Comment(1)
The owner of that repository already answered much earlier.Medico
U
5

A very simple solution is to put this code into your loop:

Put this in the body (i.e. top) of your file:

import sys

Put this in the body of your loop:

sys.stdout.write("-") # prints a dash for each iteration of loop
sys.stdout.flush() # ensures bar is displayed incrementally
Unshaped answered 12/6, 2018 at 14:37 Comment(0)
W
4

I am using progress from reddit. I like it because it can print progress for every item in one line, and it shouldn't erase printouts from the program.

Edit: fixed link

Walliw answered 26/10, 2010 at 11:33 Comment(2)
Your link is broken — the actual line in source code is 1274th, not the 1124th! So, the right link is this one: github.com/reddit/reddit/blob/master/r2/r2/lib/utils/…Kinakinabalu
This variant has the best design on my taste: it uses iterators and works possibly with any kind of measurable work, it shows elapsed time.Kinakinabalu
N
4

based on the above answers and other similar questions about CLI progress bar, I think I got a general common answer to all of them. Check it at https://mcmap.net/q/67443/-python-progress-bar

In summary, the code is this:

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

Looks like

Percent: [##########] 99.0%

Neoma answered 7/4, 2013 at 11:50 Comment(0)
T
3

I recommend using tqdm - https://pypi.python.org/pypi/tqdm - which makes it simple to turn any iterable or process into a progress bar, and handles all messing about with terminals needed.

From the documentation: "tqdm can easily support callbacks/hooks and manual updates. Here’s an example with urllib"

import urllib
from tqdm import tqdm

def my_hook(t):
  """
  Wraps tqdm instance. Don't forget to close() or __exit__()
  the tqdm instance once you're done with it (easiest using `with` syntax).

  Example
  -------

  >>> with tqdm(...) as t:
  ...     reporthook = my_hook(t)
  ...     urllib.urlretrieve(..., reporthook=reporthook)

  """
  last_b = [0]

  def inner(b=1, bsize=1, tsize=None):
    """
    b  : int, optional
        Number of blocks just transferred [default: 1].
    bsize  : int, optional
        Size of each block (in tqdm units) [default: 1].
    tsize  : int, optional
        Total size (in tqdm units). If [default: None] remains unchanged.
    """
    if tsize is not None:
        t.total = tsize
    t.update((b - last_b[0]) * bsize)
    last_b[0] = b
  return inner

eg_link = 'http://www.doc.ic.ac.uk/~cod11/matryoshka.zip'
with tqdm(unit='B', unit_scale=True, miniters=1,
          desc=eg_link.split('/')[-1]) as t:  # all optional kwargs
    urllib.urlretrieve(eg_link, filename='/dev/null',
                       reporthook=my_hook(t), data=None)
Tartan answered 13/9, 2016 at 15:26 Comment(0)
C
2
import sys
def progresssbar():
         for i in range(100):
            time.sleep(1)
            sys.stdout.write("%i\r" % i)

progressbar()

NOTE: if you run this in interactive interepter you get extra numbers printed out

Cottbus answered 12/9, 2010 at 10:33 Comment(0)
C
2

lol i just wrote a whole thingy for this heres the code keep in mind you cant use unicode when doing block ascii i use cp437

import os
import time
def load(left_side, right_side, length, time):
    x = 0
    y = ""
    print "\r"
    while x < length:
        space = length - len(y)
        space = " " * space
        z = left + y + space + right
        print "\r", z,
        y += "█"
        time.sleep(time)
        x += 1
    cls()

and you call it like so

print "loading something awesome"
load("|", "|", 10, .01)

so it looks like this

loading something awesome
|█████     |
Cliffcliffes answered 14/2, 2013 at 16:32 Comment(0)
C
2

With the great advices above I work out the progress bar.

However I would like to point out some shortcomings

  1. Every time the progress bar is flushed, it will start on a new line

    print('\r[{0}]{1}%'.format('#' * progress* 10, progress))  
    

    like this:
    [] 0%
    [#]10%
    [##]20%
    [###]30%

2.The square bracket ']' and the percent number on the right side shift right as the '###' get longer.
3. An error will occur if the expression 'progress / 10' can not return an integer.

And the following code will fix the problem above.

def update_progress(progress, total):  
    print('\r[{0:10}]{1:>2}%'.format('#' * int(progress * 10 /total), progress), end='')
Chainman answered 13/4, 2013 at 7:12 Comment(0)
W
2

For python 3:

def progress_bar(current_value, total):
    increments = 50
    percentual = ((current_value/ total) * 100)
    i = int(percentual // (100 / increments ))
    text = "\r[{0: <{1}}] {2}%".format('=' * i, increments, percentual)
    print(text, end="\n" if percentual == 100 else "")
Westing answered 25/4, 2018 at 16:40 Comment(0)
H
1

Code for python terminal progress bar

import sys
import time

max_length = 5
at_length = max_length
empty = "-"
used = "%"

bar = empty * max_length

for i in range(0, max_length):
    at_length -= 1

    #setting empty and full spots
    bar = used * i
    bar = bar+empty * at_length

    #\r is carriage return(sets cursor position in terminal to start of line)
    #\0 character escape

    sys.stdout.write("[{}]\0\r".format(bar))
    sys.stdout.flush()

    #do your stuff here instead of time.sleep
    time.sleep(1)

sys.stdout.write("\n")
sys.stdout.flush()
Hartebeest answered 7/9, 2016 at 19:57 Comment(0)
S
1

function from Greenstick for 2.7:

def printProgressBar (iteration, total, prefix = '', suffix = '',decimals = 1, length = 100, fill = '#'):

percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print'\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix),
sys.stdout.flush()
# Print New Line on Complete                                                                                                                                                                                                              
if iteration == total:
    print()
Snippet answered 20/4, 2017 at 9:24 Comment(0)
D
1

The python module progressbar is a nice choice. Here is my typical code:

import time
import progressbar

widgets = [
    ' ', progressbar.Percentage(),
    ' ', progressbar.SimpleProgress(format='(%(value_s)s of %(max_value_s)s)'),
    ' ', progressbar.Bar('>', fill='.'),
    ' ', progressbar.ETA(format_finished='- %(seconds)s  -', format='ETA: %(seconds)s', ),
    ' - ', progressbar.DynamicMessage('loss'),
    ' - ', progressbar.DynamicMessage('error'),
    '                          '
]

bar = progressbar.ProgressBar(redirect_stdout=True, widgets=widgets)
bar.start(100)
for i in range(100):
    time.sleep(0.1)
    bar.update(i + 1, loss=i / 100., error=i)
bar.finish()
Dempsey answered 26/5, 2017 at 5:49 Comment(0)
C
1

i wrote a simple progressbar:

def bar(total, current, length=10, prefix="", filler="#", space=" ", oncomp="", border="[]", suffix=""):
    if len(border) != 2:
        print("parameter 'border' must include exactly 2 symbols!")
        return None

    print(prefix + border[0] + (filler * int(current / total * length) +
                                      (space * (length - int(current / total * length)))) + border[1], suffix, "\r", end="")
    if total == current:
        if oncomp:
            print(prefix + border[0] + space * int(((length - len(oncomp)) / 2)) +
                  oncomp + space * int(((length - len(oncomp)) / 2)) + border[1], suffix)
        if not oncomp:
            print(prefix + border[0] + (filler * int(current / total * length) +
                                        (space * (length - int(current / total * length)))) + border[1], suffix)

as you can see, it have: length of bar, prefix and suffix, filler, space, text in bar on 100%(oncomp) and borders

here an example:

from time import sleep, time
start_time = time()
for i in range(10):
    pref = str((i+1) * 10) + "% "
    complete_text = "done in %s sec" % str(round(time() - start_time))
    sleep(1)
    bar(10, i + 1, length=20, prefix=pref, oncomp=complete_text)

out in progress:

30% [######              ]

out on complete:

100% [   done in 9 sec   ] 
Congou answered 1/7, 2017 at 11:51 Comment(0)
L
1

Putting together some of the ideas I found here, and adding estimated time left:

import datetime, sys

start = datetime.datetime.now()

def print_progress_bar (iteration, total):

    process_duration_samples = []
    average_samples = 5

    end = datetime.datetime.now()

    process_duration = end - start

    if len(process_duration_samples) == 0:
        process_duration_samples = [process_duration] * average_samples

    process_duration_samples = process_duration_samples[1:average_samples-1] + [process_duration]
    average_process_duration = sum(process_duration_samples, datetime.timedelta()) / len(process_duration_samples)
    remaining_steps = total - iteration
    remaining_time_estimation = remaining_steps * average_process_duration

    bars_string = int(float(iteration) / float(total) * 20.)
    sys.stdout.write(
        "\r[%-20s] %d%% (%s/%s) Estimated time left: %s" % (
            '='*bars_string, float(iteration) / float(total) * 100,
            iteration,
            total,
            remaining_time_estimation
        ) 
    )
    sys.stdout.flush()
    if iteration + 1 == total:
        print 


# Sample usage

for i in range(0,300):
    print_progress_bar(i, 300)
Lamar answered 19/10, 2017 at 22:10 Comment(0)
Z
0

Well here is code that works and I tested it before posting:

import sys
def prg(prog, fillchar, emptchar):
    fillt = 0
    emptt = 20
    if prog < 100 and prog > 0:
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%")
        sys.stdout.flush()
    elif prog >= 100:
        prog = 100
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nDone!")
        sys.stdout.flush()
    elif prog < 0:
        prog = 0
        prog2 = prog/5
        fillt = fillt + prog2
        emptt = emptt - prog2
        sys.stdout.write("\r[" + str(fillchar)*fillt + str(emptchar)*emptt + "]" + str(prog) + "%" + "\nHalted!")
        sys.stdout.flush()

Pros:

  • 20 character bar (1 character for every 5 (number wise))
  • Custom fill characters
  • Custom empty characters
  • Halt (any number below 0)
  • Done (100 and any number above 100)
  • Progress count (0-100 (below and above used for special functions))
  • Percentage number next to bar, and it's a single line

Cons:

  • Supports integers only (It can be modified to support them though, by making the division an integer division, so just change prog2 = prog/5 to prog2 = int(prog/5))
Zucchetto answered 23/7, 2013 at 20:59 Comment(0)
H
0

Here's my Python 3 solution:

import time
for i in range(100):
    time.sleep(1)
    s = "{}% Complete".format(i)
    print(s,end=len(s) * '\b')

'\b' is a backslash, for each character in your string. This does not work within the Windows cmd window.

Heliogabalus answered 3/12, 2013 at 19:45 Comment(0)
E
0

https://pypi.python.org/pypi/progressbar2/3.30.2

Progressbar2 is a good library for ascii base progressbar for the command line import time import progressbar

bar = progressbar.ProgressBar()
for i in bar(range(100)):
    time.sleep(0.02)
bar.finish()

https://pypi.python.org/pypi/tqdm

tqdm is a alternative of progressbar2 and i think it use in pip3 but i am not sure of that

from tqdm import tqdm
for i in tqdm(range(10000)):
...
Excrescence answered 15/6, 2017 at 14:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.