Skip to content

Commit 77343bd

Browse files
authored
Expand ydensity range for nicer violin plots (#1783)
Fixes #1700 * Expand ydensity range for nicer violin plots * Add news bullet * Update unit tests
1 parent 1ee809a commit 77343bd

File tree

3 files changed

+29
-13
lines changed

3 files changed

+29
-13
lines changed

NEWS.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
* The `theme()` constructor now has named arguments rather than ellipsis. This
7070
should make autocomplete substantially more useful.
7171

72+
* geom_violin now again has a nicer looking range that allow the density to
73+
reach zero. The range of each violin is now automatically extended 3 * bw for
74+
either end of the data range (#1700)
7275

7376
* `position_stack()` and `position_fill()` now sorts the stacking order so it
7477
matches the order of the grouping. Use level reordering to alter the stacking

R/stat-ydensity.r

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ StatYdensity <- ggproto("StatYdensity", Stat,
6969
} else {
7070
range <- scales$y$dimension()
7171
}
72-
dens <- compute_density(data$y, data$w, from = range[1], to = range[2],
72+
bw <- calc_bw(data$y, bw)
73+
dens <- compute_density(data$y, data$w, from = range[1] - 3*bw, to = range[2] + 3*bw,
7374
bw = bw, adjust = adjust, kernel = kernel)
7475

7576
dens$y <- dens$x
@@ -107,3 +108,22 @@ StatYdensity <- ggproto("StatYdensity", Stat,
107108
}
108109

109110
)
111+
112+
calc_bw <- function(x, bw) {
113+
if (is.character(bw)) {
114+
if (length(x) < 2)
115+
stop("need at least 2 points to select a bandwidth automatically", call. = FALSE)
116+
bw <- switch(
117+
tolower(bw),
118+
nrd0 = stats::bw.nrd0(x),
119+
nrd = stats::bw.nrd(x),
120+
ucv = stats::bw.ucv(x),
121+
bcv = stats::bw.bcv(x),
122+
sj = ,
123+
`sj-ste` = stats::bw.SJ(x, method = "ste"),
124+
`sj-dpi` = stats::bw.SJ(x, method = "dpi"),
125+
stop("unknown bandwidth rule")
126+
)
127+
}
128+
bw
129+
}

tests/testthat/test-geom-violin.R

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
context("geom_violin")
22

3-
test_that("", {
3+
test_that("range is expanded", {
44
df <- rbind(
55
data.frame(x = "a", y = c(0, runif(10), 1)),
66
data.frame(x = "b", y = c(0, runif(10), 2))
@@ -10,9 +10,10 @@ test_that("", {
1010
geom_violin() +
1111
facet_grid(x ~ ., scales = "free") +
1212
coord_cartesian(expand = FALSE)
13-
14-
expect_equal(layer_scales(p, 1)$y$dimension(), c(0, 1))
15-
expect_equal(layer_scales(p, 2)$y$dimension(), c(0, 2))
13+
expand_a <- stats::bw.nrd0(df$y[df$x == "a"]) * 3
14+
expand_b <- stats::bw.nrd0(df$y[df$x == "b"]) * 3
15+
expect_equal(layer_scales(p, 1)$y$dimension(), c(0 - expand_a, 1 + expand_a))
16+
expect_equal(layer_scales(p, 2)$y$dimension(), c(0 - expand_b, 2 + expand_b))
1617
})
1718

1819
# create_quantile_segment_frame -------------------------------------------------
@@ -31,13 +32,5 @@ test_that("quantiles do not fail on zero-range data", {
3132

3233
# This should return without error and have length one
3334
expect_equal(length(layer_grob(p)), 1)
34-
35-
# All rows should be identical in layer_data, with some specific values
36-
unique.layer.data <- unique(layer_data(p))
37-
expect_equal(nrow(unique.layer.data), 1)
38-
expect_equal(unique.layer.data$density, 0.55216039)
39-
expect_equal(unique.layer.data$count, 1.65648117)
40-
expect_equal(unique.layer.data$xmin, 0.55)
41-
expect_equal(unique.layer.data$xmax, 1.45)
4235
})
4336

0 commit comments

Comments
 (0)