R/plot_bland_altman.R

Defines functions check_args_model_data model_data.lmerMod model_data.lm model_data.lvmisc_cv model_data.default model_data plot_bland_altman

Documented in plot_bland_altman

#' Create a Bland-Altman plot
#'
#' Create a Bland-Altman plot as described by Bland & Altman (1986).
#'
#' @param x An object of class \code{lvmisc_cv} or an object containing a model.
#' @param ... Additional arguments to be passed to \code{ggplot2::aes()}.
#'
#' @return A \code{ggplot} object.
#'
#' @references \itemize{
#'   \item Bland, J.M. & Altman, D.G. (1986). Statistical methods for assessing
#'   agreement between two methods of clinical measurement. 
#'   Lancet, 8(1), 307-10. \doi{https://doi.org/10.1016/S0140-6736(86)90837-8}
#'  }
#'
#' @export
#'
#' @examples
#' mtcars <- tibble::as_tibble(mtcars, rownames = "car")
#' m <- stats::lm(disp ~ mpg, mtcars)
#' cv <- loo_cv(m, mtcars, car)
#' plot_bland_altman(cv, colour = as.factor(am))
plot_bland_altman <- function(x, ...) {
  data <- model_data(x)
  plot_data <- data$model_data
  bias <- data$bias
  lower_loa <- data$loa$lower
  upper_loa <- data$loa$upper

  ggplot2::ggplot(plot_data) +
    ggplot2::geom_point(ggplot2::aes(x = mean, y = diff, ...)) +
    ggplot2::geom_hline(yintercept = bias) +
    ggplot2::geom_hline(yintercept = lower_loa, linetype = "longdash") +
    ggplot2::geom_hline(yintercept = upper_loa, linetype = "longdash")
}

model_data <- function(x) {
 UseMethod("model_data")
}

model_data.default <- function(x) {
  msg <- glue::glue(
    "If you would like it to be implemented, please file an issue at \\
    https://github.com/verasls/lvmisc/issues."
  )
  abort_no_method_for_class("model_data", class(x), msg)
}

model_data.lvmisc_cv <- function(x) {
  check_args_model_data(x)

  mean <- (x[[".actual"]] + x[[".predicted"]]) / 2
  diff <- x[[".actual"]] - x[[".predicted"]]

  bias <- bias(x[[".actual"]], x[[".predicted"]], na.rm = TRUE)
  loa <- loa(x[[".actual"]], x[[".predicted"]], na.rm = TRUE)

  list(
    model_data = cbind(x, mean, diff),
    bias = bias, loa = loa
  )
}

model_data.lm <- function(x) {
  check_args_model_data(x)

  formula <- stats::formula(x)
  outcome <- as.character(rlang::f_lhs(formula))

  actual <- x$model[[outcome]]
  predicted <- stats::predict(x)
  mean <- (actual + predicted) / 2
  diff <- actual - predicted

  bias <- bias(actual, predicted, na.rm = TRUE)
  loa <- loa(actual, predicted, na.rm = TRUE)

  list(
    model_data = tibble::tibble(mean, diff),
    bias = bias, loa = loa
  )
}

model_data.lmerMod <- function(x) {
  check_args_model_data(x)

  formula <- stats::formula(x)
  outcome <- as.character(rlang::f_lhs(formula))

  actual <- stats::model.frame(x)[[outcome]]
  predicted <- stats::predict(x)
  mean <- (actual + predicted) / 2
  diff <- actual - predicted

  bias <- bias(actual, predicted, na.rm = TRUE)
  loa <- loa(actual, predicted, na.rm = TRUE)

  list(
    model_data = tibble::tibble(mean, diff),
    bias = bias, loa = loa
  )
}

check_args_model_data <- function(x) {
  if ("lvmisc_cv" %!in% class(x) & length(class(x)) > 1) {
    classes <- class(x)[class(x) %!in% c("lm", "lmerMod")]
    msg <- glue::glue(
      "If you would like it to be implemented, please file an issue at \\
      https://github.com/verasls/lvmisc/issues."
    )
    abort_no_method_for_class("model_data", classes, msg)
  }
}

Try the lvmisc package in your browser

Any scripts or data that you put into this service are public.

lvmisc documentation built on April 5, 2021, 5:06 p.m.