Search code examples
rggplot2false-positive

False positive vs. false negative trade off plot


I'm working on a decision making analysis where I'm trying to illustrate the trade off between false positive (false go) vs. false negative (false no-go) using R. I have created a density plot with null and alternative hypothesis curves, but would like to further illustrate the relationship via the example plots like these. Would appreciate the help in creating plots like example 1 and 2, especially example 1. Thank you!

Density plot

my density plot

Example 1

example 1

Example 2

example 2


Solution

  • I used two offset normal distributions, the premise carries into whatever curves you can imagine.

    library(ggplot2)
    
    xs <- seq(-2, 4, length.out = 201)
    dat <- do.call(rbind,
      list(data.frame(x=xs, y=dnorm(xs), id="1"),
           data.frame(x=xs, y=dnorm(xs, 2), id="2")))
    

    plot 1

    vline <- 1
    eps <- 1e-3
    
    ggplot(dat, aes(x, y, group = id, color = id)) +
      geom_line() +
      geom_area(aes(fill = id),
                data = ~ subset(., (id == "1" & x > (vline+eps)) | (id == "2" & x < (vline-eps)))) +
      geom_vline(xintercept = vline, linetype = "dashed") +
      labs(x = "Hazard Ratio", y = NULL) +
      guides(color = "none", fill = "none") +
      theme_classic() +
      theme(
        axis.line.y = element_blank(),
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()
      )
    

    enter image description here

    The vline is the differentiating line here, if it is not at the intersection then it can still be useful. For instance,

    vline <- 1.2
    

    enter image description here

    plot 2

    rng <- c(0.75, 0.85)
    rngdat <- do.call(rbind,
      by(dat, dat$id, function(z) with(z, data.frame(approx(x, y, xout = rng), id = id[1]))))
    rngdat$otherx <- fifelse(rngdat$id == "1", Inf, -Inf)
    
    ggplot(dat, aes(x, y, group = id, color = id)) +
      geom_line(na.rm = TRUE) +
      geom_segment(aes(xend = x, yend = 0),
                   data = subset(rngdat, id == 1),
                   color = "black", linetype = "dashed") +
      geom_segment(aes(xend = otherx, yend = y),
                   data = rngdat, linetype = "dashed") +
      coord_cartesian(xlim = c(0, 2)) +
      scale_x_continuous(name = "HR gate") +
      scale_y_continuous(
        name = "False Go Probability",
        sec.axis = sec_axis(~ ., name = "False No-Go Probability")) +
      scale_color_manual(values = c("1" = "blue", "2" = "red")) +
      guides(color = "none") +
      theme_classic() +
      theme(
        axis.line.y.left = element_line(color = "red"),
        axis.line.y.right = element_line(color = "blue")
      )
    

    enter image description here

    plot 3

    offset <- max(rngdat$y[rngdat$id == "1"]) + 0.1
    cutoff <- 0
    dat <- transform(
      dat,
      yoff = ifelse(id == "1", 0.05 + offset, 0),
      cat = ifelse(id == "1",
                   ifelse(x < cutoff, "True Positive", "False Negative"),
                   ifelse(x < cutoff, "False Positive", "True Negative")))
    
    ggplot(dat, aes(x, y = y + yoff)) +
      geom_ribbon(aes(ymin = yoff, ymax = y + yoff,
                      group = cat, fill = cat, alpha = cat),
                  na.rm = TRUE) +
      geom_vline(xintercept = cutoff) +
      scale_fill_manual(
        name = NULL,
        values = c("True Positive" = "red", "False Negative" = "red",
                   "False Positive" = "blue", "True Negative" = "blue")) +
      scale_alpha_manual(
        name = NULL,
        values = c("True Positive" = 1, "False Negative" = 0.2,
                   "False Positive" = 0.2, "True Negative" = 1)) +
      labs(x = NULL, y = NULL) +
      theme(
        legend.position = "bottom",
        axis.text.y = element_blank(),
        axis.ticks.y = element_blank()
      )
    

    enter image description here