yihui / knitr

A general-purpose tool for dynamic report generation in R
https://yihui.org/knitr/
2.37k stars 874 forks source link

Progress bar for non-interactive contexts #2221

Closed hadley closed 1 year ago

hadley commented 1 year ago

I think it would be useful for knitr to bundle a progress bar that's well suited to non-interactive contexts (i.e. when you're logging to a file and \r doesn't work). Here's one that I've been playing around this:


cat_line <- function(..., file = stdout()) {
  cat(paste0(..., "\n", collapse = ""), file = file)
}

batch_progress <- function(total, labels) {
  file <- getOption("knitr.progress.output", "")
  n_code <- sum(labels != "")

  update <- function(i) {
    lab <- labels[[i]]
    n_done <- sum(labels[seq_len(i)] != "")

    if (lab != "") {
      cat_line("Chunk: ", lab, " [", n_done, "/", n_code, "]", file = file)
    }
  }
  done <- function() {
    cat_line("Complete", file = file)
  }

  list(
    update = update,
    done = done
  )
}

By filing an issue to this repo, I promise that

I understand that my issue may be closed if I don't fulfill my promises.

hadley commented 1 year ago

This sort of progress bar also works a little more nicely if you are logging data to stderr():

```{r alpha}
Sys.sleep(1)
cat("Reticulating splines\n", file = stderr())
Sys.sleep(1)
cat("Evaluating lambdas\n", file = stderr())
Sys.sleep(1)
cat("Integration factuals\n", file = stderr())
hadley commented 1 year ago

As an example of why the current default could be improved, here's the log file for an Rmd that I recently deployed to Posit Connect:

Screenshot 2023-02-09 at 10 50 49
hadley commented 1 year ago

One way to determine which progress bar to use would be to implement something like cli::is_dynamic_tty()

yihui commented 1 year ago

This feature request is definitely reasonable. I wonder how hard it is to approximate cli::is_dynamic_tty() when cli is not installed. Would this be good enough?

isatty(getOption("knitr.progress.output", stdout())) || rstudioapi::isAvailable()
hadley commented 1 year ago

@yihui this would only be used if cli wasn't installed, right? IOTW is ok for knitr to suggest cli?

@gaborcsardi can you answer Yihui's question?

gabor commented 1 year ago

@hadley sorry, you probably wanted to ping someone else, not me 😄

hadley commented 1 year ago

@gabor oops, sorry!

@gaborcsardi can you answer Yihui's question?

gaborcsardi commented 1 year ago

Not perfect, but it is something. Are the build pane and the render pane relevant? They have \r support I believe, but I suspect you would get FALSE there?

You could also try to include other GUIs, see cli:::is_rapp_stdx(stream) and cli:::is_rkward_stdx(stream).

yihui commented 1 year ago

is ok for knitr to suggest cli?

@hadley Yes, I'll definitely suggest cli.

Not perfect, but it is something. Are the build pane and the render pane relevant? They have \r support I believe, but I suspect you would get FALSE there?

@gaborcsardi This is just a fallback (when cli is not available) so doesn't need to be perfect. I just tested it and rstudioapi::isAvailable() did return FALSE but rstudioapi::versionInfo() returns information about RStudio, so I guess I can use the latter.

Thanks!

gaborcsardi commented 1 year ago

OTOH the job pane did not have \r support the last time I checked, so ideally it would return FALSE there. See the dynamic_tty entries here for the capabilities: https://github.com/r-lib/cli/blob/01f932adafd58a59d596b745bf88359c5cb5a969/R/aab-rstudio-detect.R#L205-L291

You could also copy this file, it should be self-contained. But yeah, for a fallback a good-enough solution is perfectly fine.

yihui commented 1 year ago

Now the bar will be suppressed when knitr.progress.output is not a connection (e.g., a file instead), or the connection is not isatty(). It's also possible to manually specify options(knitr.progress.simple = TRUE/FALSE) if the default is not good (TRUE means no bar).

github-actions[bot] commented 8 months ago

This old thread has been automatically locked. If you think you have found something related to this, please open a new issue by following the issue guide (https://yihui.org/issue/), and link to this old issue if necessary.