E.D. August
E.D. August

Reputation: 43

Using Facet Grid to Display Nested / Multiple - Level Categories on Y Axis

I'm new to the forum but have been reading a lot and appreciate all the expertise. I've got a question about using facetgrid to add two levels of categorical variables to the y axis a ggplot2 graph.

In particular - I'm trying to figure out how to display my facets in line, above their particular category names directly alongside on the Y axis of my graph

Up to this point I've been able to add them in, but they have to exist outside the axis. There's no strip placement option that allows me to land the values along the axis, they have to be outside / inside etc. Using hjust doesn't work because the strip text gets cut off. I've researched potentially creating this into a grob in order to turn off the clipping but that seems really messy and outside my comfort level.

enter image description here

Ideally the bolded values would sit directly along the axis.

Code sample is below, the leg_summary$group variable is the higher order (more general) categorization, the leg_summary$name is the lower order categorization for the Y axis.

I've already tried using an interaction rather than facet grid, which looks like:ggplot(aes(xmin=-.10, xmax = .20, x=Estimate, y=interaction(group, name, lex.order = TRUE)))

This is OK but not exactly what I'm looking for.

I've read a bunch of other threads including ggplot `facet_grid` label cut off Multi-row x-axis labels in ggplot line chart

Here's my current code for the graph:

library(ggplot2)
library(tidyverse)
leg_graph_test <- 
  leg_summary %>%
  filter(name!="Intercept") %>%
  ggplot(aes(xmin=-.10*100, xmax = .20*100, x=Estimate*100, y=name)) +
  geom_point (shape=1) +
  geom_errorbarh(aes(xmax= upper.95*100, xmin = lower.95*100), height = .00000000000001) +
  labs(x= "Legislators") + 
  geom_vline(xintercept = 0, lty = "longdash") +  
    theme(axis.title.y=element_blank()) + 
  facet_grid(group ~ .,
             scales = "free_y",
             switch = "y"
  ) +
  theme_classic() + 
  theme(panel.spacing = unit(0, "cm"),
        axis.title.y = element_blank(),
        strip.background = element_blank(),
        strip.placement = "outside" ,
        strip.text.y = element_text(face = "bold", angle=180, vjust = 1)
  ) +
  ggtitle("Plot 1") +
  labs(x= "Legislator")

Here is the dput file for the first few rows of the dataset

structure(list(Estimate = c(0.1784, 0.073, 0.0619, 0.1367, 0.1795, 
0.087), name = structure(c(1L, 6L, 5L, 4L, 3L, 2L), .Label = c("Intercept", 
"Doctor spouse", "8 years experience", "3 years experience", 
"1 year experience", "Female"), class = "factor"), group = structure(c(1L, 
2L, 3L, 3L, 3L, 4L), .Label = c("Intercept", "Male to", "0 Years Experience to", 
"No Spouse to"), class = "factor"), upper.95 = c(0.209, 0.0899, 
0.0858, 0.1606, 0.2034, 0.1077), lower.95 = c(0.1478, 0.0561, 
0.038, 0.1129, 0.1556, 0.0662), resp_type = c("Legislator", "Legislator", 
"Legislator", "Legislator", "Legislator", "Legislator")), row.names = c(NA, 
-6L), class = c("tbl_df", "tbl", "data.frame"))

Any help would be fantastic!

Upvotes: 4

Views: 1782

Answers (2)

Axeman
Axeman

Reputation: 35242

If you don't want to manipulate grobs, you'll have to abuse geom_text I think:

leg_summary2 <- filter(leg_summary, name != "Intercept")

grps <- leg_summary2 %>% 
  filter(name != "Intercept") %>% 
  group_by(group) %>% 
  mutate(n = n()) %>% 
  slice(n())

ggplot(leg_summary2, aes(Estimate*100, forcats::fct_inorder(droplevels(name)))) +
  ggstance::geom_pointrangeh(aes(xmin = lower.95*100, xmax = upper.95*100)) +
  geom_text(aes(x = 3, y = n + 0.5, label = group), data = grps, hjust = 1) +
  facet_grid(group ~ ., scales = "free_y", switch = "y", space = 'free') +
  coord_cartesian(xlim = c(4, 21), clip = 'off') +
  labs(y = NULL) +
  theme_classic() +
  theme(
    panel.spacing = unit(0, "cm"),
    strip.text.y = element_blank(),
    plot.margin = margin(30, 30, 30, 60)
  )

enter image description here

Upvotes: 1

dc37
dc37

Reputation: 16178

Your code was not very far from getting it. The main thing I changed was in the aes of the beginning and used coord_flip instead. Then, I used almost the same arguments than you for the facetting:

library(ggplot2)
library(tidyverse)
df %>%
  filter(name!="Intercept") %>%
  ggplot(aes(x = name, y= Estimate*100))+
  geom_point(shape = 1)+
  geom_hline(yintercept = 0, lty = "longdash")+
  geom_errorbar(aes(ymax = upper.95*100, ymin = lower.95*100), width = 0.001)+
  coord_flip()+
  facet_grid(group ~.,scales = "free", space = "free", switch = "y")+
  theme(strip.placement = "outside",
        strip.text.y = element_text(face = "bold", angle=180, vjust = 1))+
  xlab("")

enter image description here

Upvotes: 2

Related Questions