Still thinking of multiple axis labels for scale_discrete

Whew, time flies! Unfortunately my first question has now closed due to inactivity, but I'm still struggling to get labels the way I would like. Here's the initial reprex:

library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
  mutate(labeling = paste(year, retiree)) %>%
  drop_na()
#> `summarise()` has grouped output by 'year', 'marital', 'race'. You can override
#> using the `.groups` argument.


ggplot(gss_summarize, aes(x=labeling, y=prop, fill = race)) + 
  geom_col() + 
  facet_grid(rows = vars(marital)) + 
  coord_flip()

Created on 2022-08-23 by the reprex package (v2.0.1)

@martin.R had a nice idea to use ifelse to make the labels less repetitive, which works in theory but I can't get to work in practice. If I make those labels and use them as my x all the "no"s (for example) get collapsed together, because there's nothing to make them distinct in the variable.

library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
  mutate(group = paste(year, retiree)) %>%
  mutate(labeling = ifelse(retiree == "yes", group, retiree)) %>%
  drop_na()
#> `summarise()` has grouped output by 'year', 'marital', 'race'. You can override
#> using the `.groups` argument.


ggplot(gss_summarize, aes(x=labeling, y=prop, fill = race)) + 
  geom_col() + 
  facet_grid(rows = vars(marital)) + 
  coord_flip()

Created on 2022-09-21 by the reprex package (v2.0.1)

I thought I might be able to use the original group variable as my x, and then bring labeling in to re-label them, but I get an error.

library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
  mutate(group = paste(year, retiree)) %>%
  mutate(labeling = ifelse(retiree == "yes", group, retiree)) %>%
  drop_na()
#> `summarise()` has grouped output by 'year', 'marital', 'race'. You can override
#> using the `.groups` argument.


ggplot(gss_summarize, aes(x=group, y=prop, fill = race)) + 
  geom_col() + 
  facet_grid(rows = vars(marital)) + 
  coord_flip() + 
  scale_x_discrete(labels = labeling)
#> Error in check_breaks_labels(breaks, labels): object 'labeling' not found

Created on 2022-09-21 by the reprex package (v2.0.1)

I suspect this is because labeling isn't in my aes() at the beginning, so maybe is not accessible to ggplot? I tried writing a little function as well, and got a similar error. Passing in the vector doesn't give an error, but clearly isn't the right result,

library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
  mutate(group = paste(year, retiree)) %>%
  mutate(labeling = ifelse(retiree == "yes", group, retiree)) %>%
  drop_na()
#> `summarise()` has grouped output by 'year', 'marital', 'race'. You can override
#> using the `.groups` argument.


ggplot(gss_summarize, aes(x=group, y=prop, fill = race)) + 
  geom_col() + 
  facet_grid(rows = vars(marital)) + 
  coord_flip() + 
  scale_x_discrete(labels = gss_summarize$labeling)

Created on 2022-09-21 by the reprex package (v2.0.1)

I suspect this idea is a bit out of scope for ggplot2, but I'd appreciate any other ideas on how to make it work!

my solution is hacky, using different whitespace to differentiate one "no" from the other, but it works

library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
   ungroup()  %>% 
  drop_na() %>%
  arrange(year,retiree) %>%
  mutate(old_lab = as_factor(paste(year, retiree)),
         labelling = as_factor(ifelse(retiree=="yes",
                                      as.character(old_lab),
                                      paste0(strrep(" ",as.integer(old_lab)),"no"))))


ggplot(gss_summarize, aes(x=labelling, y=prop, fill = race)) + 
  geom_col() + 
  facet_grid(rows = vars(marital)) + 
  coord_flip()

1 Like

Nir's solution is what I had aimed for but I forgot about the "no"s collapsing.

However, the ggh4x package was mentioned in the original thread:
Facets • ggh4x (teunbrand.github.io)

It looks like this would be the most elegant solution if the facet panels were on the same side as the labels (either on the left or right), i.e. a nested facet of marital, then year, then retiree.

2 Likes

It took a bit of thinking, but that ggh4x package did what I wanted! To close the loop, here's what I came up with:

library(ggh4x)
#> Loading required package: ggplot2
library(tidyverse)
data("gss_cat")
gss_summarize <- gss_cat %>%
  mutate(retiree = if_else(age>62, "yes", "no")) %>%
  filter(year %in% c(2000, 2014)) %>%
  mutate(year = as_factor(year)) %>%
  group_by(year, marital, race, retiree) %>%
  summarize(n = n()) %>%
  mutate(prop = n/sum(n)) %>%
  mutate(group = paste(year, retiree)) %>%
  mutate(labeling = ifelse(retiree == "yes", group, retiree)) %>%
  drop_na()
#> `summarise()` has grouped output by 'year', 'marital', 'race'. You can override
#> using the `.groups` argument.

ggplot(gss_summarize, aes(x=retiree, y=prop, fill = race)) + 
  geom_col() +
  coord_flip() +
  facet_nested(rows = vars(marital, year), switch = "y",
               strip = strip_nested(size = "variable")) +
  theme(strip.placement = "outside") + 
  theme(
    strip.text.y.left = element_text(angle = 0)
  )

Created on 2022-10-05 by the reprex package (v2.0.1)

Thanks to everyone who had solutions for me!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.