Double Progress Bar in Python
Use the nested progress bars feature of tqdm, an extremely low overhead, very customisable progress bar library:
$ pip install -U tqdm
Then:
from tqdm import tqdm# from tqdm.auto import tqdm # notebook compatibleimport timefor i1 in tqdm(range(5)): for i2 in tqdm(range(300), leave=False): # do something, e.g. sleep time.sleep(0.01)
(The leave=False
is optional - needed to discard the nested bars upon completion.)
You can also use from tqdm import trange
and then replace tqdm(range(...))
with trange(...)
. You can also get it working in a notebook.
I basically just want to add to the answer of @casper.dcl. In the slightly different case, where you have two nested for loops and want just a SINGLE progress bar you can do the following.
from tqdm import tqdmimport timen = 5m = 300with tqdm(total=n * m) as pbar: for i1 in tqdm(range(n)): for i2 in tqdm(range(m)): # do something, e.g. sleep time.sleep(0.01) pbar.update(1)
I know that was not the question, but it might be still helpful for some folks.
It would require you to move the cursor position. I have written you a hacky thing to do it.
This script relies on the fact that the progressbar module assumes that you are on a fresh line to draw the progress bar. By simply moving the cursor up (using the escape code for "move cursor 1 row up"), and down (just using a newline. I could also use an escape code, but newline is easier and faster), one can maintain multiple progress bars.
import progressbar, time, sysdef up(): # My terminal breaks if we don't flush after the escape-code sys.stdout.write('\x1b[1A') sys.stdout.flush()def down(): # I could use '\x1b[1B' here, but newline is faster and easier sys.stdout.write('\n') sys.stdout.flush()# Total bar is at the bottom. Move down to draw itdown()total = progressbar.ProgressBar(maxval=50)total.start()for i in range(1,51): # Move back up to prepare for sub-bar up() # I make a new sub-bar for every iteration, thinking it could be things # like "File progress", with total being total file progress. sub = progressbar.ProgressBar(maxval=50) sub.start() for y in range(51): sub.update(y) time.sleep(0.005) sub.finish() # Update total - The sub-bar printed a newline on finish, so we already # have focus on it total.update(i)total.finish()
This is of course a bit hacky, but it gets the job done. I hope that it is useful.