Skip to content

Commit 10e0100

Browse files
authored
Accommodate breaking changes in ggplot2 3.4.0 (#2200)
* Close #2193: Accomodate breaking changes in ggplot2 3.4.0 * Line-based theme elements now also use linewidth over size * Support GeomBoxplot linewidth as well * Support GeomPolygon linewidth as well * Support GeomBar linewidth as well * Handle more linewidth theme changes * Use both linewidth and size for sf * geom_area() now has a different default for stat * Approve differences due to changes in legend order * Convert borderwidth correctly on colorbar * Refactor/consolidate core logic * Approve new sf baseline * Fix sf issue * Approve new sf baseline * break_positions() no longer contains post-transformed values tidyverse/ggplot2#5029 * Add comment; prefer dimension() of the scale over .range
1 parent 51d276f commit 10e0100

19 files changed

+113
-51
lines changed

DESCRIPTION

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,5 @@ LazyData: true
8282
RoxygenNote: 7.2.1
8383
Encoding: UTF-8
8484
Roxygen: list(markdown = TRUE)
85+
Remotes:
86+
tidyverse/ggplot2

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ S3method(highlight_key,plotly)
2626
S3method(layout,matrix)
2727
S3method(layout,plotly)
2828
S3method(layout,shiny.tag.list)
29+
S3method(linewidth_or_size,Geom)
30+
S3method(linewidth_or_size,element)
2931
S3method(plotly_build,"NULL")
3032
S3method(plotly_build,gg)
3133
S3method(plotly_build,list)

R/ggplotly.R

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,14 @@ gg2list <- function(p, width = NULL, height = NULL,
304304
d[["y_plotlyDomain"]] <- d[["y"]]
305305
d
306306
})
307+
# And since we're essentially adding an "unknown" (to ggplot2)
308+
# aesthetic, add it to the dropped_aes field to avoid fals positive
309+
# warnings (https://github.com/tidyverse/ggplot2/pull/4866)
310+
layers <- lapply(layers, function(l) {
311+
l$stat$dropped_aes <- c(l$stat$dropped_aes, "x_plotlyDomain")
312+
l$stat$dropped_aes <- c(l$stat$dropped_aes, "y_plotlyDomain")
313+
l
314+
})
307315

308316
# Transform all scales
309317
data <- lapply(data, ggfun("scales_transform_df"), scales = scales)
@@ -676,9 +684,10 @@ gg2list <- function(p, width = NULL, height = NULL,
676684
d$y <- scales::rescale(d$y, rng$y_range, from = c(0, 1))
677685
params <- list(
678686
colour = panelGrid$colour,
679-
size = panelGrid$size,
680687
linetype = panelGrid$linetype
681688
)
689+
nm <- linewidth_or_size(panelGrid)
690+
params[[nm]] <- panelGrid[[nm]]
682691
grill <- geom2trace.GeomPath(d, params)
683692
grill$hoverinfo <- "none"
684693
grill$showlegend <- FALSE
@@ -723,8 +732,12 @@ gg2list <- function(p, width = NULL, height = NULL,
723732
isDiscrete <- identical(sc$scale_name, "position_d")
724733
isDiscreteType <- isDynamic && isDiscrete
725734

726-
ticktext <- rng[[xy]]$get_labels %()% rng[[paste0(xy, ".labels")]]
727-
tickvals <- rng[[xy]]$break_positions %()% rng[[paste0(xy, ".major")]]
735+
# In 3.2.x .major disappeared in favor of break_positions()
736+
# (tidyverse/ggplot2#3436), but with 3.4.x break_positions() no longer
737+
# yields the actual final positions on a 0-1 scale, but .major does
738+
# (tidyverse/ggplot2#5029)
739+
ticktext <- rng[[paste0(xy, ".labels")]] %||% rng[[xy]]$get_labels()
740+
tickvals <- rng[[paste0(xy, ".major")]] %||% rng[[xy]]$break_positions()
728741

729742
# https://github.com/tidyverse/ggplot2/pull/3566#issuecomment-565085809
730743
hasTickText <- !(is.na(ticktext) | is.na(tickvals))
@@ -735,7 +748,7 @@ gg2list <- function(p, width = NULL, height = NULL,
735748
# TODO: log type?
736749
type = if (isDateType) "date" else if (isDiscreteType) "category" else "linear",
737750
autorange = isDynamic,
738-
range = rng[[paste0(xy, ".range")]] %||% rng[[paste0(xy, "_range")]],
751+
range = rng[[xy]]$dimension %()% rng[[paste0(xy, ".range")]] %||% rng[[paste0(xy, "_range")]],
739752
tickmode = if (isDynamic) "auto" else "array",
740753
ticktext = ticktext,
741754
tickvals = tickvals,
@@ -958,7 +971,10 @@ gg2list <- function(p, width = NULL, height = NULL,
958971
gglayout$legend <- list(
959972
bgcolor = toRGB(theme$legend.background$fill),
960973
bordercolor = toRGB(theme$legend.background$colour),
961-
borderwidth = unitConvert(theme$legend.background$size, "pixels", "width"),
974+
borderwidth = unitConvert(
975+
theme$legend.background[[linewidth_or_size(theme$legend.background)]],
976+
"pixels", "width"
977+
),
962978
font = text2font(theme$legend.text)
963979
)
964980

@@ -1191,7 +1207,7 @@ verifyUnit <- function(u) {
11911207

11921208
## the default unit in ggplot2 is millimeters (unless it's element_text())
11931209
if (inherits(u, "element")) {
1194-
grid::unit(u$size %||% 0, "points")
1210+
grid::unit(u[[linewidth_or_size(u)]] %||% 0, "points")
11951211
} else {
11961212
grid::unit(u %||% 0, "mm")
11971213
}
@@ -1411,7 +1427,8 @@ gdef2trace <- function(gdef, theme, gglayout) {
14111427
bgcolor = toRGB(theme$legend.background$fill),
14121428
bordercolor = toRGB(theme$legend.background$colour),
14131429
borderwidth = unitConvert(
1414-
theme$legend.background$size, "pixels", "width"
1430+
theme$legend.background[[linewidth_or_size(theme$legend.background)]],
1431+
"pixels", "width"
14151432
),
14161433
thickness = unitConvert(
14171434
theme$legend.key.width, "pixels", "width"

R/layers2traces.R

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -387,9 +387,11 @@ to_basic.GeomHex <- function(data, prestats_data, layout, params, p, ...) {
387387
dy <- resolution(data[["y"]], FALSE)/sqrt(3)/2 * 1.15
388388
hexC <- hexbin::hexcoords(dx, dy, n = 1)
389389
n <- nrow(data)
390-
data$size <- ifelse(data$size < 1, data$size ^ (1 / 6), data$size ^ 6)
391-
x <- rep.int(hexC[["x"]], n) * rep(data$size, each = 6) + rep(data[["x"]], each = 6)
392-
y <- rep.int(hexC[["y"]], n) * rep(data$size, each = 6) + rep(data[["y"]], each = 6)
390+
nm <- linewidth_or_size(GeomHex)
391+
size <- data[[nm]]
392+
data[[nm]] <- ifelse(size < 1, size ^ (1 / 6), size ^ 6)
393+
x <- rep.int(hexC[["x"]], n) * rep(data[[nm]], each = 6) + rep(data[["x"]], each = 6)
394+
y <- rep.int(hexC[["y"]], n) * rep(data[[nm]], each = 6) + rep(data[["y"]], each = 6)
393395
data <- data[rep(seq_len(n), each = 6), ]
394396
data[["x"]] <- x
395397
data[["y"]] <- y
@@ -558,13 +560,15 @@ to_basic.GeomSpoke <- function(data, prestats_data, layout, params, p, ...) {
558560
#' @export
559561
to_basic.GeomCrossbar <- function(data, prestats_data, layout, params, p, ...) {
560562
# from GeomCrossbar$draw_panel()
561-
middle <- base::transform(data, x = xmin, xend = xmax, yend = y, size = size * params$fatten, alpha = NA)
563+
middle <- base::transform(data, x = xmin, xend = xmax, yend = y, alpha = NA)
564+
nm <- linewidth_or_size(GeomCrossbar)
565+
data[[nm]] <- data[[nm]] * params$fatten
562566
list(
563567
prefix_class(to_basic.GeomRect(data), "GeomCrossbar"),
564568
prefix_class(to_basic.GeomSegment(middle), "GeomCrossbar")
565569
)
566570
}
567-
utils::globalVariables(c("xmin", "xmax", "y", "size", "COL", "PANEL", "ROW", "yaxis"))
571+
utils::globalVariables(c("xmin", "xmax", "y", "size", "linewidth", "COL", "PANEL", "ROW", "yaxis"))
568572

569573
#' @export
570574
to_basic.GeomRug <- function(data, prestats_data, layout, params, p, ...) {
@@ -710,7 +714,7 @@ geom2trace.GeomPath <- function(data, params, p) {
710714
name = if (inherits(data, "GeomSmooth")) "fitted values",
711715
line = list(
712716
# TODO: line width array? -- https://github.com/plotly/plotly.js/issues/147
713-
width = aes2plotly(data, params, "size")[1],
717+
width = aes2plotly(data, params, linewidth_or_size(GeomPath))[1],
714718
color = toRGB(
715719
aes2plotly(data, params, "colour"),
716720
aes2plotly(data, params, "alpha")
@@ -803,7 +807,7 @@ geom2trace.GeomBar <- function(data, params, p) {
803807
aes2plotly(data, params, "alpha")
804808
),
805809
line = list(
806-
width = aes2plotly(data, params, "size"),
810+
width = aes2plotly(data, params, linewidth_or_size(GeomBar)),
807811
color = aes2plotly(data, params, "colour")
808812
)
809813
)
@@ -812,7 +816,7 @@ geom2trace.GeomBar <- function(data, params, p) {
812816

813817
#' @export
814818
geom2trace.GeomPolygon <- function(data, params, p) {
815-
819+
816820
data <- group2NA(data)
817821

818822
L <- list(
@@ -826,7 +830,7 @@ geom2trace.GeomPolygon <- function(data, params, p) {
826830
type = "scatter",
827831
mode = "lines",
828832
line = list(
829-
width = aes2plotly(data, params, "size"),
833+
width = aes2plotly(data, params, linewidth_or_size(GeomPolygon)),
830834
color = toRGB(
831835
aes2plotly(data, params, "colour"),
832836
aes2plotly(data, params, "alpha")
@@ -873,7 +877,7 @@ geom2trace.GeomBoxplot <- function(data, params, p) {
873877
),
874878
line = list(
875879
color = aes2plotly(data, params, "colour"),
876-
width = aes2plotly(data, params, "size")
880+
width = aes2plotly(data, params, linewidth_or_size(GeomBoxplot))
877881
)
878882
))
879883
}
@@ -976,11 +980,11 @@ geom2trace.default <- function(data, params, p) {
976980
# since plotly.js can't draw two polygons with different fill in a single trace
977981
split_on <- function(dat) {
978982
lookup <- list(
979-
GeomHline = c("linetype", "colour", "size"),
980-
GeomVline = c("linetype", "colour", "size"),
981-
GeomAbline = c("linetype", "colour", "size"),
982-
GeomPath = c("fill", "colour", "size"),
983-
GeomPolygon = c("fill", "colour", "size"),
983+
GeomHline = c("linetype", "colour", "size", "linewidth"),
984+
GeomVline = c("linetype", "colour", "size", "linewidth"),
985+
GeomAbline = c("linetype", "colour", "size", "linewidth"),
986+
GeomPath = c("fill", "colour", "size", "linewidth"),
987+
GeomPolygon = c("fill", "colour", "size", "linewidth"),
984988
GeomBar = "fill",
985989
GeomBoxplot = c("colour", "fill", "size"),
986990
GeomErrorbar = "colour",
@@ -1079,7 +1083,7 @@ aes2plotly <- function(data, params, aes = "size") {
10791083
# Hack to support this geom_sf hack
10801084
# https://github.com/tidyverse/ggplot2/blob/505e4bfb/R/sf.R#L179-L187
10811085
defaults <- if (inherits(data, "GeomSf")) {
1082-
type <- if (any(grepl("point", class(data)))) "point" else if (any(grepl("line", class(data)))) "line" else ""
1086+
type <- if (any(grepl("[P-p]oint", class(data)))) "point" else if (any(grepl("[L-l]ine", class(data)))) "line" else ""
10831087
ggfun("default_aesthetics")(type)
10841088
} else {
10851089
geom_obj <- ggfun(geom)
@@ -1093,7 +1097,8 @@ aes2plotly <- function(data, params, aes = "size") {
10931097
vals <- uniq(data[[aes]]) %||% params[[aes]] %||% defaults[[aes]] %||% NA
10941098
converter <- switch(
10951099
aes,
1096-
size = mm2pixels,
1100+
size = mm2pixels,
1101+
linewidth = mm2pixels,
10971102
stroke = mm2pixels,
10981103
colour = toRGB,
10991104
fill = toRGB,
@@ -1112,6 +1117,26 @@ aes2plotly <- function(data, params, aes = "size") {
11121117
converter(vals)
11131118
}
11141119

1120+
1121+
# ggplot2 3.4.0 deprecated size in favor of linewidth in line-based geoms (e.g.,
1122+
# GeomLine, GeomRect, etc) and elements (e.g., element_line(), element_rect(),
1123+
# etc). Note that, some geoms (e.g., GeomBoxplot, GeomSf) can have both
1124+
# linewidth and size
1125+
linewidth_or_size <- function(x) {
1126+
UseMethod("linewidth_or_size")
1127+
}
1128+
1129+
#' @export
1130+
linewidth_or_size.Geom <- function(x) {
1131+
if ("linewidth" %in% x$aesthetics()) "linewidth" else "size"
1132+
}
1133+
1134+
#' @export
1135+
linewidth_or_size.element <- function(x) {
1136+
if ("linewidth" %in% names(x)) "linewidth" else "size"
1137+
}
1138+
1139+
11151140
# Convert R pch point codes to plotly "symbol" codes.
11161141
pch2symbol <- function(x) {
11171142
lookup <- list(

tests/testthat/_snaps/cookbook-axes/cookbook-axes-log2-coord.svg

Lines changed: 1 addition & 1 deletion
Loading

0 commit comments

Comments
 (0)