Skip to contents

Save a ggplot2, lattice or Base R plot as an HTML file with interactive MAIDR accessibility features.

Usage

save_html(
  plot = NULL,
  file = "plot.html",
  use_cdn = NULL,
  width = NULL,
  height = NULL,
  ...
)

Arguments

plot

A ggplot2 object, a lattice (trellis) object, or NULL for Base R auto-detection

file

File path where to save the HTML file (e.g., "plot.html")

use_cdn

Logical. Controls where MAIDR.js is loaded from:

  • TRUE: Use CDN. The file is self-contained but needs internet access when it is viewed. It names the latest published MAIDR.js by version (looked up once per R session, or the bundled version when the lookup cannot be made); pin a version with options(maidr.cdn_version = ...), see ?"maidr-options".

  • FALSE or NULL (default): Use the bundled files. The MAIDR.js library is written to a lib/ folder beside file, which has to travel with it.

width, height

The size to draw the chart at, in inches: each a single positive number no larger than 50, or NULL (the default) for 7 x 5 in, 12 x 6 in for a candlestick chart. A side not given takes its default. See Chart size.

...

Additional arguments passed to internal functions

Value

The file path where the HTML was saved (invisibly)

Details

By default the MAIDR.js library is written to a lib/ folder beside file, and the two have to be shared together: zip the folder that holds both, or copy both. An .html sent on its own loads no MAIDR.js and shows a plain, inaccessible chart. use_cdn = TRUE writes one self-contained file instead, which needs internet access whenever it is viewed and loads the latest published MAIDR.js from jsDelivr rather than the copy bundled with this package.

Base R charts

A Base R chart is read from the plotting calls recorded on the current device, and is the page that device shows: the last one. R draws a high-level plot on a new page when it moves past the last panel of the page it is on – every plot on a page of one panel, the fifth under par(mfrow = c(2, 2)), the first after par(mfrow = ), par(mfcol = ) or layout() sets a page up again – and plot.new() and frame() move on a panel as a plot does. So after hist(a); hist(b) the chart is the histogram of b alone, and after five plots under par(mfrow = c(2, 2)) it is the fifth, in the first panel of a 2 x 2 grid. Each plot of a grid is in the panel R drew it in: a plot drawn after par(new = TRUE), or with add = TRUE, is drawn in the panel of the plot before it, one par(mfg = ) sends to a panel out of turn is in that panel, and a panel plot.new() or frame() passed over stays empty. So it is where the call that set the grid up was not recorded: one made through graphics::par() or graphics::layout(), before maidr_on(), or before an earlier show() or save_html() on the device. A plot drawn in a region of the page par(fig = ) gave it, as an inset is, or in a screen of split.screen(), is drawn in that region, and read with the plot before it. lines(), points(), abline(), text(), legend(), title(), axis() and the other low-level calls add to the plot they are drawn on: after par(mfg = ), or screen(n, new = FALSE) of split.screen(), sends R back to the panel or screen of an earlier plot, to that plot. Drawn on a panel plot.new() or frame() took, as a legend of its own is, or on a plot maidr does not record, such as smoothScatter(), they are drawn there, and read as part of no plot. Drawn over a plot after par(new = TRUE) and plot.new(), as a second series with an axis of its own is – also over the plot of an earlier panel or screen par(mfg = ) or screen() sent R back to – they are drawn in the coordinates they were drawn in, and read with that plot. Nothing drawn on an earlier page reaches the chart: not its data, its titles or the size it is drawn at. A page replayPlot() puts back, from a plot recordPlot() saved on a device that keeps a display list, is the page the chart is read from, with what was drawn on it when it was saved and what has been drawn on it since. A page that holds no plot maidr recorded – one R started with plot.new() or frame(), with a plot maidr does not record, or with one drawn while maidr_off() was in effect, even with lines() or text() drawn on it since, or one replayPlot() put back from such a page, or from a plot saved in another session or on another device – is not read as the plot before it: show() and save_html() stop, and say so. Each figure of an R Markdown or Quarto document is read the same way, from the calls on its own page.

Chart size

A chart is drawn at a size in inches, as ggplot2::ggsave() and knitr's fig.width and fig.height size a figure, and its SVG is 72 pixels to the inch: a 10 x 4 in chart is 720 pixels wide and 288 high. The size is the room the chart is laid out in – how far apart its ticks and labels are, how lattice arranges its panels, where Base R puts its titles – and not what maidr reads out: the data, titles and axis labels a reader hears are the same at every size. Only how a reader moves between panels can change: lattice arranges the panels of a chart conditioned on one variable with no layout = for the shape of the page, 1 x 2 at 7 x 5 in and 2 x 1 at 5 x 8 in for two panels, and the subplot grid a reader moves through follows; give layout = to keep it. The size is set by width and height in show() and save_html(), by fig_width and fig_height in render_maidr(), and by the chunk's fig.width and fig.height in an R Markdown or Quarto document (see maidr_on()). Nothing else sets it: not the size of the device a chart was drawn on, nor the size of the window, viewer or Shiny output it is shown in, which shrinks a chart wider than itself to fit.

Unset, a chart is 7 x 5 in. A candlestick chart is 12 x 6 in, and is never drawn smaller than that: quantmod's chartSeries() needs the room for its title, date range and date labels. A smaller size asked for is enlarged, with a message naming the size the chart is drawn at. A side larger than 50 in is refused, as ggplot2::ggsave() refuses one: the size is in inches, not the pixels maidr_output() takes.

A Base R chart's margins and text take the same room at every size, as do the cells a layout() call sizes with lcm(), so a chart can be too small for them – R itself stops with "figure margins too large", or for those cells "figure region too large", at such a size. maidr draws the chart with the margins and text size its par() calls set, so it fits where R draws it with them. Asked for a size too small, maidr stops too, with an error naming the size, rather than show an empty chart: draw it larger. With no size asked for, a chart too small for 7 x 5 in, such as a par(mfrow) grid of five rows or more, is drawn on the 7 x 7 in page maidr laid every Base R chart out on before it drew one at its size. Where that is too small too, it is drawn on the smallest larger page that leaves each of its plots a sixth of an inch, 12 px, each way, each side grown in whole inches only as far as it needs: 7 x 9 in for six rows, 12 x 5 in for twelve columns. A message names the size it is drawn at. The picture of a Base R chart maidr cannot read is held to its size in the same way.

Examples

# ggplot2 bar chart
library(ggplot2)
p <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
  geom_bar(stat = "identity")
# \donttest{
maidr::save_html(p, tempfile(fileext = ".html"))

# The same chart, 10 inches wide and 4 high
maidr::save_html(p, tempfile(fileext = ".html"), width = 10, height = 4)
# }

# ggplot2 violin plot
p_violin <- ggplot(mtcars, aes(x = factor(cyl), y = mpg)) +
  geom_violin(fill = "lightblue", alpha = 0.7) +
  labs(title = "MPG by Cylinders", x = "Cylinders", y = "MPG")
# \donttest{
maidr::save_html(p_violin, tempfile(fileext = ".html"))
# }

# lattice chart [experimental]
# \donttest{
if (requireNamespace("lattice", quietly = TRUE)) {
  p_lattice <- lattice::bwplot(factor(cyl) ~ mpg, data = mtcars)
  maidr::save_html(p_lattice, tempfile(fileext = ".html"))
}
# }

# Base R example (requires interactive session for function patching)
if (interactive()) {
  barplot(c(10, 20, 30), names.arg = c("A", "B", "C"))
  maidr::save_html(file = tempfile(fileext = ".html"))
}