Как добавить счетчики поверх баров и процент заполнения внутри баров?

У меня есть некоторые данные, в которых каждое наблюдение содержит 2 фактора, классы (буква между A и E) и флаг (0 или 1). После применения group_by(classes,flag) и summary(frequency=n()) я получаю кадр данных, похожий на этот:

classes <-as.factor(c("A", "A", "B", "B", "C", "C", "D", "D", "E", "E"))
    flag <- as.factor(rep(c(0,1),10))
    quantity <- c(856, 569, 463, 125, 795, 313, 1000, 457, 669, 201)
    df <- data.frame(classes, flag, quantity)

Мне удалось получить диаграмму, которую я хочу (упорядоченные столбцы, по одному для каждого уровня классов, каждый столбец заполнен пропорцией флага) с помощью этого кода:

    ggplot(df, aes(x = reorder(classes, -quantity), y = quantity)) +
      geom_bar(aes(fill = as.factor(flag)), stat="identity") +
      theme(axis.text.x=element_text(angle = 90, hjust = 1)) +
      labs(x = NULL, y = "Quantity", fill = "flag") +
      scale_fill_manual(values=c("firebrick","dodgerblue4"), 
      labels=c("1"="Yes","0"="No"))+
      theme(axis.ticks = element_blank())

Однако я не уверен, как использовать geom_text(), чтобы включить как общее количество в верхней части каждого столбца, так и долю значения заполнения внутри столбцов.

Спасибо за помощь!


person The Governor    schedule 21.04.2019    source источник


Ответы (1)


Я не знаю, как это автоматизировать, наверное, проще всего вычислять пропорции и суммы вне сюжета.

Легче переупорядочить классы за пределами графика, чтобы ваш текст мог взять на себя уровни факторов.

df$x <- reorder(df$classes, -df$quantity)

Далее вы можете рассчитать нужную статистику. Ниже я предположил, что если мы разделим df по классам, это всегда будет порядок flag = 0, flag = 1, поэтому мы можем взять x[2]/x[1] в качестве пропорции.

text_df <- data.frame(
  class = sapply(split(df$classes,  df$classes), unique),
  sum   = sapply(split(df$quantity, df$classes), sum),
  prop  = sapply(split(df$quantity, df$classes), function(x){x[2]/(x[1]+x[2])})
)

Затем мы позволяем text_df$class принять тот же порядок, что и df$x.

text_df$class <- factor(text_df$class, levels = levels(df$x))

Затем мы делаем график похожим на ваш пример, помните, что ранее мы изменили порядок переменной x:

ggplot(df, aes(x = x, y = quantity)) +
  geom_bar(aes(fill = as.factor(flag)), stat="identity") +
  theme(axis.text.x=element_text(angle = 90, hjust = 1)) +
  labs(x = NULL, y = "Quantity", fill = "flag") +
  scale_fill_manual(values=c("firebrick","dodgerblue4"), 
                    labels=c("1"="Yes","0"="No"))+
  theme(axis.ticks = element_blank())

И добавьте два геометрии для текста, один для пропорции, один для суммы; оба со смещением по оси y.

 +geom_text(data = text_df, 
            aes(x = class, 
                y = sum + 100, # some offset
                label = sum)) +
  geom_text(data = text_df,
            aes(x = class, 
                y = sum - 100, # opposite offset
                label = scales::percent(prop)))

И я думаю, что это сделало свое дело. Удачи!

person teunbrand    schedule 21.04.2019
comment
Большое спасибо за ответ! Очевидно, мне пришлось изменить несколько вещей, чтобы получить именно то, что я хотел, но ваш код помог. Однако есть одна вещь, которую нужно изменить. Чтобы получить пропорцию флага значения == 1 при создании text_df, столбец реквизита должен быть создан следующим образом prop = sapply(split(df$quantity, df$classes), function(x){x[2]/(x[1]+x[2])}). - person The Governor; 23.04.2019