Progress bars
Progress bars displays are updated in the background while your code executes. This is done by having the display rendering code run on a separate thread. If you're using a single thread (see: https://docs.julialang.org/en/v1/manual/multi-threading/) you'll need to add a sleep(0.001)
or yield()
command inside your code whose progress you're monitoring to ensure that the display is updated correctly.
Overview
Progress bars! We all love progress bars, and Julia has some great progress bars packages. But this is Term
, and Term
too has its own progress bars API. We think you'll like it. If not, worry not! Term
's progress bars play well ProgressLogging.jl
, scroll to the bottom of this page!
Progress bars do some terminal magic that doesn't play well with how the docs are rendered here. If you want to see what progress bars actually look like, we encourage you to copy-paste the code below and try it out in your own console. Or head to github where you can find more examples.
So this is what a progress bar looks like in Term
:
using Term.Progress
pbar = ProgressBar()
job = addjob!(pbar; N=5)
start!(pbar)
for i in 1:5
update!(job)
sleep(0.01)
render(pbar)
end
stop!(pbar)
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━ ● 2/5 40%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 3/5 60%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 4/5 80%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Let's see what's happening. We start by creating a progress bar
pbar = ProgressBar()
and then we add a "job"
job = addjob!(pbar; N=5)
what's that? Term
's ProgressBar
s can handle multiple "jobs" simultaneously. So if you have multiple things you want to keep track of (e.g. multiple nested loops), you can have a job for each. Next we start the progress bar:
start!(pbar)
we update the job at each step of the loop and render the updated display:
update!(job)
render(pbar)
and finally we stop the whole thing:
stop!(pbar)
.
Okay, why do we need all of this starting and stopping business? Updating the job makes sense, we need to know when we made progress, but why do we need to start and stop the progress bar? Well, ProgressBar
does a bit of terminal magic to ensure that any content you print to STDOUT is displayed without disrupting the progress bar's behavior, so we need to start and stop it to make sure that the magic happens and that the terminal is restored when we're done.
You might spot a problem: what if we forgot stop!
, or our code errors before we reach it or something else like this? That's a problem, our terminal won't be restored. Well don't worry, there's a solution:
pbar = ProgressBar()
job1 = addjob!(pbar; N=5)
job2 = addjob!(pbar; N=10)
with(pbar) do
for i in 1:10
update!(job1)
update!(job2)
i % 3 == 0 && println("text appears here!")
sleep(0.001)
end
end
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━ ● 1/5 20%
Running... ● ━━━━━ ● 1/10 10%text appears here!
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/10 50%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/10 50%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/10 50%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 6/10 60%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 6/10 60%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 6/10 60%text appears here!
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 7/10 70%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 7/10 70%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 7/10 70%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 8/10 80%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 8/10 80%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 9/10 90%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 9/10 90%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 9/10 90%text appears here!
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%
You'll notice we've used println
in the example above. Currently, using print
will break the layout and the text won't be printed correctly. Please use println
while using ProgressBar
!
with
takes care of it all. It starts the progress bar and stops it too! No matter what happens in the code inside the do
block, with
will stop the progress bar so we can use it with no fear. It also removes the need to explicitly call start!/stop!
, which helps. We recommend that you always use with
.
So with with
we loose some of the boiler plate, but it's still a bit too much isn't it? It's cool if you need something specific, but if you want a simple progress bar to monitor progress in a loop perhaps you want something simpler. That's where @track
comes in:
@track for i in 1:10
sleep(0.01)
end
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━ ● 1/10 10%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━ ● 3/10 30%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/10 50%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 6/10 60%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 8/10 80%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 10/10 100%
As simple as that!
ProgressJob
There's just couple things you need to know about ProgessJob
. First, you can set the expected number of steps in the progress bar. We've seen that before, it's the N
in addjob!(pbar; N=5)
. You don't have to though, if you don't know how long your job's going to be then just leave it out! In that case you won't see a progress bar, but you can still see some progress:
pbar = ProgressBar(; columns=:spinner)
job = addjob!(pbar; description="how long is this")
with(pbar) do
for i in 1:10
update!(job)
sleep(0.001)
end
end
──────────────────────────────── progress ─────────────────────────────────
how long is this ( ● ) 0──────────────────────────────── progress ─────────────────────────────────
how long is this ( ● ) 9
What's up with that columns=:spinner
? Read below. By the way, there's a few different kind of spinners
import Term.Progress: SPINNERS
for spinner in keys(SPINNERS)
columns_kwargs = Dict(
:SpinnerColumn => Dict(:spinnertype => spinner, :style=>"bold green"),
:CompletedColumn => Dict(:style => "dim")
)
pbar = ProgressBar(; columns=:spinner, columns_kwargs=columns_kwargs)
with(pbar) do
job = addjob!(pbar; description="{orange1}$spinner...")
for i in 1:3
update!(job)
sleep(.0025)
end
end
end
┌ Warning: Assignment to `pbar` in soft scope is ambiguous because a global variable by the same name exists: `pbar` will be treated as a new local. Disambiguate by using `local pbar` to suppress this warning or `global pbar` to assign to the existing global variable.
└ @ progressbars.md:123
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
greek... ϴ 1
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Options
The main way in which you can personalize progress bars display, is by choosing which columns to show (see below), but there's also a few additional parameters. You can use width
to specify how wide the progress bar display should be, or set expand=true
to make it fill up all available space. Also, sometimes you want to have a bunch of display bars to show progress in various bits of your code, but you don't want your final terminal display to be cluttered. In that case set transient=true
and the progress bars will be erased when they're finished!
Columns
As you've seen, each progress bar display shows various bits of information: some text description, the progress bar itself, a counts bit... Each of these is a "column" (a subtype of AbstractColumn
). There's many types of columns showing different kinds of information, and you can make your own too (see below). Term
offers different presets columns layouts do display varying levels of detail:
for details in (:minimal, :default, :detailed)
pbar = ProgressBar(; columns=details, width=80)
with(pbar) do
job = addjob!(pbar; N=5)
for i in 1:5
update!(job)
sleep(0.02)
end
end
end
┌ Warning: Assignment to `pbar` in soft scope is ambiguous because a global variable by the same name exists: `pbar` will be treated as a new local. Disambiguate by using `local pbar` to suppress this warning or `global pbar` to assign to the existing global variable.
└ @ progressbars.md:146
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━ ● 2/5 40%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 3/5 60%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 4/5 80%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ● 5/5 100%
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━ ● 2/5 40% ● elapsed: 43ms remaining: 64.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━ ● 2/5 40% ● elapsed: 62ms remaining: 93.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━ ● 3/5 60% ● elapsed: 80ms remaining: 53.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━ ● 4/5 80% ● elapsed: 99ms remaining: 25.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━ ● 5/5 100% ● elapsed: 117ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━ ● 5/5 100% ● elapsed: 135ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━ ● 5/5 100% ● elapsed: 153ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━ ● 5/5 100% ● elapsed: 172ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Running... ● ━━━━━━━━━━━━ ● 5/5 100% ● elapsed: 190ms remaining: 0.0ms
but you can also choose your own combination of columns:
import Term.Progress: CompletedColumn, SeparatorColumn, ProgressColumn, DescriptionColumn
mycols = [DescriptionColumn, CompletedColumn, SeparatorColumn, ProgressColumn]
cols_kwargs = Dict(
:DescriptionColumn => Dict(:style=>"red bold")
)
pbar = ProgressBar(; columns=mycols, columns_kwargs=cols_kwargs, width=140)
with(pbar) do
job = addjob!(pbar; N=5)
for i in 1:5
update!(job)
sleep(0.02)
end
end
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Running... 2/5 ● ━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... 2/5 ● ━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... 3/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... 4/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
what's that cols_kwargs
? You can use that to pass additional parameters to each columns, e.g. to set its style.
You can also pass a cols_kwargs
argument to addjob!
to set the column style for individual jobs!
pbar = ProgressBar(; expand = true, columns=:detailed, colors="#ffffff",
columns_kwargs = Dict(
:ProgressColumn => Dict(:completed_char => '█', :remaining_char => '░'),
)
)
job = addjob!(pbar; N = 10, description="Test")
job2 = addjob!(
pbar;
N = 10,
description="Test2",
columns_kwargs = Dict(
:ProgressColumn => Dict(:completed_char => 'x', :remaining_char => '_'),
)
)
with(pbar) do
for i in 1:10
update!(job)
update!(job2)
sleep(0.01)
end
end
──────────────────────────────── progress ─────────────────────────────────
Test ● ██░░░░░░░░░░░░░░ ● 1/10 10% ● elapsed: 177ms remaining: 1.59s
Test2 ● xx_____________ ● 1/10 10% ● elapsed: 22ms remaining: 198.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● █████░░░░░░░░░░░ ● 3/10 30% ● elapsed: 216ms remaining: 504.0ms
Test2 ● xxxx___________ ● 3/10 30% ● elapsed: 61ms remaining: 142.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████░░░░░░░░ ● 5/10 50% ● elapsed: 234ms remaining: 234.0ms
Test2 ● xxxxxxxx_______ ● 5/10 50% ● elapsed: 80ms remaining: 80.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ███████████░░░░░ ● 7/10 70% ● elapsed: 253ms remaining: 108.0ms
Test2 ● xxxxxxxxxx_____ ● 7/10 70% ● elapsed: 98ms remaining: 42.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● █████████████░░░ ● 8/10 80% ● elapsed: 272ms remaining: 68.0ms
Test2 ● xxxxxxxxxxxx___ ● 8/10 80% ● elapsed: 117ms remaining: 29.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 290ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 135ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 309ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 154ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 327ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 173ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 346ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 191ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 364ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 209ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 383ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 228ms remaining: 0.0ms──────────────────────────────── progress ─────────────────────────────────
Test ● ████████████████ ● 10/10 100% ● elapsed: 401ms remaining: 0.0ms
Test2 ● xxxxxxxxxxxxxxx ● 10/10 100% ● elapsed: 247ms remaining: 0.0ms
Custom columns
If there some kind of information that you want to display and Term doesn't have a column for it, just make your own!
You need two things: a column type that is a subtype of AbstractColumn
and an update!
method to update the column's text at each step of the progress bar. Here's a, not very useful, example of a column that displays random text:
using Random
using Term.Progress
import Term.Progress: AbstractColumn, DescriptionColumn, CompletedColumn, SeparatorColumn, ProgressColumn
import Term.Segments: Segment
import Term.Measures: Measure
struct RandomColumn <: AbstractColumn
job::ProgressJob
segments::Vector{Segment}
measure::Measure
style::String
function RandomColumn(job::ProgressJob; style="red" )
txt = Segment(randstring(6), style)
return new(job, [txt], txt.measure, style)
end
end
function Progress.update!(col::RandomColumn, color::String, args...)::String
txt = Segment(randstring(6), col.style)
return txt.text
end
which you can use as you would any column:
mycols = [DescriptionColumn, CompletedColumn, SeparatorColumn, ProgressColumn, RandomColumn]
cols_kwargs = Dict(
:RandomColumn => Dict(:style=>"green bold")
)
pbar = ProgressBar(; columns=mycols, columns_kwargs=cols_kwargs, width=140)
with(pbar) do
job = addjob!(pbar; N=5)
for i in 1:5
update!(job)
sleep(0.02)
end
end
──────────────────────────────── progress ─────────────────────────────────
──────────────────────────────── progress ─────────────────────────────────
Running... 2/5 ● ━━━━━━━━━━━━━━━━━━━━ bSl8Cy──────────────────────────────── progress ─────────────────────────────────
Running... 2/5 ● ━━━━━━━━━━━━━━━━━━━━ y85IZx──────────────────────────────── progress ─────────────────────────────────
Running... 3/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8wRWK8──────────────────────────────── progress ─────────────────────────────────
Running... 4/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ cV5lWK──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1B1Gso──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ pafkON──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FULEpn──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ zYKT8W──────────────────────────────── progress ─────────────────────────────────
Running... 5/5 ● ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ FyKo6b
done!
For each progress
Want to just wrap an iterable in a progress bar rendering? Check this out.
using Term
using Term.Progress
pbar = Term.ProgressBar()
foreachprogress(1:100, pbar, description = "Outer ", parallel=true) do i
foreachprogress(1:5, pbar, description = " Inner") do j
sleep(rand() / 5)
end
end
The loop above will render a progress bar for each iteration of the outer loop, and a progress bar for each iteration of the inner loop - easy.
ProgressLogging
I know that some of you will be thinking: hold on, Julia already had a perfectly functioning progress API with ProgressLogging.jl
, can't we just use that? Long story short, yes you can. But Term
's API gives you so much more control over what kind information to display and what it should look like. Nonetheless, many of you will want to use ProgressLogging
in conjunction with Term, so we've made it possible, you just need to use Term's logger (see Logger):
using ProgressLogging
import Term: install_term_logger
install_term_logger()
@progress "outer...." for i in 1:3
sleep(0.01)
end