Skip to content

Commit b54904b

Browse files
committed
merge conflicts
2 parents b8b4c94 + d20bda8 commit b54904b

16 files changed

+282
-45
lines changed

DESCRIPTION

+5-3
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ Imports:
4343
rlang,
4444
crosstalk,
4545
purrr,
46-
data.table
46+
data.table,
47+
promises
4748
Suggests:
4849
MASS,
4950
maps,
@@ -52,7 +53,7 @@ Suggests:
5253
testthat,
5354
knitr,
5455
devtools,
55-
shiny (>= 0.14),
56+
shiny (>= 1.1.0),
5657
curl,
5758
rmarkdown,
5859
Rserve,
@@ -68,7 +69,8 @@ Suggests:
6869
png,
6970
IRdisplay,
7071
processx,
71-
plotlyGeoAssets
72+
plotlyGeoAssets,
73+
rstudioapi
7274
Remotes:
7375
tidyverse/ggplot2
7476
LazyData: true

NEWS.md

+40-13
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,61 @@
22

33
## NEW FEATURES & IMPROVEMENTS
44

5-
* Upgraded to plotly.js v1.38.1. A _huge_ amount of features and improvements have been made since v1.29.2 (i.e., the version included in the last CRAN release of the R package - v4.7.1). Highlights include a complete re-write of `scattergl` to make it nearly feature complete with `scatter`, localization of text rendering (i.e., international translations), and two new trace types (`violin` & `table`). Read more about the v1.32.0 release [here](https://codeburst.io/notes-from-the-latest-plotly-js-release-b035a5b43e21) and the complete list of changes [here](https://github.com/plotly/plotly.js/releases).
5+
### plotly.js and `plot_ly()` specific improvements
6+
7+
* Upgraded to plotly.js v1.38.2. A _huge_ amount of features and improvements have been made since v1.29.2 (i.e., the version included in the last CRAN release of the R package - v4.7.1). Highlights include a complete re-write of `scattergl` to make it nearly feature complete with `scatter`, localization of text rendering (i.e., international translations), and six new trace types (`cone`, `scatterpolar`, `scatterpolargl`, `splom`, `table`, & `violin`)! See [here](https://github.com/plotly/plotly.js/releases) for a complete list of plotly.js-specific improvements.
68
* Support for **sf** (simple feature) data structures was added to `plot_ly()`, `plot_mapbox()`, and `plot_geo()` (via the new `add_sf()` function). See [this blog post](https://blog.cpsievert.me/2018/03/30/visualizing-geo-spatial-data-with-sf-and-plotly) for an overview.
7-
* New "special arguments" `stroke`, `strokes`, `alpha_stroke`, `span`, and `spans` were added for easier control over the stroke (i.e., outline) appearance of various (filled) graphical marks. For an overview, see the **sf** blog post linked to in the bullet point above and the new package demos (list all demos with `demo(package = "plotly")`).
9+
* 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`). For an overview, see the **sf** blog post linked to in the bullet point above and the new package demos (list all demos with `demo(package = "plotly")`).
10+
11+
### `ggplotly()` specific improvements
12+
13+
* `ggplotly()` now supports conversion of **ggplot2**'s `geom_sf()`.
14+
* One may now inform `ggplotly()` about the relevant **shiny** output size via `session$clientData`. This ensures `ggplotly()` sizing is closer to **ggplot2** sizing, even on window resize. For an example, run `plotly_example("shiny", "ggplotly_sizing")`.
15+
16+
### Other improvements relevant for all **plotly** objects
17+
818
* The selection (i.e., linked-brushing) mode can now switch from 'transient' to 'persistent' by holding the 'shift' key. It's still possible to _force_ persistent selection by setting `persistent = TRUE` in `highlight()`, but `persistent = FALSE` (the default) is now recommended since it allows one to switch between [persistent/transient selection](https://plotly-book.cpsievert.me/linking-views-without-shiny.html#transient-versus-persistent-selection) in the browser, rather than at the command line.
19+
* The `highlight()` function gains a `debounce` argument for throttling the rate at which `on` events may be fired. This is mainly useful for improving user experience when `highlight(on = "plotly_hover")` and mousing over relevant markers at a rapid rate (#1277)
920
* The new `partial_bundle()` function makes it easy to leverage [partial bundles of plotly.js](https://github.com/plotly/plotly.js#partial-bundles) for reduced file sizes and faster render times.
10-
* The `config()` function gains a `locale` argument for easily changing localization defaults (see #1270). This makes it possible localize date axes, and in some cases, modebar buttons (see #1270)
11-
* One may now inform `ggplotly()` about the relevant **shiny** output size via `session$clientData`. This ensures `ggplotly()` sizing is closer to **ggplot2** sizing, even on window resize. For an example, run `plotly_example("shiny", "ggplotly_sizing")`.
12-
* Instead of an error, `ggplotly(NULL, "message")` and `plotly_build(NULL, "message")` now returns `htmltools::div("message")`, making it easier to relay messages in shiny when data isn't yet ready to plot (see #1116)
13-
* The `animation_button()` function gains a `label` argument, making it easier to control the label of an animation button generated through the `frame` API (see #1205).
21+
* The `config()` function gains a `locale` argument for easily changing localization defaults (#1270). This makes it possible localize date axes, and in some cases, modebar buttons (#1270).
22+
* Instead of an error, `ggplotly(NULL, "message")` and `plotly_build(NULL, "message")` now returns `htmltools::div("message")`, making it easier to relay messages in shiny when data isn't yet ready to plot (#1116).
23+
* The `animation_button()` function gains a `label` argument, making it easier to control the label of an animation button generated through the `frame` API (#1205).
24+
* Support for async rendering of inside **shiny** apps using the [promises](https://rstudio.github.io/promises/) package (#1209).
1425

1526
## CHANGES
1627

28+
### `plot_ly()` specific changes
29+
30+
* The `name` attribute is now a "special `plot_ly()` argument" and behaves similar to `split` (it ensures a different trace for every unique value supplied). Although this leads to a breaking change (`name` was previously appended to an automatically generated trace name), it leads to a more flexible and transparent API. Those that wish to have the old behavior back should provide relevant mappings to the `name` attributes (e.g. `plot_ly(mtcars, x = ~wt, y = ~mpg, color = ~factor(vs), name = "a")` should become `plot_ly(mtcars, x = ~wt, y = ~mpg, color = ~factor(vs), name = ~paste(vs, "\na"))`)
1731
* The `color` argument now maps to `fillcolor`, making it much easier to use polygon fills to encode data values (e.g., choropleth maps). For backwards-compatibilty reasons, when `color` maps to `fillcolor`, `alpha` defaults to 0.5 (instead of 1). For an example, `plot_mapbox(mn_res, color = ~INDRESNAME)` or `plot_mapbox(mn_res, split = ~INDRESNAME, color = ~AREA, showlegend = FALSE, stroke = I("black"))`.
1832
* The `color` argument no longer automatically add `"markers"` to the `mode` attribute for scatter/scattergl trace types. Those who wish to have the old behavior back, should add `"markers"` to the `mode` explicity (e.g., change `plot_ly(economics, x = ~pce, y = ~pop, color = ~as.numeric(date), mode = "lines")` to `plot_ly(economics, x = ~pce, y = ~pop, color = ~as.numeric(date), mode = "lines+markers")`).
1933
* The `size` argument now informs a default [error_[x/y].width](https://plot.ly/r/reference/#scatter-error_x-width) (and `span` informs [error_[x/y].thickness](https://plot.ly/r/reference/#scatter-error_x-thickness)). Note you can override the default by specifying directly (e.g. `plot_ly(x = 1:10, y = 1:10, size = I(10), error_x = list(value = 5, width = 0))`).
2034
* `layout.showlegend` now defaults to `TRUE` for a *single* pie trace. This is a more sensible default and matches pure plotly.js behavior.
21-
* The `elementId` field is no longer populated, which fixes the "Ignoring explicitly provided widget ID" warning in shiny applications (see #985).
35+
36+
### Other changes relevant for all **plotly** objects
37+
38+
* The `elementId` field is no longer populated, which fixes the "Ignoring explicitly provided widget ID" warning in shiny applications (#985).
2239

2340
## BUG FIXES
2441

42+
### `ggplotly()` specific fixes
2543

2644
* The default `height`/`width` that `ggplotly()` assumes is now more consistently correct in various context, but it also now requires access to one of the following devices: `Cairo::Cairo()`, `png()`, or `jpg()`.
27-
* In RStudio, `ggplotly()` was ignoring a specified `height`/`width` (see #1190).
28-
* `ggplotly()` now uses fixed heights for facet strips meaning that their height is still correct after a window resize (see #1265).
29-
* Bug fix for linking views with crosstalk where the source of the selection is an aggregated trace (see #1218).
30-
* Fixed algorithm for coercing the proposed layout to the plot schema (see #1156).
31-
* `add_*()` no longer inherits `crosstalk::SharedData` key information when `inherit = FALSE` (see #1242).
32-
* The `limits` argument of `colorbar()` wasn't being applied to `line.color`/`line.cmin`/`line.cmax` (see #1236).
45+
* In RStudio, `ggplotly()` was ignoring a specified `height`/`width` (#1190).
46+
* `ggplotly()` now uses fixed heights for facet strips meaning that their height is still correct after a window resize (#1265).
47+
48+
### `plot_ly()` specific fixes
49+
50+
* The `limits` argument of `colorbar()` wasn't being applied to `line.color`/`line.cmin`/`line.cmax` (#1236).
51+
* The `legendgroup` can now properly map data values (#1148).
52+
53+
### Other fixes relevant for all **plotly** objects
54+
55+
* Bug fix for linking views with crosstalk where the source of the selection is an aggregated trace (#1218).
56+
* Resizing behavior, after updating `height`/`width` via **shiny** reactive values, is now correct (#1068).
57+
* Fixed algorithm for coercing the proposed layout to the plot schema (#1156).
58+
* `add_*()` no longer inherits `crosstalk::SharedData` key information when `inherit = FALSE` (#1242).
59+
3360

3461
# 4.7.1
3562

R/highlight.R

+8-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
#' @param opacityDim a number between 0 and 1 used to reduce the
4444
#' opacity of non-selected traces (by multiplying with the existing opacity).
4545
#' @param selected attributes of the selection, see [attrs_selected()].
46+
#' @param debounce amount of time to wait before firing an event (in milliseconds).
47+
#' The default of 0 means do not debounce at all.
48+
#' Debouncing is mainly useful when `on = "plotly_hover"` to avoid firing too many events
49+
#' when users clickly move the mouse over relevant graphical marks.
4650
#' @param ... currently not supported.
4751
#' @export
4852
#' @author Carson Sievert
@@ -80,7 +84,8 @@ highlight <- function(p, on = "plotly_click", off,
8084
dynamic = FALSE, color = NULL,
8185
selectize = FALSE, defaultValues = NULL,
8286
opacityDim = getOption("opacityDim", 0.2),
83-
selected = attrs_selected(), ...) {
87+
selected = attrs_selected(), debounce = 0,
88+
...) {
8489

8590
# currently ... is not-supported and will catch
8691
# some arguments we supported at one point
@@ -154,7 +159,8 @@ highlight <- function(p, on = "plotly_click", off,
154159
selectize = selectize,
155160
defaultValues = defaultValues,
156161
opacityDim = opacityDim,
157-
selected = selected
162+
selected = selected,
163+
debounce = debounce
158164
)
159165

160166
p

R/layers2traces.R

+2-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ to_basic.GeomRect <- function(data, prestats_data, layout, params, p, ...) {
273273
#' @export
274274
to_basic.GeomSf <- function(data, prestats_data, layout, params, p, ...) {
275275

276-
data <- sf::st_as_sf(data)
276+
data[["geometry"]] <- sf::st_sfc(data[["geometry"]])
277+
data <- sf::st_as_sf(data, sf_column_name = "geometry")
277278
geom_type <- sf::st_geometry_type(data)
278279
# st_cast should "expand" a collection into multiple rows (one per feature)
279280
if ("GEOMETRYCOLLECTION" %in% geom_type) {

R/plotly.R

+14-9
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#' (e.g. `plot_ly(x = 1:10, y = 1:10, color = I("red"), marker = list(color = "blue"))`).
2424
#' @param type A character string specifying the trace type (e.g. `"scatter"`, `"bar"`, `"box"`, etc).
2525
#' If specified, it *always* creates a trace, otherwise
26+
#' @param name Values mapped to the trace's name attribute. Since a trace can
27+
#' only have one name, this argument acts very much like `split` in that it
28+
#' creates one trace for every unique value.
2629
#' @param color Values mapped to relevant 'fill-color' attribute(s)
2730
#' (e.g. [fillcolor](https://plot.ly/r/reference#scatter-fillcolor),
2831
#' [marker.color](https://plot.ly/r/reference#scatter-marker-color),
@@ -124,7 +127,7 @@
124127
#'
125128
#' }
126129
#'
127-
plot_ly <- function(data = data.frame(), ..., type = NULL,
130+
plot_ly <- function(data = data.frame(), ..., type = NULL, name,
128131
color, colors = NULL, alpha = NULL,
129132
stroke, strokes = NULL, alpha_stroke = 1,
130133
size, sizes = c(10, 100),
@@ -160,6 +163,7 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
160163
}
161164

162165
# tack on variable mappings
166+
attrs$name <- if (!missing(name)) name
163167
attrs$color <- if (!missing(color)) color
164168
attrs$stroke <- if (!missing(stroke)) stroke
165169
attrs$size <- if (!missing(size)) size
@@ -193,10 +197,10 @@ plot_ly <- function(data = data.frame(), ..., type = NULL,
193197
# we always deal with a _list_ of traces and _list_ of layouts
194198
# since they can each have different data
195199
layout = list(
196-
width = width,
197-
height = height,
198-
# sane margin defaults (mainly for RStudio)
199-
margin = list(b = 40, l = 60, t = 25, r = 10)
200+
width = width,
201+
height = height,
202+
# sane margin defaults (mainly for RStudio)
203+
margin = list(b = 40, l = 60, t = 25, r = 10)
200204
),
201205
source = source
202206
)
@@ -441,7 +445,8 @@ typedArrayPolyfill <- function() {
441445
# and bundle size at print time.
442446
plotlyMainBundle <- function() {
443447
htmltools::htmlDependency(
444-
"plotly-main", "1.38.1",
448+
"plotly-main",
449+
version = "1.38.2",
445450
src = depPath("plotlyjs"),
446451
script = "plotly-latest.min.js",
447452
all_files = FALSE
@@ -450,7 +455,8 @@ plotlyMainBundle <- function() {
450455

451456
plotlyHtmlwidgetsCSS <- function() {
452457
htmltools::htmlDependency(
453-
"plotly-htmlwidgets-css", "1.38.1",
458+
"plotly-htmlwidgets-css",
459+
version = plotlyMainBundle()$version,
454460
src = depPath("plotlyjs"),
455461
stylesheet = "plotly-htmlwidgets.css",
456462
all_files = FALSE
@@ -472,7 +478,6 @@ locale_dependency <- function(locale) {
472478
)
473479
}
474480

475-
476481
# some locales rely on a base/main locale (e.g. de-CH relies on de)
477482
# https://codepen.io/etpinard/pen/pKvLVX?editors=1010
478483
scripts <- paste0(locale, ".js")
@@ -487,7 +492,7 @@ locale_dependency <- function(locale) {
487492
name = paste0("plotly-locale-", locale),
488493
version = plotlyMainBundle()$version,
489494
src = list(file = locale_dir),
490-
script = scripts,
495+
script = tolower(scripts),
491496
all_files = FALSE
492497
)
493498
}

R/plotly_build.R

+4-8
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ plotly_build.plotly <- function(p, registerFrames = TRUE) {
189189
dataArrayAttrs, special_attrs(trace), npscales(), "frame",
190190
# for some reason, text isn't listed as a data array in some traces
191191
# I'm looking at you scattergeo...
192-
".plotlyGroupIndex", "text", "key", "fillcolor"
192+
".plotlyGroupIndex", "text", "key", "fillcolor", "name", "legendgroup"
193193
)
194194
tr <- trace[names(trace) %in% allAttrs]
195195
# TODO: does it make sense to "train" matrices/2D-tables (e.g. z)?
@@ -205,16 +205,12 @@ plotly_build.plotly <- function(p, registerFrames = TRUE) {
205205
isAsIs <- vapply(builtData, function(x) inherits(x, "AsIs"), logical(1))
206206
isDiscrete <- vapply(builtData, is.discrete, logical(1))
207207
# note: can only have one linetype per trace
208-
isSplit <- names(builtData) %in% c("split", "linetype", "frame", "fillcolor") |
208+
isSplit <- names(builtData) %in% c("split", "linetype", "frame", "fillcolor", "name") |
209209
!isAsIs & isDiscrete & names(builtData) %in% c("symbol", "color")
210210
if (any(isSplit)) {
211211
paste2 <- function(x, y) if (identical(x, y)) x else paste(x, y, sep = br())
212212
splitVars <- builtData[isSplit]
213-
traceIndex <- Reduce(paste2, splitVars)
214-
if (!is.null(trace$name)) {
215-
traceIndex <- paste2(traceIndex, trace$name)
216-
}
217-
builtData[[".plotlyTraceIndex"]] <- traceIndex
213+
builtData[[".plotlyTraceIndex"]] <- Reduce(paste2, splitVars)
218214
# in registerFrames() we need to strip the frame from .plotlyTraceIndex
219215
# so keep track of which variable it is...
220216
trace$frameOrder <- which(names(splitVars) %in% "frame")
@@ -980,7 +976,7 @@ traceify <- function(dat, x = NULL) {
980976
new_dat <- list()
981977
for (j in seq_along(lvls)) {
982978
new_dat[[j]] <- lapply(dat, function(y) recurse(y, n, x %in% lvls[j]))
983-
new_dat[[j]]$name <- lvls[j]
979+
new_dat[[j]]$name <- new_dat[[j]]$name %||% lvls[j]
984980
}
985981
return(new_dat)
986982
}

R/shiny.R

+10-1
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,19 @@ renderPlotly <- function(expr, env = parent.frame(), quoted = FALSE) {
3838
if (!quoted) { expr <- substitute(expr) } # force quoted
3939
# this makes it possible to pass a ggplot2 object to renderPlotly()
4040
# https://github.com/ramnathv/htmlwidgets/issues/166#issuecomment-153000306
41-
expr <- as.call(list(call("::", quote("plotly"), quote("ggplotly")), expr))
41+
expr <- as.call(list(call(":::", quote("plotly"), quote("prepareWidget")), expr))
4242
shinyRenderWidget(expr, plotlyOutput, env, quoted = TRUE)
4343
}
4444

45+
# Converts a plot, OR a promise of a plot, to plotly
46+
prepareWidget <- function(x) {
47+
if (promises::is.promising(x)) {
48+
promises::then(x, ggplotly)
49+
} else {
50+
ggplotly(x)
51+
}
52+
}
53+
4554

4655
#' Access plotly user input event data in shiny
4756
#'

R/utils.R

+13-1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ verify_attr <- function(proposed, schema) {
492492
proposed[[attr]] <- structure(proposed[[attr]], apiSrc = TRUE)
493493
}
494494

495+
if (length(proposed[["name"]]) > 0) {
496+
proposed$name <- uniq(proposed$name)
497+
}
498+
495499
# do the same for "sub-attributes"
496500
if (identical(role, "object")) {
497501
proposed[[attr]] <- verify_attr(proposed[[attr]], schema[[attr]])
@@ -1019,5 +1023,13 @@ try_library <- function(pkg, fun = NULL) {
10191023
}
10201024

10211025
is_rstudio <- function() {
1022-
identical(Sys.getenv("RSTUDIO", NA), "1")
1026+
requireNamespace('rstudioapi', quietly = TRUE) && rstudioapi::isAvailable()
1027+
}
1028+
1029+
1030+
# TODO: warn Windows users to use 1.2.x in some scenarios?
1031+
# https://github.com/ropensci/plotly/issues/1211
1032+
rstudio_version <- function() {
1033+
if (!is_rstudio()) return(NA)
1034+
rstudioapi::versionInfo()$version
10231035
}

inst/examples/shiny/async/app.R

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
library(shiny)
2+
library(plotly)
3+
library(ggplot2)
4+
library(promises)
5+
library(future)
6+
plan(multisession)
7+
8+
ui <- fluidPage(
9+
plotlyOutput("plot1"),
10+
plotlyOutput("plot2"),
11+
plotlyOutput("plot3"),
12+
plotlyOutput("plot4")
13+
)
14+
15+
server <- function(input, output, session) {
16+
output$plot1 <- renderPlotly({
17+
# Async plot_ly
18+
future({ Sys.sleep(2); cars }) %...>%
19+
plot_ly(x = ~speed, y = ~dist, type = "scatter", mode = "markers")
20+
})
21+
22+
output$plot2 <- renderPlotly({
23+
# Async ggplotly
24+
future({ Sys.sleep(2); mtcars }) %...>%
25+
{ ggplot(., aes(hp, mpg)) + geom_point() } %...>%
26+
ggplotly()
27+
})
28+
29+
output$plot3 <- renderPlotly({
30+
# Not async
31+
plot_ly(iris, x = ~Sepal.Length, y = ~Sepal.Width,
32+
type = "scatter", mode = "markers")
33+
})
34+
35+
output$plot4 <- renderPlotly({
36+
# Ensure errors are handled properly (should be blank)
37+
future({}) %...>%
38+
{ req(FALSE) }
39+
})
40+
}
41+
42+
shinyApp(ui, server)

inst/htmlwidgets/lib/plotlyjs/plotly-latest.min.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)