Search code examples
rggplot2tidyverse

Formatting coefficient plot


I have the following dataset and code to create a ggplot2:

df <- structure(list(variable = structure(7:1, levels = c("SRQ", "HH Has Apply For A Credit", 
"HH Has Any Savings", "# Coping Strategies", "Total HH Assets", 
"Monthly Non-food Expenditure", "Monthly Food Expenditure"), class = "factor"), 
    estimate = c(0.0378809385001659, 0.060384850949049, 0.0223603062331676, 
    -0.018746592104435, 0.0670924708247185, 0.0125845950096846, 
    -0.05361233279109), conf.low = c(-0.0080009132987051, 0.0153929226546019, 
    -0.0242789392007765, -0.0670778215055634, 0.0232582402812049, 
    -0.0279621551777822, -0.0987270481390539), conf.high = c(0.083762790299037, 
    0.105376779243496, 0.0689995516671118, 0.0295846372966935, 
    0.110926701368232, 0.0531313451971513, -0.0084976174431262
    ), type = c("Consumption Expenditure", "Consumption Expenditure", 
    "Household Assets", "Coping Mechanisms", "Financial", "Financial", 
    "Psycho-social well-being"), significance = c(FALSE, TRUE, 
    FALSE, FALSE, TRUE, FALSE, TRUE)), row.names = c(NA, -7L), class = c("tbl_df", 
"tbl", "data.frame"))

# Plot
df %>%
  mutate() %>%
  ggplot(aes(y = variable, x = estimate)) +
  geom_vline(xintercept = 0, color = "black", linewidth = .5, linetype = "dashed") +
  geom_hline(yintercept = Inf, color = "black", linewidth = .5, linetype = "solid") +
  geom_pointrange(
    aes(
      fill = significance,
      xmin = conf.low,
      xmax = conf.high
    ),
    size = .5,
    shape = 23,
    stroke = 1
  ) +
  geom_label(
    aes(
      x = conf.low,
      label = variable
    ),
    hjust = 1,
    fill = NA,
    label.size = 0
  ) +
  geom_label(
    data = ~ dplyr::distinct(.x, type),
    aes(
      x = -Inf,
      y = Inf,
      label = type
    ),
    hjust = 0,
    vjust = 1,
    fill = NA,
    fontface = "bold",
    label.size = 0
  ) +
  labs(
    y = NULL,
    x = "Effect size in standard deviations"
  ) +
  scale_y_discrete(breaks = NULL) +
  scale_x_continuous(expand = c(0, .2)) +
  scale_fill_manual(values = c("white", "black")) +
  facet_grid(type ~ ., switch = "y", scales = "free_y", space = "free_y") +
  guides(fill = "none") +
  theme_classic(base_size = 13) +
  theme(
    strip.text.y.left = element_blank(),
    panel.spacing.y = unit(0, "mm")
  ) +
  coord_cartesian(clip = "off")

While the code is working perfectly, I want to add a few tweaks: (1) I want the line of the geom_pointrange to be grey instead of black but I don't know how to do this while I keep the fill by significance. So, (2) make the point of geompoint_range bigger and black or white depending on the variable significance.


Solution

  • I have created four steps for you:

    1. You might separate the line and point layers using geom_linerange and geom_point. This offers distinct control over the line and point aesthetics.
    2. Add custom scales for point shape and fill based on significance.
    3. Use scale_color_manual and scale_fill_manual to manage color settings with more granularity.
    4. Optimize point and line styling parameters by setting specific aesthetic mappings and custom themes. I have revised your code with the 4 steps I mentioned above:
    library(ggplot2)
    library(dplyr)
    
    df %>%
        ggplot(aes(y = variable, x = estimate)) +
        geom_vline(xintercept = 0, color = "black", linewidth = .5, linetype = "dashed") +
        geom_hline(yintercept = Inf, color = "black", linewidth = .5, linetype = "solid") +
    
    # Separate the line component with geom_linerange for independent control
        geom_linerange(
            aes(
                xmin = conf.low,
                xmax = conf.high
            ),
            color = "grey70",       # Set line color to grey independently
            size = 0.5
        ) +
    
        # Separate the point component with geom_point for size and fill control
        geom_point(
            aes(
                fill = significance
            ),
            size = 3,               # Set point size larger
            shape = 21,             # Shape that allows color fill and outline
            color = "black",        # Outline color, customizable if desired
            stroke = 1
        ) +
    
        # Label layers (kept as-is from original request)
        geom_label(
            aes(
                x = conf.low,
                label = variable
            ),
            hjust = 1,
            fill = NA,
            label.size = 0
        ) +
        geom_label(
            data = ~ dplyr::distinct(.x, type),
            aes(
                x = -Inf,
                y = Inf,
                label = type
            ),
            hjust = 0,
            vjust = 1,
            fill = NA,
            fontface = "bold",
            label.size = 0
        ) +
    
        # Scales and fill management
        labs(
            y = NULL,
            x = "Effect size in standard deviations"
        ) +
        scale_y_discrete(breaks = NULL) +
      scale_x_continuous(expand = c(0, .2)) +
      scale_fill_manual(values = c("white", "black")) +
      facet_grid(type ~ ., switch = "y", scales = "free_y", space = "free_y") +
      guides(fill = "none") +
      theme_classic(base_size = 13) +
      theme(
        strip.text.y.left = element_blank(),
        panel.spacing.y = unit(0, "mm")
      ) +
      coord_cartesian(clip = "off")