4

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!

  • 1
    I don't have an answer, but I do recommend you use `space = "free"` in your `facet_grid`. You will be more likely to receive an answer if you provide a reproducible example. – Axeman Dec 04 '19 at 20:30
  • @Axeman What would be helpful for a reproducible example? Provide a sample data set or some other additional info? – E.D. August Dec 04 '19 at 20:36
  • See https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example – Axeman Dec 04 '19 at 20:37

2 Answers2

2

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

dc37
  • 15,840
  • 4
  • 15
  • 32
  • Not quite, though it's not bad looking. I was hoping to show the facet (column: group) names on the left hand side of the Y axis labels once, above the more specific Y values. Essentially it would be a bolded category header – E.D. August Dec 04 '19 at 21:32
  • Ok, I see. Let me think about this. – dc37 Dec 04 '19 at 21:36
  • @ElliottAugust, does it look better now ? – dc37 Dec 04 '19 at 21:53
  • It does look better. This is essentially the orientation I was looking for, except that I wanted to put the strip labeling in line with the axis labeling (i.e. directly over it). Unfortunately I don't believe the ggplot allows for placing the strip labeling along the axis and it would require a different package to turn the graph into a grob and disable some of the built in clipping that separates the axis from the strip labels. If you know of an easy workaround that would be great but I'm not too optimistic based on what I'v read (which is why I posted the question) – E.D. August Dec 04 '19 at 21:59
  • @ElliottAugust, Do you mean center aligned in each grey boxes ? or just flip by 90 degree ? – dc37 Dec 04 '19 at 22:02
  • @ElliottAugust, I just the edition of your comment. Sorry, I don't know how to do it except than manually using an image editor (e.g. Inkscape for example). I'm afraid that doing it will also mess with the clarity of your figure and the labeling – dc37 Dec 04 '19 at 22:11
1

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

Axeman
  • 32,068
  • 8
  • 81
  • 94
  • Thanks for sharing. Based on a few conversations, I was pretty confident I would need to do something along these lines. I have a more traditional approach with ggplot that's not bad where I just display the facet labels running up/down along the left-hand side of the figure. I'll take a closer look at this code too and see which way I'd like to go. Thanks for your help! – E.D. August Dec 04 '19 at 22:44