\r in Python does not delete the entire line - python

i have a quite complex problem, but here is the "simplest version" so you can better understand it.
import time
for i in range(10):
time.sleep(1)
print('{}\r'.format(i), end="")
and here everything works fine, the problem comes when i try to make a countdown
import time
for i in range(10):
time.sleep(1)
print('{}\r'.format(10-i), end="")
the output is 10... then 90... 80... 70 and so on, it seems like if the second cipher of the 10 is not cancelled. can someone tell me why?

\r moves the cursor to the beginning of the line, but it doesn't "clear" anything already printed unless you overwrite it (this may be platform-dependent). Thus, the 0 character will remain visible. You can deal with that by always printing a "fixed-width" column, so that empty spaces are printed to blank out anything left over from before. You can also just put the CR in the end param.
Thus:
import time
for i in range(10):
time.sleep(1)
print('{: <3}'.format(10-i), end='\r')
This uses a format specifier to indicate a space-filled, <left-aligned, 3-width column. You can change the 3 to any higher number depending on how many digits your counter needs.

It's caused by a simple error, you are missing a space before the \r:
Your Code:
print('{}\r'.format(10-i), end="")
# > 10,90,80
Change it to:
print('{} \r'.format(10-i),
#> 10, 9, 8

The issue is like old typewriters when you press \r carriage return it goes to line start and chages one character from there. so 10 will become 90 as the first character changes.
import time
for i in range(10):
time.sleep(1)
print('{:02d}'.format(10-i), end="\r")
So one potential solution is to fix the width. here I have made it 2 digit

Related

Delaying text printing using the Time module with VSC results in the full text being printed after a while rather than each character one by one?

I am facing an odd bug in VSC on Windows 10. I made a simple Python program that print each character of some sample text one by one over time with a constant delay in the printing of each character.
In an IDE like Thonny, this works as expected. Each character is printed after the other slowly. However in VSC, on the latest version, rather than printing each character one by one slowly, absolutely nothing happens for a period of time, and suddenly the entire text is printed all at once
import time
def slowText(quote, endChar = '\n'):
for i in quote:
print(i, end = endChar)
time.sleep(0.12)
def intro():
slowText('Name please?: ', endChar = '')
name = input()
slowText(f"You've come to the right place...{name}",endChar = '')
intro()
So for instance, here, rather printing each character of 'Name Please?: ' at once, it pauses for a duration of time roughly equal to the total time it would have spent, if it printed each character one by one normally, and suddenly dumps the text 'Name Please?: ' on screen at once
Thonny on the other hand, prints each letter one by one, separated by a 0.12 second gap. Is there a specific reason this issue happens with VSC and is there a way to fix it?

How to overwrite a line with carriage return, using a for-loop in Python?

I'm trying to print out a string with the end=\r to send the cursor back to beginning of the line, and overwrite the printed string using a for loop
This is the code thus far I got :
import time
print("░░░░░░░░░░░░░", end='\r')
for i in ("SECRET"):
print(i ,end='')
time.sleep(0.3)
Ideally, it should slowly overwrite some of the dotted pattern characters with characters from `"SECRET" every 0.3 seconds.
However, when run, the for loop instead iterates and prints characters on a single space, overwriting the characters it prints out itself, instead of advancing to the next available space, overwriting the dot pattern there and typing out the remaining characters in the string it iterates over
Removing the entire print statement associated with the dotted pattern characters allows the loop to function normally, printing out the string it iterates over properly, however, it is needed for the loop to print out the string and overwrite the dotted characters
Essentially, I want to overwrite some of the dotted pattern characters one by one using characters from the string the for loop iterates over, with the help of \r
I am on Ubuntu Studio
Screen output is line-buffered. This means that when you print something followed by a newline it appears on the screen immediately, but if you print something without a newline it might take a while to appear.
This is what's happening to you -- the output inside the for loop is not followed by a newline, so it doesn't appear onscreen immediately.
You can add flush=True to the print call to force the output to appear immediately instead of waiting:
print(i, end='', flush=True)
you can't overwrite characters in python.
you can, though, clear the whole screen by using os.system('cls') on windows or os.system('clear') on linux and unix.
here is the full code:
import time, os
output = '░░░░░░░░░░░░░'
for i in range(7):
print(output)
output = "SECRET"[:i]+output[i:]
time.sleep(0.3)
if os.name == 'nt': #on windows
os.system("cls")
else:
os.system("clear") #not on windows
print(output)
also, this will only work when you are not running from the shell and if you want to see the full output, write time.sleep(1) at the end.

Python: deleting the nth acharcter in console

example output estimate of pi:
3.13658765
then a new better estimate comes along. Say, 3.1416232.
So I find the first character in the old estimate that doesn't match the new. In this case, it is the 4th character.
Question: Is there a way to delete the 4th character in console(and then repeat this until all characters after 3.1 are gone) so that I can then print the new, better values for each of those characters?
Note: I don't want to delete everything and console and then reprint, as this would get considerably slower as the number of digits increases.
It sounds like you want something like:
best_est = None
while True:
est = some_estimate_method() # assuming this is a 'str'
if not best_est:
best_est = est
else:
if (float(est) > float(best_est)):
best_est = est
print(best_est, end = '\r')''
Depending on the directional relation of the estimate (i.e. is less better or is more better), you would have to change the inequality to accommodate.
However, if we look at your example:
# initial print
3.13658765
# get new estimate (3.1416232)
# overwrite the print
3.1416232
You originally wanted to "re-print" 3.1 then print all the new characters in the new estimate. That begs to ask the question why not just print the whole new estimate?
Since the entire value of the new estimate is greater, that means the comparison you are looking for (starting at index 4 and beyond) has already be checked when using < or > for inequality. Simply calling a print(est, end = '\r') returns the console cursor to the beginning of the line, effectively overwriting the value each time.
If you just need to overwrite your last line, you can do something like this. The "\r" means instead of a newline, a return carriage will be printed, moving you back to the start of the same line to overwrite
print("3.1515", end="\r")
print("3.1415")
Furthermore, if you want to do tricky things, you could look into ANSI escape codes, these will let you print to any arbitrary location, although they aren't the most portable. These will also let you do fun things like setting the colour.
For example print("\033[31;1HX") would print an X to the 31's column and 1st row. To delete a character, you could simply print a space over top (print("\033[31;1H ")).
This may not work on all terminals
http://ascii-table.com/ansi-escape-sequences.php

Overwrite previous output on same line

I want the output of my code to overwrite the previous output on the same line.
I have read the previous answers to a similar question and have read that I can do this using a ',' and a '\r', but this doesn't seem to work for me. I tried:
for i in range(length):
print 'Minutes:',minute,'of {0}'.format(length),'\r',
minute+=1
time.sleep(1)
But it doesn't print anything other than the last line of the loop. I've tried other arrangements,but nothing yet has worked. Could someone let me know what I'm doing wrong?
Thanks.
If You are doing this in Linux, You can simply use ASCII escape sequence to move cursor up one line (\033[1A). Of course, You will still use \r to move to the beginning of the line. You could use something like this:
for i in range(length):
print('Minutes: ' + minutes + '\033[1A\r')
minutes += 1
sleep(1)
You need sys.stderr for fast output on a screen:
import sys,time
length,minute = 10,0
for i in range(length):
sys.stderr.write('Minutes:{} of {}\r'.format(minute,length))
minute+=1
time.sleep(1)
Don't forget to add sys.stderr.write('\n') at the end of your loop to avoid printing into the same line.
The easiest way I can think of doing this is, if you know how many lines your shell is, then you can just
print "\n" * (number_of_lines - 1)
then
print 'Minutes:',minute,'of {0}'.format(length)
So together,
for i in range(length):
print "\n" * (number_of_lines - 1)
print 'Minutes:',minute,'of {0}'.format(length)
minute += 1
time.sleep(1)
General Tips
You use commas and str.format() in the same print statement, instead just use str.format() for all of it. e.g print 'Minutes: {0}, of {1}'.format(minute, length).
You used minute as your counter even though it appears you are counting by seconds. For clarity you may want to rename that variable second.
Note
sys.stderr is the better way to do this. Please look at rth's answer
If you are using Python3, you can use a code like this:
import time
minute, length = 1, 100
for i in range(length):
print ('Minutes: {0} of {1}\r'.format(minute, length), end = "")
minute+=1
time.sleep(1)
However if you are using Python2, you can import print_function from __future__ module like this example:
from __future__ import print_function
import time
minute, length = 1, 100
for i in range(length):
print("Minutes: {0} of {1}\r".format(minute, length), end = "")
minute+=1
time.sleep(1)
PS: I have a strange issue when running the last code from my terminal using Python2.7.10. The script work but there is not any output.
However within Python 2.7.10 interpreter the code works fine.
Test both solutions and leave your feedbacks if you encounter any problems within Python2.
EDIT:
I think the better solution to avoid the strange issue that i encounter, and i don't know the cause, is using the ASCII escape as #Fejs said in his answer.
Your code will be something like this:
import time
minute, length = 1, 100
for i in range(length):
print "Minutes: {0} of {1} {2}".format(minute, length, '\033[1A\r')
minute+=1
time.sleep(1)
Try flushing the output before each sleep.
minute+=1
sys.stdout.flush()
time.sleep(1)

Dynamic single-line printing in Python (time?)

I'd like to make a simple clock (CLI) that prints the time into one line, and updates it every second. Is this even possible? Should I just print a new line every second?
This is what I have at the moment, which functions terribly:
import calendar, time
a = 1
while a == 1:
print (calendar.timegm(time.gmtime()))
If I understand, what you want to do is write the time, then, a second later, overwrite it with the new time, and so on.
On most terminals, printing a carriage return without a newline will take you back to the start of the same line. So, you can almost just do this:
print('\r{}'.format(calendar.timegm(time.gmtime())), end='')
In general, there's a problem with this: the carriage return doesn't erase the existing text, it just lets you overwrite it. So, what happens if the new value is shorter than the old one? Well, in your case, that isn't possible; you're printing a 10-digit number that can never turn into a 9-digit number. But if it were a problem, the easiest solution would be to change that {} to something like {<70}, which will pad a short line with spaces, up to 70 characters. (Of course if your lines could be longer than 70 character, or your terminal could be narrower than 70, don't use that number.)
Meanwhile, if you just do this over and over as fast as possible, you're wasting a lot of CPU and I/O, and possibly screwing up your terminal's scrollback buffer, and who knows what else. If you want to do this once per second, you should sleep for a second in between.
So:
while True:
print('\r{}'.format(calendar.timegm(time.gmtime())))
time.sleep(1)
If you want to get fancy, you can take over the whole terminal with curses on most non-Windows platforms, msvcrt console I/O on Windows, or even manually printing out terminal escape sequences. But you probably don't want to get fancy.
print function print newline (\n) after the string you passed. Specify carriage return (\r) explicitly does what you want.
To print every second, call time.sleep(1) after printing.
import calendar
import time
while 1:
print(calendar.timegm(time.gmtime()), end='\r')
time.sleep(1)
UPDATE
To make cursor remains at the end of the line, prepend \r:
print('\r', calendar.timegm(time.gmtime()), sep='', end='')

Categories

Resources