在 ggplot 中的图表旁边显示总数和平均值

Display totals and means next to chart in ggplot

我正在尝试将平均值和总计显示在条形图的左侧,如上例所示。 我在 ggplot 中创建了条形图。图片和代码如下。关于如何让手段和总数显示在正确的地方有什么建议吗?可能 custom_annotations?

谢谢

  percentData = stotal %>% #stotal = survey data frame
    group_by(qtext, div, response) %>%  #qtext is my question text
    summarise(N = n()) %>% 
    mutate(prop = N/sum(N))
  percentData$prop = label_percent(accuracy = 1)(percentData$prop) #make percent from decimal
  percentData
  
  
  #colors
  myColors <- c("green4","springgreen2","yellow1","orange1","red1","black", "black", "black")
  
  ggplot(stotal)+
    geom_bar(aes(x = div, fill = response), position = 'fill', width = 0.5)+
    facet_grid(rows = vars(qtext))+
    scale_fill_manual (values = myColors)+
    coord_flip()+
    ylab('')+
    xlab('')+
    scale_y_continuous(labels = percent)+
    ggtitle(i)+
    geom_text(data = percentData, aes(fill = response, y = N, label = prop, x = div),
              position=position_fill(vjust=0.5))+
    theme(strip.text.y = element_text(size = 12, angle = 0, family = "serif"))

  

实现此目的的一种方法是通过第二个 ggplot 制作 table,可以通过例如将其粘贴到主图patchwork。基本上 table 图复制了只有一个类别的主图,使用分面来获得具有均值和总计的列布局,并摆脱了轴、网格、背景颜色,...

使用一些随机示例数据试试这个:

library(ggplot2)
library(dplyr)
library(scales)
library(patchwork)

# Random example data
set.seed(42)

stotal <- data.frame(
  qtext = rep(c("A", "B"), 50),
  div = sample(c("University", "KSAS-HUM"), 100, replace = TRUE),
  response = sample(c("Poor", "Fair", "Good", "Very good", "Excellent"), 100, replace = TRUE)
)
stotal$response <- factor(stotal$response, levels = c("Poor", "Fair", "Good", "Very good", "Excellent"))

percentData = stotal %>% #stotal = survey data frame
  group_by(qtext, div, response) %>%  #qtext is my question text
  summarise(N = n()) %>% 
  mutate(prop = N/sum(N))
#> `summarise()` regrouping output by 'qtext', 'div' (override with `.groups` argument)
percentData$prop = label_percent(accuracy = 1)(percentData$prop) #make percent from decimal

#colors
myColors <- c("green4","springgreen2","yellow1","orange1","red1","black", "black", "black")

p1 <- ggplot(stotal)+
  geom_bar(aes(x = div, fill = response), position = 'fill', width = 0.5)+
  facet_grid(rows = vars(qtext))+
  scale_fill_manual (values = myColors)+
  coord_flip()+
  ylab('')+
  xlab('')+
  scale_y_continuous(labels = percent)+
  #ggtitle(i)+
  geom_text(data = percentData, aes(fill = response, y = N, label = prop, x = div),
            position=position_fill(vjust=0.5))+
  theme(strip.text.y = element_text(size = 12, angle = 0, family = "serif"))
#> Warning: Ignoring unknown aesthetics: fill


# Table plot

table_data <- stotal %>% 
  mutate(response = as.numeric(response)) %>% 
  group_by(qtext, div) %>%
  summarise(Mean = mean(response), "Total N" = n()) %>% 
  mutate(Mean = round(Mean, 1)) %>% 
  tidyr::pivot_longer(-c(qtext, div), names_to = "var")
#> `summarise()` regrouping output by 'qtext' (override with `.groups` argument)

p2 <- ggplot(table_data, aes(x = div)) +
  geom_bar(color = "white", fill = "white", position = 'fill', width = .5)+
  #geom_vline(color = "grey", xintercept = c(.5, 1.5, 2.5)) +
  geom_text(aes(y = 1, label = value), position=position_fill(vjust=0.5), size = 0.8 * 11 /.pt) + 
  facet_grid(qtext ~ var, switch = "y") +
  coord_flip() +
  labs(x = NULL, y = NULL) +
  theme_minimal() +
  theme(strip.text.y = element_blank()) +
  theme(axis.ticks.y = element_blank(), 
        axis.text.y = element_blank(),
        axis.text.x = element_text(color = "transparent"), 
        axis.ticks.x = element_line(color = "transparent"),
        axis.title = element_blank(),
        panel.grid = element_blank(), panel.spacing.x = unit(0, "pt"))
            

# Glue together

p2 + p1 + plot_layout(widths = c(1, 3))