- Notifications
You must be signed in to change notification settings - Fork11
三 R package: An Inclusive, Unifying API for Progress Updates
futureverse/progressr
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Theprogressr package provides a minimal API for reportingprogress updates inR. The design is toseparate the representation of progress updates from how they arepresented. What type of progress to signal is controlled by thedeveloper. How these progress updates are rendered is controlled bythe end user. For instance, some users may prefer visual feedbacksuch as a horizontal progress bar in the terminal, whereas others mayprefer auditory feedback. Theprogressr framework is designedto work out-of-the-box also with parallel and distributed processing,especially with thefutureverse ecosystem.
Design motto:
The developer is responsible for providing progress updates but it'sonly the end user who decides if, when, and how progress should bepresented. No exceptions will be allowed.
| Developer's API |
|---|
1. Set up a progressor with a certain number of steps: p <- progressor(nsteps)p <- progressor(along = x) 2. Signal progress: p() # one-step progressp(amount = 0) # "still alive"p("loading ...") # pass on a message |
| End-user's API |
|---|
1a. Subscribe to progress updates from everywhere: handlers(global = TRUE)y <- slow_sum(1:5)y <- slow_sum(6:10) 1b. Subscribe to a specific expression: with_progress({ y <- slow_sum(1:5) y <- slow_sum(6:10)})2. Configure how progress is presented: handlers("progress")handlers("txtprogressbar", "beepr")handlers(handler_pbcol(enable_after = 3.0))handlers(handler_progress(complete = "#")) |
Assume that we have a functionslow_sum() for adding up the valuesin a vector. It is so slow, that we like to provide progress updatesto whoever might be interested in it. With theprogressr package,this can be done as:
slow_sum<-function(x) {p<-progressr::progressor(along=x)sum<-0for (kkin seq_along(x)) { Sys.sleep(0.1)sum<-sum+x[kk] p(message= sprintf("Adding %g",x[kk])) }sum}
Note how there areno arguments (e.g..progress = TRUE) in thecode that specify how progress is presented. This is by design andbecause the only task for the developer is to decide on where in thecode it makes sense to signal that progress has been made. As we willsee next, it should be up to the end user, and end user only, of thiscode to decide whether they want to receive progress updates or not,and, if so, in what format. Asking them to specify a special"progress" argument adds a lot of friction, it clutters up the code,and, importantly, might not even be possible for end users to do(e.g. they call a package function that in turn calls the progressreporting function of interest).
Now, if we call this function, without further settings:
>y<- slow_sum(1:10)>y[1]55>
the default is that there will beno progress updates. To getprogress updates, we need to request them to be "handled", which we doby:
>progressr::handlers(global=TRUE)
After this, progress will be reported;
>y<- slow_sum(1:10)|====================|40%>y<- slow_sum(10:1)|========================================|80%
To disable reporting again, do:
> handlers(global=FALSE)
By default,progressr presents progress via the built-inutils::txtProgressBar(). It presents itself as a rudimentaryASCII-based horizontal progress bar in the R terminal. Seehelp("handler_txtprogressbar") for how to customize the look of"txtprogressbar", e.g. colorization and Unicode. There are many otherways to report on progress, including visually, auditory, and vianotification systems. You can also use a mix of these, e.g.
handlers(c("cli","beepr","ntfy"))
See the 'Customizing How Progress is Reported' vignette for for examples.
Note that progression updates byprogressr is designed to work outof the box for any iterator framework in R. See the different packagevignettes for details. Prominent examples are:
lapply()etc. of base Rmap()etc. by thepurrr packagellply()etc. by theplyr packageforeach()iterations by theforeach package
and near-live progress reporting in parallel and distributedprocessing via thefuture framework:
future_lapply()etc. by thefuture.apply packagefuture_map()etc. by thefurrr packagellply()etc. by theplyr anddoFuture packagesforeach()iterations via theforeach anddoFuture packagesbplapply()etc. by theBiocParallel anddoFuture packages
Other uses ofprogressr are:
- make packages that report progress via thecli package(e.g.purrr) report progress viaprogressr
- make
knit()of theknitr package report viaprogressr
In contrast to other progress-bar frameworks, output frommessage(),cat(),print() and so on, willnot interfere with progressreported viaprogressr. For example, say we have:
slow_sqrt<-function(xs) {p<- progressor(along=xs) lapply(xs,function(x) { message("Calculating the square root of",x) Sys.sleep(2) p(sprintf("x=%g",x)) sqrt(x) })}
we will get:
> library(progressr)> handlers(global=TRUE)> handlers("progress")>y<- slow_sqrt(1:8)Calculatingthesquarerootof1Calculatingthesquarerootof2- [===========>-----------------------------------]25%x=2
This works becauseprogressr will briefly buffer any outputinternally and only release it when the next progress update isreceived just before the progress is re-rendered in the terminal.This is why you see a two second delay when running the above example.Note that, if we use progress handlers that do not output to theterminal, such ashandlers("beepr"), then output does not have to bebuffered and will appear immediately.
Comment: When signaling a warning usingwarning(msg, immediate. = TRUE) the message is immediately outputted to the standard-errorstream. However, this is not possible to emulate when warnings areintercepted using calling handlers. This is a limitation of R thatcannot be worked around. Because of this, the above call will behavethe same aswarning(msg) - that is, all warnings will be buffered byR internally and released only when all computations are done.
As seen above, some progress handlers present the progress message aspart of its output, e.g. the "progress" handler will display themessage as part of the progress bar. It is also possible to "push"the message up together with other terminal output. This can be doneby adding class attribute"sticky" to the progression signaled.This works for several progress handlers that output to the terminal.For example, with:
slow_sum<-function(x) {p<-progressr::progressor(along=x)sum<-0for (kkin seq_along(x)) { Sys.sleep(0.1)sum<-sum+x[kk] p(sprintf("Step %d",kk),class=if (kk%%5==0)"sticky",amount=0) p(message= sprintf("Adding %g",x[kk])) }sum}
we get
> handlers("txtprogressbar")>y<- slow_sum(1:30)Step5Step10|====================|43%
and
> handlers("progress")>y<- slow_sum(1:30)Step5Step10/ [===============>-------------------------]43%Adding13
R package progressr is available onCRAN and can be installed in R as:
install.packages("progressr")To install the pre-release version that is available in Git branchdevelop on GitHub, use:
remotes::install_github("futureverse/progressr",ref="develop")
This will install the package from source.
To contribute to this package, please seeCONTRIBUTING.md.
About
三 R package: An Inclusive, Unifying API for Progress Updates
Topics
Resources
Contributing
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors5
Uh oh!
There was an error while loading.Please reload this page.
