Setup

This section contains the setup and the various utility functions used throughout.

Libraries used:

library(data.table)
library(ggplot2)
library(grid)
library(gridExtra)
library(ggrepel)

Some fake data. The N correspond to the number in the subgroup that were allocated to each group. The other variables should be self-evident.

dat <- data.table(
  idx = 1:11,
  label = c(
    "Age (<50)", 
    "Age (>=50)", 
    "Sex (F)",
    "Sex (M)",
    "Comorbidity (N)",
    "Comorbidity (Y)",
    "Hypertension (N)",
    "Hypertension (Y)",
    "O2 reqd (N)",
    "O2 reqd (Y)",
    "Overall"
  ),
  N_ARB =     c(198,186,136,248,279,105,297,87,279,105,384),
  N_Control = c(195,187,140,242,265,117,264,118,276,106,382),
  OR = exp(c(0.433,0.386,0.332,0.457,
             0.433,0.359,0.361,
             0.529,0.406,0.424, 0.411)),
  LL = exp(c(-0.056,-0.103,-0.289,
             0.021,-0.006,-0.236,
             -0.123,0.033,-0.061,-0.045,0.023)),
  UL = exp(c(0.941,0.844,0.830,0.926,0.892,
             0.855,0.801,1.206,0.867,0.903,0.801))
)
dat[, CI:= sprintf("%.2f, %.2f", LL, UL)]
dat[, shape:= 18]
# toying with the option of specifying a different shape for overall
dat[label == "Overall", shape:= 18]
p1 <- ggplot(dat, aes(y = idx, x = OR)) +
  geom_errorbarh(aes(xmin = LL, xmax = UL), height = 0.25) +
  geom_point(aes(shape = shape), size = 3) +  
  # When using integers to indicate shapes through aesthetics, you need 
  # to include this otherwise you will get an error.
  scale_shape_identity() +
  # scale_color_manual(values = c("A" = "black", "B" = "white")) +
  geom_vline(xintercept = 1, linetype = "dashed", cex = 0.25) +
  scale_y_continuous(name = "", breaks=1:11, labels = dat$label, trans = "reverse") +
  xlab("Odds Ratio (95% CI)") + 
  ylab(" ") + 
  theme_bw() +
  theme(panel.border = element_blank(),
        panel.background = element_blank(),
        panel.grid.major = element_blank(), 
        panel.grid.minor = element_blank(), 
        axis.line = element_line(colour = "black"),
        axis.text.y = element_text(size = 10, colour = "black"),
        axis.text.x.bottom = element_text(size = 10, colour = "black"),
        axis.title.x = element_text(size = 10, colour = "black"),
        legend.position = "none")
p1

The code that follows sets up the text elements.

## Create the table-base pallete
tbl1 <- ggplot(dat, aes(y=label)) +
  ylab(NULL) + xlab("  ") + 
  theme(plot.title = element_text(hjust = 0.5, size=10), 
        ## This is used to help with alignment
        axis.text.x = element_text(color="white", hjust = -3, size = 25), 
        axis.line = element_blank(),
        axis.text.y = element_blank(), 
        axis.ticks = element_blank(),
        axis.title.y = element_blank(), 
        legend.position = "none",
        panel.background = element_blank(), 
        panel.border = element_blank(), 
        panel.grid.major = element_blank(),
        panel.grid.minor = element_blank(), 
        plot.background = element_blank())

## OR point estimate table
txtscale <- 3.5
p2 <- tbl1 + 
  labs(title = "space") +
  ## decimal places
  geom_text(aes(
    y = rev(idx), x = 1, 
    label = sprintf("%0.2f", round(OR, digits = 1))), size = txtscale) + 
  ggtitle("OR")

## 95% CI table
p3 <- tbl1 +
  geom_text(aes(y = rev(idx), x = 1, label = CI), size = txtscale) + 
  ggtitle("95% CI")

## 95% CI table
p4 <- tbl1 +
  geom_text(aes(y = rev(idx), x = 1, label = N_ARB), size = txtscale) + 
  ggtitle("N (ARB)")
p5 <- tbl1 +
  geom_text(aes(y = rev(idx), x = 1, label = N_Control), size = txtscale) + 
  ggtitle("N (Control)")

And now, using the grid package allows us to lay out the plots onto an arbitrary panel.

pp1 <- ggplotGrob(p1)
pp2 <- ggplotGrob(p2)
pp3 <- ggplotGrob(p3)
pp4 <- ggplotGrob(p4)
pp5 <- ggplotGrob(p5)
  
grid::grid.newpage()
vp <- viewport(x = 0.0, y = 0, 
               width = 0.5, height = 1,
               just = c("left", "bottom"))
pushViewport(vp)
grid.draw(pp1)
popViewport()
  
vp <- viewport(x = 0.5, y = 0.0, 
               width = 0.1, height = 1,
               just = c("left", "bottom"))
pushViewport(vp)
grid.draw(pp2)
popViewport()
  
vp <- viewport(x = 0.6, y = 0.0, 
               width = 0.2, height = 1,
               just = c("left", "bottom"))
pushViewport(vp)
grid.draw(pp3)
popViewport()

vp <- viewport(x = 0.8, y = 0.0, 
               width = 0.1, height = 1,
               just = c("left", "bottom"))
pushViewport(vp)
grid.draw(pp4)
popViewport()

vp <- viewport(x = 0.9, y = 0.0, 
               width = 0.1, height = 1,
               just = c("left", "bottom"))
pushViewport(vp)
grid.draw(pp5)
popViewport()