MultiRangeBar

MultiRangeBar shows several named ranges as segments of one bar.

Reach for it to visualize a whole made of distinct categories (done, processing, scheduled, not started) as proportional segments of a single bar, rather than a single fill fraction. markers gives one character per category, and the segment sizes come from the bar variable named by name. In the demo, units migrate between segments until every one is “done”.

class progressbar.widgets.MultiRangeBar(name, markers, **kwargs: Any)[source]

Bases: Bar, VariableMixin

A bar with multiple sub-ranges, each represented by a different symbol.

The various ranges are represented on a user-defined variable, formatted as

[['Symbol1', amount1], ['Symbol2', amount2], ...]

Create a MultiRangeBar.

Parameters:
  • namedata[‘variables’] key holding the range amounts (see VariableMixin).

  • markers – One single-character marker (or callable, see string_or_lambda) per range, in the same order as the amounts in data[‘variables’][name].

  • **kwargs – Forwarded to Bar.__init__.

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

Return the configured [amount, …] list, or [] if unset.

Example

MultiRangeBar
"""``MultiRangeBar`` shows several named ranges as segments of one bar.

Reach for it to visualize a whole made of distinct categories -- done,
processing, scheduled, not started -- as proportional segments of a
single bar, rather than a single fill fraction. Compare
``MultiProgressBar``, which shows independent per-job progress instead
of categories of one whole. Its loop runs until every unit reaches the
"done" range rather than a fixed ``STEPS`` count, since that is what the
widget is for.
"""

import random
import time

import progressbar

random.seed(0)

UNITS = 25


def main() -> None:
    markers = [
        '\x1b[38;5;2m█\x1b[39m',  # Done (green)
        '\x1b[38;5;3m#\x1b[39m',  # Processing (yellow)
        '\x1b[38;5;1m.\x1b[39m',  # Scheduled (red)
        ' ',  # Not started
    ]
    widgets = [progressbar.MultiRangeBar('amounts', markers=markers)]
    amounts = [0] * (len(markers) - 1) + [UNITS]
    with progressbar.ProgressBar(widgets=widgets) as bar:
        while True:
            incomplete = [
                idx
                for idx, amount in enumerate(amounts)
                for _ in range(amount)
                if idx != 0
            ]
            if not incomplete:
                break
            which = random.choice(incomplete)
            amounts[which] -= 1
            amounts[which - 1] += 1
            bar.update(amounts=amounts, force=True)
            time.sleep(0.005)


if __name__ == '__main__':
    main()

See also

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

  • JobStatusBar: per-job success/failure markers instead of proportional segments.