@@ -1211,26 +1211,40 @@ generate_nanoplot <- function(
1211
1211
box_thickness <- data_point_radius [1 ] * 6
1212
1212
1213
1213
# Calculate statistics for boxplot
1214
- stat_p05 <- unname(stats :: quantile(y_vals , probs = 0.05 , na.rm = TRUE ))
1215
1214
stat_q_1 <- unname(stats :: quantile(y_vals , probs = 0.25 , na.rm = TRUE ))
1216
1215
stat_med <- unname(stats :: quantile(y_vals , probs = 0.50 , na.rm = TRUE ))
1217
1216
stat_q_3 <- unname(stats :: quantile(y_vals , probs = 0.75 , na.rm = TRUE ))
1218
- stat_p95 <- unname( stats :: quantile (y_vals , probs = 0.95 , na.rm = TRUE ) )
1217
+ stat_iqr <- stats :: IQR (y_vals , na.rm = TRUE )
1219
1218
1220
- if (length(y_vals ) > 25 ) {
1219
+ low_outliers <- y_vals [y_vals < stat_q_1 - (1.5 * stat_iqr )]
1220
+ high_outliers <- y_vals [y_vals > stat_q_3 + (1.5 * stat_iqr )]
1221
+
1222
+ stat_min_excl_low_outliers <-
1223
+ min(base :: setdiff(y_vals , low_outliers ), na.rm = TRUE )
1224
+
1225
+ stat_max_excl_high_outliers <-
1226
+ max(base :: setdiff(y_vals , high_outliers ), na.rm = TRUE )
1227
+
1228
+ plot_only_outliers <- length(y_vals ) > = 20
1229
+
1230
+ if (plot_only_outliers ) {
1221
1231
1222
1232
# Plot only outliers since the number of data values is sufficiently high
1223
- y_vals_plot <- y_vals [ y_vals < stat_p05 | y_vals > stat_p95 ]
1233
+ y_vals_plot <- c( low_outliers , high_outliers )
1224
1234
1225
1235
data_point_radius <- 4
1226
1236
data_point_stroke_width <- 2
1227
- data_point_stroke_color <- adjust_luminance(data_bar_stroke_color [1 ], steps = 0.75 )
1228
- data_point_fill_color <- adjust_luminance(data_point_stroke_color [1 ], steps = 1.75 )
1237
+
1238
+ data_point_stroke_color <-
1239
+ adjust_luminance(data_bar_stroke_color [1 ], steps = 0.75 )
1240
+
1241
+ data_point_fill_color <-
1242
+ adjust_luminance(data_point_stroke_color [1 ], steps = 1.75 )
1229
1243
1230
1244
} else {
1231
1245
1232
1246
# Plot all data values but diminish the visibility of the data points
1233
- # as the number approaches 25
1247
+ # as the number approaches 20
1234
1248
y_vals_plot <- y_vals
1235
1249
1236
1250
if (length(y_vals ) < 10 ) {
@@ -1241,7 +1255,9 @@ generate_nanoplot <- function(
1241
1255
data_point_stroke_width <- 2
1242
1256
}
1243
1257
1244
- data_point_stroke_color <- adjust_luminance(" black" , steps = length(y_vals ) / 25 )
1258
+ data_point_stroke_color <-
1259
+ adjust_luminance(" black" , steps = length(y_vals ) / 25 )
1260
+
1245
1261
data_point_fill_color <- " transparent"
1246
1262
}
1247
1263
@@ -1251,42 +1267,53 @@ generate_nanoplot <- function(
1251
1267
vals = y_vals ,
1252
1268
all_vals = all_y_vals ,
1253
1269
y_vals_plot = y_vals_plot ,
1254
- stat_low = stat_p05 ,
1270
+ stat_min = stat_min_excl_low_outliers ,
1255
1271
stat_qlow = stat_q_1 ,
1256
1272
stat_med = stat_med ,
1257
1273
stat_qup = stat_q_3 ,
1258
- stat_high = stat_p95
1274
+ stat_max = stat_max_excl_high_outliers
1259
1275
)
1260
1276
1261
1277
y_proportions <- y_proportions_list [[" vals" ]]
1262
1278
y_proportions_plot <- y_proportions_list [[" y_vals_plot" ]]
1263
- y_stat_p05 <- y_proportions_list [[" stat_low " ]]
1279
+ y_stat_min <- y_proportions_list [[" stat_min " ]]
1264
1280
y_stat_q_1 <- y_proportions_list [[" stat_qlow" ]]
1265
1281
y_stat_med <- y_proportions_list [[" stat_med" ]]
1266
1282
y_stat_q_3 <- y_proportions_list [[" stat_qup" ]]
1267
- y_stat_p95 <- y_proportions_list [[" stat_high " ]]
1283
+ y_stat_max <- y_proportions_list [[" stat_max " ]]
1268
1284
1269
1285
# Calculate boxplot x values
1270
- fence_start <- y_stat_p05 * data_x_width
1286
+ fence_start <- y_stat_min * data_x_width
1271
1287
box_start <- y_stat_q_1 * data_x_width
1272
1288
median_x <- y_stat_med * data_x_width
1273
1289
box_end <- y_stat_q_3 * data_x_width
1274
- fence_end <- y_stat_p95 * data_x_width
1290
+ fence_end <- y_stat_max * data_x_width
1275
1291
box_width <- (y_stat_q_3 - y_stat_q_1 ) * data_x_width
1276
1292
1277
1293
# Establish positions for plottable x and y values
1278
1294
plotted_x_vals <- y_proportions_plot * data_x_width
1279
1295
1280
1296
if (length(y_vals ) == 1 ) {
1297
+
1281
1298
plotted_y_vals <- bottom_y / 2
1299
+
1282
1300
} else {
1283
- plotted_y_vals <- jitter(rep(bottom_y / 2 , length(plotted_x_vals )), factor = 10 )
1301
+
1302
+ if (plot_only_outliers ) {
1303
+
1304
+ plotted_y_vals <- rep(bottom_y / 2 , length(plotted_x_vals ))
1305
+
1306
+ } else {
1307
+
1308
+ plotted_y_vals <-
1309
+ jitter(rep(bottom_y / 2 , length(plotted_x_vals )), factor = 10 )
1310
+ }
1284
1311
}
1285
1312
1286
1313
# Format numbers compactly
1287
- stat_p05_value <-
1314
+ stat_min_value <-
1288
1315
format_number_compactly(
1289
- val = stat_p05 ,
1316
+ val = stat_min_excl_low_outliers ,
1290
1317
currency = currency ,
1291
1318
fn = y_val_fmt_fn
1292
1319
)
@@ -1308,9 +1335,9 @@ generate_nanoplot <- function(
1308
1335
currency = currency ,
1309
1336
fn = y_val_fmt_fn
1310
1337
)
1311
- stat_p95_value <-
1338
+ stat_max_value <-
1312
1339
format_number_compactly(
1313
- val = stat_p95 ,
1340
+ val = stat_max_excl_high_outliers ,
1314
1341
currency = currency ,
1315
1342
fn = y_val_fmt_fn
1316
1343
)
@@ -1358,7 +1385,7 @@ generate_nanoplot <- function(
1358
1385
" font-size=\" 30px\" " ,
1359
1386
" text-anchor=\" end\" " ,
1360
1387
" >" ,
1361
- stat_p05_value ,
1388
+ stat_min_value ,
1362
1389
" </text>" ,
1363
1390
" <text " ,
1364
1391
" x=\" " , box_start - 6 , " \" " ,
@@ -1396,7 +1423,7 @@ generate_nanoplot <- function(
1396
1423
" stroke=\" transparent\" " ,
1397
1424
" font-size=\" 30px\" " ,
1398
1425
" >" ,
1399
- stat_p95_value ,
1426
+ stat_max_value ,
1400
1427
" </text>"
1401
1428
)
1402
1429
}
0 commit comments