Skip to content

Commit 053840c

Browse files
authored
Geom errorbar issure 1751 (#1779)
* Fix bug. If is.null(data_xy): Set data_xy to mean of data_xy_min and data_xy_max. * Add test. Check geom_errorbar is rendered when y aes is not set. * Fix bug. geom_errobar is now rendered with flipped aes. Add test. * Minor fixes. Add explanation and reprex for flipped_aes in geom2trace.GeomErrorbar. Simplify code in make_error. * Update R/layers2traces.R * Add visual test to check that geom_errobar is rendered when y aes is not set. * Add visual test to check that geom_errobar is rendered with flipped aes.
1 parent 5e5db59 commit 053840c

File tree

5 files changed

+84
-2
lines changed

5 files changed

+84
-2
lines changed

R/layers2traces.R

+18-2
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,11 @@ to_basic.GeomErrorbar <- function(data, prestats_data, layout, params, p, ...) {
451451
# width for ggplot2 means size of the entire bar, on the data scale
452452
# (plotly.js wants half, in pixels)
453453
data <- merge(data, layout$layout, by = "PANEL", sort = FALSE)
454-
data$width <- (data[["xmax"]] - data[["x"]]) /(data[["x_max"]] - data[["x_min"]])
454+
data$width <- if (params[["flipped_aes"]]) {
455+
(data[["ymax"]] - data[["y"]]) /(data[["y_max"]] - data[["y_min"]])
456+
} else {
457+
(data[["xmax"]] - data[["x"]]) /(data[["x_max"]] - data[["x_min"]])
458+
}
455459
data$fill <- NULL
456460
prefix_class(data, "GeomErrorbar")
457461
}
@@ -873,7 +877,17 @@ geom2trace.GeomTile <- function(data, params, p) {
873877

874878
#' @export
875879
geom2trace.GeomErrorbar <- function(data, params, p) {
876-
make_error(data, params, "y")
880+
# Support of bi-directional GeomErrorbar introduced with ggplot2 3.3.0
881+
# g <- ggplot() + geom_errorbar(aes(y = "A", xmin = 1, xmax = 2))
882+
# ggplotly(g)
883+
# Support of bi-directional GeomErrorbar introduced with ggplot2 3.3.0:
884+
# g <- ggplot() + geom_errorbar(aes(y = "A", xmin = 1, xmax = 2))
885+
# ggplotly(g)
886+
if (params[["flipped_aes"]]) {
887+
make_error(data, params, "x")
888+
} else {
889+
make_error(data, params, "y")
890+
}
877891
}
878892

879893
#' @export
@@ -951,6 +965,8 @@ hover_on <- function(data) {
951965

952966
# make trace with errorbars
953967
make_error <- function(data, params, xy = "x") {
968+
# if xy is NULL: set xy to mean of xy_min and xy_max
969+
data[[xy]] <- data[[xy]] %||% ((data[[paste0(xy, "min")]] + data[[paste0(xy, "max")]]) / 2)
954970
color <- aes2plotly(data, params, "colour")
955971
e <- list(
956972
x = data[["x"]],
Loading
+1
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
context("Errorbar")
2+
3+
test_that("geom_errobar is rendered with flipped aes", {
4+
5+
df <- dplyr::group_by(iris, Species)
6+
df <- dplyr::summarise_if(df, is.numeric, list(m = mean, q1 = ~ quantile(.x, .25), q3 = ~ quantile(.x, .75)))
7+
gp <- ggplot(df, aes(y = Species, xmin = Sepal.Width_q1, xmax = Sepal.Width_q3)) +
8+
geom_errorbar()
9+
10+
L <- plotly_build(gp)
11+
12+
# Tests
13+
# errobar is rendered
14+
expect_doppelganger(L, "errobar-flipped-aes")
15+
# xmin and xmax equal to ggplot
16+
expect_equivalent(L[["x"]][["data"]][[1]][["x"]] + L[["x"]][["data"]][[1]][["error_x"]][["array"]],
17+
ggplot_build(gp)$data[[1]]$xmax)
18+
19+
expect_equivalent(L[["x"]][["data"]][[1]][["x"]] - L[["x"]][["data"]][[1]][["error_x"]][["arrayminus"]],
20+
ggplot_build(gp)$data[[1]]$xmin)
21+
# xmin and xmax equal to data
22+
expect_equivalent(L[["x"]][["data"]][[1]][["x"]] + L[["x"]][["data"]][[1]][["error_x"]][["array"]],
23+
df$Sepal.Width_q3)
24+
25+
expect_equivalent(L[["x"]][["data"]][[1]][["x"]] - L[["x"]][["data"]][[1]][["error_x"]][["arrayminus"]],
26+
df$Sepal.Width_q1)
27+
28+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
context("Errorbar")
2+
3+
test_that("geom_errobar is rendered when y aes is not set", {
4+
5+
# Example from issue #1751
6+
d <- data.frame(
7+
auc = c(0.268707482993197, 0.571428571428571),
8+
sup = c(0.407680628614317, 0.648343533190079),
9+
inf = c(0.129734337372078, 0.494513609667063),
10+
Names = c("Firmicutes", "Spirochaetes")
11+
)
12+
13+
# Plot with y aes set
14+
p <- ggplot(d, aes(Names)) +
15+
geom_errorbar(aes(y = auc, ymin = inf, ymax = sup))
16+
L <- plotly_build(p)
17+
18+
# Plot with y aes not set
19+
p1 <- ggplot(d, aes(Names)) +
20+
geom_errorbar(aes(ymin = inf, ymax = sup))
21+
L1 <- plotly_build(p1)
22+
23+
# Tests
24+
# errobar is rendered
25+
expect_doppelganger(L1, "errobar-no-aes-y")
26+
## array and arrayminus of L and L1 are equivalent
27+
lapply(c("array", "arrayminus"), function(x) {
28+
expect_equivalent(
29+
L[["x"]][["data"]][[1]][["error_y"]][[x]],
30+
L1[["x"]][["data"]][[1]][["error_y"]][[x]]
31+
)
32+
})
33+
## array equals difference between sup and auc, array equals difference between auc and inf
34+
expect_equivalent(L1[["x"]][["data"]][[1]]$error_y$array, d$sup - d$auc)
35+
expect_equivalent(L1[["x"]][["data"]][[1]]$error_y$arrayminus, d$auc - d$inf)
36+
})

0 commit comments

Comments
 (0)