How to keep printing on the same line after the progress bar using tqdm?

Viewed 22

I have two nested loops, each with a progress bar. In each loop, multiple functions are run which take a long time to complete. I like to see in which state the current loop is in right now by logging it after the progress bars without breaking them.

This was the best I could come up with by creating another instance of tqdm and setting the desc of it as my desired print output.


class tqdm_print():
    def __init__(self) -> None:
        self.progress_bars: List[tqdm] = list()

    def print(self, str: str):
        lines = str.split("\n")
        for line in lines:
            pbar = tqdm(desc=line, bar_format='{desc}', leave=False)
            self.progress_bars.append(pbar)

    def close(self):
        for pbar in self.progress_bars:
            pbar.close()

    def __call__(self, str: str):
        self.print(str)

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.close()

    def __enter__(self):
        return self

for subject in tqdm(range(10), desc="Subjects:"):
    for session in tqdm(range(20), desc="Session:",leave=False):
        with tqdm_print() as tqdmprint:
            tqdmprint.print("foo is running")
            foo()
            tqdmprint.print("bar is running")
            bar()
Subjects:  20%|██████████████████                                                                        | 2/10 [00:04<00:17,  2.18s/it]
Sessions: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 20/20 [00:02<00:00,  9.19it/s] 
foo is running...
Subjects:  20%|██████████████████                                                                        | 2/10 [00:04<00:17,  2.18s/it]
Sessions: 100%|██████████████████████████████████████████████████████████████████████████████████████████| 20/20 [00:02<00:00,  9.19it/s] 
foo is running...
bar is running...

Is there a more elegant way to do this? Prefeberely without using another instance of tqdm since the cursor keeps glitching from line to line which doesn't really cause any problem but it just looks kinda ugly.

1 Answers

The bits that you need in the print statement are:

  • end='\r'
  • flush=True

i do this which works nicely:

import time

def print_progressbar(total, current, barsize=60):
    progress = int(current*barsize/total)
    completed = str(int(current*100/total)) + '%'
    print('[', chr(9608)*progress, ' ', completed, '.'*(barsize-progress), '] ', str(current)+'/'+str(total), sep='', end='\r', flush=True)



total = 600
barsize = 60
print_frequency = max(min(total//barsize, 100), 1)
print("Start Task..")
for i in range(1, total+1):
    time.sleep(0.0001)
    if i%print_frequency == 0 or i == 1:
        print_progressbar(total, i, barsize)
print("\nFinished")

or this which is quicker to implement and does not require an import:

import time


n = 25
for i in range(n):
    time.sleep(0.1)
    progress = int(i / n * 50)
    print(f'running {i+1} of {n} {progress*"."}', end='\r', flush=True)
Related