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.
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()
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:
For Python 3.6 and below
For Python 2.x.
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.
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.
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)
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()
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.
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 x\r", file=sys.stdout, end=" ")
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('\n\n')
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:
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!
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)
Had the same problem and tried many solutions.
import sys
sys.stdout.write('\r Blablabla')
worked like a charm!
Related
So, my goal is to change this output from datetime:
time left: -1 day, 23:57:28
To this:
time left: 0:00:30
Now, this needs to be dynamic, as the code is supposed to be changed in the dictionary. I'm trying to figure out why it is outputting with
-1 day, 23:57:28
I've tried moving where it executes and even changing some other code. I just don't understand why it's showing with -1 day. It seems likes it is executing one too many times
Also, a side note, the purpose of this program is to figure out how many songs can fit into a playlist given a time restraint. I can't seem to figure out the right if statement for it to work. Could someone also help with this?
This is the current output of the program:
0:02:34
0:06:30
Reached limit of 0:07:00
time left: -1 day, 23:57:28
See code below:
import datetime
#durations and names of songs are inputted here
timeDict = {
'Song1' : '2:34',
'Song2' : '3:56',
'Song3' : '3:02'
}
def timeAdder():
#assigns sum to the datetime library's timedelta class
sum = datetime.timedelta()
#sets the limit, can be whatever
limit = '0:07:00'
#calculates the sum
for i in timeDict.values():
(m, s) = i.split(':')
d = datetime.timedelta(minutes=int(m), seconds=int(s))
sum += d
#checks whether the limit has been reached
while str(sum)<limit:
print(sum)
break
#commits the big STOP when limit is reached
if str(sum)>limit:
print("Reached limit of " + limit)
break
#timeLeft variable created as well as datetime object conversion to a string
x = '%H:%M:%S'
timeLeft = datetime.datetime.strptime(limit, x) - datetime.datetime.strptime(str(sum), x)
for i in timeDict:
if timeDict[i] <= str(timeLeft):
print("You can fit " + i + " into your playlist.")
print("time left: " + str(timeLeft))
def main():
timeAdder()
main()
Any help with this would be appreciated.
It seems likes it is executing one too many times
Bingo. The problem is here:
sum += d
...
#commits the big STOP when limit is reached
if str(sum)>limit:
print("Reached limit of " + limit)
break
You are adding to your sum right away, and then checking whether it has passed the limit. Instead, you need to check whether adding to the sum will pass the limit before you actually add it.
Two other things: first, sum is a Python keyword, so you don't want to use it as a variable name. And second, you never want to compare data as strings, you will get weird behavior. Like:
>>> "0:07:30" > "2:34"
False
So all of your times should be timedelta objects.
Here is new code:
def timeAdder():
#assigns sum to the datetime library's timedelta class
sum_ = datetime.timedelta()
#sets the limit, can be whatever
limit = '0:07:00'
(h, m, s) = (int(i) for i in limit.split(":"))
limitDelta = datetime.timedelta(hours=h, minutes=m, seconds=s)
#calculates the sum
for i in timeDict.values():
(m, s) = i.split(':')
d = datetime.timedelta(minutes=int(m), seconds=int(s))
if (sum_ + d) > limitDelta:
print("Reached limit of " + limit)
break
# else, loop continues
sum_ += d
print(sum_)
timeLeft = limitDelta - sum_
for songName, songLength in timeDict.items():
(m, s) = (int(i) for i in songLength.split(':'))
d = datetime.timedelta(minutes=m, seconds=s)
if d < timeLeft:
print("You can fit " + songName + " into your playlist.")
print("time left: " + str(timeLeft))
Demo
I have ipython 5.3.0 and when i am in the middle of expression (cursor is marked as <cursor>), for example:
In [69]: x = np.arange(<cursor>1, 21, 2).reshape(2, 5)
Than pressing enter causes split this line into two lines.
In [69]: x = np.arange(
...: 1, 21, 2).reshape(2, 5)
But when i have cursor in other place for example:
In [69]: x = np.<cursor>arange(1, 21, 2).reshape(2, 5)
It executes expression.
Which keyboard shortcut forces execution of expression without taking care of cursor position?
I tried CTRL + ENTER or SHIFT + ENTER but no one of them working for first example.
This was fixed in IPython 5.4. Earlier, there's no way short of patching/monkey-patching at startup, but there's an easy workaround.
Here's the relevant logic from 5.4.1, in IPython/terminal/shortcuts.py. The fragment with a comment referring to the issue on the first link is the fix.
def newline_or_execute_outer(shell):
def newline_or_execute(event):
"""When the user presses return, insert a newline or execute the code."""
b = event.current_buffer
d = b.document
if b.complete_state:
cc = b.complete_state.current_completion
if cc:
b.apply_completion(cc)
else:
b.cancel_completion()
return
# If there's only one line, treat it as if the cursor is at the end.
# See https://github.com/ipython/ipython/issues/10425
if d.line_count == 1:
check_text = d.text
else:
check_text = d.text[:d.cursor_position]
status, indent = shell.input_splitter.check_complete(check_text + '\n')
if not (d.on_last_line or
d.cursor_position_row >= d.line_count - d.empty_line_count_at_the_end()
):
b.insert_text('\n' + (' ' * (indent or 0)))
return
if (status != 'incomplete') and b.accept_action.is_returnable:
b.accept_action.validate_and_handle(event.cli, b)
else:
b.insert_text('\n' + (' ' * (indent or 0)))
return newline_or_execute
As you can see, the action depends on the cursor's position relevant to a code's token.
So, if you have a complete statement, you can force execution by simply pressing End before Enter.
I've written a function that saves all numbers between two digit groups to a text file, with a step option to save some space and time, and I couldn't figure out how to show a percentage value, so I tried this.
for length in range(int(limit_min), int(limit_max) + 1):
percent_quotient = 0
j=0
while j <= (int(length * "9")):
while len(str(j)) < length:
j = "0" + str(j)
percent_quotient+=1
j = int(j) + int(step) # increasing dummy variable
for length in range(int(limit_min), int(limit_max) + 1):
counter=1
i = 0
while i <= (int(length * "9")):
while len(str(i)) < length:
i = "0" + str(i) #
print "Writing %s to file. Progress: %.2f percent." % (str(i),(float(counter)/percent_quotient)*100)
a.write(str(i) + "\n") # this is where everything actually gets written
i = int(i) + int(step) # increasing i
counter+=1
if length != int(limit_max):
print "Length %i done. Moving on to length of %i." % (length, length + 1)
else:
print "Length %i done." % (length)
a.close() # closing file stream
print "All done. Closed file stream. New file size: %.2f megabytes." % (os.path.getsize(path) / float((1024 ** 2)))
print "Returning to main..."
What I tried to do here was make the program do an iteration as many times as it would usually do it, but instead of writing to a file, I just made percent_quotient variable count how many times iteration is actually going to be repeated. (I called j dummy variable since it's there only to break the loop; I'm sorry if there is another expression for this.) The second part is the actual work and I put counter variable, and I divide it with percent_quotient and multiply with 100 to get a percentage.
The problem is, when I tried to make a dictionary from length of 1 to length of 8, it actually took a minute to count everything. I imagine it would take much longer if I wanted to make even bigger dictionary.
My question is, is there a better/faster way of doing this?
I can't really work out what this is doing. But it looks like it's doing roughly this:
a = file('d:/whatever.txt', 'wb')
limit_min = 1
limit_max = 5
step = 2
percent_quotient = (10 ** (limit_max - limit_min)) / step
for i in range(limit_min, 10**limit_max, step):
output = str(i).zfill(limit_max) + '\r\n'
a.write(output)
if i % 100 < 2:
print "Writing %s to file. Progress: %.2f percent." % (str(i),(float(i)/percent_quotient)*100)
a.close()
If that's right, then I suggest:
Do less code looping and more math
Use string.zfill() instead of while len(str(num)) < length: "0" + str(num)
Don't overwhelm the console with output every single number, only print a status update every hundred numbers, or every thousand numbers, or so.
Do less str(int(str(int(str(int(str(int(...
Avoid "" + blah inside tight loops, if possible, it causes strings to be rebuilt every time and it's particularly slow.
Okay, the step variable is giving me a lot of headache, but without it, this would be the right way to calculate how many numbers are going to be written.
percent_quota=0 #starting value
for i in range(limit_min,limit_max+1): #we make sure all lengths are covered
percent_quota+=(10**i)-1 #we subtract 1 because for length of 2, max is 99
TessellatingHeckler, thank you, your answer helped me figure this out!
I am going through a past test and the output of the code is this:
Enter the height:
5
5
44
333
2222
11111
I have to write down the code - so far I know how to make a normal triangle with:
for i in range(5):
print('*'*i)
*
**
***
****
My main question is how do I get the body if the triangle to iterate over the numbers?
So what would the code of the first triangle be?
Help would be appreciated:)
The code for this is virtually the same, you just need to change the number of times you print each character, and change the * that you are printing to a number.
for i in range(5):
print(str(5-i) * (i+1))
This generates:
5
44
333
2222
11111
To make it right aligned, like in your example, just use string multiplication on a space character.
for i in range(5):
print(' ' * (4-i) + str(5-i) * (i+1))
This will get you:
5
44
333
2222
11111
You can use str:
for i in range(5):
print(str(i)*i)
Some of the other answers have been essentially correct, but this one right justifies your triangle like the original output.
def print_triangle(rows):
for i in range(rows + 1):
print((str(rows + 1-i)*i).rjust(rows))
height = 5
for i in range(height, 0, -1):
empty_chars = ' ' * (i - 1)
filler_chars = str(i) * (height - i + 1)
print('{}{}'.format(empty_chars, filler_chars))
Formatted string & spacing with an external array and a negated variable.
def height(num):
rangenum=range(num+1)
for i in rangenum:
print(("%"+str(num)+"s")%(i*str(rangenum[-i])))
print("%(spacing as a number)s"%(a string))
returns
(spacing as a number)-(a string)
example:
print("%10s"%"this")
returns:
" this"
side note:
%-(a number)s
is right justified.
(though python tries to cut down the millions of ways to do the same thing, there still are thousands)
https://docs.python.org/2/tutorial/inputoutput.html
I have a very large code that takes some time to run. In order to make sure the process hasn't stalled somewhere I print to screen the percentage of the code that has already been executed, which depends on a for loop and an integer.
To display the percentage of the for loop already processed I use flags to indicate how much of the loop already passed.
The MWE might make it a bit more clear:
import time
N = 100
flag_15, flag_30, flag_45, flag_60, flag_75, flag_90 = False, False,\
False, False, False, False
for i in range(N):
# Large block of code.
time.sleep(0.1)
if i + 1 >= 0.15 * N and flag_15 is False:
print '15%'
flag_15 = True
elif i + 1 >= 0.3 * N and flag_30 is False:
print '30%'
flag_30 = True
elif i + 1 >= 0.45 * N and flag_45 is False:
print '45%'
flag_45 = True
elif i + 1 >= 0.6 * N and flag_60 is False:
print '60%'
flag_60 = True
elif i + 1 >= 0.75 * N and flag_75 is False:
print '75%'
flag_75 = True
elif i + 1 >= 0.9 * N and flag_90 is False:
print '90%'
flag_90 = True
elif i + 1 == N:
print '100%'
This works but is quite verbose and truly ugly. I was wondering if there might be a better/prettier way of doing this.
I like to use modulus to periodically print status messages.
import time
N = 100
for i in range(N):
#do work here
if i % 15 == 0:
print "{}% complete".format(int(100 * i / N))
print "100% complete"
Result:
0% complete
15% complete
30% complete
45% complete
60% complete
75% complete
90% complete
100% complete
for values of N other than 100, if you want to print every 15%, you'll have to dynamically calculate the stride instead of just using the literal 15 value.
import time
import math
N = 300
percentage_step = 15
stride = N * percentage_step / 100
for i in range(N):
#do work
if i % stride == 0:
print "{}% complete".format(int(100 * i / N))
(Posting a second answer because this solution uses a completely different technique)
You could create a list of milestone values, and print a message when the percentage complete reaches the lowest value.
milestones = [15, 30, 45, 60, 75, 90, 100]
for i in range(N):
#do work here
percentage_complete = (100.0 * (i+1) / N)
while len(milestones) > 0 and percentage_complete >= milestones[0]:
print "{}% complete".format(milestones[0])
#remove that milestone from the list
milestones = milestones[1:]
Result:
15% complete
30% complete
45% complete
60% complete
75% complete
90% complete
100% complete
Unlike the "stride" method I posted earlier, here you have precise control over which percentages are printed. They don't need to be evenly spaced, they don't need to be divisible by N, they don't even need to be integers! You could do milestones = [math.pi, 4.8, 15.16, 23.42, 99] if you wanted.
You can use combination of write() and flush() for nice ProgressBar:
import sys
import time
for i in range(100):
row = "="*i + ">"
sys.stdout.write("%s\r%d%%" %(row, i + 1))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("\n")
Progress will be displaying like this:
69%====================================================================>
You don't need any flags. You can just print the completion based on the current value of i.
for i in range(N):
# lots of code
print '{0}% completed.'.format((i+1)*100.0/N)
Just add a "\r" in Misha's answer:
import sys
import time
for i in range(100):
row = "="*i + ">"
sys.stdout.write("%s\r %d%%\r" %(row, i + 1))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("\n")
Output:
65%======================================================>
In colab.research.google.com works like this:
import sys
import time
for i in range(100):
row = "="*i + ">"
sys.stdout.write("\r %d%% %s " %( i + 1,row))
sys.stdout.flush()
time.sleep(0.1)
sys.stdout.write("\n")