Skip to content

Commit

Permalink
Merge pull request #314 from IndrajeetPatil/ggcoef_insightification
Browse files Browse the repository at this point in the history
more refactoring of `ggcoefstats` using `insight`
  • Loading branch information
IndrajeetPatil authored Sep 17, 2019
2 parents 6693a29 + 3a72b2a commit 808e2e7
Show file tree
Hide file tree
Showing 44 changed files with 346 additions and 271 deletions.
13 changes: 12 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# ggstatsplot 0.1.1.9000
#

MINOR

- Minor code refactoring that gets rid of the following dependencies:
`magrittr`, `ellipsis`, `purrrlyr`.

MAJOR

- The *p*-value label now specifies whether the *p*-value displayed in
`ggbetweenstats` and `ggwithinstats` pairwise comparisons were adjusted or
not for multiple comparisons.

# ggstatsplot 0.1.1

ANNOUNCEMENTS
Expand Down
2 changes: 1 addition & 1 deletion R/ggbetweenstats.R
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ ggbetweenstats <- function(data,
return = "plot",
messages = TRUE) {

# no pairwise comparisons are available for bayesian t-tests
# no pairwise comparisons are available for Bayesian t-tests
if (type %in% c("bf", "bayes") && isTRUE(pairwise.comparisons)) {
pairwise.comparisons <- FALSE
}
Expand Down
231 changes: 100 additions & 131 deletions R/ggcoefstats.R
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@
#' @importFrom tibble as_tibble rownames_to_column
#' @importFrom tidyr unite
#' @importFrom groupedstats lm_effsize_standardizer
#' @importFrom insight is_model
#'
#' @references
#' \url{https://indrajeetpatil.github.io/ggstatsplot/articles/web_only/ggcoefstats.html}
Expand Down Expand Up @@ -375,17 +376,6 @@ ggcoefstats <- function(x,

# =================== list of objects (for tidy and glance) ================

# dataframe objects
df.mods <- c(
"data.frame",
"data.table",
"grouped_df",
"tbl",
"tbl_df",
"spec_tbl_df",
"resampled_df"
)

# creating a list of objects which will have fixed and random "effects"
# only fixed effects will be selected
mixed.mods <-
Expand Down Expand Up @@ -432,108 +422,99 @@ ggcoefstats <- function(x,
glance_df <- broomExtra::glance(x)

# if the object is not a dataframe, check if summary caption is to be displayed
if (!class(x)[[1]] %in% df.mods) {
if (isTRUE(insight::is_model(x))) {
# if glance is not available, inform the user
if (is.null(glance_df) && output == "plot") {
if (is.null(glance_df) || !all(c("logLik", "AIC", "BIC") %in% names(glance_df))) {
# inform the user
message(cat(
crayon::green("Note: "),
crayon::blue(
"No model diagnostics information available for the object of class",
crayon::yellow(class(x)[[1]]),
".\n"
),
crayon::blue("No model diagnostics information available, so skipping caption.\n"),
sep = ""
))

# and skip the caption
caption.summary <- FALSE
} else {
# if glance is not null, but the needed metric are not available, skip caption
if (!all(c("logLik", "AIC", "BIC") %in% names(glance_df))) {
caption.summary <- FALSE
}
}
}

# ============================= dataframe ===============================

if (class(x)[[1]] %in% df.mods) {
if (isFALSE(insight::is_model(x))) {
# set tidy_df to entered dataframe
tidy_df <- tibble::as_tibble(x)

# check that statistic is specified
# check that `statistic` is specified
if (rlang::is_null(statistic)) {
message(cat(
crayon::red("Note"),
crayon::blue(
": For the object of class",
crayon::yellow(class(x)[[1]]),
", the argument `statistic` is not specified ('t', 'z', or 'f').\n",
"Statistical labels will therefore be skipped.\n"
),
sep = ""
))

# skip labels
stats.labels <- FALSE
}
# =========================== broom.mixed tidiers =======================
} else if (class(x)[[1]] %in% mixed.mods) {
# getting tidy output using `broom.mixed`
tidy_df <-
broomExtra::tidy(
x = x,
conf.int = conf.int,
# exponentiate = exponentiate,
conf.level = conf.level,
effects = "fixed",
scales = scales,
...
)

# ====================== tidying F-statistic objects ===================
} else if (class(x)[[1]] %in% f.mods) {
# creating dataframe
tidy_df <-
groupedstats::lm_effsize_standardizer(
object = x,
effsize = effsize,
partial = partial,
conf.level = conf.level,
nboot = nboot
) %>%
dplyr::rename(.data = ., statistic = F.value)

# renaming the `xlab` according to the estimate chosen
if (effsize == "eta") {
if (isTRUE(partial)) {
xlab <- "partial eta-squared"
} else {
xlab <- "eta-squared"
# inform the user
if (output == "plot") {
message(cat(
crayon::red("Note"),
crayon::blue(": For the object of class"),
crayon::yellow(class(x)[[1]]),
crayon::blue(", the argument `statistic` must be specified ('t', 'z', or 'f').\n"),
crayon::blue("Statistical labels will therefore be skipped.\n"),
sep = ""
))
}
}
}

if (effsize == "omega") {
# =========================== broom.mixed tidiers =======================

if (isTRUE(insight::is_model(x))) {
if (class(x)[[1]] %in% mixed.mods) {
# getting tidy output using `broom.mixed`
tidy_df <-
broomExtra::tidy(
x = x,
conf.int = conf.int,
# exponentiate = exponentiate,
conf.level = conf.level,
effects = "fixed",
scales = scales,
...
)

# ====================== tidying F-statistic objects ===================
} else if (class(x)[[1]] %in% f.mods) {
# creating dataframe
tidy_df <-
groupedstats::lm_effsize_standardizer(
object = x,
effsize = effsize,
partial = partial,
conf.level = conf.level,
nboot = nboot
) %>%
dplyr::rename(.data = ., statistic = F.value)

# prefix for effect size
if (isTRUE(partial)) {
xlab <- "partial omega-squared"
effsize.prefix <- "partial"
} else {
xlab <- "omega-squared"
effsize.prefix <- NULL
}

# renaming the `xlab` according to the estimate chosen
xlab <- paste(effsize.prefix, " ", effsize, "-squared", sep = "")
# ==================== tidying everything else ===========================
} else {
tidy_df <-
broomExtra::tidy(
x = x,
conf.int = conf.int,
conf.level = conf.level,
se.type = se.type,
by_class = by.class,
component = component,
# exponentiate = exponentiate,
parametric = TRUE, # relevant for `gam` objects
...
)
}
# ==================== tidying everything else ===========================
} else {
tidy_df <-
broomExtra::tidy(
x = x,
conf.int = conf.int,
conf.level = conf.level,
se.type = se.type,
by_class = by.class,
component = component,
# exponentiate = exponentiate,
parametric = TRUE, # relevant for `gam` objects
...
)
}

# =================== tidy dataframe cleanup ================================
Expand Down Expand Up @@ -611,7 +592,7 @@ ggcoefstats <- function(x,
# =================== p-value computation ==================================

# p-values won't be computed by default for some of the models
if (!class(x)[[1]] %in% df.mods && !"p.value" %in% names(tidy_df)) {
if (isTRUE(insight::is_model(x)) && !"p.value" %in% names(tidy_df)) {
# use `sjstats` S3 methods to add them to the tidy dataframe
tryCatch(
expr = tidy_df %<>%
Expand Down Expand Up @@ -678,23 +659,16 @@ ggcoefstats <- function(x,
} else {
# add NAs so that only dots will be shown
tidy_df %<>%
dplyr::mutate(
.data = .,
conf.low = NA_character_,
conf.high = NA_character_
)
dplyr::mutate(.data = ., conf.low = NA_character_, conf.high = NA_character_)

# stop displaying whiskers
conf.int <- FALSE

# inform the user that skipping labels for the same reason
message(cat(
crayon::green("Note: "),
crayon::blue(
"No confidence intervals available for regression coefficients from",
crayon::yellow(class(x)[[1]]),
"object, so skipping whiskers in the plot.\n"
),
crayon::blue("No confidence intervals available for regression coefficients"),
crayon::blue("object, so skipping whiskers in the plot.\n"),
sep = ""
))
}
Expand Down Expand Up @@ -758,7 +732,9 @@ ggcoefstats <- function(x,
# adding a column with labels to be used with `ggrepel`
if (isTRUE(stats.labels)) {
# in case a dataframe was entered, `x` and `tidy_df` are going to be same
if (class(x)[[1]] %in% df.mods) x <- tidy_df
if (isFALSE(insight::is_model(x))) {
x <- tidy_df
}

# adding a column with labels using custom function
tidy_df %<>%
Expand All @@ -777,14 +753,12 @@ ggcoefstats <- function(x,

# check if meta-analysis is to be run
if (isTRUE(meta.analytic.effect) && "std.error" %in% names(tidy_df)) {
if (dim(dplyr::filter(.data = tidy_df, is.na(std.error)))[[1]] > 0) {
if (dim(dplyr::filter(.data = tidy_df, is.na(std.error)))[[1]] > 0L) {
# inform the user that skipping labels for the same reason
message(cat(
crayon::red("Error: "),
crayon::blue(
"At least one of the values in the `std.error` column is NA.\n",
"No meta-analysis will be carried out.\n"
),
crayon::blue("At least one of the `std.error` column values is `NA`.\n"),
crayon::blue("No meta-analysis will be carried out.\n"),
sep = ""
))

Expand Down Expand Up @@ -837,35 +811,33 @@ ggcoefstats <- function(x,
# caption containing model diagnostics
if (isTRUE(caption.summary)) {
# for dataframe objects
if (class(x)[[1]] %in% df.mods && isTRUE(meta.analytic.effect)) {
if (isFALSE(insight::is_model(x)) && isTRUE(meta.analytic.effect)) {
caption <- caption.meta
}

# for non-dataframe objects
if (!class(x)[[1]] %in% df.mods) {
if (!is.na(glance_df$AIC[[1]])) {
# preparing caption with model diagnostics
caption <-
substitute(
atop(displaystyle(top.text),
expr =
paste(
"AIC = ",
AIC,
", BIC = ",
BIC,
", log-likelihood = ",
LL
)
),
env = list(
top.text = caption,
AIC = specify_decimal_p(x = glance_df$AIC[[1]], k = k.caption.summary),
BIC = specify_decimal_p(x = glance_df$BIC[[1]], k = k.caption.summary),
LL = specify_decimal_p(x = glance_df$logLik[[1]], k = k.caption.summary)
)
if (isTRUE(insight::is_model(x)) && !is.na(glance_df$AIC[[1]])) {
# preparing caption with model diagnostics
caption <-
substitute(
atop(displaystyle(top.text),
expr =
paste(
"AIC = ",
AIC,
", BIC = ",
BIC,
", log-likelihood = ",
LL
)
),
env = list(
top.text = caption,
AIC = specify_decimal_p(x = glance_df$AIC[[1]], k = k.caption.summary),
BIC = specify_decimal_p(x = glance_df$BIC[[1]], k = k.caption.summary),
LL = specify_decimal_p(x = glance_df$logLik[[1]], k = k.caption.summary)
)
}
)
}
}

Expand Down Expand Up @@ -897,10 +869,7 @@ ggcoefstats <- function(x,
if (output == "plot") {
# setting up the basic architecture
plot <-
ggplot2::ggplot(
data = tidy_df,
mapping = ggplot2::aes(x = estimate, y = factor(term))
)
ggplot2::ggplot(data = tidy_df, mapping = ggplot2::aes(x = estimate, y = term))

# if needed, adding the vertical line
if (isTRUE(vline)) {
Expand Down
5 changes: 4 additions & 1 deletion R/grouped_ggbetweenstats.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@
#' y = rating,
#' grouping.var = mpaa,
#' results.subtitle = FALSE,
#' ggplot.component = ggplot2::scale_y_continuous(breaks = seq(1, 9, 1)),
#' ggplot.component = ggplot2::scale_y_continuous(
#' breaks = seq(1, 9, 1),
#' limits = (c(1, 9))
#' ),
#' messages = FALSE
#' )
#' }
Expand Down
1 change: 0 additions & 1 deletion R/grouped_gghistostats.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#' @description Helper function for `ggstatsplot::gghistostats` to apply this
#' function across multiple levels of a given factor and combining the
#' resulting plots using `ggstatsplot::combine_plots`.
#' @author Indrajeet Patil, Chuck Powell
#'
#' @inheritParams gghistostats
#' @inheritParams grouped_ggbetweenstats
Expand Down
Loading

2 comments on commit 808e2e7

@lintr-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R/ggbarstats.R:70:1: style: functions should have cyclomatic complexity of less than 15, this has 20.

ggbarstats <- function(data,
^

R/ggbetweenstats.R:196:1: style: functions should have cyclomatic complexity of less than 15, this has 33.

ggbetweenstats <- function(data,
^

R/ggcoefstats.R:303:1: style: functions should have cyclomatic complexity of less than 15, this has 58.

ggcoefstats <- function(x,
^

R/ggcorrmat.R:167:1: style: functions should have cyclomatic complexity of less than 15, this has 30.

ggcorrmat <- function(data,
^

R/gghistostats.R:79:1: style: functions should have cyclomatic complexity of less than 15, this has 24.

gghistostats <- function(data,
^

R/ggpiestats.R:110:1: style: functions should have cyclomatic complexity of less than 15, this has 22.

ggpiestats <- function(data,
^

R/ggscatterstats.R:96:1: style: functions should have cyclomatic complexity of less than 15, this has 34.

ggscatterstats <- function(data,
^

R/ggwithinstats.R:63:1: style: functions should have cyclomatic complexity of less than 15, this has 31.

ggwithinstats <- function(data,
^

R/helpers_ggbetweenstats_graphics.R:369:26: style: %>% should always have a space before it and a new line after it, unless the full pipeline fits on one line.

​      ggsignif_xy(data %>% dplyr::pull({{ x }}), data %>% dplyr::pull({{ y }}))
                       ~~^

R/helpers_gghistostats_graphics.R:48:5: warning: local variable ‘label.value’ assigned but may not be used

label.value <- x_pos
    ^~~~~~~~~~~

@lintr-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R/ggbarstats.R:70:1: style: functions should have cyclomatic complexity of less than 15, this has 20.

ggbarstats <- function(data,
^

R/ggbetweenstats.R:196:1: style: functions should have cyclomatic complexity of less than 15, this has 33.

ggbetweenstats <- function(data,
^

R/ggcoefstats.R:303:1: style: functions should have cyclomatic complexity of less than 15, this has 58.

ggcoefstats <- function(x,
^

R/ggcorrmat.R:167:1: style: functions should have cyclomatic complexity of less than 15, this has 30.

ggcorrmat <- function(data,
^

R/gghistostats.R:79:1: style: functions should have cyclomatic complexity of less than 15, this has 24.

gghistostats <- function(data,
^

R/ggpiestats.R:110:1: style: functions should have cyclomatic complexity of less than 15, this has 22.

ggpiestats <- function(data,
^

R/ggscatterstats.R:96:1: style: functions should have cyclomatic complexity of less than 15, this has 34.

ggscatterstats <- function(data,
^

R/ggwithinstats.R:63:1: style: functions should have cyclomatic complexity of less than 15, this has 31.

ggwithinstats <- function(data,
^

R/helpers_ggbetweenstats_graphics.R:369:26: style: %>% should always have a space before it and a new line after it, unless the full pipeline fits on one line.

​      ggsignif_xy(data %>% dplyr::pull({{ x }}), data %>% dplyr::pull({{ y }}))
                       ~~^

R/helpers_gghistostats_graphics.R:48:5: warning: local variable ‘label.value’ assigned but may not be used

label.value <- x_pos
    ^~~~~~~~~~~

Please sign in to comment.