Skip to content

Commit 32dde41

Browse files
pull[bot]cpsievertalystWimpmur002
authored
[pull] master from ropensci:master (#2)
* New version of scales no longer 'spans the gamut' of a qualitative color palette * reduce Reduce() for merging lists use do.call() instead to avoid quadratic complexity of growing lists * ensure_one(): reduce noise if attrs are NULL ignore NULL values * ggplotly: fix Xaxis anchor if the last row incomplete attach X axis to the last non-empty row in a column * stylistic changes * validate new visual baselines * Doesn't seem like we need to handle yaxis being a factor and if we do, it likely needs a different fix * update shinytest baselines * ugh maintaining shinytest tests for htmlwidgets is a real pain * update sf baselines * go back to using ggplotly() to prepare the widget for shiny rendering * the extra call to plotly_build() forces more computation then necessary and fixes plotly#1569 * Generation of non-intercept data in hline/vline should respect coord_flip(), closes plotly#1519 * update news; fix typo * Account for new changes in ggplot2's internal API, fixes plotly#1561 * Break values of positional scales have moved from to * Text labels of positional scales have moved from to * sf graticule degree labels are now quoted? * include braces * gsub * moar braces * new sf baselines * update news * upgrade to plotly.js v1.49.0 * upgrade to plotly.js v1.49.2 * upgrade to plotly.js v1.49.4 * update baseline * update shinytest baseline * make a deep copy of x.layout.width/x.layout.height for use in the resize method, closes plotly#1553 * Wrap user-supplied expression in evalq(), closes plotly#1528 * Use shiny::installExprFunction to register debug hooks * Asynchronously register plot events * Revert "Merge pull request plotly#1539 from ropensci/renderWidgetPrep" This reverts commit d416cea, reversing changes made to d11bb5a. * no need to be making deep copies * Improvements to algorithm for attaching key attribute for shiny's event data, fixes plotly#1610 * Account for pointNumbers * Do nothing if we don't recognize the case * When pointNumber is a constant, relay it as such * handle the 3 cases separately * use idx instead of i * update news * Call setInputValue only if it's defined, closes plotly#1624 * Revert "Revert "Merge pull request plotly#1539 from ropensci/renderWidgetPrep"" This reverts commit 2856731. * pass along a quoted expr that calls func() * Revert "go back to using ggplotly() to prepare the widget for shiny rendering" This reverts commit a0fa68f. * update news * verify_webgl() shouldn't warn about types that are already gl, closes plotly#1569 * fix test * Do not create structure with NULL to remove warnings * Fix management of environments in renderPlotly(), fixes plotly#1639 Both assignment and evaluation of func() should happen in the local environment * Add test to prove plotly#1299 fix * proposed change to avoid peeking at 'grid' unit internals * improve previous commit * refactor Paul's unit type commits from plotly#1646 * Some CRAN builds don't have pandoc * plot_mapbox() shouldn't force a scattermapbox trace type, closes plotly#1608 * fix R CMD check notes * r-devel apparently doesn't yet have grid::unitType() * remove outdated travis config * Validate changes visual baselines due to changes in R3.6's new RNG method * Add support for new plotly_sunburstclick event, closes plotly#1648 * validate new shinytest baselines * update news * fix silly mistake from 3cbccfc * document * test expectation should account for changes in the default color palette on r-devel * improve the aforementioned test example and add a visual test * Ignore calculated aesthetics that match specified aesthestics After tidyverse/ggplot2@10fa0014, it's possible for calculated aes to exist for all default_aes * fix broken link raster2uri and improve the description * cran hyperlinks must be https * fix roxygen warning * In contrast to attr(x, unit), the new grid::unitType() function always return a vector the same length as it's input * bump to release version; submit to CRAN * Respect sf's plot12 graticule attribute when building axis ticks, fixes plotly#1673 * Remove missing values in ticktext/tickvals As discussed in tidyverse/ggplot2#3566 (comment), it's now possible for the ggplot2 labels/positions to contains missing values, and we should be able to simply ignore them * link to comment * remove outdated/bad test expectation...the visual baseline covers it * Don't assume sf geometry is always accessible via [['geometry']], fixes plotly#1659 * validate baselines * update news * update to plotly.js 1.52.2 * new baselines * Add image and treemap visual tests. Also, ensure treemap's stroke reflects the paper's bgcolor * Add Object.setPrototypeOf polyfill for shinytest and update shinytest json baseline * Add add_image() for easier rendering of image traces via raster objects * Bump version, update news, document, add unit test for add_image() * roxygen escapes % now * Only call locale_dependency() for locales not included with standard bundle, closes plotly#1686 * CRAN submission * plot_mapbox() should default to scattermapbox unless z is present, fixes plotly#1707 * add visual test for plotly#1674 * update poor test expectations that assume stringsAsFactors defaults to TRUE * bump version; update news * update visual tests * remove rnaturalearth dependency in tests Co-authored-by: Carson Sievert <[email protected]> Co-authored-by: Alexey Stukalov <[email protected]> Co-authored-by: Wim <[email protected]> Co-authored-by: Paul Murrell <[email protected]>
1 parent 8a10cdf commit 32dde41

File tree

462 files changed

+1248
-664
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

462 files changed

+1248
-664
lines changed

.travis.yml

-7
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,3 @@ before_install:
3434
before_script:
3535
- if [[ "$TRAVIS_R_VERSION_STRING" == "release" ]]; then docker run -e GITHUB_PAT=$GITHUB_PAT -e MAPBOX_TOKEN=$MAPBOX_TOKEN -e VMODE="ci" -v $(pwd):/home/plotly --privileged cpsievert/plotly-orca; fi
3636

37-
# work around temporary travis + R 3.5 bug
38-
r_packages: devtools
39-
40-
# temporary: needed for plotly input testing in shiny
41-
r_github_packages:
42-
- rstudio/shinytest
43-
- r-lib/remotes

DESCRIPTION

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: plotly
22
Title: Create Interactive Web Graphics via 'plotly.js'
3-
Version: 4.9.0.9000
3+
Version: 4.9.2.1
44
Authors@R: c(person("Carson", "Sievert", role = c("aut", "cre"),
55
email = "[email protected]", comment = c(ORCID = "0000-0002-4958-2844")),
66
person("Chris", "Parmer", role = "aut",
@@ -72,6 +72,6 @@ Suggests:
7272
plotlyGeoAssets,
7373
forcats
7474
LazyData: true
75-
RoxygenNote: 6.1.1
75+
RoxygenNote: 7.0.2
7676
Encoding: UTF-8
7777
Roxygen: list(markdown = TRUE)

NAMESPACE

+1
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export(add_heatmap)
9494
export(add_histogram)
9595
export(add_histogram2d)
9696
export(add_histogram2dcontour)
97+
export(add_image)
9798
export(add_lines)
9899
export(add_markers)
99100
export(add_mesh)

NEWS.md

+38-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,45 @@
1-
# 4.9.0.9000
1+
# 4.9.2.1
2+
3+
This is minor patch release with a few minor bug fixes and updates test expectations in anticipation of new R 4.0 defaults.
4+
5+
## BUG FIXES
6+
7+
* `plot_mapbox()` now correctly defaults to a scattermapbox trace (unless z is present, then it defaults to choroplethmapbox) (#1702).
8+
* `ggplotly()` now correctly resolves overlapping axis tick text in `coord_sf()` (#1673).
9+
* A false-positive warning is no longer thrown when attempting to cast `toWebGL()` (#1569).
10+
11+
# 4.9.2
12+
13+
## Changes to plotly.js
14+
15+
* This version of the R package upgrades the version of the underlying plotly.js library from v1.49.4 to v1.52.2. This includes many bug fixes, improvements, as well as 2 new trace types: `treemap` and `image`. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes.
16+
17+
## IMPROVEMENTS
18+
19+
* The `add_image()` function was added to make it easier to create image traces via `raster` objects.
20+
21+
## BUG FIXES
22+
23+
* `add_sf()`/`geom_sf()` now correctly handle geometry columns that are named something other than `"geometry"` (#1659).
24+
* Specifying an english locale no longer results in error (#1686).
25+
26+
# 4.9.1
227

328
## Changes to plotly.js
429

5-
* This version of the R package upgrades the version of the underlying plotly.js library from v1.46.1 to v1.48.3. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes.
30+
* This version of the R package upgrades the version of the underlying plotly.js library from v1.46.1 to v1.49.4. The [plotly.js release page](https://github.com/plotly/plotly.js/releases) has the full list of changes.
31+
32+
## IMPROVEMENTS
33+
34+
* `event_data()` gains support for the `plotly_sunburstclick` event (#1648)
35+
36+
## BUG FIXES
637

38+
* Fixed an issue with correctly capturing the return value of user-expressions to `renderPlotly()` (#1528).
39+
* Fixed a resizing issue where graphs could be incorrectly resized to their initial size in some cases (#1553).
40+
* `ggplotly()` now positions the x-axis in the last column of a `facet_wrap()` properly (#1501).
41+
* `ggplotly()` now handles `geom_hline()`/`geom_vline()` correctly in conjunction with `coord_flip()` (#1519).
42+
* `event_data()` now correctly relays the `key` attribute for statistical traces (#1610).
743

844
# 4.9.0
945

R/add.R

+38-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ add_data <- function(p, data = NULL) {
2424
#' @inheritParams plot_ly
2525
#' @param p a plotly object
2626
#' @param inherit inherit attributes from [plot_ly()]?
27-
#' @param z a numeric matrix
27+
#' @param z a numeric matrix (unless [add_image()], which wants a raster object, see [as.raster()]).
2828
#' @param x the x variable.
2929
#' @param y the y variable.
3030
#' @param text textual labels.
@@ -393,6 +393,43 @@ add_ribbons <- function(p, x = NULL, ymin = NULL, ymax = NULL, ...,
393393
)
394394
}
395395

396+
#' @inheritParams add_trace
397+
#' @rdname add_trace
398+
#' @param colormodel Sets the colormodel for image traces if `z` is not a raster object.
399+
#' If `z` is a raster object (see [as.raster()]), the `'rgba'` colormodel is always used.
400+
#' @export
401+
add_image <- function(p, z = NULL, colormodel = NULL, ..., data = NULL, inherit = TRUE) {
402+
403+
if (inherit) {
404+
z <- z %||% p$x$attrs[[1]][["z"]]
405+
colormodel <- colormodel %||% p$x$attrs[[1]][["colormodel"]]
406+
}
407+
408+
if (inherits(z, "raster")) {
409+
cols <- col2rgb(z, alpha = TRUE)
410+
dims <- c(dim(z), 4)
411+
z <- array(numeric(prod(dims)), dims)
412+
matrix_ <- function(x) {
413+
matrix(x, byrow = TRUE, nrow = dims[1], ncol = dims[2])
414+
}
415+
z[,,1] <- matrix_(cols["red",])
416+
z[,,2] <- matrix_(cols["green",])
417+
z[,,3] <- matrix_(cols["blue",])
418+
z[,,4] <- matrix_(cols["alpha",])
419+
420+
# Throw if we detect another colormodel
421+
if (!identical(colormodel %||% "rgba", "rgba")) {
422+
warning("Passing a raster object to z requires rgba colormodel")
423+
}
424+
colormodel <- "rgba"
425+
}
426+
427+
add_trace(
428+
p, z = z, colormodel = colormodel, ...,
429+
data = data, type = "image"
430+
)
431+
}
432+
396433
#' @inheritParams add_trace
397434
#' @rdname add_trace
398435
#' @param r For polar chart only. Sets the radial coordinates.

R/embed.R

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#' Embed a plot as an iframe into a Jupyter Notebook
22
#' @param x a plotly object
33
#' @param width attribute of the iframe. If `NULL`, the width in
4-
#' `plot_ly` is used. If that is also `NULL`, '100\%' is the default.
4+
#' `plot_ly` is used. If that is also `NULL`, '100%' is the default.
55
#' @param height attribute of the iframe. If `NULL`, the height in
66
#' `plot_ly` is used. If that is also `NULL`, '400px' is the default.
77
#' @param file deprecated.

R/ggplotly.R

+75-46
Original file line numberDiff line numberDiff line change
@@ -465,37 +465,51 @@ gg2list <- function(p, width = NULL, height = NULL,
465465

466466
# panel -> plotly.js axis/anchor info
467467
# (assume a grid layout by default)
468-
layout$layout$xaxis <- layout$layout$COL
469-
layout$layout$yaxis <- layout$layout$ROW
470-
layout$layout$xanchor <- nRows
471-
layout$layout$yanchor <- 1
468+
layout$layout <- dplyr::mutate(
469+
layout$layout,
470+
xaxis = COL,
471+
yaxis = ROW,
472+
xanchor = nRows,
473+
yanchor = 1L
474+
)
472475
if (inherits(plot$facet, "FacetWrap")) {
473-
if (plot$facet$params$free$x) {
474-
layout$layout$xaxis <- layout$layout$PANEL
475-
layout$layout$xanchor <- layout$layout$ROW
476-
}
477-
if (plot$facet$params$free$y) {
478-
layout$layout$yaxis <- layout$layout$PANEL
479-
layout$layout$yanchor <- layout$layout$COL
480-
layout$layout$xanchor <- nPanels
481-
}
482476
if (plot$facet$params$free$x && plot$facet$params$free$y) {
483-
layout$layout$xaxis <- layout$layout$PANEL
484-
layout$layout$yaxis <- layout$layout$PANEL
485-
layout$layout$xanchor <- layout$layout$PANEL
486-
layout$layout$yanchor <- layout$layout$PANEL
477+
layout$layout <- dplyr::mutate(
478+
layout$layout,
479+
xaxis = PANEL,
480+
yaxis = PANEL,
481+
xanchor = PANEL,
482+
yanchor = PANEL
483+
)
484+
} else if (plot$facet$params$free$x) {
485+
layout$layout <- dplyr::mutate(
486+
layout$layout,
487+
xaxis = PANEL,
488+
xanchor = ROW
489+
)
490+
} else if (plot$facet$params$free$y) {
491+
layout$layout <- dplyr::mutate(
492+
layout$layout,
493+
yaxis = PANEL,
494+
yanchor = COL
495+
)
487496
}
497+
# anchor X axis to the lowest plot in its column
498+
layout$layout <- dplyr::group_by_(layout$layout, "xaxis")
499+
layout$layout <- dplyr::mutate(layout$layout, xanchor = max(as.integer(yaxis)))
488500
}
501+
layout$layout <- as.data.frame(layout$layout)
502+
489503
# format the axis/anchor to a format plotly.js respects
490504
layout$layout$xaxis <- paste0("xaxis", sub("^1$", "", layout$layout$xaxis))
491505
layout$layout$yaxis <- paste0("yaxis", sub("^1$", "", layout$layout$yaxis))
492506
layout$layout$xanchor <- paste0("y", sub("^1$", "", layout$layout$xanchor))
493507
layout$layout$yanchor <- paste0("x", sub("^1$", "", layout$layout$yanchor))
494508
# for some layers2traces computations, we need the range of each panel
495-
layout$layout$x_min <- sapply(layout$panel_params, function(z) min(z$x.range %||% z$x_range))
496-
layout$layout$x_max <- sapply(layout$panel_params, function(z) max(z$x.range %||% z$x_range))
497-
layout$layout$y_min <- sapply(layout$panel_params, function(z) min(z$y.range %||% z$y_range))
498-
layout$layout$y_max <- sapply(layout$panel_params, function(z) max(z$y.range %||% z$y_range))
509+
layout$layout$x_min <- sapply(layout$panel_params, function(z) { min(z[["x"]]$dimension %()% z$x.range %||% z$x_range) })
510+
layout$layout$x_max <- sapply(layout$panel_params, function(z) { max(z[["x"]]$dimension %()% z$x.range %||% z$x_range) })
511+
layout$layout$y_min <- sapply(layout$panel_params, function(z) { min(z[["y"]]$dimension %()% z$y.range %||% z$y_range) })
512+
layout$layout$y_max <- sapply(layout$panel_params, function(z) { max(z[["y"]]$dimension %()% z$y.range %||% z$y_range) })
499513

500514
# layers -> plotly.js traces
501515
plot$tooltip <- tooltip
@@ -552,7 +566,7 @@ gg2list <- function(p, width = NULL, height = NULL,
552566
)
553567
# allocate enough space for the _longest_ text label
554568
axisTextX <- theme[["axis.text.x"]] %||% theme[["axis.text"]]
555-
labz <- unlist(lapply(layout$panel_params, "[[", "x.labels"))
569+
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["x"]]$get_labels %()% pp$x.labels }))
556570
lab <- labz[which.max(nchar(labz))]
557571
panelMarginY <- panelMarginY + axisTicksX +
558572
bbox(lab, axisTextX$angle, unitConvert(axisTextX, "npc", "height"))[["height"]]
@@ -564,7 +578,7 @@ gg2list <- function(p, width = NULL, height = NULL,
564578
)
565579
# allocate enough space for the _longest_ text label
566580
axisTextY <- theme[["axis.text.y"]] %||% theme[["axis.text"]]
567-
labz <- unlist(lapply(layout$panel_params, "[[", "y.labels"))
581+
labz <- unlist(lapply(layout$panel_params, function(pp) { pp[["y"]]$get_labels %()% pp$y.labels }))
568582
lab <- labz[which.max(nchar(labz))]
569583
panelMarginX <- panelMarginX + axisTicksY +
570584
bbox(lab, axisTextY$angle, unitConvert(axisTextY, "npc", "width"))[["width"]]
@@ -598,10 +612,19 @@ gg2list <- function(p, width = NULL, height = NULL,
598612
if ("CoordSf" %in% class(p$coordinates)) {
599613
# see CoordSf$render_axis_v
600614
direction <- if (xy == "x") "E" else "N"
601-
idx <- rng$graticule$type == direction & !is.na(rng$graticule$degree_label)
615+
idx <- rng$graticule$type == direction &
616+
!is.na(rng$graticule$degree_label) &
617+
# Respect the logical 'plot12' column which sf constructs for
618+
# determining which tick labels should be drawn
619+
# https://github.com/r-spatial/sf/blob/b49d37/R/graticule.R#L199
620+
# https://github.com/r-spatial/sf/blob/52a8351/R/plot.R#L580
621+
(rng$graticule$plot12 %||% TRUE)
602622
tickData <- rng$graticule[idx, ]
603623
# TODO: how to convert a language object to unicode character string?
604-
rng[[paste0(xy, ".labels")]] <- as.character(tickData[["degree_label"]])
624+
rng[[paste0(xy, ".labels")]] <- sub(
625+
"\\*\\s+degree[ ]?[\\*]?", "&#176;",
626+
gsub("\"", "", tickData[["degree_label"]])
627+
)
605628
rng[[paste0(xy, ".major")]] <- tickData[[paste0(xy, "_start")]]
606629

607630
# If it doesn't already exist (for this panel),
@@ -636,14 +659,7 @@ gg2list <- function(p, width = NULL, height = NULL,
636659
tickExists <- with(rng$graticule, sapply(degree_label, is.language))
637660
if (sum(tickExists) == 0) {
638661
theme$axis.ticks.length <- 0
639-
} else{
640-
# convert the special *degree expression in plotmath to HTML entity
641-
# TODO: can this be done more generally for all ?
642-
rng[[paste0(xy, ".labels")]] <- sub(
643-
"\\*\\s+degree[ ]?[\\*]?", "&#176;", rng[[paste0(xy, ".labels")]]
644-
)
645662
}
646-
647663
}
648664

649665
# stuff like layout$panel_params is already flipped, but scales aren't
@@ -673,16 +689,23 @@ gg2list <- function(p, width = NULL, height = NULL,
673689
isDiscrete <- identical(sc$scale_name, "position_d")
674690
isDiscreteType <- isDynamic && isDiscrete
675691

692+
ticktext <- rng[[xy]]$get_labels %()% rng[[paste0(xy, ".labels")]]
693+
tickvals <- rng[[xy]]$break_positions %()% rng[[paste0(xy, ".major")]]
694+
695+
# https://github.com/tidyverse/ggplot2/pull/3566#issuecomment-565085809
696+
ticktext <- ticktext[!is.na(ticktext)]
697+
tickvals <- tickvals[!is.na(tickvals)]
698+
676699
axisObj <- list(
677700
# TODO: log type?
678701
type = if (isDateType) "date" else if (isDiscreteType) "category" else "linear",
679702
autorange = isDynamic,
680703
range = rng[[paste0(xy, ".range")]] %||% rng[[paste0(xy, "_range")]],
681704
tickmode = if (isDynamic) "auto" else "array",
682-
ticktext = rng[[paste0(xy, ".labels")]],
683-
tickvals = rng[[paste0(xy, ".major")]],
705+
ticktext = ticktext,
706+
tickvals = tickvals,
684707
categoryorder = "array",
685-
categoryarray = rng[[paste0(xy, ".labels")]],
708+
categoryarray = ticktext,
686709
nticks = nrow(rng),
687710
ticks = if (is_blank(axisTicks)) "" else "outside",
688711
tickcolor = toRGB(axisTicks$colour),
@@ -1124,22 +1147,28 @@ unitConvert <- function(u, to = c("npc", "pixels"), type = c("x", "y", "height",
11241147
# from R, but it seems 96 is a reasonable assumption.
11251148
mm2pixels <- function(u) {
11261149
u <- verifyUnit(u)
1127-
if (attr(u, "unit") != "mm") {
1128-
stop("Unit must be in millimeters")
1150+
if (any(getUnitType(u) != "mm")) {
1151+
stop("All units must be in millimeters")
11291152
}
11301153
(as.numeric(u) * 96) / 25.4
11311154
}
1132-
1155+
11331156
verifyUnit <- function(u) {
1134-
# the default unit in ggplot2 is millimeters (unless it's element_text())
1135-
if (is.null(attr(u, "unit"))) {
1136-
u <- if (inherits(u, "element")) {
1137-
grid::unit(u$size %||% 0, "points")
1138-
} else {
1139-
grid::unit(u %||% 0, "mm")
1140-
}
1157+
if (grid::is.unit(u)) return(u)
1158+
1159+
## the default unit in ggplot2 is millimeters (unless it's element_text())
1160+
if (inherits(u, "element")) {
1161+
grid::unit(u$size %||% 0, "points")
1162+
} else {
1163+
grid::unit(u %||% 0, "mm")
11411164
}
1142-
u
1165+
}
1166+
1167+
# Use public API for getting the unit's type, if available
1168+
# https://github.com/ropensci/plotly/pull/1646#issue-331268260
1169+
getUnitType <- function(u) {
1170+
tryNULL(get("unitType", envir = asNamespace("grid"))(u)) %||%
1171+
attr(u, "unit")
11431172
}
11441173

11451174
# detect a blank theme element

R/helpers.R

+6-3
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,18 @@ plotly_empty <- function(...) {
185185
}
186186

187187

188-
#' Convert a raster object to a data URI
188+
#' Encode a raster object as a data URI
189189
#'
190-
#' Convenient embedding images via [layout()]
191-
#' \href{images}{https://plot.ly/r/reference/#layout-images}.
190+
#' Encode a raster object as a data URI, which is suitable for
191+
#' use with `layout()` \href{https://plot.ly/r/reference/#layout-images}{images}.
192+
#' This is especially convenient for embedding raster images on a plot in
193+
#' a self-contained fashion (i.e., so they don't depend on external URL links).
192194
#'
193195
#' @param r an object coercable to a raster object via [as.raster()]
194196
#' @param ... arguments passed onto [as.raster()].
195197
#' @author Carson Sievert
196198
#' @export
199+
#' @references <https://plotly-r.com/embedding-images.html>
197200
#' @examples
198201
#'
199202
#' # a red gradient (from ?as.raster)

0 commit comments

Comments
 (0)