0

I am creating a diverging bar plot based on code in this tutorial (https://rfortherestofus.com/2021/10/diverging-bar-chart/) and it all looks great, except that I want to compare by year (2021 vs. 2023). Here is an example of what I was able to produce with the two years combined (which is useless to me).Divergent plot with years combined

I have managed to create two separate diverging plots and use plot_grid() in cowplot to combine them in one figure. I would be okay with somehow nudging the plots so that they align at the middle (the line that separates agree/disagree), but what I would really like is for the bars for 2021 and 2023 to be interspersed so that they're all in one plot. example of two diverging plots by year

I can't share the raw data for ethical reasons, but here is my code based on the link I shared. This is for the two years combined.

support <- edi %>%
  dplyr::select(role, supportive, year)

#a dataframe that only includes role, year, and supportive column. Adding the "definitions" of supportive column
support <- support %>%
  mutate(define = case_when(
    supportive == "1" ~ "Strongly Disagree",
    supportive == "2" ~ "Disagree",
    supportive == "3" ~ "Neutral",
    supportive == "4" ~ "Agree",
    supportive == "5" ~ "Strongly Agree"
    ))

#creating a summary of the data with counts per choice and per role, and percents showing as decimals and as %
support_sum <- support %>% 
  group_by(role, define) %>% 
  count(name = "n_support") %>% 
  group_by(role) %>% 
  mutate(percent_support = n_support / sum(n_support)) %>% 
  ungroup() %>% 
  mutate(percent_support_labels = percent(percent_support, accuracy = 1))
support_sum

#set up for divergence - basically telling R that everything below Strongly Agree and Agree is negative and adds a "-" before the number
support_sum_div <- support_sum %>%
  mutate(percent_support = if_else(define %in% c("Strongly Agree", "Agree"), percent_support, -percent_support)) %>% 
  mutate(percent_support_labels = percent(percent_support, accuracy = 1))
support_sum_div

#change so that labels don't come up as negative
support_sum_div_labs <- support_sum_div %>%
  mutate(percent_support_labels = abs(percent_support)) %>% 
  mutate(percent_support_labels = percent(percent_support_labels, accuracy = 1))
support_sum_div_labs

#reorder bars, put neutral at the very end
support_div_ordered <- support_sum_div_labs %>% 
  mutate(define = fct_relevel(define,
                               "Netural", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree"),
         define = fct_rev(define)) 
support_div_ordered

support_div_ordered %>%
  ggplot(aes(x = role, 
             y = percent_support,
             fill = define)) +
  geom_col() +
  geom_text(aes(label = percent_support_labels),
            position = position_stack(vjust = 0.5),
            color = "white",
            fontface = "bold") +
  coord_flip() +
  scale_x_discrete() +
   scale_fill_manual(breaks = c("Neutral", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree"),
                    values = c(
                      "Neutral" = "gold",
                      "Strongly Disagree" = "slateblue",
                      "Disagree" = "plum",
                      "Agree" = "#41b6c4",
                      "Strongly Agree" = "dodgerblue4"
                    )) +

  labs(title = "People are supportive of each other.",
       x = NULL,
       fill = NULL) +
  theme_minimal() +
  theme(axis.text.x = element_blank(),
        axis.title.x = element_blank(),
        panel.grid = element_blank(),
        legend.position = "top")

To create the plot that I attached, I simply took this code and subset the data into 2021 and 2023, then combined with cowplot.

plot_grid(support2023.plot, 
          support2021.plot)+
  coord_flip()
stefan
  • 90,330
  • 6
  • 25
  • 51
Kiirsti Owen
  • 13
  • 1
  • 3
  • One possible solution to get your data into a single plot is to use `pivot_longer()` from the `'tidyr` package. `ggplot2` likes long format data. – L Tyrone Apr 08 '23 at 00:11

1 Answers1

1

You could achieve your desired result easily by using facetting both if you want separate plots by year or if you want to have the bars for the years side by side per role. For the latter map year on y and facet_wrap by role.

In either case you have to account for the year when computing the counts and percentages, i.e. add year to count and group_by for the data wrangling. Additionally I slightly revised and stripped down your code and use the group aesthetic besides fill to set the order of the stack in the right order.

Using some fake random example data:

library(tidyverse)
library(scales, warn=F)

set.seed(123)

support <- data.frame(
  year = rep(c(2021, 2022), each = 500),
  role = c("student", "prof", "staff", "partner"),
  supportive = sample(1:5, 1000, replace = TRUE)
)

levels <- c("Neutral", "Strongly Disagree", "Disagree", "Agree", "Strongly Agree")
pal_color <- c("gold", "slateblue", "plum", "#41b6c4", "dodgerblue4")
names(pal_color) <- levels

support <- support %>%
  mutate(define = factor(supportive,
    levels = c(3, 1, 2, 4, 5),
    labels = levels
  ))

support_sum <- support %>%
  count(year, role, define, name = "n_support") %>%
  group_by(year, role) %>%
  mutate(percent_support = n_support / sum(n_support)) %>%
  ungroup() %>%
  mutate(percent_support = if_else(
    define %in% c("Strongly Agree", "Agree"),
    percent_support, -percent_support
  )) %>%
  mutate(percent_support_labels = percent(abs(percent_support), accuracy = 1))

support_div_ordered <- support_sum %>%
  mutate(
    define = factor(define, levels),
    group = fct_relevel(define, c("Strongly Agree", "Agree")),
    define = fct_rev(define)
  )

support_div_ordered %>%
  ggplot(aes(
    y = factor(year),
    x = percent_support,
    fill = define,
    group = group
  )) +
  geom_col() +
  geom_text(aes(label = percent_support_labels),
    position = position_stack(vjust = 0.5),
    color = "white",
    fontface = "bold"
  ) +
  scale_fill_manual(
    breaks = levels,
    values = pal_color
  ) +
  facet_wrap(~role, ncol = 1, strip.position = "left") +
  labs(
    title = "People are supportive of each other.",
    x = NULL, y = NULL, fill = NULL
  ) +
  theme_minimal() +
  theme(
    strip.placement = "outside",
    strip.text.y.left = element_text(angle = 0),
    panel.grid = element_blank(),
    axis.text.x = element_blank(),
    legend.position = "top"
  )

stefan
  • 90,330
  • 6
  • 25
  • 51