MultiProgressBar

MultiProgressBar renders many sub-jobs as stacked fill levels.

Reach for it to show the aggregate state of several jobs, each with its own progress toward its own total, as one bar rather than one bar per job. The bar variable named by name holds one progress fraction per job, and markers sets the ascending-height histogram characters.

class progressbar.widgets.MultiProgressBar(name, markers=' ▁▂▃▄▅▆▇█', **kwargs)[source]

Bases: MultiRangeBar

A bar summarising many sub-progresses as a per-marker histogram.

data[‘variables’][name] holds one entry per sub-progress, each either a 0..1 fraction or a (value, max) pair. get_values buckets them into len(markers) histogram slots (see its docstring for the bucketing rule).

Create a MultiProgressBar.

Parameters:
  • namedata[‘variables’] key holding the sub-progress list (see the class docstring).

  • markers – Ascending-height marker characters, sparsest (0%) to fullest (100%). Reversed internally to match MultiRangeBar’s marker order.

  • **kwargs – Forwarded to MultiRangeBar.__init__.

get_values(progress: ProgressBarMixinBase, data: Data)[source]

Bucket each sub-progress fraction into the marker histogram.

Each value maps to a position along len(markers) - 1 slots; since that position is usually fractional, it spills across its two neighbouring slots weighted by how close it lands to each (e.g. a value 30% of the way from slot 2 to slot 3 adds 0.7 to slot 2’s count and 0.3 to slot 3’s), so the histogram reflects fractional progress rather than rounding every value to its nearest marker.

Example

MultiProgressBar
"""``MultiProgressBar`` renders many sub-jobs as stacked fill levels.

Reach for it to show the aggregate state of several jobs -- each with
its own progress toward its own total -- as one bar, rather than one
bar per job. Compare ``MultiRangeBar`` when the sub-ranges are simple
categories instead of independent job progress. Its loop runs until
every job finishes rather than a fixed ``STEPS`` count, since that is
what the widget is for.
"""

import random
import time

import progressbar

random.seed(0)

JOBS = 25


def main() -> None:
    jobs = [[0, random.randint(1, 10)] for _ in range(JOBS)]
    widgets = [
        progressbar.Percentage(),
        ' ',
        progressbar.MultiProgressBar('jobs'),
    ]
    max_value = sum(total for _, total in jobs)
    with progressbar.ProgressBar(max_value=max_value, widgets=widgets) as bar:
        while True:
            incomplete = [
                idx
                for idx, (progress, total) in enumerate(jobs)
                if progress < total
            ]
            if not incomplete:
                break
            which = random.choice(incomplete)
            jobs[which][0] += 1
            progress = sum(progress for progress, _ in jobs)
            bar.update(progress, jobs=jobs, force=True)
            time.sleep(0.005)


if __name__ == '__main__':
    main()

See also

  • MultiRangeBar: categories of one whole instead of independent per-job progress.