Terminal Progress Bars.
Progress bar in your R terminal
An R package to show ASCII progress bars. Heavily influenced by the https://github.com/tj/node-progress JavaScript project.
Installation
Install the package from CRAN:
install.packages("progress")
If you need the development version, install it from GitHub:
pak::pak("r-lib/progress")
Usage
Use the progress_bar
R6 class:
library(progress)
pb <- progress_bar$new(total = 100)
for (i in 1:100) {
pb$tick()
Sys.sleep(1 / 100)
}
[==========================================================-------------] 81%
The progress bar is displayed after the first tick
command. This might not be desirable for long computations, because nothing is shown before the first tick. It is good practice to call tick(0)
at the beginning of the computation or download, which shows the progress bar immediately.
pb <- progress_bar$new(total = 100)
f <- function() {
pb$tick(0)
Sys.sleep(3)
for (i in 1:100) {
pb$tick()
Sys.sleep(1 / 100)
}
}
f()
Custom format, with estimated time of completion:
pb <- progress_bar$new(
format = " downloading [:bar] :percent eta: :eta",
total = 100, clear = FALSE, width= 60)
for (i in 1:100) {
pb$tick()
Sys.sleep(1 / 100)
}
downloading [========----------------------] 28% eta: 1s
With elapsed time:
pb <- progress_bar$new(
format = " downloading [:bar] :percent in :elapsed",
total = 100, clear = FALSE, width= 60)
for (i in 1:100) {
pb$tick()
Sys.sleep(1 / 100)
}
downloading [==========================------] 80% in 1s
pb <- progress_bar$new(
format = " downloading [:bar] :elapsedfull",
total = 1000, clear = FALSE, width= 60)
for (i in 1:1000) {
pb$tick()
Sys.sleep(1 / 100)
}
downloading [=====================--------------] 00:00:08
With number of number of ticks/total:
total <- 1000
pb <- progress_bar$new(format = "[:bar] :current/:total (:percent)", total = total)
f <- function() {
pb$tick(0)
Sys.sleep(3)
for (i in 1:total) {
pb$tick(1)
Sys.sleep(1 / 100)
}
}
f()
[============================-------------------------------------------------] 370/1000 ( 37%)
With custom tokens:
pb <- progress_bar$new(
format = " downloading :what [:bar] :percent eta: :eta",
clear = FALSE, total = 200, width = 60)
f <- function() {
for (i in 1:100) {
pb$tick(tokens = list(what = "foo "))
Sys.sleep(2 / 100)
}
for (i in 1:100) {
pb$tick(tokens = list(what = "foobar"))
Sys.sleep(2 / 100)
}
}
f()
downloading foo [======------------------] 27% eta: 4s
It can show download rates for files with unknown sizes:
pb <- progress_bar$new(
format = " downloading foobar at :rate, got :bytes in :elapsed",
clear = FALSE, total = 1e7, width = 60)
f <- function() {
for (i in 1:100) {
pb$tick(sample(1:100 * 1000, 1))
Sys.sleep(2/100)
}
pb$tick(1e7)
invisible()
}
f()
downloading foobar at 5.42 MB/s, got 15.45 MB in 3s
Progress bars can also digress, by supplying negative values to tick()
:
pb <- progress_bar$new()
f <- function() {
pb$tick(50) ; Sys.sleep(1)
pb$tick(-20) ; Sys.sleep(1)
pb$tick(50) ; Sys.sleep(1)
pb$tick(-30) ; Sys.sleep(1)
pb$tick(100)
}
f()
See the manual for details and other options.
Usage with purrr
iterators
If you prefer to do your iterative tasks using the purrr
family of functional programming tools, rather than with for
loops, there are two straightforward ways to add progress bars:
Increment the ticks in-line when calling the
purrr
iterator.Define the task and increment the ticks in a separate wrapper function.
Option 1 is concise for simple one-line tasks (e.g. requiring only a single function call), while Option 2 is probably preferred for more complex multi-line tasks.
# Option 1
pb <- progress_bar$new(total = 100)
purrr::walk(1:100, ~{pb$tick(); Sys.sleep(0.1)})
[================================================>------] 89%
# Option 2
pb <- progress_bar$new(total = 100)
foo <- function(x){
pb$tick()
Sys.sleep(0.1)
}
purrr::walk(1:100, foo)
[==================>------------------------------------] 34%
Creating a plyr compatible progress bar
It is easy to create progress bars for plyr:
progress_progress <- function(...) {
pb <- NULL
list(
init = function(x, ...) {
pb <<- progress_bar$new(total = x, ...)
},
step = function() {
pb$tick()
},
term = function() NULL
)
}
You can try it with
plyr::l_ply(
1:100,
.fun = function(...) Sys.sleep(0.01),
.progress = 'progress'
)
C++ API
The package also provides a C++ API, that can be used with or without Rcpp. See the example package that is included within progress
. Here is a short excerpt that shows how it works:
#include <RProgress.h>
...
RProgress::RProgress pb("Downloading [:bar] ETA: :eta");
pb.tick(0);
for (int i = 0; i < 100; i++) {
usleep(2.0 / 100 * 1000000);
pb.tick();
}
...
The C++ API has almost the same functionality as the R API, except that it does not currently support custom tokens, custom streams, and callback functions.
Note that the C++ and the R APIs are independent and for a single progress bar you need to use either one exclusively.
License
MIT @ Gábor Csárdi, RStudio Inc.