You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让R中中间NA占比条形图与左侧Likert图问题顺序匹配?

匹配Likert图与NA占比条形图的问题顺序

你的Likert图(v1)通过data_fun中的reorder逻辑,基于「同意类选项占比」对每个分组下的问题做了自定义排序,但中间的NA占比条形图(v3)使用的是原始问题的默认顺序,导致两者问题排列不一致。解决核心是提取Likert图已排好的问题顺序,将其应用到NA占比数据中。

修改方案

以下是关键修改部分,替换原代码中df_ava和v3的生成逻辑:

1. 提取Likert图的问题排序

从v1的绘图数据中,拆分并整理每个分组对应的问题排序:

# 提取Likert图中每个分组的问题排序
likert_order <- v1$data %>%
  distinct(.question, grouping) %>%
  mutate(question = gsub("^.*\\.", "", .question)) %>%
  arrange(grouping, .question) %>%
  select(grouping, question)

2. 重构NA占比数据框,应用排序

将question列转换为因子,强制每个分组下的问题顺序与Likert图一致:

df_ava <- df %>%
  pivot_longer(!grouping, names_to = "question", values_to = "response") %>%
  mutate(count2 = case_when(is.na(response) ~ "not_available", TRUE ~"available")) %>%
  select(-response) %>%
  group_by(grouping, question) %>%
  summarise(
    total = n(),
    not_available_percent = round(sum(count2 == "not_available") / total * 100, 0),
    .groups = 'drop'
  ) %>%
  # 合并排序信息,将question转为因子
  left_join(likert_order, by = c("grouping", "question")) %>%
  group_by(grouping) %>%
  mutate(question = factor(question, levels = question)) %>%
  ungroup() %>%
  select(-matches("\\.question"))

3. 修改NA占比条形图的y轴设置

移除原scale_y_discrete中的limits = rev,直接使用因子定义的顺序:

v3 <- df_ava %>%
  ggplot(aes(y = question, x = not_available_percent)) +
  geom_bar(stat = "identity", fill = "lightgrey") +
  geom_text(aes(label = paste0(not_available_percent, "%")), 
            size = 2.5,
            position = position_stack(vjust = 0.5)) +
  scale_y_discrete(expand = c(0, 0)) +
  facet_wrap(
    facets = vars(grouping),
    labeller = labeller(grouping = label_wrap_gen(width = 10)),
    ncol = 1, scales = "free_y",
    strip.position = "left"
  ) +
  theme_light() +
  theme(
    panel.border = element_rect(color = "gray", fill = NA),
    axis.text.x = element_blank(),
    legend.position = "bottom"
  ) +
  labs(x = NULL, y = NULL)

完整运行代码

将上述修改部分替换原代码对应段落后,完整代码如下:

library(ggstats)
library(dplyr)
library(ggplot2)
library(tidyr)

likert_levels <- c(
  "Strongly disagree",
  "Disagree",
  "Neither agree nor disagree",
  "Agree",
  "Strongly agree"
)
set.seed(42)
df <-
  tibble(
    grouping = sample(c(LETTERS[1:9]), 150, replace = TRUE),
    q1 = sample(c(likert_levels, NA), 150, replace = TRUE),
    q2 = sample(c(likert_levels, NA), 150, replace = TRUE),
    q3 = sample(c(likert_levels, NA), 150, replace = TRUE),
    q4 = sample(c(likert_levels, NA), 150, replace = TRUE),
    q5 = sample(c(likert_levels, NA), 150, replace = TRUE),
    q6 = sample(c(likert_levels, NA), 150, replace = TRUE)
  ) |>
  mutate(across(-grouping, ~ factor(.x, levels = likert_levels)))

filter_df = df %>%
  dplyr::select(grouping) %>%
  dplyr::group_by(grouping) %>%
  dplyr::summarise(n = n()) %>%
  dplyr::filter(n >= 18)%>%
  dplyr::arrange(desc(n))
parameters = as.vector(filter_df[[1]])

set.seed(42)

data_fun <- function(.data) {
  .data |>
    mutate(
      .question = interaction(grouping, .question),
      .question = reorder(
        .question,
        ave(as.numeric(.answer), .question, FUN = \(x) {
          sum(x %in% 4:5) / length(x[!is.na(x)])
        }),
        decreasing = TRUE
      )
    )
}

df = df %>%
  filter(grouping %in% parameters)

v1 <- gglikert(df, q1:q6,
               facet_rows = vars(grouping),
               add_totals = TRUE,
               data_fun = data_fun
) +
  scale_y_discrete(
    labels = ~ gsub("^.*\\.", "", .x)
  ) +
  labs(y = NULL) +
  theme(
    panel.border = element_rect(color = "gray", fill = NA),
    axis.text.x = element_blank(),
    legend.position = "bottom",
    strip.text = element_text(color = "black", face = "bold"),
    strip.placement = "outside"
  ) +
  theme(strip.text.y = element_text(angle = 0)) +
  facet_wrap(
    facets = vars(grouping),
    labeller = labeller(grouping = label_wrap_gen(width = 5)),
    ncol = 1, scales = "free_y",
    strip.position = "right"
  )

v2 <- filter_df %>%
  ggplot2::ggplot(aes(y = grouping, x = n)) +
  geom_bar(stat = "identity", fill = "lightgrey") +
  geom_text(aes(label = n), position = position_stack(vjust = 0.5)) +
  scale_y_discrete(
    limits = rev, expand = c(0, 0)
  ) +
  facet_wrap(
    facets = vars(grouping),
    labeller = labeller(grouping = label_wrap_gen(width = 10)),
    ncol = 1, scales = "free_y",
    strip.position = "left"
  ) +
  theme_light() +
  theme(
    panel.border = element_rect(color = "gray", fill = NA),
    axis.text.x = element_blank(),
    legend.position = "none",
    strip.text.y = element_blank()
  ) +
  labs(x = NULL, y = NULL)

# 提取Likert图的问题排序
likert_order <- v1$data %>%
  distinct(.question, grouping) %>%
  mutate(question = gsub("^.*\\.", "", .question)) %>%
  arrange(grouping, .question) %>%
  select(grouping, question)

# 重构NA占比数据框
df_ava <- df %>%
  pivot_longer(!grouping, names_to = "question", values_to = "response") %>%
  mutate(count2 = case_when(is.na(response) ~ "not_available", TRUE ~"available")) %>%
  select(-response) %>%
  group_by(grouping, question) %>%
  summarise(
    total = n(),
    not_available_percent = round(sum(count2 == "not_available") / total * 100, 0),
    .groups = 'drop'
  ) %>%
  left_join(likert_order, by = c("grouping", "question")) %>%
  group_by(grouping) %>%
  mutate(question = factor(question, levels = question)) %>%
  ungroup() %>%
  select(-matches("\\.question"))

# 修改后的NA占比条形图
v3 <- df_ava %>%
  ggplot(aes(y = question, x = not_available_percent)) +
  geom_bar(stat = "identity", fill = "lightgrey") +
  geom_text(aes(label = paste0(not_available_percent, "%")), 
            size = 2.5,
            position = position_stack(vjust = 0.5)) +
  scale_y_discrete(expand = c(0, 0)) +
  facet_wrap(
    facets = vars(grouping),
    labeller = labeller(grouping = label_wrap_gen(width = 10)),
    ncol = 1, scales = "free_y",
    strip.position = "left"
  ) +
  theme_light() +
  theme(
    panel.border = element_rect(color = "gray", fill = NA),
    axis.text.x = element_blank(),
    legend.position = "bottom"
  ) +
  labs(x = NULL, y = NULL)

# 组合绘图
v1+v3+v2+ plot_layout(widths = c(3,1,.5)) &
  theme(legend.position = "bottom")

内容的提问来源于stack exchange,提问作者Homer Jay Simpson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 07:32:31