How to add ggplot2 gridlines or color to show multiple plot points by variables (y-axis)?

Viewed 74

I am creating a figure that shows 4 outcome beta's + CI lines per variable.

I want to more clearly show that the 4 plotted points (outcome) and lines (CIs) relate to each variable.

Therefore, I am curious how I might 1) make clearer panels or grid changes to show which 4 outcomes relate to which variable OR 2) Create brackets around the variable on the y axis?

Code and figure below.

library(tidyverse)
library(viridis)
#> Loading required package: viridisLite

df <- tribble(
  ~var, ~gender, ~outcome, ~est, ~l95, ~u95,
  "A", "Men", "X", 0.2, 0.1, 0.3,
  "A", "Men", "Y", 0.3, 0.25, 0.35,
  "B", "Men", "X", -0.4, -0.5, -0.3,
  "B", "Men", "Y", -0.45, -0.5, -0.4,
  "A", "Women", "X", 0.4, 0.3, 0.5,
  "A", "Women", "Y", 0.6, 0.55, 0.65,
  "B", "Women", "X", -0.1, -0.2, 0,
  "B", "Women", "Y", -0.3, -0.4, -0.2,
  "A", "Men", "Z", 0.2, 0.1, 0.3,
  "A", "Men", "AA", 0.3, 0.25, 0.35,
  "B", "Men", "Z", -0.4, -0.5, -0.3,
  "B", "Men", "AA", -0.45, -0.5, -0.4,
  "A", "Women", "Z", 0.4, 0.3, 0.5,
  "A", "Women", "AA", 0.6, 0.55, 0.65,
  "B", "Women", "Z", -0.1, -0.2, 0,
  "B", "Women", "AA", -0.3, -0.4, -0.2
)

df %>%
  ggplot(aes(x=est, y=var, color=outcome)) +
  geom_point(position = position_dodge2(width = 1.0)) +
  scale_y_discrete(limits=rev, expand=c(0, 0)) +
  scale_color_viridis_d() +
  geom_linerange(aes(xmin=l95, xmax=u95),
    position = position_dodge2(width=1.0)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_grid(~ gender) +
  theme_minimal() +
  theme(plot.title.position = "plot",
    plot.title = element_text(face="bold"),
    legend.position = "top",
    strip.text = element_text(face="bold")) +
  labs(y = NULL,
    x = "Standardized Beta",
    title = "My cool plot shows this thing",
    subtitle = "More important details, 95% confidence intervals",
    caption = "Even more important details")

Created on 2021-06-03 by the reprex package (v2.0.0)

2 Answers

I think I would facet on both gender and var, with outcome being used on the actual y axis. To my eye, a little gray line round each panel also improves the clarity:

df %>%
  ggplot(aes(x=est, y=outcome, color=outcome)) +
  geom_point(position = position_dodge2(width = 1.0)) +
  scale_y_discrete(limits=rev, expand=c(0, 0)) +
  scale_color_viridis_d() +
  geom_linerange(aes(xmin=l95, xmax=u95),
    position = position_dodge2(width=1.0)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_grid(var ~ gender, switch = "y") +
  theme_minimal() +
  theme(plot.title.position = "plot",
    plot.title = element_text(face="bold"),
    legend.position = "top",
    strip.placement = "outside",
    strip.text = element_text(face="bold"),
    panel.background = element_rect(color = "gray50")) +
  labs(y = NULL,
    x = "Standardized Beta",
    title = "My cool plot shows this thing",
    subtitle = "More important details, 95% confidence intervals",
    caption = "Even more important details")

Created on 2021-06-02 by the reprex package (v0.3.0)

Just additional information on the theme attributes that you can manage include

  • panel.spacing - space between grid in facet
  • panel.border - border around grid in facet
  • strip.background - border around the facet title
df %>%
  # change y axis to outcome
  ggplot(aes(x=est, y = outcome, color = outcome)) +
  geom_point(position = position_dodge2(width = 1.0)) +
  scale_y_discrete(limits=rev, expand=c(0, 0)) +
  scale_color_viridis_d() +
  geom_linerange(aes(xmin=l95, xmax=u95),
    position = position_dodge2(width=1.0)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  # facet grid by var & gender
  facet_grid(var ~ gender) +
  theme_minimal() +
  theme(plot.title.position = "plot",
    plot.title = element_text(face="bold"),
    legend.position = "top",
    strip.text = element_text(face="bold")) +
  labs(y = NULL,
    x = "Standardized Beta",
    title = "My cool plot shows this thing",
    subtitle = "More important details, 95% confidence intervals",
    caption = "Even more important details") +
  # add the panel border around each facet
  theme(panel.spacing = unit(5, "mm"),
    panel.border = element_rect(color = "black", fill = NA, size = 1), 
    strip.background = element_rect(color = "black", size = 1))

Created on 2021-06-03 by the reprex package (v2.0.0)

Another way not using facet though it may need some extra hack to reduce the space between var

df %>%
  ggplot(aes(x=est, y=var, color=outcome)) +
  geom_point(position = position_dodge2(width = 1.0)) +
  # add a middle discrete value for y-axis "C" then draw a horizontal line
  # on x
  scale_y_discrete(limits=c("B", "C", "A"), expand=c(0, 0),
    breaks = c("B", "A")) +
  geom_hline(yintercept = "C", linetype = "44") +
  scale_color_viridis_d() +
  geom_linerange(aes(xmin=l95, xmax=u95),
    position = position_dodge2(width=1.0)) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  facet_grid(~ gender) +
  theme_minimal() +
  theme(plot.title.position = "plot",
    plot.title = element_text(face="bold"),
    legend.position = "top",
    strip.text = element_text(face="bold")) +
  labs(y = NULL,
    x = "Standardized Beta",
    title = "My cool plot shows this thing",
    subtitle = "More important details, 95% confidence intervals",
    caption = "Even more important details") +
  theme(panel.spacing = unit(0, "mm"),
    panel.border = element_rect(color = "black", fill = NA, size = 1))

Created on 2021-06-04 by the reprex package (v2.0.0)

Related