I have a Python script and I want to make it display a increasing number from 0 to 100% in the terminal. I know how to print the numbers on the terminal but how can I "rewrite" them so 0 turns into 1, 1 into 2, and so on until 100?
Printing a carriage return (\r) without a newline resets the cursor to the beginning of the line, making the next print overwriting what's already printed:
import time
import sys
for i in range(100):
print i,
sys.stdout.flush()
time.sleep(1)
print "\r",
This doesn't clear the line, so if you try to, say, print decreasing numbers using this methods, you'll see leftover text from previous prints. You can work around this by padding out your output with spaces, or using some of the control codes in the other answers.
This recipe here should prove useful. Using that module as tc, the following code does what you want:
from tc import TerminalController
from time import sleep
import sys
term = TerminalController()
for i in range(10):
sys.stdout.write("%3d" % i)
sys.stdout.flush()
sleep(2)
sys.stdout.write(term.BOL + term.CLEAR_EOL)
The recipe uses terminfo to get information about the terminal and works in Linux and OS X for a number of terminals. It does not work on Windows, though. (Thanks to piquadrat for testing, as per the comment below).
Edit: The recipe also gives capabilities for using colours and rewriting part of the line. It also has a ready made text progress bar.
Using the blessings package - clear your screen (clear/cls) and enter:
import sys
from blessings import Terminal
from time import sleep # <- boy, does this sound tempting a.t.m.
term = Terminal()
for i in range(6):
with term.location(term.width - 3, term.height - 3):
print('{}'.format(i))
sleep(2)
if (i == 3):
print('what was I doing, again?')
print('done')
To install it from CheeseShop, just...
pip install blessings
Based on this answer, but without the terminal controller:
import time
import sys
for i in range(100):
sys.stdout.write("Downloading ... %s%%\r" % (i))
sys.stdout.flush()
time.sleep(1)
Tested on GNOME terminal (Linux) and Windows console.
Tip: Don't run this example in IDLE editor.
Related
So i am currently trying to make something that will print . and remove it then print ..
and also remove it then print ... When i tried using sys module to remove the prevous text this was the output: lol [Ktest so it basically adds a [K to the next line.
I also tried using another method so instead of removing the prevous text it would just add onto it like:
import time
print("lol",end="")
time.sleep(1)
print("test")
it did work in IDLE but when i tried to use it by opening the file in the command promt it waited for 1 second and then just gave loltest without any delay between them. So nothing i found in the internet worked for me.
You may print with the keyword argument end to append the special character '\r' to the end of the line.
E.g.
import time
print(".", end='\r')
time.sleep(2)
print("..", end='\r')
time.sleep(2)
print("...", end='\r')
time.sleep(2)
'\r' is carriage return and will return to the start of the line in some terminals, from where you can overwrite the text you just printed. Note that the behaviour might differ between terminals though.
To print over the prvious print, you can use end="\r.
import time
print("lol", end="\r")
time.sleep(1)
print("test")
for i in range(4):
print("."*i, end="\r")
time.sleep(1)
You can use the os module to execute shell commands.
To clear the terminal, command required in windows is cls and for unix its clear
import os
os.system('cls' if os.name == 'nt' else 'clear')
If you don't want to clear previous terminal outputs you can use flexibility of print function or the carriage return as others denoted.
for _ in range(3):
print('.', end='')
time.sleep(1)
If you specifically want to print . then .. then ..., you don't need to remove the existing text; you can just print additional dots.
To make the dots actually appear one by one, you'll need to flush the buffers, using flush=True
import time
for _ in range(3):
print('.', end='', flush=True)
time.sleep(1)
print()
This has the advantage that it will work much more generally; almost any output method can do that, whereas ANSI codes or tricks with \r or clearing the screen depend on your hardware, operating system and various other things.
You can do it with ANSI escape codes, like this:
import sys, time
clear_line = '\x1b[1K\r'
print("lol", end="")
sys.stdout.flush() # to force printing the text above
time.sleep(1)
print(clear_line+"test") # Now lol replaced with test
Please note that ANSI codes you should use depend on the environment where the program is executing (platform, terminal, etc.).
Update: you may want to see the built-in curses module.
So i have a code of a timer and When a person puts in the number i just want the timer to start and inputted number to not be visible.Code is something like
s=int(input("enter time in sec"))
countdown(s)
so the output is :
enter time in sec 5
0:4
0:3
0:2
0:1
0:0
time up
What i want is to first remove "enter time in sec 5" then when 0:4 prints i want to print 0:3 in its place not below it.
I tried Python deleting input line and copy pasted this on the code like so
s = int(input("enter time in sec "))
print ('\033[1A\033[K')
countdown(s)
and nothing seemed to happen, don't if im wrong in the implementation or it didn't work.
Edit:-
Tried both
os.system('cls')
and
print ('\033[1A\033[K')
neither seemed to work
my code,
def time_format(inp):
import os
m,s=divmod(inp,60)
#os.system('cls')
print ('\033[1A\033[K')
...code for printing time below...
Edit:- im on windows and am using Idle.
neither of the two work
You didn't specify what OS you use but if you target Linux it could
be:
#!/usr/bin/env python3
import time
def countdown(seconds):
for i in range(seconds, -1, -1):
# move to the beginning of the line and remove line
print("\r\033[K", end='', flush=True)
print(f"\r{i}", end='', flush=True)
time.sleep(1)
print("\nTime's up!")
s = int(input("enter time in sec: "))
# move one line up
print("\033[1A", end='', flush=True)
countdown(s)
It works like that:
See accepted answer of: How to clear the interpreter console?
os.system('cls') works on Windows, while
os.system('clear') works on Linux
Got a pop saying I shouldn't delete answered question therefore answering it myself.
I believe both the
print("\033[1A", end='', flush=True)
and
os.system('cls')
works. The issue is that there is no option/method to do it on IDLE. because i tried both the methods work if i double click and run the file as is but none work on IDLE
I know it is possible to consistently rewrite the last line displayed in the terminal with "\r", but I am having trouble figuring out if there is a way to go back and edit previous lines printed in the console.
What I would like to do is reprint multiple lines for a text-based RPG, however, a friend was also wondering about this for an application which had one line dedicated to a progress bar, and another describing the download.
i.e. the console would print:
Moving file: NameOfFile.txt
Total Progress: [######## ] 40%
and then update appropriately (to both lines) as the program was running.
On Unix, use the curses module.
On Windows, there are several options:
PDCurses: http://www.lfd.uci.edu/~gohlke/pythonlibs/
The HOWTO linked above recommends the Console module
http://newcenturycomputers.net/projects/wconio.html
http://docs.activestate.com/activepython/2.6/pywin32/win32console.html
Simple example using curses (I am a total curses n00b):
import curses
import time
def report_progress(filename, progress):
"""progress: 0-10"""
stdscr.addstr(0, 0, "Moving file: {0}".format(filename))
stdscr.addstr(1, 0, "Total progress: [{1:10}] {0}%".format(progress * 10, "#" * progress))
stdscr.refresh()
if __name__ == "__main__":
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
try:
for i in range(10):
report_progress("file_{0}.txt".format(i), i+1)
time.sleep(0.5)
finally:
curses.echo()
curses.nocbreak()
curses.endwin()
Like this:
#!/usr/bin/env python
import sys
import time
from collections import deque
queue = deque([], 3)
for t in range(20):
time.sleep(0.5)
s = "update %d" % t
for _ in range(len(queue)):
sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
queue.append(s)
for i in range(len(queue)):
sys.stdout.write(queue[i] + "\n") # reprint the lines
I discovered this in the Jiri project, written in Go.
Even better: erase all lines after done:
#!/usr/bin/env python
import sys
import time
from collections import deque
queue = deque([], 3)
t = 0
while True:
time.sleep(0.5)
if t <= 20:
s = "update %d" % t
t += 1
else:
s = None
for _ in range(len(queue)):
sys.stdout.write("\x1b[1A\x1b[2K") # move up cursor and delete whole line
if s != None:
queue.append(s)
else:
queue.popleft()
if len(queue) == 0:
break
for i in range(len(queue)):
sys.stdout.write(queue[i] + "\n") # reprint the lines
Ultimately, if you want to manipulate the screen, you need to use the underlying OS libraries, which will typically be:
curses (or the underlying terminal control codes as tracked by the terminfo/termcap database) on Linux or OSX
the win32 console API on Windows.
The answer from #codeape already gives you some of the many options if you don't mind sticking to one OS or are happy to install third party libraries on Windows.
However, if you want a cross-platform solution that you can simply pip install, you could use asciimatics. As part of developing this package, I've had to resolve the differences between environments to provide a single API that works on Linux, OSX and Windows.
For progress bars, you could use the BarChart object as shown in this demo using this code.
Here is a Python module for both Python 2/3, which can simply solve such situation with a few line of code ;D
reprint - A simple module for Python 2/3 to print and refresh multi line output contents in terminal
You can simply treat that output instance as a normal dict or list(depend on which mode you use). When you modify that content in the output instance, the output in terminal will automatically refresh :D
For your need, here is the code:
from reprint import output
import time
if __name__ == "__main__":
with output(output_type='dict') as output_lines:
for i in range(10):
output_lines['Moving file'] = "File_{}".format(i)
for progress in range(100):
output_lines['Total Progress'] = "[{done}{padding}] {percent}%".format(
done = "#" * int(progress/10),
padding = " " * (10 - int(progress/10)),
percent = progress
)
time.sleep(0.05)
Carriage return can be used to go to the beginning of line, and ANSI code ESC A ("\033[A") can bring you up a line. This works on Linux. It can work on Windows by using the colorama package to enable ANSI codes:
import time
import sys
import colorama
colorama.init()
print("Line 1")
time.sleep(1)
print("Line 2")
time.sleep(1)
print("Line 3 (no eol)", end="")
sys.stdout.flush()
time.sleep(1)
print("\rLine 3 the sequel")
time.sleep(1)
print("\033[ALine 3 the second sequel")
time.sleep(1)
print("\033[A\033[A\033[ALine 1 the sequel")
time.sleep(1)
print() # skip two lines so that lines 2 and 3 don't get overwritten by the next console prompt
print()
Output:
> python3 multiline.py
Line 1 the sequel
Line 2
Line 3 the second sequel
>
Under the hood, colorama presumably enables Console Virtual Terminal Sequences
using SetConsoleMode.
(also posted here: https://stackoverflow.com/a/64360937/461834)
You can try tqdm.
from time import sleep
from tqdm import tqdm
from tqdm import trange
files = [f'file_{i}' for i in range(10)]
desc_bar = tqdm(files, bar_format='{desc}')
prog_bar = trange(len(files), desc='Total Progress', ncols=50, ascii=' #',
bar_format='{desc}: [{bar}] {percentage:3.0f}%')
for f in desc_bar:
desc_bar.set_description_str(f'Moving file: {f}')
prog_bar.update(1)
sleep(0.25)
There is also nested progress bars feature of tqdm
from tqdm.auto import trange
from time import sleep
for i in trange(4, desc='1st loop'):
for k in trange(50, desc='2rd loop', leave=False):
sleep(0.01)
Note that nested progress bars in tqdm have some Known Issues:
Consoles in general: require support for moving cursors up to the previous line. For example, IDLE, ConEmu and PyCharm (also here, here, and here) lack full support.
Windows: additionally may require the Python module colorama to ensure nested bars stay within their respective lines.
For nested progress bar in Python, Double Progress Bar in Python - Stack Overflow has more info.
I found simple solution with a "magic_char".
magic_char = '\033[F'
multi_line = 'First\nSecond\nThird'
ret_depth = magic_char * multi_line.count('\n')
print('{}{}'.format(ret_depth, multi_line), end='', flush = True)
In python 3, we can easily print on the same line using the following script. I use this to understand the progress of my loop (how much time will be left). However, in jupyter it doesnt work (it prints on different lines)
import time
for f in range(10):
print(f, end='\r', flush=True)
time.sleep(10)
It doesnt work to turn pretty print off %pprint, and I tried the same with sys.stdout.write() but also there I have this issue.
Found the solution to this a bit later (note that it does not work in pycharm jupyter, but only in the browser implementation). For me print works fine, but here display is advised, but it prints apostrophes around strings.
from time import sleep
from IPython.display import clear_output, display
for f in range(10):
clear_output(wait=True)
print(f) # use display(f) if you encounter performance issues
sleep(10)
Edit: Just wanted to add that TQDM is often also a good tool for this goal. It displays progress bars and allows you to write output below it or differ the description of each bar. See also this post.
import sys
from tqdm import tqdm
from time import sleep
values = range(3)
with tqdm(total=len(values), file=sys.stdout) as pbar:
for i in values:
pbar.set_description('processed: %d' % (1 + i))
pbar.update(1)
sleep(1)
And the notebook one with nice colours
from tqdm import tqdm, tqdm_notebook
from time import sleep
for i in tqdm_notebook(range(2), desc='1st loop'):
sleep(0.01)
tqdm.write(f"Done task {i}")
Prefix a \r and add an argument end="" to print, like so
print("\rThis will be printed on the same line", end="")
This works in the Jupyter notebook in Google Colab.
The part "\r" overwrites the line, if you leave that you append to the line. Your version print(f, end='', flush=False) could work but I've read under Python 3 you need to use sys.stdout.write() and best is if you add flush command too.
import sys
import time
for f in range(10):
#delete "\r" to append instead of overwrite
sys.stdout.write("\r" + str(f))
sys.stdout.flush()
time.sleep(10)
The stdout.flush is required on some systems or you won't get any output
In some cases, the issue could arise when multiple arguments are given to the print statement.
for i in range(3):
print(i, "-", i ** 2, end="\r")
The above snippet prints 2 - 0 - 1 - 4 in a jupyter notebook. However, passing a single argument to print will give the desired result of 2 - 4 i.e. 0 - 0 is overwritten by 1 - 2 which is in-turn overwritten by 2 - 4
for i in range(3):
print(f"{i} - {i ** 2}", end="\r")
Here are the package versions that I am using.
# Name Version
notebook 6.4.12
ipython 8.4.0
python 3.8.13
jupyter-client 7.3.4
Most of questions related to this topics here in SO is as follows:
How to print some information on the same line without introducing a
new line
Q1 Q2.
Instead, my question is as follows:
I expect to see the following effect,
>> You have finished 10%
where the 10 keep increasing in the same time. I know how to do this in C++ but cannot
find a good solution in python.
import sys, time
for i in xrange(0, 101, 10):
print '\r>> You have finished %d%%' % i,
sys.stdout.flush()
time.sleep(2)
print
The \r is the carriage return. You need the comma at the end of the print statement to avoid automatic newline. Finally sys.stdout.flush() is needed to flush the buffer out to stdout.
For Python 3, you can use:
print("\r>> You have finished {}%".format(i), end='')
Python 3
You can use keyword arguments to print:
print('string', end='\r', flush=True)
end='\r' replaces the default end-of-line behavior with '\r'
flush=True flushes the buffer, making the printed text appear immediately.
Python 2
In 2.6+ you can use from __future__ import print_function at the start of the script to enable Python 3 behavior. Or use the old way:
Python's print puts a newline after each command, unless you suppress it with a trailing comma. So, the print command is:
print 'You have finished {0}%\r'.format(percentage),
Note the comma at the end.
Unfortunately, Python only sends the output to the terminal after a complete line. The above is not a complete line, so you need to flush it manually:
import sys
sys.stdout.flush()
On linux( and probably on windows) you can use curses module like this
import time
import curses
win = curses.initscr()
for i in range(100):
win.clear()
win.addstr("You have finished %d%%"%i)
win.refresh()
time.sleep(.1)
curses.endwin()
Benfit with curses as apposed to other simpler technique is that, you can draw on terminal like a graphics program, because curses provides moving to any x,y position e.g. below is a simple script which updates four views
import time
import curses
curses.initscr()
rows = 10
cols= 30
winlist = []
for r in range(2):
for c in range(2):
win = curses.newwin(rows, cols, r*rows, c*cols)
win.clear()
win.border()
winlist.append(win)
for i in range(100):
for win in winlist:
win.addstr(5,5,"You have finished - %d%%"%i)
win.refresh()
time.sleep(.05)
curses.endwin()
I had to combine a few answers above to make it work on Python 3.7 / Windows 10. The example runs on Spyder's console:
import sys, time
for i in range(0, 101, 5):
print("\r>> You have finished {}%".format(i), end='')
sys.stdout.flush()
time.sleep(.2)
The time.sleep(.2) is just used to simulates some time-consuming code.
using sys.stdout.write() instead of print works in both python 2 and 3 without any compromises.
The OP didn't specify Py2 or Py3. In Python 3 the 'import' of 'sys' and the 'sys.stdout' call can be replaced with 'flush=True':
import time
for i in range(0,101,25):
print("\r>>TESTING - {:0>3d}%".format(i), end='', flush=True)
time.sleep(.5)
print()
Thanks to Petr Viktorin for showing the "flush" parameter for Python 3 print(). I submit this because his Python 3 example doesn't include a 'format' specifier. It took me awhile to figure out that the additional parameters go after the 'format' specifier parentheses as shown in my example. I just picked an example format of 3 character integer 0 filled on the left. The best doc I found for Py3 format is: 6.1.3.1. Format Specification Mini-Language