rdataframeggplot2

Sort the gglikert based on the worst likert levels and display the top n levels of the grouping variable


i have a data frame in R called df with one grouping variable to be used as faceting in gglikert and 3 column of questions val1,val2,val3:

# Load necessary libraries
library(tibble)
library(tidyverse)
library(ggplot2)
library(ggpubr)
library(ggstats)

# Define categories and Likert levels
var_levels <- c("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q")

likert_levels <- c(
  "Strongly disagree",
  "Disagree",
  "Neither agree nor disagree",
  "Agree",
  "Strongly agree"
)

# Set seed for reproducibility
set.seed(42)

# Create the dataframe with three Likert response columns
df <- tibble(
  var = sample(var_levels, 50, replace = TRUE),  # Random values from A to Q
  val1 = sample(likert_levels, 50, replace = TRUE),  # Random values from Likert levels
  val2 = sample(likert_levels, 50, replace = TRUE),  # Random values from Likert levels
  val3 = sample(likert_levels, 50, replace = TRUE)   # Random values from Likert levels
)

# View the first few rows of the dataframe
print(df)

i want to gglikert the data set same as here but it was only for one question val.Now i have 3 questions. The problem is that i want to sort them based on the strongly disagree and disagree and display the worst 10.

if i take them all i can do :

df%>%
  mutate(id=row_number()) %>%
  pivot_longer(-c(id, var), names_to="group") %>%
  pivot_wider(names_from=var) %>%
  gglikert(c(unique(df$var)),
         facet_rows=vars(group))

but this does not do the sorting that i want neither display the worst 10 levels of var factor. How can i achieve this in R ?


Solution

  • I like the patchwork approach by @Datapumpernickel. As an alternative approach you might consider building up the plot from scratch using ggplot2 which gives you more control when it comes to customizing but requires to write the plotting code yourself and to do all the data wrangling manually.

    library(tidyverse)
    library(ggstats)
    
    dat <- df |>
      mutate(
        across(-var, ~ factor(.x, likert_levels))
      ) |>
      pivot_longer(-var, names_to = "group") |>
      count(var, value, group) |>
      complete(var, value, group, fill = list(n = 0)) |>
      mutate(
        prop = n / sum(n),
        prop_lower = sum(prop[value %in% c("Strongly disagree", "Disagree")]),
        prop_higher = sum(prop[value %in% c("Strongly agree", "Agree")]),
        .by = c(var, group)
      ) |>
      arrange(group, prop_lower) |>
      mutate(
        y_sort = paste(var, group, sep = "."),
        y_sort = fct_inorder(y_sort)
      )
    
    top10 <- dat |>
      distinct(group, var, prop_lower) |>
      slice_max(prop_lower, n = 10, by = group)
    
    dat <- dat |>
      semi_join(top10)
    
    dat_tot <- dat |>
      distinct(group, var, y_sort, prop_lower, prop_higher) |>
      pivot_longer(-c(group, var, y_sort),
        names_to = c(".value", "name"),
        names_sep = "_"
      ) |>
      mutate(
        hjust_tot = ifelse(name == "lower", 1, 0),
        x_tot = ifelse(name == "lower", -1, 1)
      )
    
    ggplot(dat, aes(y = y_sort, x = prop, fill = value)) +
      geom_col(position = position_likert(reverse = FALSE)) +
      geom_text(
        aes(
          label = label_percent_abs(hide_below = .05, accuracy = 1)(prop),
          color = after_scale(hex_bw(.data$fill))
        ),
        position = position_likert(vjust = 0.5, reverse = FALSE),
        size = 3.5
      ) +
      geom_label(
        aes(
          x = x_tot,
          label = label_percent_abs(accuracy = 1)(prop),
          hjust = hjust_tot,
          fill = NULL
        ),
        data = dat_tot,
        size = 3.5,
        color = "black",
        fontface = "bold",
        label.size = 0,
        show.legend = FALSE
      ) +
      scale_y_discrete(labels = \(x) gsub("\\..*$", "", x)) +
      scale_x_continuous(
        labels = label_percent_abs(),
        expand = c(0, .15)
      ) +
      scale_fill_brewer(palette = "BrBG") +
      facet_wrap(~group,
        scales = "free_y", ncol = 1,
        strip.position = "right"
      ) +
      theme_light() +
      theme(
        legend.position = "bottom",
        panel.grid.major.y = element_blank()
      ) +
      labs(x = NULL, y = NULL, fill = NULL)
    

    enter image description here