Search code examples
rggplot2

Control color and alpha conditionally at the same time


I'm trying to tinker with visualizing more detail about the precision of results based on some color-based variation, but running into trouble when I try to simultaneously create conditions based on both alpha and color at the same time.

How would I do something like:

-If the pvalue is >.10, all colors are gray with alpha =0.5

-If the pvalue is between .05 and .10, the colors remain as specified below in scale_color_manual(), but have alpha =0.5

-If the pvalue is <.05, the colors remain as specified below in scale_color_manual() with "full" alpha

Some simulated data and code:

set.seed(123)
terms <- c("covariate1", "covariate2", "covariate3", "covariate4")
outcomes <- c("Outcome1", "Outcome2", "Outcome3")
treatments <- c("Treatment A", "Treatment B")
results <- expand.grid(term = terms, outcome = outcomes, treatment = treatments) %>%
  mutate(
    term = factor(term, levels = terms),
    estimate = rnorm(n(), 0, 0.2),   
    se = runif(n(), 0.05, 0.2),     
    conf.low = estimate - 1.96 * se, 
    conf.high = estimate + 1.96 * se
  )

ggplot(results, aes(x = estimate, y = term, color = outcome)) +
  geom_vline(xintercept = 0, color = "black", linetype = "dashed") +
  geom_point(size = 2, position = position_dodge(width = 0.2)) +
  geom_errorbarh(aes(xmin = conf.low, xmax = conf.high), height = 0, position = position_dodge(width = 0.2)) +
  facet_wrap(~ treatment) +
  scale_color_manual(values = c("Outcome1" = "gold3", 
                                "Outcome2" = "green3", 
                                "Outcome3" = "salmon")) +
  theme_minimal()

Solution

  • One possible solution:

    First, calculate your p-values. Here's an example with a z-test, but use whatever's appropriate for your data:

    results <- results %>%
      mutate(
        p.value = 2 * (1 - pnorm(abs(estimate / se)))
      )
    

    Then, map the color aesthetic to a new factor vector that is equal to outcome unless p >= 0.10:

    color = factor(
      if_else(p.value < 0.10, outcome, "n.s."),
      levels = c(levels(outcome), "n.s.")
    )
    

    In order to keep outcomes in the legend even if none are significant, we need to add drop = FALSE to scale_color_manual() as well as show.legend = TRUE to both geom_point() and geom_errorbarh(). We also need to add the aesthetic group = outcome so that position_dodge() still works as before.

    Map alpha to a new factor vector that is one level if less than 0.05, and another otherwise:

    alpha = cut(p.value, c(0, 0.05, 1))
    

    And use scale_alpha_manual() to define the alpha values:

    scale_alpha_manual(
      values = c(1, 0.5),
      guide = "none"
    )
    

    Putting it all together (note I used a different seed):

    set.seed(789)
    terms <- c("covariate1", "covariate2", "covariate3", "covariate4")
    outcomes <- c("Outcome1", "Outcome2", "Outcome3")
    treatments <- c("Treatment A", "Treatment B")
    results <- expand.grid(term = terms, outcome = outcomes, treatment = treatments) %>%
      mutate(
        term = factor(term, levels = terms),
        estimate = rnorm(n(), 0, 0.2),   
        se = runif(n(), 0.05, 0.2),     
        conf.low = estimate - 1.96 * se, 
        conf.high = estimate + 1.96 * se
      ) %>%
      mutate(
        p.value = 2 * (1 - pnorm(abs(estimate / se)))
      )
    
    ggplot(results, 
        aes(
          x = estimate, 
          y = term, 
          group = outcome,
          color = factor(
            if_else(p.value < 0.10, outcome, "n.s."),
            levels = c(levels(outcome), "n.s.")
          ),
          alpha = cut(p.value, c(0, 0.05, 1))
        )
      ) +
      geom_vline(xintercept = 0, color = "black", linetype = "dashed") +
      geom_point(size = 2, position = position_dodge(width = 0.2), show.legend = TRUE) +
      geom_errorbarh(aes(xmin = conf.low, xmax = conf.high), height = 0, position = position_dodge(width = 0.2), show.legend = TRUE) +
      facet_wrap(~ treatment) +
      scale_color_manual(
        values = c(
          "Outcome1" = "gold3", 
          "Outcome2" = "green3", 
          "Outcome3" = "salmon",
          "n.s." = "grey"
        ),
        drop = FALSE,
        name = "Outcome"
      ) +
      scale_alpha_manual(
        values = c(1, 0.5),
        guide = "none"
      ) +
      theme_minimal()
    

    Plot with desired coloring and alpha