在 R 中的 ggplot2 中的错误栏中添加箭头,使其高于或低于限制

问题描述 投票:0回答:1

我在 R 中使用 ggplot2,并且仅在误差条高于或低于下图中的 upper_limit/lower_limit 的情况下,尝试在图中的误差条上添加箭头(请参阅限制定义的代码)。我已经玩过 geom_segment 并可以添加箭头,但它们的位置不正确。我之前也遇到过类似的问题,错误栏和点未对齐,但相同的修复,例如,组似乎在这里不起作用(请参阅之前的问题和答案此处。有人对如何解决此问题有任何建议吗?

生成箭头位置不正确的绘图的代码:

# Define custom_colors as a named vector
custom_colors <- c("HR" = "#97D9E3", "OR" = "#A59BEE", "RD" = "#FDB633", "cont" = "#F6A4B7")

custom_shapes <- c("Obs" = 15, "Between-family" = 24, "Within-family" = 25, "1SMR" = 16, "2SMR" = 18)

pd <- position_dodge(width = 1.0)

line_data <- data.frame(
  xintercept = seq(0.5, 10.5, by = 1)  # Adjust this based on the number of outcomes
)

upper_limit <- 3.5
lower_limit <- -2.3
n_methods <- 5
dodge_width <- 1.0

df_upper_arrows <- df_filtered %>%
  filter(UCI > upper_limit) %>%
  mutate(dodged_x = as.numeric(as.factor(Outcome)) + 
                    (as.numeric(Method) - 1.5) * dodge_width / n_methods)

# Subset for arrows below lower limit
df_lower_arrows <- df_filtered %>%
  filter(LCI < lower_limit) %>%
  mutate(dodged_x = as.numeric(as.factor(Outcome)) + 
                    (as.numeric(Method) - 1.5) * dodge_width / n_methods)

# Create the combined plot
p <- ggplot(df_filtered, aes(x = Outcome)) + 
 
  geom_vline(data = line_data, aes(xintercept = xintercept), 
             color = "white", linetype = 1) +
  
  geom_hline(yintercept = 0, color = "#646363", linetype = "dashed") +
  
  # Points for cont and RD on the second y-axis
  geom_point(data = df_filtered,
             aes(y = Effect_estimate, shape = Method, color = effect_type, fill = effect_type),
             size = 3, stroke=0, position = pd) +

  # Confidence intervals for cont and RD on the second y-axis
  geom_errorbar(data = df_filtered,
                aes(ymin = pmax(LCI, lower_limit), ymax = pmin(UCI, upper_limit), color = effect_type, group = interaction(Method, drop=FALSE)),
                width = 0, position = pd, size = 0.5) +
  
# Arrows for points where UCI exceeds the upper limit
  geom_segment(data = df_upper_arrows,
               aes(x = dodged_x, xend = dodged_x, 
                   y = upper_limit, yend = upper_limit + 0.2, 
                   color = effect_type, group = interaction(Method, drop = FALSE)),
               arrow = arrow(length = unit(0.1, "cm"), type = "open"),
               size = 0.5) +

  # Arrows for points where LCI is below the lower limit
  geom_segment(data = df_lower_arrows,
               aes(x = dodged_x, xend = dodged_x, 
                   y = lower_limit, yend = lower_limit - 0.2, 
                   color = effect_type, group = interaction(Method, drop = FALSE)),
               arrow = arrow(length = unit(0.1, "cm"), type = "open"),
               size = 0.5) +
  
  # Customize the theme
  theme_minimal(base_size = 15) +
  theme(panel.background = element_rect(fill = "gray90", color = NA), # Gray background
        panel.grid.major.x = element_blank(),  # No major vertical gridlines
        panel.grid.minor.x = element_blank(), # Optional: Hide minor vertical gridlines
        panel.grid.major.y = element_line(color = "white"), # Keep y major gridlines
        panel.grid.minor.y = element_line(color = "white", linewidth = 0.5),
        legend.position = "right",
        axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(y = "Effect Estimate (OR)", x = "Outcome", color = "Effect Type", fill = "Effect Type", shape = "Method") +
  
  scale_fill_manual(values = custom_colors, na.translate = FALSE, labels = c("cont" = "Continuous")) +  # Use custom colors for effect types
  scale_color_manual(values = custom_colors, na.translate = FALSE, labels = c("cont" = "Continuous")) +  # Use custom colors for effect types
  scale_shape_manual(values = custom_shapes, labels = c("Obs" = "Observational")) + 
  
  # Secondary y-axis for cont and RD
  scale_y_continuous(limits = c(-2.5,3.8), labels = c("0.14", "1", "7.39", "54.60"), sec.axis = sec_axis(trans = ~ ., name = "Effect Estimate (Continuous, RD)")) +

  guides(shape = guide_legend(override.aes = list(fill = "black", stroke = 0)))

# Print the plot
print(p)

下图: enter image description here

数据集在这里:

Exposure,Outcome,Method,Model,Effect_estimate,LCI,UCI,p_value,units,effect_type,SD
Loneliness,Self harm,Obs,logistic,0.2695129,0.23552845,0.3053514,6.33E-53,yes/no,OR,NA
Loneliness,Self harm,Between-family,logistic,0.1931246,0.01703334,0.3673559,3.00E-02,yes/no,OR,NA
Loneliness,Self harm,Within-family,logistic,0.2278867,0.05307844,0.4048337,1.00E-02,yes/no,OR,NA
Loneliness,Self harm,1SMR,ivreg,0.31,0.08,0.54,7.51E-03,yes/no,RD,NA
Loneliness,Self harm,2SMR,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Suicide attempt,Obs,logistic,0.2764618,0.23044892,0.3242825,8.76E-31,yes/no,OR,NA
Loneliness,Suicide attempt,Between-family,logistic,0.2787536,0.04139269,0.519828,2.00E-02,yes/no,OR,NA
Loneliness,Suicide attempt,Within-family,logistic,0.2671717,0.02530587,0.510545,3.00E-02,yes/no,OR,NA
Loneliness,Suicide attempt,1SMR,ivreg,0.15,-0.00743,0.31,6.00E-02,yes/no,RD,NA
Loneliness,Suicide attempt,2SMR,IVW,0.3838154,0.16435286,0.6009729,5.57E-04,NA,OR,NA
Loneliness,Depression diagnosis,Obs,logistic,0.4048337,0.38738983,0.4199557,0.00E+00,yes/no,OR,NA
Loneliness,Depression diagnosis,Between-family,logistic,0.4248816,0.34830486,0.5010593,4.64E-28,yes/no,OR,NA
Loneliness,Depression diagnosis,Within-family,logistic,0.3521825,0.2764618,0.4265113,8.17E-20,yes/no,OR,NA
Loneliness,Depression diagnosis,1SMR,ivreg,0.35,0.15,0.55,5.18E-04,yes/no,RD,NA
Loneliness,Depression diagnosis,2SMR,IVW,0.3283796,0.15228834,0.50515,2.74E-04,NA,OR,NA
Loneliness,Anxiety diagnosis,Obs,logistic,0.2787536,0.26007139,0.2966652,1.73E-180,yes/no,OR,NA
Loneliness,Anxiety diagnosis,Between-family,logistic,0.3031961,0.21748394,0.3909351,5.56E-12,yes/no,OR,NA
Loneliness,Anxiety diagnosis,Within-family,logistic,0.2278867,0.1430148,0.3138672,1.93E-07,yes/no,OR,NA
Loneliness,Anxiety diagnosis,1SMR,ivreg,0.13,-0.04,0.29,1.30E-01,yes/no,RD,NA
Loneliness,Anxiety diagnosis,2SMR,IVW,0.2810334,-0.07572071,0.6394865,1.20E-01,NA,OR,NA
Loneliness,Depression trait,Obs,linear,0.5815217,0.55706522,0.6032609,0.00E+00,score ranges from 0 to 27,cont,3.68
Loneliness,Depression trait,Between-family,linear,0.6956522,0.60326087,0.7880435,1.20E-48,score ranges from 0 to 27,cont,3.68
Loneliness,Depression trait,Within-family,linear,0.4809783,0.38315217,0.576087,1.39E-22,score ranges from 0 to 27,cont,3.68
Loneliness,Depression trait,1SMR,ivreg,3.5326087,2.07065217,4.9918478,2.16E-06,score ranges from 0 to 27,cont,3.68
Loneliness,Depression trait,2SMR,NA,NA,NA,NA,NA,NA,NA,3.68
Loneliness,Anxiety trait,Obs,linear,0.4705882,0.44705882,0.4941176,0.00E+00,score ranges from 0 to 21,cont,3.4
Loneliness,Anxiety trait,Between-family,linear,0.5735294,0.48235294,0.6676471,2.61E-33,score ranges from 0 to 21,cont,3.4
Loneliness,Anxiety trait,Within-family,linear,0.3735294,0.27647059,0.4676471,2.51E-14,score ranges from 0 to 21,cont,3.4
Loneliness,Anxiety trait,1SMR,ivreg,2.2970588,1.14117647,3.4529412,9.81E-05,score ranges from 0 to 21,cont,3.4
Loneliness,Anxiety trait,2SMR,NA,NA,NA,NA,NA,NA,NA,3.4
Loneliness,Positive affect,Obs,linear,-0.7027027,-0.71621622,-0.6891892,0.00E+00,rating ranges from 1 to 6,cont,0.74
Loneliness,Positive affect,Between-family,linear,-0.7567568,-0.83783784,-0.6891892,5.58E-85,rating ranges from 1 to 6,cont,0.74
Loneliness,Positive affect,Within-family,linear,-0.5945946,-0.67567568,-0.527027,9.56E-52,rating ranges from 1 to 6,cont,0.74
Loneliness,Positive affect,1SMR,ivreg,-2.3783784,-3.24324324,-1.5135135,7.98E-08,rating ranges from 1 to 6,cont,0.74
Loneliness,Positive affect,2SMR,IVW,-0.472973,-0.62162162,-0.3243243,3.37E-10,NA,cont,0.74
Loneliness,Meaning in Life,Obs,linear,-0.5180723,-0.54216867,-0.4939759,0.00E+00,rating ranges from 1 to 5,cont,0.83
Loneliness,Meaning in Life,Between-family,linear,-0.5903614,-0.6746988,-0.5060241,4.59E-40,rating ranges from 1 to 5,cont,0.83
Loneliness,Meaning in Life,Within-family,linear,-0.4096386,-0.4939759,-0.313253,2.67E-19,rating ranges from 1 to 5,cont,0.83
Loneliness,Meaning in Life,1SMR,ivreg,-1.1084337,-2.09638554,-0.1204819,3.00E-02,rating ranges from 1 to 5,cont,0.83
Loneliness,Meaning in Life,2SMR,NA,NA,NA,NA,NA,NA,NA,0.83
Loneliness,Wellbeing spectrum,Obs,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Wellbeing spectrum,Between-family,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Wellbeing spectrum,Within-family,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Wellbeing spectrum,1SMR,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Wellbeing spectrum,2SMR,IVW,-0.28,-0.32,-0.23,4.55E-33,NA,cont,NA
Loneliness,Life satisfaction,Obs,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Life satisfaction,Between-family,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Life satisfaction,Within-family,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Life satisfaction,1SMR,NA,NA,NA,NA,NA,NA,NA,NA
Loneliness,Life satisfaction,2SMR,IVW,-0.47,-0.69,-0.24,4.28E-05,NA,cont,NA
r ggplot2 geom-segment
1个回答
0
投票

这是一种可能的选项,它仅使用一个

geom_segment
,而不是使用单独的数据框,而是向数据中添加一些新列来绘制分段:

library(tidyverse)

df_filtered <- df_filtered |>
  mutate(
    Method = factor(Method),
    y = case_when(
      UCI > upper_limit ~ LCI,
      LCI < lower_limit ~ UCI,
      .default = NA
    ),
    yend = case_when(
      UCI > upper_limit ~ Inf,
      LCI < lower_limit ~ -Inf,
      .default = NA
    ),
    x = as.numeric(factor(Outcome)) +
      scales::rescale(
        as.numeric(Method),
        # 4 / 5 = (#(Method) - 1) / #(Method)
        to = c(-1, 1) * (dodge_width / 2) * 4 / 5
      )
  )

ggplot(df_filtered, aes(x = Outcome)) +
  geom_vline(
    data = line_data, aes(xintercept = xintercept),
    color = "white", linetype = 1
  ) +
  geom_hline(yintercept = 0, color = "#646363", linetype = "dashed") +
  geom_point(
    aes(
      y = Effect_estimate, shape = Method,
      color = effect_type, fill = effect_type,
      group = Method
    ),
    size = 3, stroke = 0, position = pd, na.rm = TRUE
  ) +
  geom_errorbar(
    aes(
      ymin = LCI,
      ymax = UCI,
      color = effect_type,
      group = Method
    ),
    width = 0, position = pd, size = 0.5, na.rm = TRUE
  ) +
  geom_segment(
    aes(
      x = x, xend = x,
      y = y, yend = yend,
      color = effect_type
    ),
    arrow = arrow(length = unit(.1, "cm"), type = "open"),
    size = 0.5, na.rm = TRUE
  ) +
  theme_minimal(base_size = 15) +
  theme(
    panel.background = element_rect(fill = "gray90", color = NA), # Gray background
    panel.grid.major.x = element_blank(), # No major vertical gridlines
    panel.grid.minor.x = element_blank(), # Optional: Hide minor vertical gridlines
    panel.grid.major.y = element_line(color = "white"), # Keep y major gridlines
    panel.grid.minor.y = element_line(color = "white", linewidth = 0.5),
    legend.position = "right",
    axis.text.x = element_text(angle = 45, hjust = 1)
  ) +
  labs(
    y = "Effect Estimate (OR)", x = "Outcome",
    color = "Effect Type", fill = "Effect Type", shape = "Method"
  ) +
  scale_fill_manual(
    values = custom_colors, na.translate = FALSE,
    labels = c("cont" = "Continuous")
  ) + # Use custom colors for effect types
  scale_color_manual(
    values = custom_colors, na.translate = FALSE,
    labels = c("cont" = "Continuous")
  ) + # Use custom colors for effect types
  scale_shape_manual(
    values = custom_shapes,
    labels = c("Obs" = "Observational")
  ) +
  scale_y_continuous(
    limits = c(-2.5, 3.8), labels = c("0.14", "1", "7.39", "54.60"),
    sec.axis = sec_axis(
      trans = ~.,
      name = "Effect Estimate (Continuous, RD)"
    )
  ) +
  guides(shape = guide_legend(
    override.aes = list(
      fill = "black",
      stroke = 0
    )
  ))

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.