5 min read

plotly 4.8.0 now on CRAN

Need help with R, plotly, data viz, and/or stats? Work with me!

I’m super excited to announce plotly 4.8.0 is now on CRAN! Go ahead and upgrade via:


This release is almost a year in the making and includes a huge amount of improvements, new features, and some slightly breaking changes. This post highlights the biggest and most recent features; but if you already use plotly, I highly recommend going over the full release report as well.

New trace types

Upgrading plotly from 4.7.1 to 4.8.0 implies an upgrade of plotly.js from 1.29.2 to 1.39.2. This means, amongst many other things, seven new trace types. Here’s a list with a link to their relevant online https://plot.ly/r documentation:

Improved static image export

The new orca() function wraps the new orca project for killer exporting of plotly graphs, dashboards, etc to various formats (most notably, svg and pdf!). Simply give orca() a plotly object and a filename with the extension that you desire. Here’s an example of exporting to SVG and post-processing the result in Adobe Illustrator:

p <- plot_ly(z = ~volcano) %>% add_surface()
orca(p, "surface-plot.svg")

Auto margins

Axis objects now default to automargin = TRUE. This helps the axis labels of any plotly graph to be more readable by default:


# plot the number of missing values by city
txhousing %>% 
  group_by(city) %>% 
  summarise(missing = sum(is.na(median))) %>% 
  filter(missing > 0) %>%
    x = ~missing, 
    y = ~forcats::fct_reorder(city, missing)

To get the old behavior back, you can set automargin = FALSE. This hopefully won’t be needed except in extreme edge cases:

layout(.Last.value, yaxis = list(automargin = FALSE))

Localization support

The new locale argument in the config() function makes it easy to switch the language used for date axes and on-graph text (e.g., modebar buttons). This example demonstrates Japanese ("ja") – see ?config for more examples and documentation of other locales.

today <- Sys.Date()
x <- seq.Date(today, today + 360, by = "day")
plot_ly(x = x, y = rnorm(length(x))) %>%
  add_lines() %>%
  config(locale = "ja")

Partial plotly.js bundles

By default, the R package ships with a full bundle of plotly.js, which is quite large (about 2.6 MB in this release). In many cases, graphs can be rendered with a partial plotly.js bundle, which can lead to a 3x reduction in file size! To take advantage, just apply the partial_bundle() function to a plotly object, which (by default) will try and find a suitable bundle.

p <- plot_ly(x = 1:10, y = 1:10) %>% add_markers()
save_widget <- function(p, f) {
  owd <- setwd(dirname(f))
  htmlwidgets::saveWidget(p, f)
  mb <- round(file.info(f)$size / 1e6, 3)
  message("File is: ", mb," MB")
f1 <- tempfile(fileext = ".html")
save_widget(p, f1)
#> File is: 2.94 MB
f2 <- tempfile(fileext = ".html")
save_widget(partial_bundle(p), f2)
#> File is: 0.973 MB

New and improved WebGL renderer

For a while now, we’ve had the ability to switch from SVG to WebGL via the function toWebGL(), which can improve performance when rendering lots of graphical elements. Now there is even more reason to do so as the new WebGL renderer is now much closer to being feature complete with the SVG renderer.

plot_ly(x = rnorm(1e6), y = rnorm(1e6)) %>%
  add_markers(color = I("transparent"), stroke = I("black"), span = I(1)) %>%

MathJax support

LaTeX rendering via MathJax is now possible via the new TeX() function may be used to flag a character vector as LaTeX. To load MathJaX externally (meaning an internet connection is needed for TeX rendering), set the new mathjax argument in config() to "cdn":


plot_ly() %>%
  add_lines(x = zoo::index(co2), y = co2) %>%
    title = TeX("CO_2 \\text{measured in } \\frac{parts}{million}"),
    xaxis = list(title = "Time"),
    yaxis = list(title = TeX("\\text{Atmospheric concentraion of CO}_2"))
  ) %>%
  config(mathjax = "cdn")

To use a local version of MathJax (so that your graphs will render without an internet connection), you need to inform plotly where it’s located. If you don’t already have MathJax locally, I recommend downloading the official MathJax git repo. Here’s how to do that using terminal commands:

$ git clone https://github.com/mathjax/MathJax.git
$ cd MathJax

Now set the PLOTLY_MATHJAX_PATH environment variable so that plotly knows where that MathJax folder lives. I recommend setting this variable in you .Rprofile so you don’t have to reset it everytime you restart R:

$ export PLOTLY_MATHJAX_PATH=`pwd`
$ echo "Sys.setenv('PLOTLY_MATHJAX_PATH' = '$PLOTLY_MATHJAX_PATH')" >> ~/.Rprofile

Once PLOTLY_MATHJAX_PATH is set, specify mathjax="local" in config():


plotly_empty() %>%
  add_trace(x = 1, y = 1, text = TeX("\\alpha"), mode = "text", size = I(100), hoverinfo = "text") %>%
  config(mathjax = "local")

MathJax caveats

  1. At least currently, plotly.js requires SVG-based rendering which doesn’t play nicely with HTML-based rendering (e.g. rmarkdown documents and shiny apps) . If you need both the SVG and HTML rendering, consider <iframe>-ing your plotly graph(s) into the larger document (see here for an example).

  2. Due to the size and nature of MathJax, using htmlwidget::saveWidget() with selfcontained = TRUE won’t work. At least for now, when you need to save a plotly graph (p) with local MathJax, do htmlwidget::saveWidget(p, selfcontained = FALSE)

Other features discussed previously

There are numerous other exciting features that come with this release that I’ve written about previously:

  • sf support via ggplotly(), plot_ly(), plot_geo(), and plot_mapbox().
  • Better control over the stroke (i.e., outline) appearance of various filled graphical marks via the new “special arguments” (stroke, strokes, alpha_stroke, span, and spans).

Read more at: