Why is tqdm printing to a newline instead of updating the same line?
Question:
I’m working on a small command-line game in python where I am showing a progress bar using the tqdm module. I listen for user input using the msvcrt module to interrupt the progress. Once interrupted, the user can restart by entering ‘restart’ into the command line prompt. The second time the progress bar is shown, instead of updating the same line with the progress, it creates a new line each time.
How would I get it to show the progress on the same line?
This code snippet illustrates my use of the progress bar.
def transfer():
for i in tqdm.tqdm(range(1000), desc="Transfer progress", ncols=100, bar_format='{l_bar}{bar}|'):
sleep(.1)
if msvcrt.kbhit():
if msvcrt.getwche() == ' ':
interrupt()
break
def interrupt():
type("File transfer interrupted, to restart the transfer, type 'restart'")
Answers:
Try from tqdm import tqdm_notebook as tqdm
instead of from tqdm import tqdm
.
Try using tqdm.tqdm.write
in place of the standard print()
This will print above the progress bar and move the progress bar one row below.
I tested this using below code, pressing space
will print into stdout but not break the loop.
It was not 100% clear what you are trying to achieve, since the interrupt()
function of yours only checks the type of the provided string. type() built-in function
import tqdm
import msvcrt
from time import sleep
def transfer():
for i in tqdm.tqdm(range(1000), desc="Transfer progress", ncols=100, bar_format='{l_bar}{bar}|'):
sleep(.1)
if msvcrt.kbhit():
if msvcrt.getwche() == ' ':
interrupt()
# break
def interrupt():
tqdm.tqdm.write("File transfer interrupted, to restart the transfer, type 'restart'", end="")
transfer()
EDIT: to include end
parameter of tqdm.write()
as noted by Paul Netherwood
tqdm.tqdm.write()
Try with position=0
and leave=True
(Solution working in Google Colab to avoid printing to a newline)
from tqdm import tqdm
import time
def foo_():
time.sleep(0.3)
range_ = range(0, 10)
total = len(range_)
with tqdm(total=total, position=0, leave=True) as pbar:
for i in tqdm((foo_, range_ ), position=0, leave=True):
pbar.update()
I’ve tried tqdm solution but as I’m using Spyder (Anaconda) it doesn’t work in my case as supposed due to mentioned in other answers conflict between write and print commands. I came up with simple and working although not fanciest solution.
def ybar(progr, total, step=50):
#starts with 1
l2=(progr/total)//(1/step)
if progr==1: print(f'[{total}]: '+'|'*int(l2), end = '')
else:
l1=((progr-1)/total)//(1/step)
ll=int(l2-l1)
if l1 < l2:
for j in range(1,ll+1):
if (int(l1)+j)%5==0:
print('*', end = '')
else:
print('|', end = '')
if progr==total: print(" DONE")
And as result you’ll get simple: [100]: ||||||
for i in range(1,101):
ybar(i,len(range(1,101)),50)
#something
There are plenty of solutions here: Python Progress Bar
The following is hacky, but seems to work reasonably well to reset tqdm:
from tqdm import tqdm as tqdm_base
def tqdm(*args, **kwargs):
if hasattr(tqdm_base, '_instances'):
for instance in list(tqdm_base._instances):
tqdm_base._decr_instances(instance)
return tqdm_base(*args, **kwargs)
Sometimes previous output is printed at the start (which I am not sure how to remove), but I find it much less annoying than newlines (especially in long loops).
Import tqdm
.
from tqdm import tqdm
First start the code, where you use tqdm
, stop it because of multiple lines output.
Then do:
list(getattr(tqdm, '_instances'))
for instance in list(tqdm._instances):
tqdm._decr_instances(instance)
If you get an error:
AttributeError: type object ‘tqdm’ has no attribute ‘_instances’
You need first to start your code, where you use tqdm
and only after that start code which mention.
And after all this manipulations your tqdm
will work fine.
from tqdm import tqdm_notebook
this command works in google colab.
tqdm_notebook is deprecated. You must use tq.notebook.tqdm instead.
import tqdm.notebook as tq
for i in tq.tqdm(...):
Furthermore, tqdm_notebook was really miserable in terms of performances. That’s fully corrected with the new library.
I have realized that closing tqdm instances before using tqdm again fixes the problem of printing status bar in a new line on Jupyter Lab:
while len(tqdm._instances) > 0:
tqdm._instances.pop().close()
Or even better, thanks to Nirmal for the suggestion:
tqdm._instances.clear()
You might have imported tqdm twice. Restart the whole notebook kernel and run again. It will solve the issue. It might also be showing because of any print statements inside the tqdm
from tqdm import notebook
Instead of tqdm(looping)
Use notebook.tqdm(looping)
leave=False
for the inner loop worked in my case.
for j in tqdm(outer_list):
for i in tqdm(inner_list, leave=False):
Evnironment with tqdm==4.38.0
and Python 3.6.7
https://github.com/tqdm/tqdm#parameters
I think sometimes tqdm cannot catch the screen width
use ncols=xx to restrict line width
ex:
tqdm(iter,ncols=80): # restrict line width=80
Besides the aforementioned position=0, leave=True
parameters, in my case the tqdm
‘s default ascii=False
parameter was also printing on new lines after a few iterations. You easily identify if this is the case by looking at the progress bar: if there are any weirdly formatted symbols (e.g. question marks) in your progress bar, you should try using ascii=True
.
So this worked for me:
from tqdm.auto import tqdm
...
with tqdm(data, position=0, leave=True, ascii=True) as iterator:
for x in iterator:
# do stuff
...
iterator.set_postfix_str(msg)
I faced this problem a lot and sometimes position = 0
& leave = True
does not works. So, I found one alternate way.
Instead of tqdm.tqdm you can use tqdm.auto.tqdm
or
instead of
from tqdm import tqdm
try using
from tqdm.auto import tqdm
The issue I’m having might not be common, but in case it’s useful to anyone, I was printing another variable to the console. Disabling that print fixes the issue.
If you encounter this problem while using tqdm
on colab or jupyter notebook, then …
Use notebook/colab version of tqdm
>>> from tqdm.notebook import trange, tqdm
>>> for i in trange(1000):
... ...
I’m working on a small command-line game in python where I am showing a progress bar using the tqdm module. I listen for user input using the msvcrt module to interrupt the progress. Once interrupted, the user can restart by entering ‘restart’ into the command line prompt. The second time the progress bar is shown, instead of updating the same line with the progress, it creates a new line each time.
How would I get it to show the progress on the same line?
This code snippet illustrates my use of the progress bar.
def transfer():
for i in tqdm.tqdm(range(1000), desc="Transfer progress", ncols=100, bar_format='{l_bar}{bar}|'):
sleep(.1)
if msvcrt.kbhit():
if msvcrt.getwche() == ' ':
interrupt()
break
def interrupt():
type("File transfer interrupted, to restart the transfer, type 'restart'")
Try from tqdm import tqdm_notebook as tqdm
instead of from tqdm import tqdm
.
Try using tqdm.tqdm.write
in place of the standard print()
This will print above the progress bar and move the progress bar one row below.
I tested this using below code, pressing space
will print into stdout but not break the loop.
It was not 100% clear what you are trying to achieve, since the interrupt()
function of yours only checks the type of the provided string. type() built-in function
import tqdm
import msvcrt
from time import sleep
def transfer():
for i in tqdm.tqdm(range(1000), desc="Transfer progress", ncols=100, bar_format='{l_bar}{bar}|'):
sleep(.1)
if msvcrt.kbhit():
if msvcrt.getwche() == ' ':
interrupt()
# break
def interrupt():
tqdm.tqdm.write("File transfer interrupted, to restart the transfer, type 'restart'", end="")
transfer()
EDIT: to include end
parameter of tqdm.write()
as noted by Paul Netherwood
tqdm.tqdm.write()
Try with position=0
and leave=True
(Solution working in Google Colab to avoid printing to a newline)
from tqdm import tqdm
import time
def foo_():
time.sleep(0.3)
range_ = range(0, 10)
total = len(range_)
with tqdm(total=total, position=0, leave=True) as pbar:
for i in tqdm((foo_, range_ ), position=0, leave=True):
pbar.update()
I’ve tried tqdm solution but as I’m using Spyder (Anaconda) it doesn’t work in my case as supposed due to mentioned in other answers conflict between write and print commands. I came up with simple and working although not fanciest solution.
def ybar(progr, total, step=50):
#starts with 1
l2=(progr/total)//(1/step)
if progr==1: print(f'[{total}]: '+'|'*int(l2), end = '')
else:
l1=((progr-1)/total)//(1/step)
ll=int(l2-l1)
if l1 < l2:
for j in range(1,ll+1):
if (int(l1)+j)%5==0:
print('*', end = '')
else:
print('|', end = '')
if progr==total: print(" DONE")
And as result you’ll get simple: [100]: ||||||
for i in range(1,101):
ybar(i,len(range(1,101)),50)
#something
There are plenty of solutions here: Python Progress Bar
The following is hacky, but seems to work reasonably well to reset tqdm:
from tqdm import tqdm as tqdm_base
def tqdm(*args, **kwargs):
if hasattr(tqdm_base, '_instances'):
for instance in list(tqdm_base._instances):
tqdm_base._decr_instances(instance)
return tqdm_base(*args, **kwargs)
Sometimes previous output is printed at the start (which I am not sure how to remove), but I find it much less annoying than newlines (especially in long loops).
Import tqdm
.
from tqdm import tqdm
First start the code, where you use tqdm
, stop it because of multiple lines output.
Then do:
list(getattr(tqdm, '_instances'))
for instance in list(tqdm._instances):
tqdm._decr_instances(instance)
If you get an error:
AttributeError: type object ‘tqdm’ has no attribute ‘_instances’
You need first to start your code, where you use tqdm
and only after that start code which mention.
And after all this manipulations your tqdm
will work fine.
from tqdm import tqdm_notebook
this command works in google colab.
tqdm_notebook is deprecated. You must use tq.notebook.tqdm instead.
import tqdm.notebook as tq
for i in tq.tqdm(...):
Furthermore, tqdm_notebook was really miserable in terms of performances. That’s fully corrected with the new library.
I have realized that closing tqdm instances before using tqdm again fixes the problem of printing status bar in a new line on Jupyter Lab:
while len(tqdm._instances) > 0:
tqdm._instances.pop().close()
Or even better, thanks to Nirmal for the suggestion:
tqdm._instances.clear()
You might have imported tqdm twice. Restart the whole notebook kernel and run again. It will solve the issue. It might also be showing because of any print statements inside the tqdm
from tqdm import notebook
Instead of tqdm(looping)
Use notebook.tqdm(looping)
leave=False
for the inner loop worked in my case.
for j in tqdm(outer_list):
for i in tqdm(inner_list, leave=False):
Evnironment with tqdm==4.38.0
and Python 3.6.7
https://github.com/tqdm/tqdm#parameters
I think sometimes tqdm cannot catch the screen width
use ncols=xx to restrict line width
ex:
tqdm(iter,ncols=80): # restrict line width=80
Besides the aforementioned position=0, leave=True
parameters, in my case the tqdm
‘s default ascii=False
parameter was also printing on new lines after a few iterations. You easily identify if this is the case by looking at the progress bar: if there are any weirdly formatted symbols (e.g. question marks) in your progress bar, you should try using ascii=True
.
So this worked for me:
from tqdm.auto import tqdm
...
with tqdm(data, position=0, leave=True, ascii=True) as iterator:
for x in iterator:
# do stuff
...
iterator.set_postfix_str(msg)
I faced this problem a lot and sometimes position = 0
& leave = True
does not works. So, I found one alternate way.
Instead of tqdm.tqdm you can use tqdm.auto.tqdm
or
instead of
from tqdm import tqdm
try using
from tqdm.auto import tqdm
The issue I’m having might not be common, but in case it’s useful to anyone, I was printing another variable to the console. Disabling that print fixes the issue.
If you encounter this problem while using tqdm
on colab or jupyter notebook, then …
Use notebook/colab version of tqdm
>>> from tqdm.notebook import trange, tqdm
>>> for i in trange(1000):
... ...