Cursus
Heb je weleens meegemaakt dat een langlopende Python-script je deed afvragen of er überhaupt iets gebeurde achter het scherm?
De onzekerheid over de voortgang kan ertoe leiden dat je een bijna voltooide run afbreekt of eindeloos wacht op een script dat al is onderbroken.
De tqdm Python-bibliotheek pakt dit probleem aan door voortgangsindicatoren te bieden voor je scripts.

Wat is tqdm?
Tqdm is een Python-bibliotheek die snelle, uitbreidbare voortgangsbalken biedt voor lussen en iterables. Het is een eenvoudige manier om de voortgang van tijdrovende taken bij te houden.
De naam van de bibliotheek betekent "vooruitgang" in het Arabisch (taqadum, تقدّم), en is een afkorting voor "ik hou zoveel van je" in het Spaans (te quiero demasiado).
Tdqm houdt de voortgang bij en werkt de weergave van de voortgangsbalk bij door iteraties te tellen, de verstreken tijd en resterende tijd te berekenen, en de totale voortgang te visualiseren via de vulling van de balk.
Het gebruikt slimme algoritmes om de resterende tijd te voorspellen en slaat onnodige iteratieweergaven over om de overhead te minimaliseren. Het gebruik van tqdm biedt verschillende voordelen, waaronder:
- Visuele feedback: Voortgangsbalken laten zien hoeveel van een taak is voltooid en helpen in te schatten hoe lang het resterende deel nog duurt.
- Werkt overal: De
tqdm-bibliotheek werkt op elk platform (Linux, Windows, Mac, FreeBSD, NetBSD, SunOS), in elke console of in een GUI. - Eenvoudige integratie:
Tqdmintegreert naadloos met Jupyter-notebooks, veelgebruikte bibliotheken zoals Pandas, en gebruikelijke Python-constructies zoals lussen. - Aanpasbaarheid: Het biedt verschillende opties om het uiterlijk en gedrag van voortgangsbalken af te stemmen, waar we later op ingaan.
- Prestaties: Terwijl vergelijkbare pakketten zoals ProgressBar een overhead van 800 ns/iteratie hebben, werkt tdqm met een overhead van 60 ns/iteratie veel sneller.
Hoe installeer je Tqdm
Zoals voor de meeste Python-bibliotheken is de eenvoudigste manier om tqdm te installeren via de package manager pip.
pip install tqdm
Tqdm: eenvoudig voorbeeld
Om een voortgangsbalk te maken, wikkelen we onze iterable in met de functie tqdm() (die we importeren uit de module tqdm). Laten we een eenvoudig voorbeeld bekijken. De functie time.sleep(0.01) dient als tijdelijke aanduiding voor de code die in elke iteratie moet worden uitgevoerd.
from tqdm import tqdm
for i in tqdm(range(1000)):
time.sleep(0.01)
# …

Als snelkoppeling voor tdqm(range(n)) kun je ook trange(n) gebruiken. De volgende code geeft exact dezelfde output als de vorige:
from tqdm import tqdm
for i in trange(1000):
time.sleep(0.01)
# …
Beide voorbeelden geven een voortgangsbalk zoals hierboven te zien is.
Kijk eens goed naar de voortgangsbalk om te zien welke informatie wordt getoond. Laten we de details van tqdm uitsplitsen:
- Voortgangsindicatoren:
- Percentage iteraties
- Vulling van de balk
- Fractie van het totaal aantal iteraties
- Statistieken:
- Verstreken tijd
- Geschatte resterende tijd
- Prestaties (iteraties per seconde)
Tqdm aanpassen: maak voortgangsbalken helemaal van jou
Tqdm biedt allerlei opties om het uiterlijk en gedrag van voortgangsbalken aan te passen. We bekijken de belangrijkste parameters voordat we meer geavanceerde use-cases van tqdm behandelen.
Een beschrijving aan de voortgangsbalk toevoegen
Een veelgebruikte aanpassing is het toevoegen van een label met de parameter desc, zodat de voortgangsbalk informatiever wordt en je het overzicht over verschillende iterables behoudt.
Als je bijvoorbeeld de parameter desc=”Processing large range” toevoegt, verschijnt de titel “Processing large range” links van de voortgangsbalk.
for _ in tqdm(range(20000000), desc="Processing large range"):
continue
Ik moedig je aan om de bovenstaande code in je eigen omgeving te draaien, met en zonder de desc-parameter, en de verschillen te bekijken.
Het totale aantal iteraties opgeven
De parameter total specificeert het totale aantal iteraties in de lus, zodat tqdm nauwkeurigere schattingen kan geven van resterende tijd en percentage voltooid.
In een basisvoorbeeld met tqdm(range()) of trange() is dit niet nodig, omdat het aantal iteraties al tussen de haakjes staat. Er zijn echter twee hoofdsituaties waarin het toevoegen van de parameter total=n (waarbij n het totaal is) handig kan zijn:
1. Iterables zonder len()-methode: Voor iterables zonder len()-methode, zoals generatoren met een onbekend aantal items, moet je de waarde total handmatig opgeven. Zonder deze parameter toont tqdm() alleen het aantal voltooide iteraties. Let op: de voortgangsbalk begint opnieuw als het daadwerkelijke aantal items het opgegeven total overschrijdt.
from tqdm import tqdm
import time
import random
# Function generating random number between 1 and 100
def generate_random_numbers():
while True:
yield random.randint(1, 100)
# Without total: tqdm() only shows number of iterations, does not know total
for num in tqdm(generate_random_numbers(), desc=’Random Iteration’):
time.sleep(0.01)
# …

Zo ziet het eruit als het aantal items onbekend is en we het totaal niet specificeren.
# With total (assuming you know the desired number of iterations): tqdm() shows progress
num_iterations = 1000
for num in tqdm(generate_random_numbers(), total=num_iterations, desc="Random Iteration"):
time.sleep(0.01)
# …

Veel beter: nu verschijnt de voortgangsbalk!
2. Handmatige updates: Als we de voortgangsbalk handmatig bijwerken binnen een functie met de methode update(), moet de totale waarde worden opgegeven om de voortgang correct te kunnen volgen. Met update() kun je bijvoorbeeld reageren op dynamisch veranderende processen of eigen voortgangslogica implementeren. Daar komen we later op terug.
Visuele weergave finetunen
Als je de volgorde wilt aanpassen waarin elementen van de voortgangsbalk verschijnen, kun je de parameter bar_format instellen op de gewenste formatstring. Zo kun je de plaatsing bepalen van elementen zoals het percentage, de verstreken tijd en het teken voor de balkvulling. Voor meer details kun je de documentatie raadplegen.
Een andere visuele aanpassing kan met de parameter colour. Je kunt zowel kleurnamen zoals ‘green’ als hexadecimale codes zoals ‘#00ff00’ gebruiken.
De parameter leave gaat meer over verdwijnen dan verschijnen: deze bepaalt of de voortgangsbalk zichtbaar blijft na voltooiing. Als True, blijft de balk staan na het einde van de lus; als False, verdwijnt hij.
Laten we de visuele verschillen in de output bekijken in een ander voorbeeld. De volgende code maakt drie voortgangsbalken: één met standaardinstellingen, één waarin de volgorde van elementen en de kleur zijn aangepast, en één die is ingesteld om te verdwijnen na voltooiing. De outputs zie je in de GIF hieronder.
from tqdm import tqdm
import time
# Progress bar 1: Default settings
for i in tqdm(range(300)):
time.sleep(0.01)
# Progress bar 2: Customized bar format and color
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='yellow'):
time.sleep(0.01)
# Progress bar 3: Customized bar format and color, leave=False
for i in tqdm(range(300), bar_format='[{elapsed}<{remaining}] {n_fmt}/{total_fmt} | {l_bar}{bar} {rate_fmt}{postfix}', colour='red', leave=False):
time.sleep(0.01)

Geavanceerd gebruik: complexere scenario’s afhandelen
Nu we weten hoe we een eenvoudige voortgangsbalk bouwen en aanpassen, kunnen we doorgaan naar wat geavanceerdere gevallen.
Geneste voortgangsbalken
Geneste lussen zijn lussen die binnen andere lussen zitten. Dienovereenkomstig zijn geneste voortgangsbalken een reeks voortgangsbalken voor elke iteratie van lussen binnen andere lussen. Om ze te maken, wikkel je elke lus in met een tqdm()-functie en voeg je beschrijvende labels toe voor elke iterable.
De volgende code heeft drie geneste lussen en laat zien hoe de geneste voortgangsbalken eruitzien:
from tqdm import trange
import time
for i in trange(3, desc='outer loop'):
for j in trange(2, desc='middle loop'):
for k in trange(6, desc='inner loop'):
time.sleep(0.01)

In de uiteindelijke output hierboven herkennen we een patroon in hoe de verschillende voortgangsbalken worden bijgewerkt. Tqdm begint altijd met de buitenste lus totdat het de binnenste lus bereikt, waarvan de iteraties worden verwerkt en de voortgangsbalk dienovereenkomstig wordt bijgewerkt.
Stel nu dat we drie geneste lussen hebben, zoals in het voorbeeld. Na de eerste binnenste iteratie gaat het omhoog naar de middelste lus, werkt die bij als één iteratie voltooid, en gaat dan terug naar de binnenste iterable. Dit proces wordt herhaald totdat de middelste lus is voltooid, waarna de buitenste balk verschijnt met één voltooide iteratie.
Hetzelfde gebeurt ook tussen de buitenste en middelste lus. Uiteindelijk voltooit de laatste binnenste run de middelste iterable, die op zijn beurt de laatste buitenste iteratie voltooit.
Handmatige updates
Het handmatig bijwerken van voortgangsbalken met tqdm kan in meerdere situaties nuttig zijn:
- Iterables met onbekende lengte: Wanneer we werken met iterables zonder gedefinieerde lengte (bijv. generatoren, netwerkstreams), kunnen we de voortgangsbalk handmatig bijwerken op basis van de hoeveelheid verwerkte data of het aantal voltooide bewerkingen.
- Dynamisch veranderende processen: Als het aantal iteraties of de verwerkingstijd per iteratie kan veranderen tijdens de uitvoering, stellen handmatige updates ons in staat de voortgangsbalk dienovereenkomstig aan te passen.
- Aangepaste voortgangsmeting: Voor meer fijnmazige controle kunnen we de balk handmatig bijwerken op basis van specifieke criteria of gebeurtenissen. Zo kun je de balk bijwerken na het bereiken van bepaalde mijlpalen of de voortgang van individuele taken binnen een groter proces.
- Integratie met externe systemen: Als we
tqdmintegreren met externe systemen of bibliotheken die zelf geen natuurlijke manier bieden om voortgang bij te houden, kunnen handmatige updates worden gebruikt om de voortgangsbalk te synchroniseren met het externe proces.
Om een tqdm-voortgangsbalk handmatig bij te werken, is het belangrijk dat de parameter total is opgegeven als schatting van het maximale verwachte aantal iteraties. Vervolgens moet na verwerking van elk nieuw element de balk worden bijgewerkt met de methode update(). De updatewaarde moet het aantal verwerkte iteraties sinds de laatste update weergeven.
Stel dat we verwachten dat onze iterable maximaal 750 elementen bevat. In dit voorbeeld is de werkelijke lengte een willekeurig getal tussen 100 en 1000, dat we niet kennen. We initialiseren de progress_bar en zetten estimated_total op 750. Vervolgens itereren we door de data en werken we de balk bij nadat elk punt is verwerkt.
from tqdm import tqdm
def process_data(data):
time.sleep(0.01) # simulate processing data
processed_data = data
return processed_data
# Generate an iterable with random length between 100 and 1,000
random_length = random.randint(100, 1000)
data_list = [i for i in range(random_length)]
# Define estimated maximum number of iterations
estimated_total = 750
# Define the progress bar using the estimated_total
progress_bar = tqdm(total=estimated_total)
# Iterating through data list of unknown length
for data in data_list:
processed_data = process_data(data)
progress_bar.update(1)

We hebben de lengte van de iterable onderschat, waardoor de output blijft tellen na het bereiken van 100% voortgang.
Multiprocessing
Multiprocessing en threading zijn technieken om taken gelijktijdig uit te voeren, wat prestaties en responsiviteit verbetert. In deze scenario’s is het lastig om de voortgang van afzonderlijke taken of de totale voortgang van de parallelle uitvoering bij te houden. Tqdm kan hierbij waardevolle visuele feedback geven en de voortgang van deze gelijktijdige operaties monitoren.
De module tqdm.contrib.concurrent biedt gespecialiseerde functies voor voortgangsbalken in multiprocessing- of threading-contexten. Deze functies verzorgen de synchronisatie en communicatie tussen het hoofdproces en de workerprocessen of -threads, zodat de voortgangsbalk correct wordt bijgewerkt. Ze zijn ontworpen om naadloos samen te werken met de concurrent.futures-API, via ProcessPoolExecutor() of ThreadPoolExecutor().
Hier is een voorbeeld met de module tqdm.contrib.concurrent.futures:
import concurrent.futures
from tqdm.contrib.concurrent import process_map
def process_data(data):
for i in tqdm(range(100), desc=f"Processing {data['name']}"):
# Process data
time.sleep(0.01)
if __name__ == '__main__':
with concurrent.futures.ProcessPoolExecutor() as executor:
results = process_map(process_data, [
{'name': 'dataset1'},
{'name': 'dataset2'},
# …
])
In dit voorbeeld bevat de functie process_data() een tqdm-voortgangsbalk om de voortgang bij te houden. De functie process_data() wordt gelijktijdig uitgevoerd voor elk data-item in de lijst. Dit betekent dat meerdere voortgangsbalken tegelijk worden weergegeven, elk voor een afzonderlijk proces. De parameter desc is dynamisch ingesteld op basis van de naam van de dataset, wat helpt om verschillende voortgangsbalken te onderscheiden.
Integratie met pandas
De module tqdm.pandas biedt een handige manier om voortgangsbalken toe te voegen aan pandas-operaties. Dit is vooral nuttig voor tijdrovende bewerkingen op grote DataFrames, omdat het visuele feedback geeft over de voortgang. We kunnen de decorator tqdm.pandas() toepassen op elke pandas-functie die op rijen of kolommen werkt.
Om te beginnen definiëren we een willekeurige DataFrame met 100.000 rijen en roepen we de decorator tqdm.pandas() aan. Als we de voortgangsbalk willen aanpassen, is dit het moment, want de functies progress_apply() en progress_map() nemen geen tqdm()-parameters aan. We willen de volgende voortgangsbalken een naam geven, dus geven we ook de parameter desc op.
import pandas as pd
import numpy as np
from tqdm import tqdm
df = pd.DataFrame(np.random.randint(0, 10, (100000, 6)))
tqdm.pandas(desc='DataFrame Operation')
Nu kunnen we functies toepassen op rijen, kolommen of de hele DataFrame. In plaats van een van de functies apply() of map() te gebruiken, roep je progress_apply() of progress_map() aan en verschijnt de voortgangsbalk. Denk eraan dat apply() en progress_apply() op DataFrames, rijen of kolommen kunnen worden toegepast, terwijl map() en progress_map() alleen op Series of kolommen kunnen worden toegepast. Bijvoorbeeld:
# Halving each value in the DataFrame using progress_apply()
Result_apply = df.progress_apply(lambda x: x / 2)
# Doubling each element of the first column using progress_map()
result_map = df[0].progress_map(lambda x: x * 2)
Tqdm: veelvoorkomende problemen en oplossingen
Laten we enkele veelvoorkomende Tqdm-problemen en -fouten bespreken en kijken hoe je ze oplost.
Voortgangsbalk wordt niet bijgewerkt
Een van de meest voorkomende problemen bij tqdm is een voortgangsbalk die niet bijwerkt. Dit komt vaak door buffering, vooral in omgevingen zoals Jupyter Notebooks. Wanneer de output wordt gebufferd, kan de voortgangsbalk niet direct worden weergegeven of bijgewerkt, wat de indruk wekt van een vastgelopen proces.
Het gebruik van de module tqdm.notebook kan bufferproblemen verhelpen en ervoor zorgen dat de balk correct bijwerkt in Jupyter Notebooks. Deze module biedt een GUI-gebaseerde voortgangsbalk die specifiek is ontworpen voor Jupyter-omgevingen.
Daarnaast biedt het gebruiksvriendelijke kleurhints (blauw: normaal, groen: voltooid, rood: fout/onderbreking).
Als we de code uit ons voorbeeld met geneste voortgangsbalken onderbreken, ziet dat er zo uit:

Geneste voortgangsbalken in Python met tqdm.notebook, die het kleurenschema van voltooide versus onderbroken balken illustreren.
Een andere effectieve manier om niet-bijwerkende balken te troubleshooten is het expliciet flushen van de outputstream. Wanneer data naar standaarduitvoer wordt geschreven (bijv. met print()), wordt deze meestal gebufferd voordat deze naar het daadwerkelijke uitvoerapparaat gaat. Door de outputstream te flushen, dwing je de Python-interpreter om gebufferde data direct te verzenden, zodat deze zonder vertraging wordt weergegeven.
Gebruik de methode flush() van de standaarduitvoer om te flushen. Voor snellere zichtbare output kun je vaker flushen, bijvoorbeeld na elke paar iteraties of na een bepaalde tijd. Houd rekening met de trade-off: flushen introduceert extra overhead. Hier is een voorbeeld van hoe je de methode opneemt in een eenvoudig tqdm-proces:
import sys
import time
from tqdm import tqdm
for i in tqdm(range(100)):
time.sleep(0.1)
sys.stdout.flush() # Flush the output stream after each iteration
Compatibiliteitsproblemen
Hoewel tqdm over het algemeen compatibel is met de meeste Python-omgevingen en -bibliotheken, kunnen er soms compatibiliteitsproblemen of onverwacht gedrag optreden. Enkele veelvoorkomende situaties om op te letten:
- Aangepaste outputstreams: Bij het gebruik van aangepaste outputstreams of het omleiden van output naar bestanden, werkt
tqdmmogelijk niet zoals verwacht. Controleer of de gebruikte stream de benodigde operaties voor het tonen van de voortgangsbalk ondersteunt. - Derde-partijbibliotheken: In sommige gevallen kan
tqdmonverwacht interageren met derde-partijbibliotheken, vooral die welke zelf output of voortgang bijhouden. Probeer relevante functies van die bibliotheek uit te schakelen of aan te passen om te zien of dat het probleem oplost. - Versiecompatibiliteit: Het is altijd verstandig om compatibele versies van
tqdmen andere bibliotheken te gebruiken. Controleer de bibliotheekdocumentatie op bekende compatibiliteitsproblemen met specifieke Python-versies of andere dependencies.
Bij compatibiliteitsproblemen kun je de volgende workarounds overwegen:
- Downgraden of upgraden: Probeer een andere versie van
tqdm. - Code aanpassen: Pas desnoods je code aan om compatibiliteitsconflicten te omzeilen.
- Hulp uit de community: Als dat allemaal niet helpt, kun je de
tqdm-community of online forums raadplegen voor hulp en mogelijke oplossingen.
Met deze potentiële compatibiliteitsproblemen en workarounds in gedachten kun je effectief problemen oplossen en verhelpen wanneer je tqdm in je Python-projecten gebruikt.
Conclusie
Kortom, Tqdm is een Python-bibliotheek die ons voorziet van voortgangsbalken en andere nuttige statistieken, waardoor het eenvoudiger wordt om de uitvoering van code te monitoren en beheren.
Of je nu over grote datasets itereert, machinelearningmodellen traint, of een andere tijdrovende bewerking uitvoert, tqdm biedt een eenvoudige maar krachtige manier om de voortgang bij te houden en op de hoogte te blijven van de status van je code.
Voor verdere verkenning kun je de andere DataCamp Python-tutorials bekijken, de Tqdm-documentatie of de broncode en Readme op GitHub.
Veelgestelde vragen
Hoe maak ik een eenvoudige voortgangsbalk met tqdm?
Installeer en importeer de bibliotheek tqdm en wikkel vervolgens je iterable in met de functie tqdm().
Kan ik tqdm gebruiken met pandas DataFrames of andere bibliotheken?
Ja, je kunt tqdm gebruiken met pandas DataFrames en andere bibliotheken. De module tqdm.pandas biedt specifieke functies om tqdm met pandas te integreren.
Kan ik het uiterlijk van de Tqdm-voortgangsbalk aanpassen?
Ja, je kunt het balkformaat, de kleur, het totale aantal iteraties en meer aanpassen met de parameters van Tqdm.
De Tqdm-voortgangsbalk wordt niet correct bijgewerkt, wat kan ik doen?
Controleer op buffering, vooral in Jupyter Notebooks. Probeer tqdm.notebook te gebruiken of de output expliciet te flushen. Zorg ook voor correct gebruik van de parameter total.
Tom is data scientist en technisch docent. Hij schrijft en beheert de data science-tutorials en blogposts van DataCamp. Eerder werkte Tom in data science bij Deutsche Telekom.

