1

Suppose that I have data on gender distribution (female, male, divers) in three different countries (USA, Nepal, Japan) with three different locations each (province, small town, city) for two years (2019, 2022).

I want to display all of these data in a facet grid of bar plots, dividing columns by gender type. Specifically, I want the gender types to be displayed as stacked, patterned (not coloured!) subcolumns. Is that possible?

My code and the "dream illustriation" are provided below:

data <- structure(list(year = c(2019, 2019, 2019, 2019, 2019, 2019, 2019, 
2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 
2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2019, 2022, 2022, 
2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 
2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 
2022, 2022, 2022), country = c("USA", "USA", "USA", "USA", "USA", 
"USA", "USA", "USA", "USA", "Nepal", "Nepal", "Nepal", "Nepal", 
"Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Japan", "Japan", 
"Japan", "Japan", "Japan", "Japan", "Japan", "Japan", "Japan", 
"USA", "USA", "USA", "USA", "USA", "USA", "USA", "USA", "USA", 
"Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", "Nepal", 
"Nepal", "Nepal", "Japan", "Japan", "Japan", "Japan", "Japan", 
"Japan", "Japan", "Japan", "Japan"), location = c("province", 
"province", "province", "small town", "small town", "small town", 
"city", "city", "city", "province", "province", "province", "small town", 
"small town", "small town", "city", "city", "city", "province", 
"province", "province", "small town", "small town", "small town", 
"city", "city", "city", "province", "province", "province", "small town", 
"small town", "small town", "city", "city", "city", "province", 
"province", "province", "small town", "small town", "small town", 
"city", "city", "city", "province", "province", "province", "small town", 
"small town", "small town", "city", "city", "city"), gender = c("male", 
"female", "divers", "male", "female", "divers", "male", "female", 
"divers", "male", "female", "divers", "male", "female", "divers", 
"male", "female", "divers", "male", "female", "divers", "male", 
"female", "divers", "male", "female", "divers", "male", "female", 
"divers", "male", "female", "divers", "male", "female", "divers", 
"male", "female", "divers", "male", "female", "divers", "male", 
"female", "divers", "male", "female", "divers", "male", "female", 
"divers", "male", "female", "divers"), quantity = c(6, 5, 1, 
7, 7, 2, 15, 18, 4, 4, 8, 0, 5, 6, 1, 11, 12, 4, 9, 4, 3, 8, 
8, 1, 16, 13, 0, 7, 5, 0, 6, 4, 2, 18, 17, 2, 5, 7, 0, 6, 6, 
2, 14, 10, 1, 5, 6, 1, 6, 4, 2, 14, 10, 5), total = c(12, NA, 
NA, 16, NA, NA, 37, NA, NA, 12, NA, NA, 12, NA, NA, 27, NA, NA, 
16, NA, NA, 17, NA, NA, 29, NA, NA, 12, NA, NA, 12, NA, NA, 37, 
NA, NA, 12, NA, NA, 14, NA, NA, 25, NA, NA, 12, NA, NA, 12, NA, 
NA, 29, NA, NA)), class = c("tbl_df", "tbl", "data.frame"), row.names = c(NA, 
-54L))

data <- data %>%
  mutate(across(year, factor, levels = c("2019","2022"))) %>%
  mutate(across(country, factor, levels = c("USA", "Nepal", "Japan"))) %>%
  mutate(across(location, factor, levels = c("province", "small town", "city"))) %>%
  mutate(across(gender, factor, levels = c("male", "female", "divers")))

ggplot(data, aes(y = total, x = location, fill = country)) +
  geom_col(position = position_dodge(width = 0.5), size = .5, width = .5) +
  labs(x = "Year", y = "Count") +
  scale_y_continuous(expand = c(0, 0), limits = c(0, 40), breaks = seq(0, 40, by = 10)) +
  scale_fill_manual(values = c("blue", "green", "red"), name = "Country") +
  scale_color_manual(values = c("black", "black", "black")) +
  facet_grid(rows = vars(country), cols = vars(year)) +
  theme(panel.background = element_rect(fill = "white"),
        panel.spacing = unit(.7, "cm"),
        strip.background = element_blank(),
        panel.border = element_rect(fill = "transparent", colour = "black"),
        strip.text = element_text(size = 14),
        axis.text = element_text(size = 12, colour="black"),
        axis.title = element_text(size = 14, colour = "black"),
        legend.position = "bottom",
        legend.background = element_rect(fill = "white"),
        legend.text = element_text(size = 12),
        legend.title = element_text(size = 14))

enter image description here

Mikael Jagan
  • 9,012
  • 2
  • 17
  • 48
Deeja
  • 13
  • 3
  • Have you looked at `ggpattern`? That's a package that enables pattern fills in ggplot2, which is not built in to ggplot2. https://cran.r-project.org/web/packages/ggpattern/vignettes/patterns-stripes.html – Jon Spring Mar 09 '23 at 18:55
  • If you're looking for specific assistance, please provide some sample data to make your question reproducible. I'd suggest taking a few minutes to read this: https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example – Jon Spring Mar 09 '23 at 18:57
  • Hello, Thank you very much for the tips! I have added the sample data to the script. I hope this works now and the data is available. I have tried ggpattern. Unfortunately, I didn't get any further with it and the resulting plot looked very confusing. – Deeja Mar 09 '23 at 19:26
  • As a start, I think you might want `ggplot(data, aes(y = quantity, x = location, fill = gender)) + geom_col(position = position_stack()) +` to make the stacked bars [but with fill instead of pattern]. Then you could update with `ggpattern` I expect. – Jon Spring Mar 09 '23 at 19:30

1 Answers1

1
ggplot(data, aes(y = quantity, x = location)) +
  ggpattern::geom_col_pattern(aes(pattern = gender), 
                              # this 
                              pattern_key_scale_factor = 0.3,
                              colour = 'black',
                              fill = 'white',
                              position = position_stack()) +
  theme(legend.key.size = unit(0.5, 'cm')) +
  ...

You may want to experiment with the scale parameters and the size of your output to get the stripes to be the scale you want.

enter image description here

Jon Spring
  • 55,165
  • 4
  • 35
  • 53
  • Thank you very much!! This works really well and looks very good. In my original dataset I want to distinguish additionally between two provinces, two small towns and two cities (that's why the function position_dodge was part of the original script). Do you have a solution to include an A and B for each location (with different colouring of A and B)? – Deeja Mar 09 '23 at 19:44
  • Is that a stacked + dodged bar plot? A little tricky in ggplot but there are prior answers with approaches for that. – Jon Spring Mar 09 '23 at 19:44
  • Yes, that's right. I will search for further solutions. Thank you a lot! – Deeja Mar 09 '23 at 19:52