11

I often see, that tqdm progress bar is broken by other print, like:

 93%|█████████▎| 28/30 [00:02<00:00, 13.44it/s]Subject S9
100%|██████████| 30/30 [00:02<00:00, 12.94it/s]
 93%|█████████▎| 28/30 [00:02<00:00, 11.49it/s]Pickling...
100%|██████████| 30/30 [00:02<00:00, 11.47it/s]

Here only 2 progress bars should be shown. Nevertheless succeeded, printing of some text interrupts progress bar at high percentage and the rest of it is printed out afterwards.

Is it possible to "flush" progress bar somehow?

I read, that tqdm prints to stderr by default and tried to flush it

sys.stderr.flush()

but this didn't helped.

All above is happened in PyCharm console simulation, so it can be related with this.

Ma0
  • 14,004
  • 2
  • 29
  • 59
Dims
  • 37,353
  • 77
  • 251
  • 478

7 Answers7

12

Without seeing more of your code, it is not possible to say with certainty what is happening here. However, what follows is the most likely explanation.

By default, tqdm prints to stderr. Your statements Subject... and Pickling... are printing to stdout. By default those two streams are not in sync (I do not know if it is possible to sync them even).

If you want tqdm to be in sync with prints, you have the option to route tqdm to stdout instead of stderr. This is achieved via:

tqdm(xrange(50), file=sys.stdout)

You would then not need to flush stdout.

ZaydH
  • 467
  • 5
  • 20
4

I think your best bet (since tqdm kinda takes over the output) is to use

tqdm.write

so if you have a progress bar you can use that to try and print during like this:

In [19]:     from tqdm import tqdm
    ...:     import time
    ...:
    ...:     for i in tqdm(xrange(50)):
    ...:         if i & 0x1 == 0:
    ...:           tqdm.write(str(i))
    ...:           time.sleep(0.5)
    ...:
0
2
4
6
8
10
12
 14%|███████████▌                                                                       | 7/50 [01:50<11:16, 15.73s/it]---------------------------------------------------------------------------             | 11/50 [00:03<00:10,  3.62it/s]

Which should end up printing and keep the bar at the bottom separately.

if you would like to refresh the bar explicitly you can try and use tqdm.refresh in addition:

In [16]: gen = tqdm(xrange(50))
  0%|                                                                                           | 0/50 [00:00<?, ?it/s]
In [17]: for i in gen:
    ...:     if i & 0x1 == 0:
    ...:       print str(i)
    ...:       gen.refresh()
    ...:       time.sleep(0.5)
    ...:
    ...:
    ...:
    ...:
0
  2%|█▋                                                                                 | 1/50 [00:01<01:17,  1.59s/it]2
  6%|████▉                                                                              | 3/50 [00:02<00:55,  1.19s/it]4
 10%|████████▎                                                                          | 5/50 [00:02<00:40,  1.10it/s]6
 14%|███████████▌                                                                       | 7/50 [00:03<00:30,  1.41it/s]8
 14%|███████████▌                                                                       | 7/50 [00:03<

But as you can see without using tqdm.write you still end up with characters beside the bar being printed.

Danku
  • 252
  • 1
  • 9
1

To explicitly flush at a time, use refresh(). To explicitly flush at the end, if tqdm gets stuck, you should call tqdm.close(self). Example:

import time
i_range=tqdm(range(5))
for i in i_range:
        i_range.refresh()
        time.sleep(1)
i_range.close()    

More complicated, nested loop example:

progress = tqdm(range(5*3 ) )
for i in range(5):
    print '============================='
    for j in range(3):
        time.sleep(1)
        progress.update()
        progress.refresh()
progress.close()

Note that tqdm has parameters related to refresh freq:

mininterval : float, optional Minimum progress display update interval [default: 0.1] seconds. maxinterval : float, optional Maximum progress display update interval [default: 10] seconds.

ntg
  • 9,002
  • 6
  • 48
  • 73
  • Could you explain your second example, please? You create a `tqdm` object but you don't iterate over it—what happens here? – HelloGoodbye Jan 16 '19 at 15:46
  • Instead of iterating over it, I am using .update() This similart to, instead of iterating on an iterable, calling its .next() method explicitly in a loop... Every time I call `progress.update()`, it advances the tqdm object by one... The range of the tqdm object is the first loop size times the second loop size... I added the `refresh()` command so that the updated value is shown in the screen. – ntg Jan 17 '19 at 14:18
0

The solution is to force the output : tqdm.write is waiting a string, and allows to specify the end.

for sentences_db, itdqm in zip(sentences_dbs, tqdm(range(len(sentences_dbs)))):
    tqdm.write(itdqm.__str__(), end='')

You can force the outputs with the file attribute (ie: file=sys.stderr), because when it's very quick, the outputs has a direction problem (stdout instead of stderr). Import the sys module to do that.

Mih Zam
  • 829
  • 7
  • 9
0

Maybe Try The Function Called

tqdm.clear

But... Before That Make An Object Or...

I'll Show You The Code :-

from tqdm import tqdm
bar = tqdm(yourList)
for i in bar:
    #Do Stuff :)
    #But Right Where You Wanna Make It Go And Come Back Do This :-
    bar.clear()

I Hope It Works :)

SK Studio
  • 1
  • 1
  • The `clear` method works well when you are not calling `print` inside your loop. If you are, you will still get weird behavior like OP reported. – ZaydH Jul 11 '20 at 12:27
0

This worked for me:

print(f'First print')
for x in tqdm(some_list):
    some_operation = 1+1

# Surround next print with some sleepy time to have give the previous tqdm bar time to finish
time.sleep(0.5)
print(f'Second print')
time.sleep(0.5)

for y in tqdm(some_other_list):
    some_other_operation = 1+3+3+7
Jake
  • 53
  • 1
  • 4
0

Just try to help with what works for me.

import sys
from tqdm import tqdm
from time import sleep
print('This is done')
sleep(.5)
for i in tqdm(range(0,30), total = (30), desc = 'Subject S9'):
    sleep(.3)
    sys.stdout.flush()
sleep(.5)

for i in tqdm(range(0,30), total = (30), desc = 'Pickling...'):
    sleep(.3)
    sys.stdout.flush()

sleep(.5)

The output would be:

This is done
Subject S9: 100%|██████████| 30/30 [00:09<00:00,  3.30it/s]
Pickling...: 100%|██████████| 30/30 [00:09<00:00,  3.30it/s]

Just putting sleep() between each iteration would help to give it time to end the process before the next iteration. Hope it helps. CMIIW :)

jeo
  • 1
  • 3