I'm writing an arcanoid game in python on windows console and what bothers me is annoying blinking after every iteration of "displaying" loop. Does anyone have any idea how to reduce it? This is part of the code:
#-*- coding: UTF-8 -*-
import time
import os
clear = lambda: os.system('cls')
def gra():
koniec='0'
while koniec!='1':
for i in range(4):
for j in range(10):
print '[___]',
print '\n',
for i in range(10):
print '\n'
for i in range(10):
print ' ',
print '~~~~~~~~~~'
time.sleep(0.1)
clear()
gra()
There is a limit to what you can do, but gathering everything into 1 big string and then printing once between screen clears is better than a number of small prints in a loop. Run the following code and look how much better the second half of the program runs than the first half:
import time, os, random
def display1(chars):
os.system('cls')
for row in chars:
print(''.join(row))
def display2(chars):
os.system('cls')
print('\n'.join(''.join(row) for row in chars))
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
display1(chars)
os.system('cls')
time.sleep(1)
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
display2(chars)
On Edit: You can combine these ideas with the excellent idea of #GingerPlusPlus to avoid cls. The trick is to print a large number of backspaces.
First -- write your own version of cls:
def cls(n = 0):
if n == 0:
os.system('cls')
else:
print('\b'*n)
The first time it is called -- pass it zero and it just clear the screen.
The following function pushes a character array to the command window in one big print and returns the number of characters printed (since this is the number of backspaces needed to reposition the cursor):
def display(chars):
s = '\n'.join(''.join(row) for row in chars)
print(s)
return len(s)
Used like thus:
chars = []
for i in range(40):
chars.append(["-"]*40)
for i in range(100):
n = 0
r = random.randint(0,39)
c = random.randint(0,39)
chars[r][c] = "X"
time.sleep(0.1)
cls(n)
n = display(chars)
when the above code is run, the display changes smoothly with virtually no flicker.
You could do:
rows_full=row_count+2
print("\033[F"*rows_full)
#print the screen again
The disadvantages are that you can't overwrite the very top bit of the console, and have to know how many rows have been printed. But knowing the row amount should be trivial when working with a fixed-rowed ASCII graphics game. It also isn't a CLS, it just moves you to the top.
Oh, the explanation! It uses the ANSI escape sequence F, which moves to the row above. It prints this many times, which puts you to the top of the screen. Also, you have to add 2 to the rowcount, otherwise the top rows will repeat.
PS: If anyone knows how to make it so that that method can reach the top part of the console, I'll give you some cookies.
I figured it out... You can use ANSI codes to move the cursor then clear the lines without any BLINK!
print('\033[4A\033[2K', end='')
\033[4A Moves the cursor 4 lines up (\033[{lines}A you can replace lines with however many you need)
\033[2K Clears all those lines without the screen blinking.
You can use it in a simple typewrite function that needs a constant message or a box around it like this:
from time import sleep
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[3A\033[2K', end='')
The only problem with this is that the top line is blinking. To fix this all we need to do is to add a empty line that is blinking so the user cant see it. We also move the cursor up from 3 to 4 lines.
def typewrite(text: str):
lines = text.split('\n')
for line in lines:
display = ''
for char in line:
display += char
print('')
print(f'╭─ SOME MESSAGE OR SOMEONES NAME ────────────────────────────────────────────╮')
print(f'│ {display:74} │') # :74 is the same as ' ' * 74
print(f'╰────────────────────────────────────────────────────────────────────────────╯')
sleep(0.05)
print('\033[4A\033[2K', end='')
To make this into your code just print your text and add a print('') at the start. Then use this print('\033[4A\033[2K', end='') but change the 4 to however many lines that you printed including the print(''). Then it should work without blinking. You can put print('\033[4B', end='') at the end which just moves the cursor back up.
If you want to hide the cursor you can use this gibberish or make the cursor the same color as the background:
import ctypes
if os.name == 'nt':
class _CursorInfo(ctypes.Structure):
_fields_ = [("size", ctypes.c_int),
("visible", ctypes.c_byte)]
def hide_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = False
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
def show_cursor() -> None:
if os.name == 'nt':
ci = _CursorInfo()
handle = ctypes.windll.kernel32.GetStdHandle(-11)
ctypes.windll.kernel32.GetConsoleCursorInfo(handle, ctypes.byref(ci))
ci.visible = True
ctypes.windll.kernel32.SetConsoleCursorInfo(handle, ctypes.byref(ci))
Note: All of this is still new to me so I am still testing this out to fully understand it.
anything really done with the windows console will blink if your clearing and rewriting the screen, unless you find something quite advanced I don't think you can remove the blinking
my only suggestion is to limit the clearing to when something actually changes.
or to use a tkinter text box instead of the cmd. If you want to use that idea I can help with it, although I mostly use tkinter for python 3.4
hopefully that helps!
Related
I want to print Text 'Loading...' But its dots would be moving back and forward (in shell).
I am creating a text game and for that it will look better.
I know writing slowly a word but dots also have to go back.
I am thinking that I should forget dots to come back.And for that:
import sys
import time
shell = sys.stdout.shell
shell.write('Loading',"stdout")
str = '........'
for letter in str:
sys.stdout.write(letter)
time.sleep(0.1)
What do you think?
If you have that dots would be moving back and forward Then please share with me.
If you want more information I am ready to Provide to you.
Thanks
You can use backtracking via backspace (\b) in your STDOUT to go back and 'erase' written characters before writing them again to simulate animated loading, e.g.:
import sys
import time
loading = True # a simple var to keep the loading status
loading_speed = 4 # number of characters to print out per second
loading_string = "." * 6 # characters to print out one by one (6 dots in this example)
while loading:
# track both the current character and its index for easier backtracking later
for index, char in enumerate(loading_string):
# you can check your loading status here
# if the loading is done set `loading` to false and break
sys.stdout.write(char) # write the next char to STDOUT
sys.stdout.flush() # flush the output
time.sleep(1.0 / loading_speed) # wait to match our speed
index += 1 # lists are zero indexed, we need to increase by one for the accurate count
# backtrack the written characters, overwrite them with space, backtrack again:
sys.stdout.write("\b" * index + " " * index + "\b" * index)
sys.stdout.flush() # flush the output
Keep in mind that this is a blocking process so you either have to do your loading checks within the for loop, or run your loading in a separate thread, or run this in a separate thread - it will keep running in a blocking mode as long as its local loading variable is set to True.
Check This Module Keyboard with many features. Install It, perhaps with this command:
pip3 install keyboard
Then Write the following code in File textdot.py:
def text(text_to_print,num_of_dots,num_of_loops):
from time import sleep
import keyboard
import sys
shell = sys.stdout.shell
shell.write(text_to_print,'stdout')
dotes = int(num_of_dots) * '.'
for last in range(0,num_of_loops):
for dot in dotes:
keyboard.write('.')
sleep(0.1)
for dot in dotes:
keyboard.write('\x08')
sleep(0.1)
Now Paste the file in Lib from your python folder.
Now you Can use it like following example:
import textdot
textdot.text('Loading',6,3)
Thanks
A bit late but for anyone else its not that complicated.
import os, time #import os and time
def loading(): #make a function called loading
spaces = 0 #making a variable to store the amount of spaces between the start and the "."
while True: #infinite loop
print("\b "*spaces+".", end="", flush=True) #we are deleting however many spaces and making them " " then printing "."
spaces = spaces+1 #adding a space after each print
time.sleep(0.2) #waiting 0.2 secconds before proceeding
if (spaces>5): #if there are more than 5 spaces after adding one so meaning 5 spaces (if that makes sense)
print("\b \b"*spaces, end="") #delete the line
spaces = 0 #set the spaces back to 0
loading() #call the function
I believe the following code is what you are looking for. Simply thread this in your script, and it will flash dots while the user is waiting.
################################################################################
"""
Use this to show progress in the terminal while other processes are runnning
- show_running.py -
"""
################################################################################
#import _thread as thread
import time, sys
def waiting(lenstr=20, zzz=0.5, dispstr='PROCESSING'):
dots = '.' * lenstr
spaces = ' ' * lenstr
print(dispstr.center(lenstr, '*'))
while True:
for i in range(lenstr):
time.sleep(zzz)
outstr = dots[:i] + spaces[i:]
sys.stdout.write('\b' * lenstr + outstr)
sys.stdout.flush()
for i in range(lenstr, 0, -1):
time.sleep(zzz)
outstr = dots[:i] + spaces[i:]
sys.stdout.write('\b' * lenstr + outstr)
sys.stdout.flush()
#------------------------------------------------------------------------------#
if __name__ == '__main__':
import _thread as thread
from tkinter import *
root = Tk()
Label(root, text="I'm Waiting").pack()
start = time.perf_counter()
thread.start_new_thread(waiting, (20, 0.5))
root.mainloop()
finish = time.perf_counter()
print('\nYour process took %.2f seconds to complete.' % (finish - start))
Just like in the movies and in games, the location of a place comes up on screen as if it's being typed live. I want to make a game about escaping a maze in python. At the start of the game it gives the background information of the game:
line_1 = "You have woken up in a mysterious maze"
line_2 = "The building has 5 levels"
line_3 = "Scans show that the floors increase in size as you go down"
Under the variables, I tried to do a for loop for each line similar to this:
from time import sleep
for x in line_1:
print (x)
sleep(0.1)
The only problem with this is that it print one letter per line. The timing of it is ok, but how can I get it to go on one line?
Because you tagged your question with python 3 I will provide a python 3 solution:
Change your end character of print to an empty string: print(..., end='')
Add sys.stdout.flush() to make it print instantly (because the output is buffered)
Final code:
from time import sleep
import sys
for x in line_1:
print(x, end='')
sys.stdout.flush()
sleep(0.1)
Making it random is also very simple.
Add this import:
from random import uniform
Change your sleep call to the following:
sleep(uniform(0, 0.3)) # random sleep from 0 to 0.3 seconds
lines = ["You have woken up in a mysterious maze",
"The building has 5 levels",
"Scans show that the floors increase in size as you go down"]
from time import sleep
import sys
for line in lines: # for each line of text (or each message)
for c in line: # for each character in each line
print(c, end='') # print a single character, and keep the cursor there.
sys.stdout.flush() # flush the buffer
sleep(0.1) # wait a little to make the effect look good.
print('') # line break (optional, could also be part of the message)
To iterate over the lines, change the loop to:
for x in (line_1, line_2, line_3):
You can change the end of line character automatically added by print with print("", end=""). To printfoobar, you could do this:
print("foo", end="")
print("bar", end="")
From the documentation:
All non-keyword arguments are converted to strings like str() does and written to the stream, separated by sep and followed by end. Both sep and end must be strings; they can also be None, which means to use the default values.
Python Typewriter Effect
For every letter in the string, my answer provides 0.1 of a second to wait, so the text would appear one by one. Python 3 allows the use of sys.stdout.write.
import time, sys
def anything(str):
for letter in str:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(0.1)
anything("Blah Blah Blah...")
Your full code will look like this:
import time, sys
def anything(str):
for letter in str:
sys.stdout.write(letter)
sys.stdout.flush()
time.sleep(0.1)
anything("You have woken up in a
mysterious maze")
anything("The building has five
levels")
anything("Scans show that the floors
increase in size as you go down")
It's easiest solving:
import time
def tt(text, delay):
for i in text:
print(end = i)
time.sleep(delay)
print(tt("sample text", 0.2)
This solution will not change ur algorithm
from time import sleep
line_1 = "You have woken up in a mysterious maze"
line_2 = "The building has 5 levels"
line_3 = "Scans show that the floors increase in size as you go down"
for x in line_1:
print(x, end='')
sleep(0.05)
If I had the following code:
for x in range(10):
print(x)
I would get the output of
1
2
etc..
What I would like to do is instead of printing a newline, I want to replace the previous value and overwrite it with the new value on the same line.
Simple Version
One way is to use the carriage return ('\r') character to return to the start of the line without advancing to the next line.
Python 3
for x in range(10):
print(x, end='\r')
print()
Python 2.7 forward compatible
from __future__ import print_function
for x in range(10):
print(x, end='\r')
print()
Python 2.7
for x in range(10):
print '{}\r'.format(x),
print
Python 2.0-2.6
for x in range(10):
print '{0}\r'.format(x),
print
In the latter two (Python 2-only) cases, the comma at the end of the print statement tells it not to go to the next line. The last print statement advances to the next line so your prompt won't overwrite your final output.
Line Cleaning
If you can’t guarantee that the new line of text is not shorter than the existing line, then you just need to add a “clear to end of line” escape sequence, '\x1b[1K' ('\x1b' = ESC):
for x in range(75):
print('*' * (75 - x), x, end='\x1b[1K\r')
print()
Since I ended up here via Google but am using Python 3, here's how this would work in Python 3:
for x in range(10):
print("Progress {:2.1%}".format(x / 10), end="\r")
Related answer here: How can I suppress the newline after a print statement?
#Mike DeSimone answer will probably work most of the time. But...
for x in ['abc', 1]:
print '{}\r'.format(x),
-> 1bc
This is because the '\r' only goes back to the beginning of the line but doesn't clear the output.
If POSIX support is enough for you, the following would clear the current line and leave the cursor at its beginning:
print '\x1b[2K\r',
It uses ANSI escape code to clear the terminal line. More info can be found in wikipedia and in this great talk.
Other approach
This other, (arguably worse) solution I have found looks like this:
last_x = ''
for x in ['abc', 1]:
print ' ' * len(str(last_x)) + '\r',
print '{}\r'.format(x),
last_x = x
-> 1
One advantage is that it will work on windows too.
I had the same question before visiting this thread. For me the sys.stdout.write worked only if I properly flush the buffer i.e.
for x in range(10):
sys.stdout.write('\r'+str(x))
sys.stdout.flush()
Without flushing, the result is printed only at the end out the script
Suppress the newline and print \r.
print 1,
print '\r2'
or write to stdout:
sys.stdout.write('1')
sys.stdout.write('\r2')
for x in range(10):
time.sleep(0.5) # shows how its working
print("\r {}".format(x), end="")
time.sleep(0.5) is to show how previous output is erased and new output is printed
"\r" when its at the start of print message , it gonna erase previous output before new output.
Try this:
import time
while True:
print("Hi ", end="\r")
time.sleep(1)
print("Bob", end="\r")
time.sleep(1)
It worked for me. The end="\r" part is making it overwrite the previous line.
WARNING!
If you print out hi, then print out hello using \r, you’ll get hillo because the output wrote over the previous two letters. If you print out hi with spaces (which don’t show up here), then it will output hi. To fix this, print out spaces using \r.
This works on Windows and python 3.6
import time
for x in range(10):
time.sleep(0.5)
print(str(x)+'\r',end='')
Here's a cleaner, more "plug-and-play", version of #Nagasaki45's answer. Unlike many other answers here, it works properly with strings of different lengths. It achieves this by clearing the line with just as many spaces as the length of the last line printed print. Will also work on Windows.
def print_statusline(msg: str):
last_msg_length = len(getattr(print_statusline, 'last_msg', ''))
print(' ' * last_msg_length, end='\r')
print(msg, end='\r')
sys.stdout.flush() # Some say they needed this, I didn't.
setattr(print_statusline, 'last_msg', msg)
Usage
Simply use it like this:
for msg in ["Initializing...", "Initialization successful!"]:
print_statusline(msg)
time.sleep(1)
This small test shows that lines get cleared properly, even for different lengths:
for i in range(9, 0, -1):
print_statusline("{}".format(i) * i)
time.sleep(0.5)
I couldn't get any of the solutions on this page to work for IPython, but a slight variation on #Mike-Desimone's solution did the job: instead of terminating the line with the carriage return, start the line with the carriage return:
for x in range(10):
print '\r{0}'.format(x),
Additionally, this approach doesn't require the second print statement.
The accepted answer is not perfect. The line that was printed first will stay there and if your second print does not cover the entire new line, you will end up with garbage text.
To illustrate the problem save this code as a script and run it (or just take a look):
import time
n = 100
for i in range(100):
for j in range(100):
print("Progress {:2.1%}".format(j / 100), end="\r")
time.sleep(0.01)
print("Progress {:2.1%}".format(i / 100))
The output will look something like this:
Progress 0.0%%
Progress 1.0%%
Progress 2.0%%
Progress 3.0%%
What works for me is to clear the line before leaving a permanent print. Feel free to adjust to your specific problem:
import time
ERASE_LINE = '\x1b[2K' # erase line command
n = 100
for i in range(100):
for j in range(100):
print("Progress {:2.1%}".format(j / 100), end="\r")
time.sleep(0.01)
print(ERASE_LINE + "Progress {:2.1%}".format(i / 100)) # clear the line first
And now it prints as expected:
Progress 0.0%
Progress 1.0%
Progress 2.0%
Progress 3.0%
I'm a bit surprised nobody is using the backspace character. Here's one that uses it.
import sys
import time
secs = 1000
while True:
time.sleep(1) #wait for a full second to pass before assigning a second
secs += 1 #acknowledge a second has passed
sys.stdout.write(str(secs))
for i in range(len(str(secs))):
sys.stdout.write('\b')
Here's my solution! Windows 10, Python 3.7.1
I'm not sure why this code works, but it completely erases the original line. I compiled it from the previous answers. The other answers would just return the line to the beginning, but if you had a shorter line afterwards, it would look messed up like hello turns into byelo.
import sys
#include ctypes if you're on Windows
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
#end ctypes
def clearline(msg):
CURSOR_UP_ONE = '\033[K'
ERASE_LINE = '\x1b[2K'
sys.stdout.write(CURSOR_UP_ONE)
sys.stdout.write(ERASE_LINE+'\r')
print(msg, end='\r')
#example
ig_usernames = ['beyonce','selenagomez']
for name in ig_usernames:
clearline("SCRAPING COMPLETE: "+ name)
Output - Each line will be rewritten without any old text showing:
SCRAPING COMPLETE: selenagomez
Next line (rewritten completely on same line):
SCRAPING COMPLETE: beyonce
(Python3) This is what worked for me. If you just use the \010 then it will leave characters, so I tweaked it a bit to make sure it's overwriting what was there. This also allows you to have something before the first print item and only removed the length of the item.
print("Here are some strings: ", end="")
items = ["abcd", "abcdef", "defqrs", "lmnop", "xyz"]
for item in items:
print(item, end="")
for i in range(len(item)): # only moving back the length of the item
print("\010 \010", end="") # the trick!
time.sleep(0.2) # so you can see what it's doing
One more answer based on the prevous answers.
Content of pbar.py:
import sys, shutil, datetime
last_line_is_progress_bar=False
def print2(print_string):
global last_line_is_progress_bar
if last_line_is_progress_bar:
_delete_last_line()
last_line_is_progress_bar=False
print(print_string)
def _delete_last_line():
sys.stdout.write('\b\b\r')
sys.stdout.write(' '*shutil.get_terminal_size((80, 20)).columns)
sys.stdout.write('\b\r')
sys.stdout.flush()
def update_progress_bar(current, total):
global last_line_is_progress_bar
last_line_is_progress_bar=True
completed_percentage = round(current / (total / 100))
current_time=datetime.datetime.now().strftime('%m/%d/%Y-%H:%M:%S')
overhead_length = len(current_time+str(current))+13
console_width = shutil.get_terminal_size((80, 20)).columns - overhead_length
completed_width = round(console_width * completed_percentage / 100)
not_completed_width = console_width - completed_width
sys.stdout.write('\b\b\r')
sys.stdout.write('{}> [{}{}] {} - {}% '.format(current_time, '#'*completed_width, '-'*not_completed_width, current,
completed_percentage),)
sys.stdout.flush()
Usage of script:
import time
from pbar import update_progress_bar, print2
update_progress_bar(45,200)
time.sleep(1)
update_progress_bar(70,200)
time.sleep(1)
update_progress_bar(100,200)
time.sleep(1)
update_progress_bar(130,200)
time.sleep(1)
print2('some text that will re-place current progress bar')
time.sleep(1)
update_progress_bar(111,200)
time.sleep(1)
print('\n') # without \n next line will be attached to the end of the progress bar
print('built in print function that will push progress bar one line up')
time.sleep(1)
update_progress_bar(111,200)
time.sleep(1)
Better to overwrite the whole line otherwise the new line will mix with the old ones if the new line is shorter.
import time, os
for s in ['overwrite!', 'the!', 'whole!', 'line!']:
print(s.ljust(os.get_terminal_size().columns - 1), end="\r")
time.sleep(1)
Had to use columns - 1 on Windows.
This worked for me, using Python 3.7.9 within Spyder, in Windows:
from IPython.display import clear_output
from time import sleep
def print_and_overwrite(text):
'''Remember to add print() after the last print that you want to overwrite.'''
clear_output(wait=True)
print(text, end='\r')
for i in range(15):
#I print the results backwards (from 15 to 1), to test shorter strings
message = "Iteration %d out of 15" %(15-i)
print_and_overwrite(message)
sleep(0.5)
print() #This stops the overwriting
print("This will be on a new line")
Anyway if somebody wants to overprint (clear) a many lines previously printed in stdout, than this answer should be helpful for him. (Thanks Thijmen Dam for the nice article Overwrite Previously Printed Lines)
In ANSI console you can use special sequences:
\033[1A and \033[K
First of them lift up a cursor, second - erase a line entirely.
Example of the clearing a console (Python 3):
LINE_UP = '\033[1A'
LINE_CLEAR = '\033[K'
CONSOLE_HEIGHT = 24 #lines
def clear_console():
for a in range(CONSOLE_HEIGHT):
print(LINE_UP, end=LINE_CLEAR, flush=True)
or eventually simply (will clear screen and move cursor to 0,0):
print('\033[2J', end='', flush=True)
If you want just positioning cursor, then use this:
print('\033[<L>;<C>f', end='', flush=True)
where <L> and <C> are Line and Column correspondingly.
Handful reference for you ANSI escape sequences
I need to print out rotating fan based on this answer with Python.
import threading
import subprocess
I = 0
class RepeatingTimer(threading._Timer):
def run(self):
while True:
self.finished.wait(self.interval)
if self.finished.is_set():
return
else:
self.function(*self.args, **self.kwargs)
def status():
global I
icons = ['|','/','--','\\']
print icons[I]
I += 1
if I == 4: I = 0
timer = RepeatingTimer(1.0, status)
timer.daemon = True # Allows program to exit if only the thread is alive
timer.start()
proc = subprocess.Popen([ 'python', "wait.py" ])
proc.wait()
timer.cancel()
This code works as I can show the fan, but with carriage return to show as follows.
|
/
--
\
|
/
--
...
What's the python code to print the characters without moving the caret position?
\n (new line) is automatically inserted by your print statement. The way to avoid it is to end your statement with a comma.
If you want your fan to be on a line on it's own, use:
print icons[I]+"\r",
\r represents the carriage return.
If you want your fan to be at the end of a non-empty line, use \b for the backspace character:
print icons[I]+"\b",
but be wary of not writing anything other than the fan characters after it.
Since print has got some other peculiarities, you may want to go with kshahar suggestion of using sys.stdout.write().
Here is your total solution:
import itertools
import sys
import time
def whirl(max=50):
parts = ['|', '/', '-', '\\']
cnt = 1
for part in itertools.cycle(parts):
if cnt >= max:
break
sys.stdout.write(part)
sys.stdout.flush()
time.sleep(.1)
sys.stdout.write('\b')
cnt += 1
def spin():
sys.stdout.write('\\')
sys.stdout.fflush()
time.sleep(1)
sys.stdout.write('\b|')
That's a start. print prints newlines; sys.stdout.write doesn't. The \b character is a backspace, and fflush is sometimes necessary to flush buffers when printing incomplete lines. You should be able to extend this method to work with your code pretty easily.
You could use sys.stdout.write to print without the new lines
sys.stdout.write(icons[I])
This question already has answers here:
How to overwrite the previous print to stdout?
(18 answers)
Why doesn't print output show up immediately in the terminal when there is no newline at the end?
(1 answer)
Closed last month.
Basically I want to do the opposite of what this guy did... hehe.
Python Script: Print new line each time to shell rather than update existing line
I have a program that is telling me how far along it is.
for i in some_list:
#do a bunch of stuff.
print i/len(some_list)*100," percent complete"
So if len(some_list) was 50, I'd get that last line printed 50 times over. I want to print one line and keep updating that line. I know I know this is probably the lamest question you'll read all day. I just can't figure out the four words I need to put into google to get the answer.
Update! I tried mvds' suggestion which SEEMED right. The new code
print percent_complete," \r",
Percent complete is just a string (I was abstracting the first time now I an trying to be literal). The result now is that it runs the program, doesn't print ANYTHING until after the program is over, and then prints "100 percent complete" on one and only one line.
Without the carriage return (but with the comma, half of mvds' suggestion) it prints nothing until the end. And then prints:
0 percent complete 2 percent complete 3 percent complete 4 percent complete
And so on. So now the new issue is that with the comma it doesn't print until the program is finished.
With the carriage return and no comma it behaves the exact same as with neither.
It's called the carriage return, or \r
Use
print i/len(some_list)*100," percent complete \r",
The comma prevents print from adding a newline. (and the spaces will keep the line clear from prior output)
Also, don't forget to terminate with a print "" to get at least a finalizing newline!
From python 3.x you can do:
print('bla bla', end='')
(which can also be used in Python 2.6 or 2.7 by putting from __future__ import print_function at the top of your script/module)
Python console progressbar example:
import time
# status generator
def range_with_status(total):
""" iterate from 0 to total and show progress in console """
n=0
while n<total:
done = '#'*(n+1)
todo = '-'*(total-n-1)
s = '<{0}>'.format(done+todo)
if not todo:
s+='\n'
if n>0:
s = '\r'+s
print(s, end='')
yield n
n+=1
# example for use of status generator
for i in range_with_status(10):
time.sleep(0.1)
For me, what worked was a combo of Remi's and siriusd's answers:
from __future__ import print_function
import sys
print(str, end='\r')
sys.stdout.flush()
In Python 3.3+ you don’t need sys.stdout.flush(). print(string, end='', flush=True) works.
So
print('foo', end='')
print('\rbar', end='', flush=True)
will overwrite ‘foo’ with ‘bar’.
for Console you'll probably need
sys.stdout.flush()
to force update. I think using , in print will block stdout from flushing and somehow it won't update
Late to the game - but since the none of the answers worked for me (I didn't try them all) and I've come upon this answer more than once in my search ... In python 3, this solution is pretty elegant and I believe does exactly what the author is looking for, it updates a single statement on the same line. Note, you may have to do something special if the line shrinks instead of grows (like perhaps make the string a fixed length with padded spaces at the end)
if __name__ == '__main__':
for i in range(100):
print("", end=f"\rPercentComplete: {i} %")
time.sleep(0.2)
As of end of 2020 and Python 3.8.5 on linux console for me only this works:
print('some string', end='\r')
Credit goes to: This post
If you are using Spyder, the lines just print continuously with all the previous solutions. A way to avoid that is using:
for i in range(1000):
print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
sys.stdout.flush()
This works for me, hacked it once to see if it is possible, but never actually used in my program (GUI is so much nicer):
import time
f = '%4i %%'
len_to_clear = len(f)+1
clear = '\x08'* len_to_clear
print 'Progress in percent:'+' '*(len_to_clear),
for i in range(123):
print clear+f % (i*100//123),
time.sleep(0.4)
raw_input('\nDone')
As of 2021, for Python 3.9.0 the following solution worked for me in Windows 10, Pycharm.
print('\r some string ', end='', flush=True)
import time
import sys
def update_pct(w_str):
w_str = str(w_str)
sys.stdout.write("\b" * len(w_str))
sys.stdout.write(" " * len(w_str))
sys.stdout.write("\b" * len(w_str))
sys.stdout.write(w_str)
sys.stdout.flush()
for pct in range(0, 101):
update_pct("{n}%".format(n=str(pct)))
time.sleep(0.1)
\b will move the location of the cursor back one space
So we move it back all the way to the beginning of the line
We then write spaces to clear the current line - as we write spaces the cursor moves forward/right by one
So then we have to move the cursor back at the beginning of the line before we write our new data
Tested on Windows cmd using Python 2.7
Try it like this:
for i in some_list:
#do a bunch of stuff.
print i/len(some_list)*100," percent complete",
(With a comma at the end.)
For Python 3+
for i in range(5):
print(str(i) + '\r', sep='', end ='', file = sys.stdout , flush = False)
In those cases, with python 3.x, I'm using the following code:
for ii in range(100):
print(f"\rPercent: {ii+1} %", end=" "*20)
The problem with some other answers is that if your printed string goes shorter at one step, the last characters from the previous string won't be overwrited.
So I use end=" "*20 in order to overwrite the previous line with whitespace. Just make sure that 20 is longer than the length of your longest string.
Based on Remi answer for Python 2.7+ use this:
from __future__ import print_function
import time
# status generator
def range_with_status(total):
""" iterate from 0 to total and show progress in console """
import sys
n = 0
while n < total:
done = '#' * (n + 1)
todo = '-' * (total - n - 1)
s = '<{0}>'.format(done + todo)
if not todo:
s += '\n'
if n > 0:
s = '\r' + s
print(s, end='\r')
sys.stdout.flush()
yield n
n += 1
# example for use of status generator
for i in range_with_status(50):
time.sleep(0.2)
For Python 3.6+ and for any list rather than just ints, as well as using the entire width of your console window and not crossing over to a new line, you could use the following:
note: please be informed, that the function get_console_with() will work only on Linux based systems, and as such you have to rewrite it to work on Windows.
import os
import time
def get_console_width():
"""Returns the width of console.
NOTE: The below implementation works only on Linux-based operating systems.
If you wish to use it on another OS, please make sure to modify it appropriately.
"""
return int(os.popen('stty size', 'r').read().split()[1])
def range_with_progress(list_of_elements):
"""Iterate through list with a progress bar shown in console."""
# Get the total number of elements of the given list.
total = len(list_of_elements)
# Get the width of currently used console. Subtract 2 from the value for the
# edge characters "[" and "]"
max_width = get_console_width() - 2
# Start iterating over the list.
for index, element in enumerate(list_of_elements):
# Compute how many characters should be printed as "done". It is simply
# a percentage of work done multiplied by the width of the console. That
# is: if we're on element 50 out of 100, that means we're 50% done, or
# 0.5, and we should mark half of the entire console as "done".
done = int(index / total * max_width)
# Whatever is left, should be printed as "unfinished"
remaining = max_width - done
# Print to the console.
print(f'[{done * "#"}{remaining * "."}]', end='\r')
# yield the element to work with it
yield element
# Finally, print the full line. If you wish, you can also print whitespace
# so that the progress bar disappears once you are done. In that case do not
# forget to add the "end" parameter to print function.
print(f'[{max_width * "#"}]')
if __name__ == '__main__':
list_of_elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
for e in range_with_progress(list_of_elements):
time.sleep(0.2)
If you are using Python 3
then this is for you and it really works.
print(value , sep='',end ='', file = sys.stdout , flush = False)
Just figured this out on my own for showing a countdown but it would also work for a percentage.
import time
#Number of seconds to wait
i=15
#Until seconds has reached zero
while i > -1:
#Ensure string overwrites the previous line by adding spaces at end
print("\r{} seconds left. ".format(i),end='')
time.sleep(1)
i-=1
print("") #Adds newline after it's done
As long as whatever comes after '/r' is the same length or longer (including spaces) than the previous string, it will overwrite it on the same line. Just make sure you include the end='' otherwise it will print to a newline. Hope that helps!
for object "pega" that provides StartRunning(), StopRunning(),
boolean getIsRunning() and integer getProgress100() returning
value in range of 0 to 100, this provides text progress bar
while running...
now = time.time()
timeout = now + 30.0
last_progress = -1
pega.StartRunning()
while now < timeout and pega.getIsRunning():
time.sleep(0.5)
now = time.time()
progress = pega.getTubProgress100()
if progress != last_progress:
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", end='', flush=True)
last_progress = progress
pega.StopRunning()
progress = pega.getTubProgress100()
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", flush=True)