rggplot2plotlegendx-axis

Improve presentation of logistic regression plot R ggplot2


It's my first time asking a question. I hope it is ok.

Minimum reproducible example:plot

library(tidyverse)


OR <- c(0.98, 1.02, 1.00, 1.03)
conf.low <- c(0.64, 0.69, 0.65, 0.68)
conf.high <- c(1.51, 1.56, 1.54, 1.58)
Variable <- c("variable", "variable", "variable", "variable")
cohort <- c("cohort 1", "cohort 2", "cohort 3", "cohort 4")
df <- data.frame(OR, conf.low, conf.high, Variable, cohort)  

ggplot(df, aes(x = OR, xmin = conf.low, xmax = conf.high, y = Variable, group = cohort, 
color = cohort)) + 
  geom_pointrange(position = position_dodge(width = 0.5)) +
  geom_vline(aes(xintercept = 1), linewidth = .25, linetype = "dashed", colour = "red") +
  labs(x = "OR (95% CI)", y = "", color = "") +
  scale_x_log10(limits= c(0.5, 2), breaks = c(0.5, 0.75, 1.0, 1.33, 2.0)) +
  scale_color_brewer(palette = "Dark2") +
  theme_classic() +
  theme(axis.text.y = element_blank(), axis.ticks=element_blank()) 

I would like to do the following:

  1. Add text "Lower in intervention group" and "Lower in control group" below the x-axis to the left and right respectively of the line at 1.0.

  2. Reverse the order of the lines so the green line (cohort 1) appears at the top of the plot.

  3. Move the position of the legend to the left so that it is within the area of the plot (or even better add the text as annotations above each line)

Any help would be greatly appreciated.

Thanks.

I tried to search for the answer but I was unable to find it.


Solution

  • To reverse the order of the lines convert the variable mapped on group to a factor and reverse the order of the levels which could be achieved in one go using forcats::fct_rev. To get rid of the legend you could use a geom_text or a geom_label to add the labels on top of the line. I use geom_label as it automatically adds some padding. Most tricky part is to put some annotations below the x axis. To this end I prefer to use an annotation_custom over an annotate as it gives more control to place the label. Additionally, we have to set clip="off" via coord_cartesian and finally I shifted the axis title by increasing the top margin via theme() options.

    library(ggplot2)
    
    OR <- c(0.98, 1.02, 1.00, 1.03)
    conf.low <- c(0.64, 0.69, 0.65, 0.68)
    conf.high <- c(1.51, 1.56, 1.54, 1.58)
    Variable <- c("variable", "variable", "variable", "variable")
    cohort <- c("cohort 1", "cohort 2", "cohort 3", "cohort 4")
    df <- data.frame(OR, conf.low, conf.high, Variable, cohort)
    
    ggplot(df, aes(
      x = OR, xmin = conf.low, xmax = conf.high,
      y = Variable,
      color = cohort,
      group = forcats::fct_rev(cohort)
    )) +
      geom_pointrange(
        position = position_dodge(width = .5)
      ) +
      geom_label(
        aes(
          label = cohort,
          x = conf.low
        ),
        hjust = 0,
        fill = NA,
        vjust = 0,
        label.size = 0,
        position = position_dodge(width = .5)
      ) +
      geom_vline(aes(xintercept = 1),
        linewidth = .25,
        linetype = "dashed", colour = "red"
      ) +
      labs(x = "OR (95% CI)", y = "", color = "") +
      scale_x_log10(
        limits = c(0.5, 2),
        breaks = c(0.5, 0.75, 1.0, 1.33, 2.0)
      ) +
      annotation_custom(
        grob = grid::textGrob(
          label = "Lower in intervention group",
          x = unit(.5, "npc"),
          y = unit(0, "npc") - unit(16, "pt"),
          vjust = 1,
          gp = grid::gpar(fontsize = 10)
        ),
        xmax = log10(1)
      ) +
      annotation_custom(
        grob = grid::textGrob(
          label = "Lower in control group",
          x = unit(.5, "npc"),
          y = unit(0, "npc") - unit(16, "pt"),
          vjust = 1,
          gp = grid::gpar(fontsize = 10)
        ),
        xmin = log10(1)
      ) +
      scale_color_brewer(palette = "Dark2") +
      theme_classic() +
      theme(
        axis.text.y = element_blank(),
        axis.ticks = element_blank(),
        legend.position = "none",
        axis.title.x = element_text(margin = margin(t = 20))
      ) +
      coord_cartesian(clip = "off")