Skip to content

Commit c42ca9d

Browse files
committed
Draft update StatDensity to have bounds argument.
1 parent dbbcd43 commit c42ca9d

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

R/stat-density.r

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#' not line-up, and hence you won't be able to stack density values.
1616
#' This parameter only matters if you are displaying multiple densities in
1717
#' one plot or if you are manually adjusting the scale limits.
18+
#' @param bounds Known lower and upper bounds for estimated data. Default
19+
#' `c(-Inf, Inf)` means that there are no (finite) bounds.
1820
#' @section Computed variables:
1921
#' \describe{
2022
#' \item{density}{density estimate}
@@ -35,6 +37,7 @@ stat_density <- function(mapping = NULL, data = NULL,
3537
n = 512,
3638
trim = FALSE,
3739
na.rm = FALSE,
40+
bounds = c(-Inf, Inf),
3841
orientation = NA,
3942
show.legend = NA,
4043
inherit.aes = TRUE) {
@@ -54,6 +57,7 @@ stat_density <- function(mapping = NULL, data = NULL,
5457
n = n,
5558
trim = trim,
5659
na.rm = na.rm,
60+
bounds = bounds,
5761
orientation = orientation,
5862
...
5963
)
@@ -84,7 +88,8 @@ StatDensity <- ggproto("StatDensity", Stat,
8488
extra_params = c("na.rm", "orientation"),
8589

8690
compute_group = function(data, scales, bw = "nrd0", adjust = 1, kernel = "gaussian",
87-
n = 512, trim = FALSE, na.rm = FALSE, flipped_aes = FALSE) {
91+
n = 512, trim = FALSE, na.rm = FALSE, bounds = c(-Inf, Inf),
92+
flipped_aes = FALSE) {
8893
data <- flip_data(data, flipped_aes)
8994
if (trim) {
9095
range <- range(data$x, na.rm = TRUE)
@@ -93,15 +98,17 @@ StatDensity <- ggproto("StatDensity", Stat,
9398
}
9499

95100
density <- compute_density(data$x, data$weight, from = range[1],
96-
to = range[2], bw = bw, adjust = adjust, kernel = kernel, n = n)
101+
to = range[2], bw = bw, adjust = adjust, kernel = kernel, n = n,
102+
bounds = bounds)
97103
density$flipped_aes <- flipped_aes
98104
flip_data(density, flipped_aes)
99105
}
100106

101107
)
102108

103109
compute_density <- function(x, w, from, to, bw = "nrd0", adjust = 1,
104-
kernel = "gaussian", n = 512) {
110+
kernel = "gaussian", n = 512,
111+
bounds = c(-Inf, Inf)) {
105112
nx <- length(x)
106113
if (is.null(w)) {
107114
w <- rep(1 / nx, nx)
@@ -122,8 +129,15 @@ compute_density <- function(x, w, from, to, bw = "nrd0", adjust = 1,
122129
), n = 1))
123130
}
124131

125-
dens <- stats::density(x, weights = w, bw = bw, adjust = adjust,
126-
kernel = kernel, n = n, from = from, to = to)
132+
if (all(is.infinite(bounds))) {
133+
dens <- stats::density(x, weights = w, bw = bw, adjust = adjust,
134+
kernel = kernel, n = n, from = from, to = to)
135+
} else {
136+
dens <- stats::density(x, weights = w, bw = bw, adjust = adjust,
137+
kernel = kernel, n = n)
138+
139+
dens <- reflect_density(dens = dens, bounds = bounds, from = from, to = to)
140+
}
127141

128142
new_data_frame(list(
129143
x = dens$x,
@@ -134,3 +148,26 @@ compute_density <- function(x, w, from, to, bw = "nrd0", adjust = 1,
134148
n = nx
135149
), n = length(dens$x))
136150
}
151+
152+
reflect_density <- function(dens, bounds, from, to) {
153+
if (all(is.infinite(bounds))) {
154+
return(dens)
155+
}
156+
157+
f_dens <- stats::approxfun(
158+
x = dens$x, y = dens$y, method = "linear", yleft = 0, yright = 0
159+
)
160+
161+
out_x <- intersection_grid(dens$x, bounds, from, to)
162+
out_y <- f_dens(out_x) + f_dens(bounds[1] + (bounds[1] - out_x)) +
163+
f_dens(bounds[2] + (bounds[2] - out_x))
164+
165+
list(x = out_x, y = out_y)
166+
}
167+
168+
intersection_grid <- function(grid, bounds, from, to) {
169+
left <- max(from, bounds[1])
170+
right <- min(to, bounds[2])
171+
172+
seq(from = left, to = right, length.out = length(grid))
173+
}

man/geom_density.Rd

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)