rggplot2modelsummary

Swap group and y-axis variable in R's modelsummary::modelplot?


I really like the modelplots in R's modelsummary package. I'd like to show coefficients from multiple models in the same plot. Model summary can do this. When you do this, the y-axis is each of the independent variables (or levels of categorical independent variables). Each color shown in the legend corresponds to the dependent variable in the models. An example from my data: modelplot results

In this case, the data has five models. Model 1 is a logistic regression between health status (dependent variable) and the phenotypes (categorical independent variable). Model 2 is a logistic regression between stair use limitations (dependent variable) and the phenotypes. And so on.

I'd really prefer to see a similar graph but that swaps the y-axis and the group variable. In this data, that would mean the models are shown on the y-axis (health status, stair use limitations, etc.) and the phenotypes are shown with different colors and appear in the legend (PTSD, polytrauma, etc.). I've made some progress toward that goal but am stuck.

I don't see a way to do what I want within modelplot itself, so I've been trying to accomplish this with ggplot alone. First I made a dataframe with information from the models. Here is that dataframe:

structure(list(term = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L, 4L, 4L, 4L, 4L, 4L, 5L, 5L, 5L, 
5L, 5L), levels = c("phenoAnx & Dep", "phenoBipolar/SUD", "phenoChronic Disease", 
"phenoPolytrauma", "phenoPTSD"), class = "factor"), model = structure(c(1L, 
2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L, 1L, 2L, 
3L, 4L, 5L, 1L, 2L, 3L, 4L, 5L), levels = c("VR12 General health status", 
"VR12 Health limits stair use", "VR12 Accomplished less due to physical health", 
"VR12 Limited by physical health", "VR12 Pain interfered with work"
), class = "factor"), coefficient = c(1.91123981558174, 1.40024605361994, 
1.90970090461908, 2.75649886514587, 1.67628212308195, 2.72379539809111, 
1.4472309732964, 1.07442405215262, 1.40277545613009, 1.24616849327483, 
3.39624915110633, 3.2054647054651, 2.99175579701405, 5.48712780938336, 
2.19464317924988, 4.08917158330606, 2.51189847873651, 5.09781695229606, 
7.21945376039937, 4.21087546137556, 4.3741972952768, 1.94330159662364, 
2.0143074179206, 2.60661608247103, 2.27295212807288), expconf.low = c(0.918462487481577, 
0.673531740189031, 0.974946113808984, 1.40154076145751, 0.834730597617744, 
1.2250335992925, 0.635625179465413, 0.505054590091018, 0.665043208878459, 
0.568094816439671, 1.53303890836152, 1.46524207909881, 1.33436407662968, 
2.38242727405621, 0.952989702514056, 1.85271834832212, 1.1498402871681, 
2.06491737333688, 2.92843475823212, 1.62024483102831, 1.92001546284344, 
0.843404294246996, 0.89554902291646, 1.16349450724506, 0.95609739952869
), expconf.high = c(4.07437297558818, 2.95918987059318, 3.78640349776017, 
5.53057807290023, 3.40215980839657, 6.18840501842061, 3.30091047199966, 
2.29354938807089, 2.98296958418844, 2.77155647849335, 7.73326686600638, 
7.19882838285894, 6.9970258867374, 13.4478840728456, 5.25968406812367, 
9.31461169998007, 5.60698215110374, 14.0548110937565, 19.9428178576458, 
12.4839923645194, 10.2974984328988, 4.5194542391295, 4.66520465181955, 
6.03980187335148, 5.70723046647557)), row.names = c(2L, 18L, 
34L, 50L, 66L, 3L, 19L, 35L, 51L, 67L, 4L, 20L, 36L, 52L, 68L, 
5L, 21L, 37L, 53L, 69L, 6L, 22L, 38L, 54L, 70L), class = "data.frame")

From there, I've tried to use ggplot to show what I want. Here's my code and the results so far:

ggplot(data = test, mapping = 
aes(x = coefficient, y = model, group = term, color = term)) + 
    geom_point() +
    geom_errorbar(aes(xmax = expconf.high, xmin = expconf.low, width = 0.2))

my progress

I know I can separate the points from each other a little bit by using geom_jitter with a width of 0 instead of geom_point. But I don't know how to move the confidence intervals along with the points when I do that. I also don't know how to make sure the points stay in the same order within each model (meaning that, within each of "pain interferes with work", "limited by physical health", etc., the point for the Anx & Dep is on top, then Bipolar/SUD, then Chronic Disease, etc.).

How would you accomplish what I'm looking for?

Thanks in advance!


Solution

  • You have to use position = position_dodge() for the points and the error bars:

    library(ggplot2)
    
    pd <- position_dodge(width = .75)
    
    ggplot(
      data = test, mapping =
        aes(x = coefficient, y = model, group = term, color = term)
    ) +
      geom_point(position = pd) +
      geom_errorbar(
        aes(xmax = expconf.high, xmin = expconf.low),
        position = pd, width = 0.2
      ) +
      guides(color = guide_legend(reverse = TRUE))