Skip to content

Commit a1a79f5

Browse files
committed
add support for partial updates in style(), fixes #1342
1 parent a245f20 commit a1a79f5

File tree

3 files changed

+54
-2
lines changed

3 files changed

+54
-2
lines changed

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Upgraded to plotly.js v1.40.1.
66
* The `orca()` function now supports conversion of much larger figures (#1322) and works without a mapbox api token (#1314).
7+
* The `style()` function now supports "partial updates" (i.e. modification of a particular property of an object, rather than the entire object). For example, notice how the first plot retains the original marker shape (a square): `p <- plot_ly(x = 1:10, y = 1:10, symbol = I(15)); subplot(style(p, marker.color = "red"), style(p, marker = list(color = "red")))` (#1342).
78

89
## BUG FIXES
910

R/style.R

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
#' # keep the hover info for points, but remove it for the line/ribbon
1818
#' style(p, hoverinfo = "none", traces = c(2, 3))
1919
#'
20+
#'
21+
#' # to turn the marker's red, without destroying the marker's other properties
22+
#' # https://github.com/plotly/plotly.js/issues/1866#issuecomment-314115744
23+
#' style(p, marker.color = "red", traces = 1)
24+
#' style(p, marker.line.color = "red", traces = 1)
25+
#'
2026
style <- function(p, ..., traces = NULL) {
2127
p <- plotly_build(p)
2228
nTraces <- length(p$x$data)
@@ -25,10 +31,30 @@ style <- function(p, ..., traces = NULL) {
2531
traces <- traces[!idx]
2632
if (any(idx)) warning("You've referenced non-existent traces", call. = FALSE)
2733
argz <- list(...)
34+
35+
# argument names that contain a '.' signify a "partial update"
36+
isPartialUpdate <- grepl("\\.", names(argz))
37+
# expand these special arguments to a suitable list object,
38+
# `list(marker.color = "red")`, to `list(marker = list(color = "red"))`
39+
nms <- strsplit(names(argz), "\\.")
40+
for (i in seq_along(nms)) {
41+
nm <- nms[[i]]
42+
if (length(nm) == 1) next
43+
val <- argz[[i]]
44+
for (j in seq(length(nm), 2)) {
45+
val <- setNames(list(val), nm[j])
46+
}
47+
argz[[i]] <- val
48+
}
49+
argz <- setNames(argz, unlist(lapply(nms, `[[`, 1)))
50+
51+
# perform the replacement
2852
for (i in traces) {
29-
for (j in names(argz)) {
30-
p$x$data[[i]][[j]] <- argz[[j]]
53+
for (j in seq_along(argz)) {
54+
attr <- names(argz)[j]
55+
p$x$data[[i]][[attr]] <- if (isPartialUpdate[j]) modify_list(p$x$data[[i]][[attr]], argz[[attr]]) else argz[[attr]]
3156
}
3257
}
58+
3359
p
3460
}

tests/testthat/test-style.R

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
context("style/restyle functionality")
2+
3+
p1 <- plot_ly(x = 1:10, y = 1:10, symbol = I(15))
4+
marker1 <- plotly_build(p)$x$data[[1]]$marker
5+
6+
test_that("Whole update works as expected", {
7+
p2 <- style(p1, marker = list(color = "red"))
8+
marker2 <- plotly_build(p2)$x$data[[1]]$marker
9+
expect_equal(marker2, list(color = "red"))
10+
11+
p3 <- style(p1, marker = list(line = list(color = "red", width = 10)))
12+
marker3 <- plotly_build(p3)$x$data[[1]]$marker
13+
expect_equal(marker3, list(line = list(color = "red", width = 10)))
14+
})
15+
16+
17+
test_that("Partial update works as expected", {
18+
p4 <- style(p, marker.color = "red")
19+
marker4 <- plotly_build(p4)$x$data[[1]]$marker
20+
expect_equal(marker4, modifyList(marker4, list(color = "red")))
21+
22+
p5 <- style(p, marker.line.color = "red")
23+
marker5 <- plotly_build(p5)$x$data[[1]]$marker
24+
expect_equal(marker5, modifyList(marker5, list(line = list(color = "red"))))
25+
})

0 commit comments

Comments
 (0)