From 01923f01c1cba93d4eeb4bbed063d9c54b146e77 Mon Sep 17 00:00:00 2001 From: Matthew Kay Date: Tue, 6 Feb 2024 22:30:20 -0600 Subject: [PATCH] linting fixes --- .lintr | 10 +++-- R/density.R | 12 +++--- R/distributions.R | 8 ++-- R/geom_dotsinterval.R | 14 +++--- R/geom_lineribbon.R | 50 ++++++++++++---------- R/geom_slabinterval.R | 30 +++++++------ R/geom_spike.R | 2 +- R/parse_dist.R | 35 +++++++++++---- R/point_interval.R | 66 +++++++++++++++++------------ R/position_dodgejust.R | 4 +- R/pr.R | 3 +- R/stat_dotsinterval.R | 4 +- R/stat_slabinterval.R | 38 ++++++++--------- tests/testthat/test.distributions.R | 15 +++++++ tests/testthat/test.parse_dist.R | 4 +- 15 files changed, 178 insertions(+), 117 deletions(-) diff --git a/.lintr b/.lintr index 5b298798..4a171218 100755 --- a/.lintr +++ b/.lintr @@ -2,6 +2,7 @@ linters: all_linters( assignment_linter = NULL, commas_linter(allow_trailing = TRUE), consecutive_assertion_linter = NULL, + duplicate_argument_linter(except = c("mutate", "transmute", "c")), implicit_integer_linter = NULL, infix_spaces_linter(exclude_operators = c("/", "*")), keyword_quote_linter = NULL, @@ -12,9 +13,9 @@ linters: all_linters( object_name_linter( styles = c("snake_case", "symbols"), regexes = c( - misc = "^(F_x|x_1_hat,x_n_hat)$", - CamelCase = "^(RankCorr.*|.*Geom.*|.*Stat.*|Scale.*|K|.*Pr.*)$", - dot.case = "^(na\\.rm|lower\\.tail|log\\.p)$", + misc = "^(F_x|x_1_hat,x_n_hat|R_inv|Amat|Aind)$", + CamelCase = "^(RankCorr.*|.*Geom.*|.*Stat.*|Scale.*|Position.*|K|.*Pr.*)$", + dot.case = "^(na\\.rm|na\\.translate|na\\.value|lower\\.tail|log\\.p)$", bandwidth = "^(bandwidth_.*)$" ) ), @@ -34,5 +35,6 @@ linters: all_linters( defaults = all_undesirable_operators, "<-" = "House style is to use `=`, not `<-`, for assignment." )), - unnecessary_concatenation_linter(allow_single_expression = FALSE) + unnecessary_concatenation_linter(allow_single_expression = FALSE), + unnecessary_nesting_linter = NULL ) diff --git a/R/density.R b/R/density.R index ef2a231a..649804db 100755 --- a/R/density.R +++ b/R/density.R @@ -373,18 +373,18 @@ density_histogram = auto_partial(name = "density_histogram", function( # work as expected if 1 is a bin edge. eps = min(diff(h$breaks)/4, 2*.Machine$double.eps) - if (!outline_bars) { + if (outline_bars) { + # have to return to 0 in between each bar so that bar outlines are drawn + input = as.vector(rbind(input_1, input_1, input_1 + eps, input_, input_, input_2 - eps, input_2, input_2)) + pdf = as.vector(rbind(0, h$density, h$density, h$density, h$density, h$density, h$density, 0)) + cdf = as.vector(rbind(cdf_1, cdf_1, cdf_1, cdf_1, cdf_, cdf_2, cdf_2, cdf_2)) + } else { # as.vector(rbind(x, y)) interleaves vectors x and y, giving # us the bin endpoints --- then just need to repeat the same value of density # for both endpoints of the same bin input = as.vector(rbind(input_1, input_1 + eps, input_, input_, input_2 - eps, input_2)) pdf = rep(h$density, each = 6) cdf = as.vector(rbind(cdf_1, cdf_1, cdf_1, cdf_, cdf_2, cdf_2)) - } else { - # have to return to 0 in between each bar so that bar outlines are drawn - input = as.vector(rbind(input_1, input_1, input_1 + eps, input_, input_, input_2 - eps, input_2, input_2)) - pdf = as.vector(rbind(0, h$density, h$density, h$density, h$density, h$density, h$density, 0)) - cdf = as.vector(rbind(cdf_1, cdf_1, cdf_1, cdf_1, cdf_, cdf_2, cdf_2, cdf_2)) } structure(list( diff --git a/R/distributions.R b/R/distributions.R index 56625e6d..5d772578 100755 --- a/R/distributions.R +++ b/R/distributions.R @@ -204,8 +204,8 @@ distr_levels = function(dist) { if (inherits(dist, "rvar_factor")) { levels(dist) } else if (inherits(dist, "distribution")) { - levels = lapply(vec_data(dist), distr_levels) - unique(do.call(c, levels)) + levs = lapply(vec_data(dist), distr_levels) + unique(do.call(c, levs)) } else if (inherits(dist, "dist_categorical")) { as.character(dist[["x"]] %||% seq_along(dist[["p"]])) } else if (inherits(dist, "ggdist__wrapped_categorical")) { @@ -218,7 +218,7 @@ distr_levels = function(dist) { unique(s) } } else { - warning("Don't know how to determine the levels of distribution: ", format(dist)) + warning0("Don't know how to determine the levels of distribution: ", format(dist)) NULL } } @@ -233,7 +233,7 @@ distr_probs = function(dist) { } else if (inherits(dist, "ggdist__wrapped_categorical")) { distr_probs(dist[["wrapped_dist"]]) } else { - warning("Don't know how to determine the category probabilities of distribution: ", format(dist)) + warning0("Don't know how to determine the category probabilities of distribution: ", format(dist)) NULL } } diff --git a/R/geom_dotsinterval.R b/R/geom_dotsinterval.R index 9ac8a963..401bd438 100755 --- a/R/geom_dotsinterval.R +++ b/R/geom_dotsinterval.R @@ -173,13 +173,14 @@ makeContent.dots_grob = function(x) { subguide_params[, c(y, ymin, ymax, "side", "justification", "scale")], c(y, "side", "justification", "scale"), function(d) { - if (nrow(unique(d)) > 1) { + if (nrow(unique(d)) > 1) { # nocov start + # this should not be possible cli_abort( "Cannot draw a subguide for the dot count axis when multiple dots geometries with different parameters are drawn on the same axis.", class = "ggdist_incompatible_subguides" ) - } + } # nocov end d = d[1, ] dot_height = binwidth * heightratio / stackratio @@ -553,9 +554,9 @@ GeomDotsinterval = ggproto("GeomDotsinterval", GeomSlabinterval, # so size can only occur in cases where colour is also set (so we can just check colour) if ( params$show_slab && - any(!is.na(data[,c( - "fill","alpha","slab_fill","slab_colour","slab_linewidth","slab_size", - "slab_linetype","slab_alpha","slab_shape" + !all(is.na(data[, c( + "fill", "alpha", "slab_fill", "slab_colour", "slab_linewidth", "slab_size", + "slab_linetype", "slab_alpha", "slab_shape" )])) ) { s_key_data = self$override_slab_aesthetics(key_data) @@ -603,7 +604,8 @@ GeomDots = ggproto("GeomDots", GeomDotsinterval, s_data$fill = s_data[["slab_fill"]] %||% s_data[["fill"]] s_data$fill = apply_colour_ramp(s_data[["fill"]], s_data[["fill_ramp"]]) s_data$alpha = s_data[["slab_alpha"]] %||% s_data[["alpha"]] - s_data$linewidth = s_data[["slab_linewidth"]] %||% s_data[["slab_size"]] %||% s_data[["linewidth"]] %||% s_data[["size"]] + s_data$linewidth = s_data[["slab_linewidth"]] %||% s_data[["slab_size"]] %||% + s_data[["linewidth"]] %||% s_data[["size"]] s_data$shape = s_data[["slab_shape"]] %||% s_data[["shape"]] s_data }, diff --git a/R/geom_lineribbon.R b/R/geom_lineribbon.R index 609b3ada..bbf48b89 100755 --- a/R/geom_lineribbon.R +++ b/R/geom_lineribbon.R @@ -227,7 +227,9 @@ GeomLineribbon = ggproto("GeomLineribbon", AbstractGeom, # draw all the ribbons ribbon_grobs = data %>% dlply_(grouping_columns, function(d) { - group_grobs = list(GeomRibbon$draw_panel(transform(d, linewidth = NA), panel_scales, coord, flipped_aes = flipped_aes)) + group_grobs = list( + GeomRibbon$draw_panel(transform(d, linewidth = NA), panel_scales, coord, flipped_aes = flipped_aes) + ) list( order = mean(d[["order"]], na.rm = TRUE), grobs = group_grobs @@ -273,25 +275,29 @@ stepify = function(df, x = "x", direction = "hv") { # sort by x and double up all rows in the data frame step_df = df[rep(order(df[[x]]), each = 2),] - if (direction == "hv") { - # horizontal-to-vertical step => lead x and drop last row - step_df[[x]] = lead(step_df[[x]]) - step_df[-2*n,] - } else if (direction == "vh") { - # vertical-to-horizontal step => lag x and drop first row - step_df[[x]] = lag(step_df[[x]]) - step_df[-1,] - } else if (direction == "mid") { - # mid step => last value in each pair is matched with the first value in the next pair, - # then we set their x position to their average. - # Need to repeat the last value one more time to make it work - step_df[2*n + 1,] = step_df[2*n,] - - x_i = seq_len(n)*2 - mid_x = (step_df[x_i, x] + step_df[x_i + 1, x]) / 2 - - step_df[x_i, x] = mid_x - step_df[x_i + 1, x] = mid_x - step_df - } + switch(direction, + hv = { + # horizontal-to-vertical step => lead x and drop last row + step_df[[x]] = lead(step_df[[x]]) + step_df[-2*n,] + }, + vh = { + # vertical-to-horizontal step => lag x and drop first row + step_df[[x]] = lag(step_df[[x]]) + step_df[-1,] + }, + mid = { + # mid step => last value in each pair is matched with the first value in the next pair, + # then we set their x position to their average. + # Need to repeat the last value one more time to make it work + step_df[2*n + 1,] = step_df[2*n,] + + x_i = seq_len(n)*2 + mid_x = (step_df[x_i, x] + step_df[x_i + 1, x]) / 2 + + step_df[x_i, x] = mid_x + step_df[x_i + 1, x] = mid_x + step_df + } + ) } diff --git a/R/geom_slabinterval.R b/R/geom_slabinterval.R index 2b494960..8bace8b3 100755 --- a/R/geom_slabinterval.R +++ b/R/geom_slabinterval.R @@ -348,7 +348,8 @@ override_point_aesthetics = function(self, p_data, size_domain, size_range, fatt p_data$fill = p_data[["point_fill"]] %||% p_data[["fill"]] p_data$alpha = p_data[["point_alpha"]] %||% p_data[["alpha"]] # TODO: insert fatten_point deprecation warning - p_data$size = p_data[["point_size"]] %||% (fatten_point * transform_size(p_data[["interval_size"]] %||% p_data[["size"]], size_domain, size_range)) + p_data$size = p_data[["point_size"]] %||% + (fatten_point * transform_size(p_data[["interval_size"]] %||% p_data[["size"]], size_domain, size_range)) p_data } @@ -357,16 +358,21 @@ override_interval_aesthetics = function(self, i_data, size_domain, size_range) { i_data$colour = apply_colour_ramp(i_data[["colour"]], i_data[["colour_ramp"]]) i_data$alpha = i_data[["interval_alpha"]] %||% i_data[["alpha"]] # TODO: insert interval_size deprecation warning - i_data$linewidth = transform_size(i_data[["linewidth"]] %||% i_data[["interval_size"]] %||% i_data[["size"]], size_domain, size_range) + i_data$linewidth = transform_size( + i_data[["linewidth"]] %||% i_data[["interval_size"]] %||% i_data[["size"]], size_domain, size_range + ) i_data$linetype = i_data[["interval_linetype"]] %||% i_data[["linetype"]] i_data } transform_size = function(size, size_domain, size_range) { pmax( - (size - size_domain[[1]]) / (size_domain[[2]] - size_domain[[1]]) * - (size_range[[2]] - size_range[[1]]) + size_range[[1]], - 0) + (size - size_domain[[1]]) / + (size_domain[[2]] - size_domain[[1]]) * + (size_range[[2]] - size_range[[1]]) + + size_range[[1]], + 0 + ) } @@ -618,7 +624,7 @@ GeomSlabinterval = ggproto("GeomSlabinterval", AbstractGeom, slab_colour = NA ), - required_aes = c("x|y"), + required_aes = "x|y", optional_aes = c( "ymin", "ymax", "xmin", "xmax", "width", "height", "thickness" @@ -671,9 +677,9 @@ GeomSlabinterval = ggproto("GeomSlabinterval", AbstractGeom, # INTERVAL PARAMS interval_size_domain = glue_doc(' - A length-2 numeric vector giving the minimum and maximum of the values of the `size` and `linewidth` aesthetics that will be - translated into actual sizes for intervals drawn according to `interval_size_range` (see the documentation - for that argument.) + A length-2 numeric vector giving the minimum and maximum of the values of the `size` and `linewidth` aesthetics + that will be translated into actual sizes for intervals drawn according to `interval_size_range` (see the + documentation for that argument.) '), interval_size_range = glue_doc(' A length-2 numeric vector. This geom scales the raw size aesthetic values when drawing interval and point @@ -810,7 +816,7 @@ GeomSlabinterval = ggproto("GeomSlabinterval", AbstractGeom, # ensure thickness is a thickness-type vector so it is not normalized again data$thickness = normalize_thickness(as_thickness(data$thickness)) }, - stop('`normalize` must be "all", "panels", "xy", groups", or "none", not "', params$normalize, '"') + stop0('`normalize` must be "all", "panels", "xy", groups", or "none", not "', params$normalize, '"') ) ggproto_parent(AbstractGeom, self)$draw_layer(data, params, layout, coord) @@ -975,7 +981,7 @@ group_slab_data_by = function( define_orientation_variables(orientation) aesthetics = intersect(aesthetics, names(slab_data)) - groups = factor(do.call(paste, slab_data[,aesthetics])) + groups = factor(do.call(paste, slab_data[, aesthetics])) if (nlevels(groups) > 1) { # need to split into groups based on varying aesthetics @@ -1013,7 +1019,7 @@ group_slab_data_by = function( slab_data } bottomleft = function() { - slab_data = slab_data[nrow(slab_data):1,] + slab_data = slab_data[rev(seq_len(nrow(slab_data))), ] slab_data[[y]] = slab_data[[ymin]] slab_data } diff --git a/R/geom_spike.R b/R/geom_spike.R index b32fa38a..a6196ce9 100755 --- a/R/geom_spike.R +++ b/R/geom_spike.R @@ -192,7 +192,7 @@ GeomSpike = ggproto("GeomSpike", GeomSlab, point_key = if ( !all(is.na(s_key_data$size) | s_key_data$size == 0) && ( - !all(is.na(data[c("size","stroke","shape","alpha")])) || + !all(is.na(data[c("size", "stroke", "shape", "alpha")])) || # only draw point for `fill` aesthetic if a shape that has a fill colour is used (!all(is.na(data[c("fill", "fill_ramp")])) && length(intersect(data$shape, 21:25)) > 0) || (!all(is.na(data[c("fill", "fill_ramp")])) && length(intersect(data$shape, 21:25)) > 0) diff --git a/R/parse_dist.R b/R/parse_dist.R index dcd3015c..1888b0c8 100644 --- a/R/parse_dist.R +++ b/R/parse_dist.R @@ -101,9 +101,12 @@ parse_dist = function( #' @rdname parse_dist #' @export parse_dist.default = function(object, ...) { - stop( - "Objects of type ", deparse0(class(object)), " are not currently supported by `parse_dist`.\n", - "A character vector or a data frame are expected.\n" + cli_abort( + c( + "{.arg object} must be a character vector, factor, data frame, or {.help brms::prior} object.", + "x" = "{.arg object} was {.type {object}}" + ), + class = "ggdist_unsupported_type" ) } @@ -148,7 +151,15 @@ parse_dist.data.frame = function( #' @rdname parse_dist #' @export -parse_dist.character = function(object, ..., dist = ".dist", args = ".args", dist_obj = ".dist_obj", package = NULL, to_r_names = TRUE) { +parse_dist.character = function( + object, + ..., + dist = ".dist", + args = ".args", + dist_obj = ".dist_obj", + package = NULL, + to_r_names = TRUE +) { package = package %||% parent.frame() na_spec = tibble( # for unparseable specs @@ -247,11 +258,17 @@ check_dist_name = function(dist) { is.na(mget(paste0("q", dist), inherits = TRUE, ifnotfound = NA)) failed_names = dist[invalid & !is.na(dist)] if (length(failed_names) > 0) { - warning( - "The following distribution names were not recognized and were ignored: \n", - " ", paste(failed_names, collapse = ", "), "\n", - " See help('stat_slabinterval') for information on specifying distribution names.", - if ("lkjcorr" %in% failed_names) "\n See help('marginalize_lkjcorr') for help visualizing LKJ distributions." + cli_warn( + c( + "The following distribution names were not recognized and were ignored: {failed_names}", + "i" = "See {.emph Details} in the {.help stat_slabinterval} documentation for information + on specifying distribution names.", + if ("lkjcorr" %in% failed_names) c( + "i" = "See the {.help marginalize_lkjcorr} documentation for help visualizing LKJ + distributions." + ) + ), + class = "ggdist_unsupported_distribution_name" ) } dist[invalid] = NA diff --git a/R/point_interval.R b/R/point_interval.R index 56e11d80..a78986ab 100644 --- a/R/point_interval.R +++ b/R/point_interval.R @@ -267,7 +267,7 @@ point_interval.default = function(.data, ..., .width = .95, .point = median, .in # if the values we are going to summarise are not already list columns, make them into list columns # (making them list columns first is faster than anything else I've tried) # this also ensures that rvars and distributional objects are supported (as those act as lists) - if (!all(map_lgl_(data[,names(col_exprs)], is.list))) { + if (!all(map_lgl_(data[, names(col_exprs)], is.list))) { data = summarise_at(data, names(col_exprs), list) } @@ -338,10 +338,8 @@ point_interval.numeric = function(.data, ..., .width = .95, .point = median, .in result[[".interval"]] = interval_name if (.simple_names) { - result %>% - rename(.value = y, .lower = ymin, .upper = ymax) - } - else { + rename(result, .value = y, .lower = ymin, .upper = ymax) + } else { result } } @@ -396,7 +394,7 @@ ll = function(x, .width = .95, na.rm = FALSE) { lower_prob = 1 - .width upper_prob = rep(1, length(.width)) - out = qi_(x, lower_prob, upper_prob, na.rm) + qi_(x, lower_prob, upper_prob, na.rm) } #' @export @@ -405,7 +403,7 @@ ul = function(x, .width = .95, na.rm = FALSE) { lower_prob = rep(0, length(.width)) upper_prob = .width - out = qi_(x, lower_prob, upper_prob, na.rm) + qi_(x, lower_prob, upper_prob, na.rm) } #' @export @@ -517,8 +515,7 @@ Mode = function(x, na.rm = FALSE, ...) { Mode.default = function(x, na.rm = FALSE, ..., density = density_bounded(trim = TRUE), n = 2001, weights = NULL) { if (na.rm) { x = x[!is.na(x)] - } - else if (anyNA(x)) { + } else if (anyNA(x)) { return(NA_real_) } density = match_function(density, "density_") @@ -542,9 +539,9 @@ Mode.default = function(x, na.rm = FALSE, ..., density = density_bounded(trim = #' @export #' @rdname point_interval Mode.rvar = function(x, na.rm = FALSE, ...) { - draws <- posterior::draws_of(x) - dim <- dim(draws) - apply(draws, seq_along(dim)[-1], Mode, na.rm = na.rm, weights = weights(x)) + draws = posterior::draws_of(x) + .dim = dim(draws) + apply(draws, seq_along(.dim)[-1], Mode, na.rm = na.rm, weights = weights(x)) } #' @importFrom stats optim #' @export @@ -649,75 +646,90 @@ hdci_.distribution = function(x, .width = .95, na.rm = FALSE, ...) { #' @export #' @rdname point_interval -mean_qi = function(.data, ..., .width = .95) +mean_qi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = mean, .interval = qi) +} #' @export #' @rdname point_interval -median_qi = function(.data, ..., .width = .95) +median_qi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = median, .interval = qi) +} #' @export #' @rdname point_interval -mode_qi = function(.data, ..., .width = .95) +mode_qi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = Mode, .interval = qi) +} #' @export #' @rdname point_interval -mean_ll = function(.data, ..., .width = .95) +mean_ll = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = mean, .interval = ll) +} #' @export #' @rdname point_interval -median_ll = function(.data, ..., .width = .95) +median_ll = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = median, .interval = ll) +} #' @export #' @rdname point_interval -mode_ll = function(.data, ..., .width = .95) +mode_ll = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = Mode, .interval = ll) +} #' @export #' @rdname point_interval -mean_ul = function(.data, ..., .width = .95) +mean_ul = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = mean, .interval = ul) +} #' @export #' @rdname point_interval -median_ul = function(.data, ..., .width = .95) +median_ul = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = median, .interval = ul) +} #' @export #' @rdname point_interval -mode_ul = function(.data, ..., .width = .95) +mode_ul = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = Mode, .interval = ul) +} #' @export #' @rdname point_interval -mean_hdi = function(.data, ..., .width = .95) +mean_hdi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = mean, .interval = hdi) +} #' @export #' @rdname point_interval -median_hdi = function(.data, ..., .width = .95) +median_hdi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = median, .interval = hdi) +} #' @export #' @rdname point_interval -mode_hdi = function(.data, ..., .width = .95) +mode_hdi = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = Mode, .interval = hdi) +} #' @export #' @rdname point_interval -mean_hdci = function(.data, ..., .width = .95) +mean_hdci = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = mean, .interval = hdci) +} #' @export #' @rdname point_interval -median_hdci = function(.data, ..., .width = .95) +median_hdci = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = median, .interval = hdci) +} #' @export #' @rdname point_interval -mode_hdci = function(.data, ..., .width = .95) +mode_hdci = function(.data, ..., .width = .95) { point_interval(.data, ..., .width = .width, .point = Mode, .interval = hdci) +} diff --git a/R/position_dodgejust.R b/R/position_dodgejust.R index d8095ade..0a0d6097 100755 --- a/R/position_dodgejust.R +++ b/R/position_dodgejust.R @@ -261,12 +261,12 @@ collide = function( intervals = as.numeric(t(unique(data[c("xmin", "xmax")]))) intervals = intervals[!is.na(intervals)] - if (length(unique(intervals)) > 1 & any(diff(scale(intervals)) < -1e-6)) { + if (length(unique(intervals)) > 1 && any(diff(scale(intervals)) < -1e-6)) { warning0(paste0(name, " requires non-overlapping ", x_name, " intervals")) } # workaround so that mapped_discrete columns can be combined with numerics - xy_cols = intersect(c("x","y","xmin","xmax","ymin","ymax"), names(data)) + xy_cols = intersect(c("x", "y", "xmin", "xmax", "ymin", "ymax"), names(data)) data[xy_cols] = lapply(data[xy_cols], as.numeric) if (!is.null(data$ymax)) { diff --git a/R/pr.R b/R/pr.R index dbcec7ac..ba9a492e 100755 --- a/R/pr.R +++ b/R/pr.R @@ -176,7 +176,8 @@ standardize_Pr_element = function(e) { } check_Pr_cdf_element_combination = function(e1, e2, label = NULL) { - if (!list(sort(c(e1, e2))) %in% list( + if ( + !list(sort(c(e1, e2))) %in% list( c("x", "xdist"), c("y", "ydist"), c("dist", "value") diff --git a/R/stat_dotsinterval.R b/R/stat_dotsinterval.R index 6da89e48..3ed3df82 100755 --- a/R/stat_dotsinterval.R +++ b/R/stat_dotsinterval.R @@ -34,14 +34,14 @@ compute_slab_dots = function( if (distr_is_sample(dist)) { input = map_character(distr_get_sample(dist)) - weights = distr_get_sample_weights(dist) + .weights = distr_get_sample_weights(dist) if (quantiles_provided) { # ppoints() with a = 1/2 corresponds to quantile() with type = 5 # (on continuous samples --- on discrete, we use type = 1) # and ensures that if quantiles == length(data[[x]]) then input == data[[x]] quantile_type = if (distr_is_discrete(dist)) 1 else 5 input = weighted_quantile( - input, ppoints(quantiles, a = 1/2), type = quantile_type, na.rm = na.rm, weights = weights, names = FALSE + input, ppoints(quantiles, a = 1/2), type = quantile_type, na.rm = na.rm, weights = .weights, names = FALSE ) } } else { diff --git a/R/stat_slabinterval.R b/R/stat_slabinterval.R index ae0b66f3..3b39ddf5 100755 --- a/R/stat_slabinterval.R +++ b/R/stat_slabinterval.R @@ -27,14 +27,14 @@ compute_limits_slabinterval = function( } if (distr_is_constant(dist)) { - median = distr_quantile(dist)(0.5) - return(data.frame(.lower = median, .upper = median)) + .median = distr_quantile(dist)(0.5) + return(data.frame(.lower = .median, .upper = .median)) } if (distr_is_sample(dist)) { - sample = distr_get_sample(dist) - weights = distr_get_sample_weights(dist) - return(compute_limits_sample(sample, trans, trim, adjust, ..., weights = weights)) + .sample = distr_get_sample(dist) + .weights = distr_get_sample_weights(dist) + return(compute_limits_sample(.sample, trans, trim, adjust, ..., weights = .weights)) } quantile_fun = distr_quantile(dist) @@ -142,7 +142,12 @@ compute_slab_slabinterval = function( # work as expected if 1 is a bin edge. eps = 2*.Machine$double.eps - if (!outline_bars) { + if (outline_bars) { + # have to return to 0 in between each bar so that bar outlines are drawn + input = as.vector(rbind(input_1, input_1, input_1 + eps, input_, input_, input_2 - eps, input_2, input_2)) + pdf = as.vector(rbind(0, pdf, pdf, pdf, pdf, pdf, pdf, 0)) + cdf = as.vector(rbind(lag_cdf, lag_cdf, lag_cdf, lag_cdf, cdf, cdf, cdf, cdf)) + } else { # as.vector(rbind(x, y, z, ...)) interleaves vectors x, y, z, ..., giving # us the bin endpoints and midpoints --- then just need to repeat the same # value of density for both endpoints of the same bin and to make sure the @@ -150,11 +155,6 @@ compute_slab_slabinterval = function( input = as.vector(rbind(input_1, input_1 + eps, input_, input_, input_2 - eps, input_2)) pdf = rep(pdf, each = 6) cdf = as.vector(rbind(lag_cdf, lag_cdf, lag_cdf, cdf, cdf, cdf)) - } else { - # have to return to 0 in between each bar so that bar outlines are drawn - input = as.vector(rbind(input_1, input_1, input_1 + eps, input_, input_, input_2 - eps, input_2, input_2)) - pdf = as.vector(rbind(0, pdf, pdf, pdf, pdf, pdf, pdf, 0)) - cdf = as.vector(rbind(lag_cdf, lag_cdf, lag_cdf, lag_cdf, cdf, cdf, cdf, cdf)) } } else { pdf = pdf_fun(input) @@ -305,10 +305,10 @@ compute_interval_slabinterval = function( #' @inheritParams density_histogram #' @param geom Use to override the default connection between #' [stat_slabinterval()] and [geom_slabinterval()] -#' @param slab_type (deprecated) The type of slab function to calculate: probability density (or mass) function (`"pdf"`), -#' cumulative distribution function (`"cdf"`), or complementary CDF (`"ccdf"`). Instead of using `slab_type` to -#' change `f` and then mapping `f` onto an aesthetic, it is now recommended to simply map the corresponding -#' computed variable (e.g. `pdf`, `cdf`, or `1 - cdf`) directly onto the desired aesthetic. +#' @param slab_type (deprecated) The type of slab function to calculate: probability density (or mass) function +#' (`"pdf"`), cumulative distribution function (`"cdf"`), or complementary CDF (`"ccdf"`). Instead of using +#' `slab_type` to change `f` and then mapping `f` onto an aesthetic, it is now recommended to simply map the +#' corresponding computed variable (e.g. `pdf`, `cdf`, or `1 - cdf`) directly onto the desired aesthetic. #' @param p_limits Probability limits (as a vector of size 2) used to determine the lower and upper #' limits of *theoretical* distributions (distributions from *samples* ignore this parameter and determine #' their limits based on the limits of the sample). E.g., if this is `c(.001, .999)`, then a slab is drawn @@ -521,7 +521,7 @@ StatSlabinterval = ggproto("StatSlabinterval", AbstractStatSlabinterval, # check for dist-like objects in x / y axis: these are likely user errors # caused by assigning a distribution to x / y instead of xdist / ydist - dist_like_cols = c("x","y")[map_lgl_(c("x", "y"), function(col) is_dist_like(data[[col]]))] + dist_like_cols = c("x", "y")[map_lgl_(c("x", "y"), function(col) is_dist_like(data[[col]]))] if (length(dist_like_cols) > 0) { s = if (length(dist_like_cols) > 1) "s" stop0( @@ -547,8 +547,8 @@ StatSlabinterval = ggproto("StatSlabinterval", AbstractStatSlabinterval, if (is.na(dist)) { dist_missing() } else { - args = args_from_aes(...) - do.call(dist_wrap, c(list(dist), args)) + .args = args_from_aes(...) + do.call(dist_wrap, c(list(dist), .args)) } }) } @@ -557,7 +557,7 @@ StatSlabinterval = ggproto("StatSlabinterval", AbstractStatSlabinterval, # Need to group by rows in the data frame to draw correctly, as # each output slab will need to be in its own group. # First check if we are grouped by rows already (in which case leave it) - if (length(unique(data$group)) != nrow(data)) { + if (anyDuplicated(data$group)) { # need to make new groups that ensure every row is unique but which # preserve old group order at the top level data$group = as.numeric(interaction( diff --git a/tests/testthat/test.distributions.R b/tests/testthat/test.distributions.R index 8bd123f6..10de36c5 100755 --- a/tests/testthat/test.distributions.R +++ b/tests/testthat/test.distributions.R @@ -28,6 +28,21 @@ test_that("distribution functions work on wrapped distributions", { }) +# weighted sample distributions ------------------------------------------- + +test_that("distribution functions work on weighted sample distributions", { + x = .dist_weighted_sample(list(qnorm(ppoints(20000), mean = c(1,5), c(1,2))), list(rep(c(1,3), 10000))) + ref = dist_mixture(dist_normal(1,1), dist_normal(5,2), weights = c(1,3)/4) + eps = 0.005 + expect_equal(mean(x), mean(ref), tolerance = eps) + expect_equal(median(x), median(ref), tolerance = eps) + expect_equal(Mode(x), 5, tolerance = 0.01) + expect_equal(distr_pdf(x)(2), distr_pdf(ref)(2), tolerance = eps) + expect_equal(distr_cdf(x)(1), distr_cdf(ref)(1), tolerance = eps) + expect_equal(distr_quantile(x)(0.5), distr_quantile(ref)(0.5), tolerance = eps) +}) + + # distributional objects -------------------------------------------------- test_that("distribution functions work on distributional objects", { diff --git a/tests/testthat/test.parse_dist.R b/tests/testthat/test.parse_dist.R index b3fbbdaa..b2973c9f 100755 --- a/tests/testthat/test.parse_dist.R +++ b/tests/testthat/test.parse_dist.R @@ -91,7 +91,7 @@ test_that("parse_dist + marginalize_lkjcorr produces correct results", { test_that("unsupported objects throw error with parse_dist", { expect_error( parse_dist(list()), - 'Objects of type "list" are not currently supported by `parse_dist`.' + class = "ggdist_unsupported_type" ) }) @@ -101,6 +101,6 @@ test_that("unsupported objects throw error with parse_dist", { test_that("check_dist ignores unknown distributions", { expect_warning( expect_equal(check_dist_name(c("norm","foo","bar","t")), c("norm",NA,NA,"t")), - "The following distribution names were not recognized and were ignored:.*foo, bar" + class = "ggdist_unsupported_distribution_name" ) })