There are two problems:
(1) The forest plot I'm trying to make with ggplot2 would ideally be limited between 0 and 16 in the x-axis. I have tried adding arrows to points whose error bars go beyond the set limit, but their error bars that point in the opposite direction disappear completely.
(2) The x-axis is an odds ratio, which I would like to be log2 transformed. I would expect to see 1, 2, 4, 8, 16. But what I currently see is 0, 5, 10, 15. It may well be that the 1st problem is interfering with ggplot's ability to do this.
Here is some data and the code I used for you, the kind and helpful reader, to reproduce the problem.
library(tidyverse, gt, scales)
data <- tibble('SNP'=c('Univariable CM','1','2','3','4','5','6','7','8','9'),
'OR'=c(10.13, 5.16, 2.83, 5.92, 4.71, 6.22, 3.79, 6.64, 7.80, 7.88),
`lower OR`=c(5.3, 1.8, 1.6, 2.8, 2.3, 2.7, 1.3, 3.5, 3.8, 3.9),
`upper OR`=c(19,14,5,12,7,14,11,13,18,17))
data$OR_u <- ifelse(data$`upper OR` > 16, 16, NA_real_) # for the limit x=16
data |>
ggplot(aes(y = fct_rev(fct_relevel(SNP, "Univariable CM")))) +# fct_rev reverses the order of factor levels, A at top, J at bottom
theme_classic() +
geom_point(aes(x=OR, color=OR>0), shape=15, size=3, position = position_dodge(0.5)) + # estimates
geom_linerange(aes(xmin=`lower OR`, xmax=`upper OR`), position = position_dodge(0.5)) + # CIs
geom_vline(xintercept = 1, linetype="dashed") + # OR so x=1
scale_x_continuous(trans='log2',
breaks=c(1,2,4,8,16),
labels=trans_format('log2', math_format(2^.x))) +
xlim(0, 16) +
labs(x="OR", y="") +# x-axis renamed
theme(axis.line.y = element_blank(),
axis.ticks.y= element_blank(),
axis.text.y= element_blank(),
axis.title.y= element_blank(),
legend.position = 'none') +
geom_segment(
aes(x = OR, xend = OR_u, y = fct_rev(fct_relevel(SNP, "Univariable CM")), yend = fct_rev(fct_relevel(SNP, "Univariable CM"))),
position = position_dodge(0.5), arrow = arrow(length = unit(0.3, "cm")))
Thank you so very much in advance!
To check, does this match what you're aiming to do? The small fixes:
xlim
truncates things that are outside of plot area. coord_cartesian(xlim = ...)
plots 'up to' the limits.library(tidyverse)
library(scales)
data <- tibble('SNP'=c('Univariable CM','1','2','3','4','5','6','7','8','9'),
'OR'=c(10.13, 5.16, 2.83, 5.92, 4.71, 6.22, 3.79, 6.64, 7.80, 7.88),
`lower OR`=c(5.3, 1.8, 1.6, 2.8, 2.3, 2.7, 1.3, 3.5, 3.8, 3.9),
`upper OR`=c(19,14,5,12,7,14,11,13,18,17))
data$OR_u <- ifelse(data$`upper OR` > 16, 16, NA_real_) # for the limit x=16
data |>
ggplot(aes(y = fct_rev(fct_relevel(SNP, "Univariable CM")))) +# fct_rev reverses the order of factor levels, A at top, J at bottom
theme_classic() +
geom_point(aes(x=OR, color=OR>0), shape=15, size=3, position = position_dodge(0.5)) + # estimates
geom_linerange(aes(xmin=`lower OR`, xmax=`upper OR`), position = position_dodge(0.5)) + # CIs
geom_vline(xintercept = 1, linetype="dashed") + # OR so x=1
scale_x_continuous(trans='log2',
breaks=c(1,2,4,8,16),
labels=trans_format('log2', math_format(2^.x))) +
coord_cartesian(expand = FALSE, xlim = c(0.8, 16)) +
labs(x="OR", y="") +# x-axis renamed
theme(axis.line.y = element_blank(),
axis.ticks.y= element_blank(),
axis.text.y= element_blank(),
axis.title.y= element_blank(),
legend.position = 'none') +
geom_segment(
aes(x = OR, xend = OR_u, y = fct_rev(fct_relevel(SNP, "Univariable CM")), yend = fct_rev(fct_relevel(SNP, "Univariable CM"))),
position = position_dodge(0.5), arrow = arrow(length = unit(0.3, "cm")))