R/error_plot.R

Defines functions error_plot

Documented in error_plot

#' Error plot for `euler` objects
#'
#' This is a diagnostic tool for evaluating the fit from a call
#' to [euler()] visually. A color key is provided by default, which
#' represents the chosen error metric so that one can easily detect
#' which areas in the diagram to be skeptical about.
#'
#' Notice that this function is purely provided for diagnostic reasons
#' and does not come with the same kind of customization that
#' [plot.euler()] provides: the color legend can only be customized
#' in regards to its color palette and another key (instead of labels)
#' is completely turned off.
#'
#' @param x an object of class `euler`, typically the result of
#'   a call to [euler()].
#' @param type error metric. `'regionError'` is the difference in
#'   *percentage points* from the input
#' @param quantities whether to draw the error metric on the plot
#' @param pal color palette for the fills in the legend
#' @param ... arguments passed down to [plot.euler()]. Currently,
#'   providing `fills`, `legend`, or `strips` are not allowed and
#'   will return a warning.
#'
#' @return Returns an object of class `eulergram`, which will be
#' plotted on the device in the same manner as objects from
#' [plot.euler()]. See [plot.eulergram()] for details.
#'
#' @export
#'
#' @seealso [plot.euler()], [euler()],
#'   [plot.eulergram()]
#'
#' @examples
#' error_plot(euler(organisms), quantities = FALSE)
error_plot <- function(x,
                       type = c("regionError", "residuals"),
                       quantities = TRUE,
                       pal = NULL,
                       ...)
{
  type <- match.arg(type)
  dots <- list(...)
  n <- 101 # number of colors in legend

  if (!is.null(dots$fills))
    stop("values for 'fills' are not allowed here and will be ignored.")

  if (!is.null(dots$legend))
    stop("values for 'legend' are not allowed here and will be ignored.")

  if (!is.null(dots$strips))
    stop("values for 'strips' are not allowed here and will be ignored.")

  r <- switch(type,
              residuals = stats::residuals(x),
              regionError = sign(stats::residuals(x))*x$regionError)

  if (is.null(pal)) {
    pal <- grDevices::colorRampPalette(c("#67001F", "#B2182B", "#D6604D",
                                         "#F4A582", "#FDDBC7", "#F7F7F7",
                                         "#D1E5F0", "#92C5DE", "#4393C3",
                                         "#2166AC", "#053061"),
                                       space = "rgb")
  }

  lim <- max(c(abs(r), ifelse(type == "regionError", 0.01, 0)))

  rng <- grDevices::extendrange(c(-lim, lim))

  labels <- grid::grid.pretty(rng)
  n_labels <- length(labels)

  s <- seq(rng[1], rng[2], length.out = n)

  ind <- findInterval(r, s)

  labels_grob <- grid::textGrob(label = labels,
                                x = rep(0, length(labels)),
                                y = labels,
                                just = "left",
                                vp = grid::viewport(yscale = rng),
                                default.units = "native",
                                name = paste("eulerr", "error_plot", sep = "."))

  heights <- grid::unit(c(1, 1, 1), c("lines", "null", "lines"))
  widths <- grid::unit(c(1, 1, 1),
                       c("lines", "lines", "grobwidth"),
                       data = list(NULL, NULL, labels_grob))

  layout <- grid::grid.layout(nrow = 3, ncol = 3,
                              heights = heights,
                              widths = widths,
                              respect = TRUE)

  frame <- grid::frameGrob(
    layout = layout,
    vp = NULL,
    name = paste("eulerr", "error_plot", "key", sep = ".")
  )

  step <- diff(range(s))/(n - 1)
  y_rect <- seq(min(s) + step/2, max(s) - step/2, length.out = n - 1)

  ticks_grob <- grid::segmentsGrob(
    x0 = rep(0, n_labels),
    y0 = labels,
    x1 = rep(0.7, n_labels),
    y1 = labels,
    default.units = "native",
    name = paste("eulerr", "error_plot", "key", "ticks", sep = "."),
    vp = grid::viewport(yscale = rng)
  )

  box_grob <- grid::rectGrob(
    vp = grid::viewport(yscale = rng),
    height = diff(rng),
    default.units = "native",
    name = paste("eulerr", "error_plot", "key", "box", sep = "."),
    gp = grid::gpar(fill = "transparent")
  )

  rect_grob <- grid::rectGrob(
    x = rep(0.5, length(y_rect)),
    y = y_rect,
    default.units = "native",
    height = step,
    vp = grid::viewport(yscale = rng),
    name = paste("eulerr", "error_plot", "key", "rect", sep = "."),
    gp = grid::gpar(fill = pal(n), col = "transparent")
  )

  frame <- grid::placeGrob(frame, rect_grob, row = 2, col = 1)
  frame <- grid::placeGrob(frame, box_grob, row = 2, col = 1)
  frame <- grid::placeGrob(frame, ticks_grob, row = 2, col = 2)
  frame <- grid::placeGrob(frame, labels_grob, row = 2, col = 3)

  graphics::plot(x,
                 fills = pal(n)[ind],
                 labels = TRUE,
                 quantities = if (quantities) round(r, 3) else FALSE,
                 legend = frame,
                 ...)
}
jolars/eulerr documentation built on April 2, 2024, 11:42 p.m.