数据准备
library(dplyr)
library(ggplot2)
library(ggrepel)
library(scales)
set.seed(20260910)
reference_data <- tibble(
label = paste("Reference", LETTERS[1:9]),
group = paste("Region", LETTERS[1:9]),
source = "Literature",
x_mean = round(runif(9, 150, 820)),
x_error = round(runif(9, 35, 180)),
y_mean = round(0.004 + x_mean * 0.000035 + rnorm(9, 0, 0.006), 4),
y_error = round(runif(9, 0.002, 0.010), 4)
) |>
mutate(
y_mean = pmax(y_mean, 0.003),
x_lower = pmax(x_mean - x_error, 0), # 截到 0:这些量不可能是负的
x_upper = x_mean + x_error,
y_lower = pmax(y_mean - y_error, 0),
y_upper = y_mean + y_error
)
target_data <- tibble(
label = "This study", group = "Target", source = "This Study",
x_mean = 380, x_lower = 340, x_upper = 420,
y_mean = 0.0034, y_lower = 0.0028, y_upper = 0.0040
)
plot_data <- bind_rows(target_data, reference_data) |>
mutate(
# 兜底:从文献里抄数据时 lower/upper 录反是常事,而且画出来不报错
x_min = pmin(x_lower, x_upper, na.rm = TRUE),
x_max = pmax(x_lower, x_upper, na.rm = TRUE),
y_min = pmin(y_lower, y_upper, na.rm = TRUE),
y_max = pmax(y_lower, y_upper, na.rm = TRUE),
source = factor(source, levels = c("This Study", "Literature"))
)
方法 A · 基础二维误差棒
x 方向没有现成的 geom_errorbarh 那么顺手,用 geom_segment() 画一条水平线更直接。
#| fig: basic
#| fig-width: 7
#| fig-height: 5
ggplot(plot_data, aes(x = x_mean, y = y_mean)) +
# 横棒:从 x_min 拉到 x_max,y 固定在中心估计上
geom_segment(
aes(x = x_min, xend = x_max, y = y_mean, yend = y_mean),
color = "grey50", alpha = 0.7, linewidth = 0.5, na.rm = TRUE
) +
geom_errorbar(
aes(ymin = y_min, ymax = y_max),
width = 0, # 关键:不要帽子。两个方向都带帽会在每个点周围画出一个十字架
color = "grey50", alpha = 0.7, linewidth = 0.5, na.rm = TRUE
) +
geom_point(size = 2.8, color = "#1f77b4") + # 点最后画,压在两条棒上面
labs(x = "Input measure", y = "Rate measure",
title = "Scatter Plot with X and Y Error Bars") +
theme_bw(base_size = 12) +
theme(
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "grey90", linewidth = 0.3),
plot.title = element_text(face = "bold", hjust = 0)
)