I am generating a forest plot of hazard ratios using ggplot2. I have different groups and within the groups, I have 2 different models: weighted models and unweighted models which are signified by different colours on the plot. This is all fine, but I’d like to annotate the plot as well with the coefficients, but I can’t work out how to do this so that the coefficients are aligned with each point, taking into account the position_dodge()? Here is the code:
library(ggplot2)
# Sample data
final_cox_dat <- data.frame(
comparator = rep(c("Group A", "Group B", "Group C"), each = 2),
estimate = c(1.2, 1.5, 0.8, 0.9, 1.4, 1.7),
conf.low = c(1.0, 1.3, 0.7, 0.8, 1.3, 1.5),
conf.high = c(1.5, 1.7, 0.9, 1.0, 1.6, 1.9),
model = rep(c("Weighted", "Unweighted"), times = 3)
)
# Create a forest plot using ggplot2 with sanitized facet labels
forest_plot <- ggplot(final_cox_dat, aes(x = estimate, y = comparator, xmin = conf.low, xmax = conf.high, color = model)) +
geom_pointrange(position = position_dodge(width = 0.8)) +
geom_vline(xintercept = 1, linetype = "dashed") +
facet_wrap(~ comparator, ncol = 1, scales = "free_y") +
labs(
title = "Forest Plot",
x = "Hazard Ratio (HR)",
y = NULL
) +
theme_minimal() +
theme(
strip.text = element_blank(), # Hide both x and y-axis labels in facet
legend.title = element_blank(),
legend.position = "bottom",
axis.title.y = element_blank(),
axis.ticks.y = element_blank()
) +
scale_color_manual(values = c("Weighted" = "blue", "Unweighted" = "red")) +
geom_text(
aes(
x = max(final_cox_dat$conf.high) + 0.05,
y = ifelse(model == "Weighted", 0.03, -0.03),
label = paste0(round(estimate, digits = 2), " (", round(conf.low, digits = 2), ", ", round(conf.high, digits = 2), ")")
),
hjust = 0, vjust = 0.5, size = 3, color = "black"
)
# Print the forest plot
print(forest_plot)
>Solution :
You could simply use position_dodge for the labels as well. To make this work map model on the group= aes in geom_text:
ggplot(
final_cox_dat,
aes(
x = estimate, y = comparator,
xmin = conf.low, xmax = conf.high,
color = model
)
) +
geom_pointrange(position = position_dodge(width = 0.8)) +
geom_vline(xintercept = 1, linetype = "dashed") +
facet_wrap(~comparator, ncol = 1, scales = "free_y") +
labs(
title = "Forest Plot",
x = "Hazard Ratio (HR)",
y = NULL
) +
theme_minimal() +
theme(
strip.text = element_blank(), # Hide both x and y-axis labels in facet
legend.title = element_blank(),
legend.position = "bottom",
axis.title.y = element_blank(),
axis.ticks.y = element_blank()
) +
scale_color_manual(
values = c("Weighted" = "blue", "Unweighted" = "red")
) +
geom_text(
aes(
x = max(conf.high) + 0.05,
group = model,
label = paste0(
round(estimate, digits = 2), " (",
round(conf.low, digits = 2), ", ",
round(conf.high, digits = 2), ")"
)
),
hjust = 0, vjust = 0.5, size = 3, color = "black",
position = position_dodge(width = 0.8)
)

