@@ -141,6 +141,9 @@ StatDensity2d <- ggproto("StatDensity2d", Stat,
141
141
check_installed(" MASS" , reason = " for calculating 2D density." )
142
142
# first run the regular layer calculation to infer densities
143
143
data <- ggproto_parent(Stat , self )$ compute_layer(data , params , layout )
144
+ if (empty(data )) {
145
+ return (data_frame0())
146
+ }
144
147
145
148
# if we're not contouring we're done
146
149
if (! isTRUE(params $ contour %|| % TRUE )) return (data )
@@ -178,10 +181,8 @@ StatDensity2d <- ggproto("StatDensity2d", Stat,
178
181
179
182
compute_group = function (data , scales , na.rm = FALSE , h = NULL , adjust = c(1 , 1 ),
180
183
n = 100 , ... ) {
181
- if (is.null(h )) {
182
- h <- c(MASS :: bandwidth.nrd(data $ x ), MASS :: bandwidth.nrd(data $ y ))
183
- h <- h * adjust
184
- }
184
+
185
+ h <- precompute_2d_bw(data $ x , data $ y , h = h , adjust = adjust )
185
186
186
187
# calculate density
187
188
dens <- MASS :: kde2d(
@@ -214,3 +215,27 @@ StatDensity2dFilled <- ggproto("StatDensity2dFilled", StatDensity2d,
214
215
contour_type = " bands"
215
216
)
216
217
218
+ precompute_2d_bw <- function (x , y , h = NULL , adjust = 1 ) {
219
+
220
+ if (is.null(h )) {
221
+ # Note: MASS::bandwidth.nrd is equivalent to stats::bw.nrd * 4
222
+ h <- c(MASS :: bandwidth.nrd(x ), MASS :: bandwidth.nrd(y ))
223
+ # Handle case when when IQR == 0 and thus regular nrd bandwidth fails
224
+ if (h [1 ] == 0 && length(x ) > 1 ) h [1 ] <- bw.nrd0(x ) * 4
225
+ if (h [2 ] == 0 && length(y ) > 1 ) h [2 ] <- bw.nrd0(y ) * 4
226
+ h <- h * adjust
227
+ }
228
+
229
+ check_numeric(h )
230
+ check_length(h , 2L )
231
+
232
+ if (any(is.na(h ) | h < = 0 )) {
233
+ cli :: cli_abort(c(
234
+ " The bandwidth argument {.arg h} must contain numbers larger than 0." ,
235
+ i = " Please set the {.arg h} argument to stricly positive numbers manually."
236
+ ))
237
+ }
238
+
239
+ h
240
+ }
241
+
0 commit comments