Showing progress

It is a small and very popular progress meter. It is easy to use, fast (<100ns per iteration overhead), has an intelligent estimated time remaining, works nearly everywhere and is dependency-free.

A minimal example is :

from tqdm import tqdm
from time import sleep
for i in tqdm(range(100)):
    sleep(0.01)
100%|██████████| 100/100 [00:01<00:00, 98.57it/s]

It works basically everywhere : * in the notebook * in the console * on MacOS * on Linux * on Windows

The trange(N) is a convinience function that can be used as a shortcut for tqdm(range(N))

from tqdm import trange
from time import sleep
for i in trange(100):
    sleep(0.01)
100%|██████████| 100/100 [00:01<00:00, 98.31it/s]

You can add a description and units to the progress bar

from tqdm import trange
from time import sleep
for i in trange(100, desc='my progress bar', unit="epoch"):
    sleep(0.01)
my progress bar: 100%|██████████| 100/100 [00:01<00:00, 98.77epoch/s]

tqdm can be used outside of python, for example in a pipe in order to show the progress

!seq 999999 | python -m tqdm | wc -l
999999it [00:00, 2908577.61it/s]
999999

or the number of bytes per second

!seq 999999 | python -m tqdm --bytes | wc -l
6.57MB [00:00, 232MB/s]
999999

we can also have a progress bar if we specify a total

!seq 999999 | python -m tqdm --bytes --total 7628000| wc -l
 90%|███████████████████████████████████▏   | 6.57M/7.27M [00:00<00:00, 225MB/s]
999999

Iterable-based use

Wrap tqdm() around any iterable (i.e. list, numpy array, pandas dataframe, etc.)

text = ""
for c in tqdm(["a", "b", "c","d"]):
    sleep(0.25)
    text = text + c
100%|██████████| 4/4 [00:01<00:00,  3.98it/s]

The progress bar can be instantiated outside of the loop

pbar = tqdm(["a", "b", "c","d"])
for c in pbar:
    sleep(0.25)
    pbar.set_description(f"Processing {c}")
Processing d: 100%|██████████| 4/4 [00:01<00:00,  3.98it/s]

Manual

tqdm can be manually controled by using a with statement. If you specify a total (or an iterable with len()), predictive stats are displayed.

with tqdm(total=100) as pbar:
    for i in range(10):
        sleep(0.1)
        pbar.update(10)
100%|██████████| 100/100 [00:01<00:00, 99.08it/s]

Desciption and additional stats

Custom information can be displayed and updated dynamically on tqdm bars with the desc and postfix arguments.

This can be useful for machine learning where we want to print the metrics or losses during the training process.

from tqdm import trange
from random import random, randint
from time import sleep

with trange(10) as t:
    for i in t:
        t.set_description(f"GEN {i}")
        t.set_postfix(loss=random(), gen=randint(1, 999), str="h", lst=[1,2])
        sleep(0.1)
GEN 9: 100%|██████████| 10/10 [00:01<00:00,  9.80it/s, gen=927, loss=0.505, lst=[1, 2], str=h]

You can customise what your bar looks like with the bar_format option.

with tqdm(total=10, bar_format="{postfix[0]} {postfix[1][value]:>8.2g}", postfix=["Batch", dict(value = 0)]) as t:
    for i in range(10):
        sleep(0.1)
        t.postfix[1]["value"] = i/2
        t.update()
Batch      4.5

Hooks and callbacks

tqdm can be integrated with other libaries. In the example, we integrate tqdm with urllib

In order to download a file in python we use the following code but it doesn't show any progress.

import urllib.request, os

eg_link = "http://mirrors.melbourne.co.uk/ubuntu-releases/19.10/ubuntu-19.10-desktop-amd64.iso"

urllib.request.urlretrieve(eg_link, filename=os.devnull, data=None)

We can create a class called TqdmUpTo to show the progress. It is recommended to use miniters=1 whenever there is a potentially large difference in iteration speed (e.g. downloading a file over a patchy connection).

tqdm expect a call to update and urllib needs an update_to method

class TqdmUpTo(tqdm):
    def update_to(self, blocks_so_far=1, block_size=1, total=None):
        if total is not None:
            self.total = total
        self.update(blocks_so_far * block_size - self.n)
with TqdmUpTo(unit='B', unit_scale=True, miniters=1, desc=eg_link.split("/")[-1]) as t:
    urllib.request.urlretrieve(eg_link, filename=os.devnull, data=None, reporthook=t.update_to)
ubuntu-19.10-desktop-amd64.iso:   0%|          | 4.38M/2.46G [00:06<56:58, 720kB/s]

The hooks can be useful for dispalying the progress of training a neural network with keras

with tqdm(total=10, unit="epoch") as t:
    def cbk(epoch, logs):
        t.set_postfix(logs, refresh=False)
        t.update()
    cbkWrapped = keras.callbacks.LambdaCallback(on_epoch_end=cbk)

    model.fit(x, y, epochs=t.total, verbose=0, callbacks=[cbkWrapped])
  0%|          | 0/10 [00:00<?, ?epoch/s]

tqdm can also be applyied to pandas

import pandas as pd
import numpy as np
from tqdm import tqdm

df= pd.DataFrame(np.random.rand(5,10))
#Registed `pandas.progress_apply`, `pandas.Series.map_apply`, etc with tqdm
#tqdm_gui, tqdm_notebook, optional kwargs can be used
tqdm.pandas(desc="my bar!")

#replace apply by progress_apply or map by progress_map
df.progress_apply(lambda x:x**2)
/home/guillaume/anaconda3/lib/python3.7/site-packages/tqdm/std.py:654: FutureWarning: The Panel class is removed from pandas. Accessing it from the top-level namespace will also be removed in the next version
  from pandas import Panel
my bar!: 100%|██████████| 10/10 [00:00<00:00, 818.46it/s]
0 1 2 3 4 5 6 7 8 9
0 0.072067 0.192319 0.354137 0.226678 0.092123 0.003836 0.190529 0.129519 0.272106 0.918287
1 0.048068 0.157399 0.047842 0.024008 0.029614 0.067597 0.891104 0.909314 0.000385 0.090840
2 0.965366 0.000364 0.159109 0.550288 0.494446 0.157180 0.113372 0.427566 0.086719 0.004057
3 0.323191 0.524031 0.000673 0.037876 0.274079 0.036120 0.479730 0.095726 0.085360 0.006432
4 0.707128 0.041636 0.339444 0.105327 0.111249 0.331656 0.172311 0.940055 0.003604 0.463608

Notebook integration

Use tnrange via the tqdm_notebook submodule

```python from tqdm import tnrange, tqdm_notebook from time import sleep

for i in tnrange(3, desc="1st loop"): for j in tqdm_notebook(range(100), desc="2nd loop"): sleep(0.01)

If you are not sure if your users are using a notebook or a console you can use tqdm.auto

```python from tqdm.auto import tqdm tqdm.pandas()