Skip to content

Commit d4527cd

Browse files
authored
Use ragg::agg_png over Cairo::CairoPNG if available (#3654)
* Close #3626: use ragg::agg_png over Cairo::CairoPNG if available * Update documentation
1 parent 474f140 commit d4527cd

File tree

8 files changed

+55
-59
lines changed

8 files changed

+55
-59
lines changed

NEWS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ shiny development
55

66
### Breaking changes
77

8+
* Closed #3626: `renderPlot()` (and `plotPNG()`) now uses `ragg::agg_png()` by default when the [`{ragg}` package](https://github.com/r-lib/ragg) is installed. To restore the previous behavior, set `options(shiny.useragg = FALSE)`. (#3654)
9+
810
### Minor new features and improvements
911

1012
* Shiny's internal HTML dependencies are now mounted dynamically instead of statically. (#3537)

R/imageutils.R

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
startPNG <- function(filename, width, height, res, ...) {
2-
# shiny.useragg is an experimental option that isn't officially supported or
3-
# documented. It's here in the off chance that someone really wants
4-
# to use ragg (say, instead of showtext, for custom font rendering).
5-
# In the next shiny release, this option will likely be superseded in
6-
# favor of a fully customizable graphics device option
7-
if ((getOption('shiny.useragg') %||% FALSE) && is_installed("ragg")) {
8-
pngfun <- ragg::agg_png
2+
pngfun <- if ((getOption('shiny.useragg') %||% TRUE) && is_installed("ragg")) {
3+
ragg::agg_png
94
} else if (capabilities("aqua")) {
105
# i.e., png(type = 'quartz')
11-
pngfun <- grDevices::png
6+
grDevices::png
127
} else if ((getOption('shiny.usecairo') %||% TRUE) && is_installed("Cairo")) {
13-
pngfun <- Cairo::CairoPNG
8+
Cairo::CairoPNG
149
} else {
1510
# i.e., png(type = 'cairo')
16-
pngfun <- grDevices::png
11+
grDevices::png
1712
}
1813

1914
args <- rlang::list2(filename=filename, width=width, height=height, res=res, ...)
@@ -57,33 +52,31 @@ startPNG <- function(filename, width, height, res, ...) {
5752
grDevices::dev.cur()
5853
}
5954

60-
#' Run a plotting function and save the output as a PNG
55+
#' Capture a plot as a PNG file.
6156
#'
62-
#' This function returns the name of the PNG file that it generates. In
63-
#' essence, it calls `png()`, then `func()`, then `dev.off()`.
64-
#' So `func` must be a function that will generate a plot when used this
65-
#' way.
66-
#'
67-
#' For output, it will try to use the following devices, in this order:
68-
#' quartz (via [grDevices::png()]), then [Cairo::CairoPNG()],
69-
#' and finally [grDevices::png()]. This is in order of quality of
70-
#' output. Notably, plain `png` output on Linux and Windows may not
71-
#' antialias some point shapes, resulting in poor quality output.
72-
#'
73-
#' In some cases, `Cairo()` provides output that looks worse than
74-
#' `png()`. To disable Cairo output for an app, use
75-
#' `options(shiny.usecairo=FALSE)`.
57+
#' The PNG graphics device used is determined in the following order:
58+
#' * If the ragg package is installed (and the `shiny.useragg` is not
59+
#' set to `FALSE`), then use [ragg::agg_png()].
60+
#' * If a quartz device is available (i.e., `capabilities("aqua")` is
61+
#' `TRUE`), then use `png(type = "quartz")`.
62+
#' * If the Cairo package is installed (and the `shiny.usecairo` option
63+
#' is not set to `FALSE`), then use [Cairo::CairoPNG()].
64+
#' * Otherwise, use [grDevices::png()]. In this case, Linux and Windows
65+
#' may not antialias some point shapes, resulting in poor quality output.
7666
#'
7767
#' @param func A function that generates a plot.
7868
#' @param filename The name of the output file. Defaults to a temp file with
7969
#' extension `.png`.
8070
#' @param width Width in pixels.
8171
#' @param height Height in pixels.
82-
#' @param res Resolution in pixels per inch. This value is passed to
83-
#' [grDevices::png()]. Note that this affects the resolution of PNG rendering in
72+
#' @param res Resolution in pixels per inch. This value is passed to the
73+
#' graphics device. Note that this affects the resolution of PNG rendering in
8474
#' R; it won't change the actual ppi of the browser.
85-
#' @param ... Arguments to be passed through to [grDevices::png()].
86-
#' These can be used to set the width, height, background color, etc.
75+
#' @param ... Arguments to be passed through to the graphics device. These can
76+
#' be used to set the width, height, background color, etc.
77+
#'
78+
#' @return A path to the newly generated PNG file.
79+
#'
8780
#' @export
8881
plotPNG <- function(func, filename=tempfile(fileext='.png'),
8982
width=400, height=400, res=72, ...) {

R/render-plot.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#' When rendering an inline plot, you must provide numeric values (in pixels)
3535
#' to both \code{width} and \code{height}.
3636
#' @param res Resolution of resulting plot, in pixels per inch. This value is
37-
#' passed to [grDevices::png()]. Note that this affects the resolution of PNG
37+
#' passed to [plotPNG()]. Note that this affects the resolution of PNG
3838
#' rendering in R; it won't change the actual ppi of the browser.
3939
#' @param alt Alternate text for the HTML `<img>` tag if it cannot be displayed
4040
#' or viewed (i.e., the user uses a screen reader). In addition to a character
@@ -44,7 +44,7 @@
4444
#' ggplot objects; for other plots, `NA` results in alt text of "Plot object".
4545
#' `NULL` or `""` is not recommended because those should be limited to
4646
#' decorative images.
47-
#' @param ... Arguments to be passed through to [grDevices::png()].
47+
#' @param ... Arguments to be passed through to [plotPNG()].
4848
#' These can be used to set the width, height, background color, etc.
4949
#' @inheritParams renderUI
5050
#' @param execOnResize If `FALSE` (the default), then when a plot is

R/shiny-options.R

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,10 @@ getShinyOption <- function(name, default = NULL) {
140140
#' messages).}
141141
#' \item{shiny.autoload.r (defaults to `TRUE`)}{If `TRUE`, then the R/
142142
#' of a shiny app will automatically be sourced.}
143-
#' \item{shiny.usecairo (defaults to `TRUE`)}{This is used to disable graphical rendering by the
144-
#' Cairo package, if it is installed. See [plotPNG()] for more
145-
#' information.}
143+
#' \item{shiny.useragg (defaults to `TRUE`)}{Set to `FALSE` to prevent PNG rendering via the
144+
#' ragg package. See [plotPNG()] for more information.}
145+
#' \item{shiny.usecairo (defaults to `TRUE`)}{Set to `FALSE` to prevent PNG rendering via the
146+
#' Cairo package. See [plotPNG()] for more information.}
146147
#' \item{shiny.devmode (defaults to `NULL`)}{Option to enable Shiny Developer Mode. When set,
147148
#' different default `getOption(key)` values will be returned. See [devmode()] for more details.}
148149
### Not documenting as 'shiny.devmode.verbose' is for niche use only

man/plotPNG.Rd

Lines changed: 18 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/renderCachedPlot.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/renderPlot.Rd

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/shinyOptions.Rd

Lines changed: 4 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)