Replace console output in Python

I’m wondering how I could create one of those nifty console counters in Python as in certain C/C++-programs.

I’ve got a loop doing things and the current output is along the lines of:

Doing thing 0
Doing thing 1
Doing thing 2
...

what would be neater would be to just have the last line update;

X things done.

I’ve seen this in a number of console programs and am wondering if/how I’d do this in Python.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

An easy solution is just writing "r" before the string and not adding a newline; if the string never gets shorter this is sufficient…

sys.stdout.write("rDoing thing %i" % i)
sys.stdout.flush()

Slightly more sophisticated is a progress bar… this is something I am using:

def start_progress(title):
    global progress_x
    sys.stdout.write(title + ": [" + "-"*40 + "]" + chr(8)*41)
    sys.stdout.flush()
    progress_x = 0

def progress(x):
    global progress_x
    x = int(x * 40 // 100)
    sys.stdout.write("#" * (x - progress_x))
    sys.stdout.flush()
    progress_x = x

def end_progress():
    sys.stdout.write("#" * (40 - progress_x) + "]n")
    sys.stdout.flush()

You call start_progress passing the description of the operation, then progress(x) where x is the percentage and finally end_progress()

Method 2

A more elegant solution could be:

def progress_bar(current, total, bar_length=20):
    fraction = current / total

    arrow = int(fraction * bar_length - 1) * '-' + '>'
    padding = int(bar_length - len(arrow)) * ' '

    ending = 'n' if current == total else 'r'

    print(f'Progress: [{arrow}{padding}] {int(fraction*100)}%', end=ending)

Call this function with current and total:

progress_bar(69, 100)

The result should be

Progress: [------------->      ] 69%

Note:

Method 3

In python 3 you can do this to print on the same line:

print('', end='r')

Especially useful to keep track of the latest update and progress.

I would also recommend tqdm from here if one wants to see the progress of a loop. It prints the current iteration and total iterations as a progression bar with an expected time of finishing. Super useful and quick. Works for python2 and python3.

Method 4

I wrote this a while ago and really happy with it. Feel free to use it.

It takes an index and total and optionally title or bar_length. Once done, replaces the hour glass with a check-mark.

⏳ Calculating: [████░░░░░░░░░░░░░░░░░░░░░] 18.0% done

✅ Calculating: [█████████████████████████] 100.0% done

I included an example that can be run to test it.

import sys
import time

def print_percent_done(index, total, bar_len=50, title='Please wait'):
    '''
    index is expected to be 0 based index. 
    0 <= index < total
    '''
    percent_done = (index+1)/total*100
    percent_done = round(percent_done, 1)

    done = round(percent_done/(100/bar_len))
    togo = bar_len-done

    done_str = '█'*int(done)
    togo_str = '░'*int(togo)

    print(f't⏳{title}: [{done_str}{togo_str}] {percent_done}% done', end='r')

    if round(percent_done) == 100:
        print('t✅')


r = 50
for i in range(r):
    print_percent_done(i,r)
    time.sleep(.02)

I also have a version with responsive progress bar depending on the terminal width using shutil.get_terminal_size() if that is of interest.

Method 5

It can be done without using the sys library if we look at the print() function

print(*objects, sep=' ', end='n', file=sys.stdout, flush=False)

Here is my code:

def update(n):
    for i in range(n):
        print("i:",i,sep='',end="r",flush=True)
        #time.sleep(1)

Method 6

For anyone who stumbles upon this years later (like I did), I tweaked 6502’s methods a little bit to allow the progress bar to decrease as well as increase. Useful in slightly more cases. Thanks 6502 for a great tool!

Basically, the only difference is that the whole line of #s and -s is written each time progress(x) is called, and the cursor is always returned to the start of the bar.

def startprogress(title):
    """Creates a progress bar 40 chars long on the console
    and moves cursor back to beginning with BS character"""
    global progress_x
    sys.stdout.write(title + ": [" + "-" * 40 + "]" + chr(8) * 41)
    sys.stdout.flush()
    progress_x = 0


def progress(x):
    """Sets progress bar to a certain percentage x.
    Progress is given as whole percentage, i.e. 50% done
    is given by x = 50"""
    global progress_x
    x = int(x * 40 // 100)                      
    sys.stdout.write("#" * x + "-" * (40 - x) + "]" + chr(8) * 41)
    sys.stdout.flush()
    progress_x = x


def endprogress():
    """End of progress bar;
    Write full bar, then move to next line"""
    sys.stdout.write("#" * 40 + "]n")
    sys.stdout.flush()

Method 7

The other answer may be better, but here’s what I was doing. First, I made a function called progress which prints off the backspace character:

def progress(x):
    out = '%s things done' % x  # The output
    bs = 'b' * 1000            # The backspace
    print bs,
    print out,

Then I called it in a loop in my main function like so:

def main():
    for x in range(20):
        progress(x)
    return

This will of course erase the entire line, but you can mess with it to do exactly what you want. I ended up make a progress bar using this method.

Method 8

If I understood well (not sure) you want to print using <CR> and not <LR>?

If so this is possible, as long the console terminal allows this (it will break when output si redirected to a file).

from __future__ import print_function
print("count xr", file=sys.stdout, end=" ")

Method 9

Added a little bit more functionality to the example of Aravind Voggu:

def progressBar(name, value, endvalue, bar_length = 50, width = 20):
        percent = float(value) / endvalue
        arrow = '-' * int(round(percent*bar_length) - 1) + '>'
        spaces = ' ' * (bar_length - len(arrow))
        sys.stdout.write("r{0: <{1}} : [{2}]{3}%".format(
                         name, width, arrow + spaces, int(round(percent*100))))
        sys.stdout.flush()
        if value == endvalue:     
             sys.stdout.write('nn')

Now you are able to generate multiple progressbars without replacing the previous one.

I’ve also added name as a value with a fixed width.

For two loops and two times the use of progressBar() the result will look like:

progress bar animation

Method 10

from time import sleep

max_val = 40

for done in range(max_val):
    sleep(0.05)

    undone = max_val - 1 - done
    proc = (100 * done) // (max_val - 1)
    print(f"rProgress: [{('#' * done) + ('_' * undone)}] ({proc}%)", end='r')

print("nDone!")
Progress: [###################_____________________] (47%)
Progress: [########################################] (100%)
Done!

Method 11

Below code will count Message from 0 to 137 each 0.3 second replacing previous number.

Number of symbol to backstage = number of digits.

stream = sys.stdout
for i in range(137):
    stream.write('b' * (len(str(i)) + 10))
    stream.write("Message : " + str(i))
    stream.flush()
    time.sleep(0.3)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x