Skip to main content

Progress Bars in Python: A Complete Guide with Examples

Learn how to create Python progress bars using tqdm, progressbar2, alive-progress, and Tkinter, with best practices for better UX and app performance.
May 9, 2025  · 13 min read

In today's apps, users want immediate feedback, especially when tasks take a long time to complete. Python progress bars are a clear and easy way to show that something is happening in the background. A strong progress bar helps a program feel quicker, adds a professional touch, and improves user-friendliness. 

In this article, you'll learn how to implement Python progress bars using popular libraries like tqdm, progress, progressbar2, alive-progress, and Tkinter, along with best practices to enhance user experience and application performance.

To learn more about Python concepts in a hands-on way, check out our Python Programming Fundamentals skill track

What are Progress Bars in Python?

Progress bars are ubiquitous. They are often used for file downloads, software installations, and ETL pipelines. They are also useful for tracking the progress of machine learning model training.

The progress bar displays how much of a task is complete and how much remains. It can appear as text in a command-line interface (CLI) or as a visual bar in a graphical user interface (GUI).

Progress bars improve user experience. They give real-time updates, showing users their progress in the process. If a delay occurs, users can decide whether to intervene or wait. This visibility cuts frustration and makes wait times seem shorter. Users won't stare at a static screen, wondering if anything is happening; they stay involved and feel reassured that progress is happening.

Developers use progress bars to track application performance. They help identify bottlenecks, benchmark code, and track task duration. Progress bars in scripts and workflows show clear status updates. They help users understand long-running processes better. They also enhance the usability of interactive tools and notebooks.

Progress bars can also serve as a simple form of performance monitoring. They show how long each task takes. This helps developers spot slow stages and measure efficiency. This allows for easy comparison of different implementations. 

Command-Line Progress Bars

Command-line progress bars provide visual feedback for long-running tasks directly in the terminal, making scripts more informative and user-friendly. Python offers several libraries, each with strengths in speed, customization, and visual style. We will look at four of these: tqdm, progress, progressbar2, and alive-progress

Tqdm: the standard for speed and simplicity

tqdm is a popular library in Python for creating progress bars. It provides fast and versatile progress indicators for loops and iterables. It tracks iterations and calculates both time remaining and elapsed time. This information updates the bar in real time. tqdm operates in the background. It predicts how much time remains and skips updates that aren't needed. It is simple to learn, lightweight in memory usage, and backed by a strong community. 

Installation process

An easy way to install tqdm is to use the pip installer. Type the following command from the terminal.

pip install tqdm

Print the version number to ensure that the library is installed properly.

import tqdm
print(tqdm.__version__)

4.67.1

Basic usage of tqdm

tqdm is simple to use. Import the library. Wrap any iterable with tqdm(iterable) to display a progress bar.

Instead of writing tqdm(range(n)), you can use the shorthand trange(n) for convenience.

from tqdm import trange
import time

for _ in trange(100, desc="Processing"):
    # Do stuff here
    time.sleep(0.05)  # simulate a task

This code produces a live progress bar during execution.

The progress bar shows

  • Percentage completed (22%)
  • Number of iterations completed out the total (224/1000)
  • Elapsed time and estimated remaining time (12 seconds elapsed, 42 seconds remaining)
  • Iterations per second (18.09 it/s).

To add a description to the progress bar, specify the desc option.

for i in trange(1000, desc='Processing'):  # description
    # Simulate a task
    time.sleep(0.05)

Nested progress bars 

Nested progress bars in tqdm help you track progress across multiple loops. They are also useful when you need to track multiple work stages. Examples include batch processing, nested loops, and model training. 

Wrap each loop in a nested loop with tqdm. Use the position and leave arguments to control how they appear.

  • position: Sets the vertical position of each progress bar. position=0 is the topmost bar, position=1 appears below it, and so on.
  • leave: If leave=True, the progress bar stays on screen after it finishes. If leave=False, it disappears to prevent clutter.
for i in trange(3, desc='Outer loop', leave=True):
    for j in trange(5, desc='Inner loop', leave=False):
        for j in trange(4, desc='Inner inner loop', leave=False):
            time.sleep(0.05)

Nested progress bars show a clear hierarchy. They help you visualize the different stages of a task. They provide detailed insights at various levels. This helps developers identify slowdowns or bottlenecks with ease.

Pandas integration

Tqdm integrates well with pandas. It provides a straightforward way to add progress bars to DataFrame and series tasks. It shows real-time progress for functions like apply, groupby, and map. These functions can be slow with large datasets.

To enable this feature, call tqdm.pandas(). Then, use progress_apply instead of pandas' regular apply method. This will show a progress bar as your function runs over rows or columns. You’ll see the operation's progress without rewriting your code.

In the following program, we create a DataFrame with a column named "numbers." This column holds integers ranging from 0 to 1000. We then generate a new column by applying a "slow" operation called slow_squared

Instead of using the standard pandas apply function, we use progress_apply from tqdm. A progress bar shows up during the operation. It gives real-time updates on how much processing is complete.

import pandas as pd
from tqdm import tqdm
import time

# Simulate a time-consuming operation
def slow_square(x):
    time.sleep(0.01)
    return x**2

# Create a sample DataFrame
df = pd.DataFrame({'numbers': range(1000)})

# Initialize tqdm for pandas
tqdm.pandas(desc="Processing")

# Use progress_apply instead of apply
df['slow_squared'] = df['numbers'].progress_apply(slow_square)
# Print the result
print(df.head())

The output of the code is as follows.

We can use progress_apply for other DataFrame operations such as groupby.

grouped = df.groupby('numbers').progress_apply(lambda g: g.sum())

Customization options

Tqdm lets you customize progress bars to fit various environments and user needs. You can adjust the width with ncols. The bar_format argument gives you full control over the text layout. Also, setting dynamic_ncols=True makes the bar automatically resize to fit the terminal.

Performance considerations specific to tqdm

Tqdm is quick and light. It adds little overhead, even in fast loops. You can disable progress bars with disable=True. This is helpful in production settings where performance is key. For fast loops, updating the bar each time can be too much. So, tqdm lets you control how often it updates. You can use parameters like mininterval and maxinterval

Progress: Customizable styles and spinners

The Progress library in Python lets you create easy text-based progress bars for the command line. It features a straightforward API. It supports both progress bars and spinners and allows for basic output customization. It's small, fast, and has no dependencies. This makes it great for quick scripts and simple setups. 

The progress library includes seven built-in styles of progress bars: Bar, ChargingBar, FillingSquaresBar, FillingCirclesBar, IncrementalBar, PixelBar, and Shadybar. 

To set up, use pip install.

pip install progress

To use, import the desired style, instantiate a variable, use .next() in the loop and .finish() after the process is done. For instance, to use a ChargingBar, use the following code.

import time
from progress.bar import ChargingBar
bar = ChargingBar('Processing', max=20)
for i in range(20):
    # Do some work
    time.sleep(0.5)
    
    bar.next()
bar.finish()
`

Progress also includes spinners for tasks of unknown duration. The code to implement a spinner is straightforward.

import time
from progress.spinner import Spinner

spinner = Spinner('Processing... ')

# Spinner during a task of unknown duration.
for _ in range(50): 
    # Do stuff 
    time.sleep(0.1)  # simulate a running task

    spinner.next()

spinner.finish()

This code results in the description ("Processing…") followed by a spinner.

The progress library is simple and lightweight, but it has some limitations to consider. It doesn't support Jupyter notebooks, and it can't resize dynamically. Plus, it offers fewer customization options than libraries like tqdm. It works well for basic command-line tasks, but it may struggle with complex or high-performance jobs.

Progressbar2: Enhanced customization and compatibility

Progressbar2 is a powerful Python library. It helps you create flexible and customizable progress bars for command-line apps. It has many widgets, like percentage, ETA, animated markers, and counters. This makes it great for more complex or polished CLI tasks. 

Progressbar2 offers more control and formatting options than simpler libraries like progress. It also works better with logging and multithreaded workflows.

To install, use pip install.

pip install progressbar2

The ProgressBar class in progressbar2 shows the current progress state. It does this with a set of customizable widgets. 

A widget is a modular part that updates based on the progress bar's state. This includes the percentage complete, elapsed time, and estimated time left. 

You can choose from many types of widgets. These include text labels, progress markers, counters, timers, spinners, and custom formatters. This variety lets you customize the bar’s look and function for your app.

The basic usage of Progressbar2 is quite simple. 

import time
import progressbar

for i in progressbar.progressbar(range(1000)):
    time.sleep(0.02)

The output displays the percentage completed, iterations complete/total iterations, elapsed time, and estimated time remaining.

Progress bar libraries typically rely on updating a single line in the terminal using carriage returns (\r). This means regular print() statements can interfere by pushing the bar down or corrupting its output. The progressbar2 library provides a way to safely print messages without interfering with the progress bar.

import time
import progressbar

bar = progressbar.ProgressBar(redirect_stdout=True)
for i in range(10):
    # Do some task
    time.sleep(0.1)

    # Print statement
    print(f'Loop #{i}')
    bar.update(i)

The progressbar2 library offers extensive customization through its modular widget system. Widgets show details in the progress bar including percentage completed, elapsed time, estimated time left, counters, or bar animations. You can mix and match these widgets to make a custom progress bar. For instance, you can show the percentage and ETA. Or you can add more details like file names, timestamps, or spinners. 

import time
import progressbar

# Define a custom set of widgets
widgets = [
    'Progress: ',                                # Description text
    progressbar.Percentage(),         # Show percentage completed
    ' ',                              
    progressbar.Bar(marker=':'),      # Custom bar with specified marker
    ' ',
    progressbar.ETA(),                    # Estimated time remaining
    ' | ',
    progressbar.Timer(),                  # Time elapsed
]

# Initialize the progress bar with widgets
bar = progressbar.ProgressBar(widgets=widgets, max_value=50)

# Task
for i in range(50):
    # Do stuff
    time.sleep(0.1)  # Simulate task
    
    bar.update(i + 1)

Alive-progress: dynamic animations for modern terminals

Alive-progress shows animated progress bars that change in real time. This gives command-line apps a modern and responsive look. The bar moves forward and shows helpful real-time metrics. It displays the percentage complete, elapsed time, estimated time left, and iteration speed. This makes it both attractive and informative.

To install the alive-progress library, pip install it.

pip install alive-progress

As shown on its GitHub page, to see a demo of its capabilities, use the following code.

from alive_progress.styles import showtime

showtime()

You'll see output similar to the following.

Alive-progress has the ability to display and manage multiple progress bars simultaneously.

from alive_progress import alive_bar
import time
import threading

# Simulate a task
def simulate_task(name, total):
    with alive_bar(total, title=name) as bar:
        for _ in range(total):
            # Do something
            time.sleep(0.5)

            bar()

# Define threads
threads = [
    threading.Thread(target=simulate_task, args=('Task A', 50)),
    threading.Thread(target=simulate_task, args=('Task B', 70)),
    threading.Thread(target=simulate_task, args=('Task C', 40)),
]

# Start each thread
for t in threads:
    t.start()

# Block the main thread until the program is finished
for t in threads:
    t.join()

The alive-progress library includes several built-in themes. Themes control elements such as the animation style, the characters used to fill the bar, and the overall movement effect. Common themes include classic, pulse, and brackets.

import time
from alive_progress import alive_bar

with alive_bar(100, bar='blocks') as bar:
    for _ in range(100):
        # Do something
        time.sleep(0.02)
        
        bar()

Pause/resume – temporarily stop and resume progress without losing state

from alive_progress import alive_bar
import time

# Run a task...
with alive_bar(100) as bar:
    for i in range(50):
        # Do something
        time.sleep(0.02)

        bar()
    
    # Pause
    bar.text('Temporarily pausing...')
    time.sleep(1)

    # Resume
    bar.text('Resuming...')
    for i in range(50):
        time.sleep(0.02)
        bar()

GUI Progress Bars with Tkinter

Tkinter is Python’s standard GUI (Graphical User Interface) toolkit. The design includes built-in features and is ready to use, so you don’t need to install anything extra. You can create windows, buttons, text fields, menus, progress bars, and more. Tkinter is ideal for building simple desktop applications, interactive tools, and prototypes. 

A basic progress bar can be created using the following code. 

import tkinter as tk
from tkinter import ttk
import time

def start_progress():
    progress["value"] = 0
    root.update_idletasks()
    for i in range(101):
        time.sleep(0.02)
        progress["value"] = i
        root.update_idletasks()

# Set up the window
root = tk.Tk()
root.title("Progress Bar")
root.geometry("300x100")

# Create a progress bar
progress = ttk.Progressbar(root, orient="horizontal", length=250, mode="determinate")
progress.pack(pady=20)

# Create a start button
start_button = ttk.Button(root, text="Start", command=start_progress)
start_button.pack()

# Start the tkinter loop
root.mainloop()

Output on my Mac:

There are two modes available with ttk.Progressbar: determinate and indeterminate. The determinate mode is used when the duration or number of steps in a task is known. The indeterminate mode is used when the task duration is unknown or cannot be measured in steps.

The code above is for a determinate mode, since we knew the length of the task was 250 steps. An example of an indeterminate mode follows.

import tkinter as tk
from tkinter import ttk
import time
import threading

def start_indeterminate():
    def run():
        # 10 ms between moves
        progress.start(10)

        # Simulate task of unknown duration
        time.sleep(10)

        # Stop
        progress.stop()
    
    # Run in a thread, else the tkinter GUI loop is unresponsive
    threading.Thread(target=run).start()

# Set up the GUI
root = tk.Tk()
root.title("Indeterminate Progress Bar")
root.geometry("300x100")

# Create an indeterminate progress bar
progress = ttk.Progressbar(root, mode='indeterminate', length=250)
progress.pack(pady=20)

# Start button
start_button = ttk.Button(root, text="Start", command=start_indeterminate)
start_button.pack()

# Run the tkinter loop
root.mainloop()

Note that the progress bar was run in a separate thread. If we used run() directly in the main thread, the the time.sleep() call would block the main Tkinter event loop and cause the entire GUI to freeze, including button clicks, window redraws, and the progress bar animation.

Performance Considerations and Optimization

Which library should you use for your progress bar? Part of the decision depends on your overhead requirements and your use case.

Library

Overhead

Use Case

tqdm

Very low

Fast loops, data pipelines, minimal impact on performance

progress

Low

Simple CLI scripts, lightweight and no dependencies

progressbar2

Moderate

Custom layouts, ETA, and logging; slight slowdown in fast tasks

alive-progress

Moderate to high

Visually rich tasks, multi-bar output, smooth animations; best for longer tasks

To enhance performance, optimize update frequency. One method is to not update the bar with every iteration. This is especially important in fast or high-frequency loops. Use conditional logic to update every N steps, for example, every 100 iterations.

In critical performance settings or production code, disable progress bars. Visual feedback isn’t needed here. This saves resources while ensuring the logic stays the same for development or debugging. 

Cutting down I/O operations is key for performance. Writing to the terminal, disk, or network can slow things down. Here are some strategies to reduce I/O in performance-critical tasks.

  • Buffer output and write in batches instead of per iteration.
  • Only update at fixed intervals or under specified conditions.
  • Minimize or disable print() inside loops.
  • Add flags to suppress unnecessary output in production.
  • Separate I/O and computation using threads or multiprocessing.
  • Compress or batch large writes to reduce disk I/O frequency.

Best Practices for Effective Progress Bars

Let’s take a look at some of the best practices to bear in mind when creating progress bars in Python. 

Why use progress bars?

There are many good reasons to use progress bars in your applications. First, they provide real-time feedback, reassuring users that tasks are progressing and reducing uncertainty. This visibility enhances user experience, making wait times seem shorter and interactions more intuitive. 

Second, by visually tracking task completion, progress bars allow for easy performance monitoring, enabling both users and developers to quickly spot bottlenecks or stalled processes during long-running operations. Finally, incorporating progress bars elevates the professionalism of your application’s interface, conveying clarity and a thoughtful, user-centric design approach.

Known vs unknown duration tasks

Use a determinate progress bar for tasks that have a set time. This includes file processing, loops, or machine learning training epochs. This type of bar fills based on measurable progress and gives users a clear sense of how much work remains.

For tasks with unknown lengths, like API calls or background checks, use a spinner or an indeterminate bar. These offer a visual cue that the process is ongoing, even if we can't predict how long it will take.

Which library should I use?

The library you use depends on the tasks you're trying to accomplish.

Task 

Library

Notes

High-frequency loops

tqdm

Lightweight, efficient; use mininterval to reduce updates

Simple one-off scripts

progress

Minimal setup, no dependencies, ideal for quick tasks

Structured or custom output

progressbar2

Widget-based, supports ETA, timers, and layout control

Multi-stage or nested tasks

tqdm, alive-progress

Supports nested bars or multi-bar displays for layered tasks

CLI scripts with visual polish

alive-progress

Animated and modern visuals, smooth user experience

GUI applications

tkinter

Built-in GUI toolkit with determinate and indeterminate bars

Customization

When customizing progress bars, focus on clarity and useful information. Strive for a good balance between the two. A clear, simple bar with key metrics is usually better than one crowded with too much information. 

You can use libraries like progressbar2 and alive-progress. They let you change the layout, color, and animation of your progress bars. Use themes or formatting to improve the user experience. Avoid cluttering the display with too many widgets or complex visuals. The goal is to give helpful feedback. We want to avoid distracting the user or making them feel overwhelmed.

Exception handling and compatibility testing

Wrap progress bar logic in try-except blocks. This helps avoid UI glitches or crashes if an error occurs during a task. This is key in scripts that run for a long time or when using uncertain external dependencies.

Also, test your progress bars in different environments. Check across various operating systems, terminal types, and display widths. This way, you can ensure their behavior remains consistent.

Some libraries behave differently in Jupyter notebooks, remote terminals, or GUI shells. Verifying compatibility early can help prevent unexpected issues. This way, users will have a smoother experience in production.

Accessibility considerations

When creating progress indicators, consider accessibility. This helps all users receive clear feedback. Some suggestions:

  • Don't rely only on color or animation to show progress. Add text elements like percentages, step counts, or time estimates.
  • Use clear, high-contrast visuals for better readability.
  • Ensure your progress bars work well with screen readers in GUI applications.
  • For command-line tools, consider verbosity options that print progress updates in plain text.

Making accessibility a priority boosts usability. It also makes your tools more inclusive and professional.

Conclusion 

Progress bars are a simple yet strong feature for any Python app. They give instant feedback, improve user experience, and track performance and code clarity. Choosing the right progress bar library is key. It can enhance your software, whether you're making a quick script, a command-line tool, or a full GUI app. A thoughtful implementation can enhance your software's speed, professionalism, and user-friendliness. Prioritizing customization, performance, compatibility, and accessibility makes progress bars more than mere visuals. They become an important part of how users engage with your work.

To keep learning, check out these resources:

Python Progress Bar FAQs

What is a progress bar?

A progress bar is a visual indicator that shows how much of a task is completed and how much remains. It improves the user experience by providing feedback during long operations.

What are the popular progress bar libraries in Python?

The most common libraries are tqdm, progress, progressbar2, and alive-progress.

Can I use progress bars with the pandas library?

Yes, you can. tqdm integrates with pandas via progress_apply() (instead of apply) and similar methods.

Can I customize the appearance of a progress bar?

Yes. Libraries such as tqdm and progressbar2 let you customize layout, width, color, and update frequency.

Which library should I use for Jupyter Notebooks.

The library tqdm.notebook integrates well with Jupyter.


Mark Pedigo's photo
Author
Mark Pedigo
LinkedIn

Mark Pedigo, PhD, is a distinguished data scientist with expertise in healthcare data science, programming, and education. Holding a PhD in Mathematics, a B.S. in Computer Science, and a Professional Certificate in AI, Mark blends technical knowledge with practical problem-solving. His career includes roles in fraud detection, infant mortality prediction, and financial forecasting, along with contributions to NASA’s cost estimation software. As an educator, he has taught at DataCamp and Washington University in St. Louis and mentored junior programmers. In his free time, Mark enjoys Minnesota’s outdoors with his wife Mandy and dog Harley and plays jazz piano.

Topics

Top Python Courses

Track

Python Programming Fundamentals

16 hr
Build your Python programming skills. Learn how to work with modules and packages, work with built-in data types, and write custom functions.
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related

Tutorial

Tqdm Python: A Guide With Practical Examples

tqdm is a Python library that provides a fast, extensible progress bar for loops and iterables, making it easy to visualize the progress of your code.
Tom Farnschläder's photo

Tom Farnschläder

11 min

Tutorial

Python Count Tutorial

Learn how to use the counter tool with an interactive example.
DataCamp Team's photo

DataCamp Team

3 min

Tutorial

Introduction to GUI With Tkinter in Python

In this tutorial, you are going to learn how to create GUI apps in Python. You'll also learn about all the elements needed to develop GUI apps in Python.
Aditya Sharma's photo

Aditya Sharma

11 min

Tutorial

Python Multiprocessing: A Guide to Threads and Processes

Learn how to manage threads and processes with Python’s multiprocessing module. Discover key techniques for parallel programming. Enhance your code efficiency with examples.
Kurtis Pykes 's photo

Kurtis Pykes

7 min

Tutorial

Python Tabulate: A Full Guide

Use the tabulate library in Python to create well-formatted tables. Learn about its advanced features and options for customizing table appearance.
Allan Ouko's photo

Allan Ouko

8 min

Tutorial

Python Modules Tutorial: Importing, Writing, and Using Them

Learn how to create and import Python modules. Discover best practices, examples, and tips for writing reusable, organized, and efficient Python code!

Nishant Kumar

8 min

See MoreSee More