Как включить процентные изменения, подобные «мышлению», в диаграмму водопада, сгенерированную в ggplot2 - PullRequest
0 голосов
/ 27 декабря 2018

Я пытаюсь установить R в качестве инструмента визуализации данных в моей компании.Типичным типом графика, используемым в моем отделе, являются диаграммы водопадов (https://en.wikipedia.org/wiki/Waterfall_chart).

В R есть несколько пакетов и подсказок для ggplot для создания диаграммы водопадов (https://learnr.wordpress.com/2010/05/10/ggplot2-waterfall-charts/),, которые я уже использовал.

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

См. Пример ниже:

Percentage Change Annotations to a Bar / Waterfall Chart

Или здесь, в этом видео (https://www.youtube.com/watch?v=WMHf7uFR6Rk)

Программное обеспечение, используемое для создания таких графиков, - это интеллектуальная ячейка (https://www.think -cell.com / ), который является дополнением к Excel и Powerpoint.

Проблема, с которой я столкнулся, заключается в том, что я не знаю, как начать заниматься этой темой. Мои первые мысли идут в этом направлении:

  • Использование geom_segment для генерации стрелок и полей
  • Использование функции аннотации ggplot для размещения текста на стрелках или в полях
  • Автоматический расчет позиций на основеданные, предоставленные Waterfall график.

Могу ли я спросить вас, есть ли у вас дополнительные мысли / идеи для реализации таких графиков в ggplot?

С наилучшими пожеланиями Markus

1 Ответ

0 голосов
/ 27 декабря 2018

Вот пример подхода, который я бы выбрал.

Шаг 1. Выберите, какие элементы следует добавить, и добавляйте их по одному за раз.

Допустим, мы начинаем сэтот простой график:

df <- data.frame(x = c(2007, 2008, 2009),
                 y = c(100, 120, 140))
ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5)

enter image description here

Прежде всего, нам нужно дополнительное вертикальное пространство:

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(10, 50))) # Add 50 y padding

enter image description here

Теперь я постепенно добавляю слои, пока они не будут выглядеть так, как я хочу:

# Semi-manual proof of concept
ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(10, 50))) + # Add 50 y padding

  # Line with arrow
  geom_segment(aes(x    = df$x[3], y    = df$y[3] + 50,
                   xend = df$x[3], yend = df$y[3] + 50), 
               arrow = arrow(length = unit(0.02, "npc"), type = "closed")) +

  # Background box
  geom_tile(aes(x = mean(c(df$x[3], df$x[3])),
                y = mean(c(df$y[3], df$y[3])) + 50, width = 1, height = 40), 
            fill = "white", color = "black", size = 0.5) +

  # Text
  geom_text(aes(x = mean(c(df$x[3], df$x[3])),
                y = mean(c(df$y[3], df$y[3])) + 50,
                label = paste0("CAGR\n", 
                               df$x[3], "-", df$x[3], "\n", 
                               scales::percent((df$y[3] / df$y[3]) ^ (1/(df$x[3]-df$x[3])) - 1))))

enter image description here

Шаг 2. Превратим его в функцию

Теперь я переместил слои, связанные с CAGR, в функцию, заменив большинство констант параметрами функции.

add_CAGR <- function(df, first_val_pos, second_val_pos, 
                     y_offset, box_width = 1, box_height) {
  list(
    # Line with arrow
    geom_segment(aes(x    = df$x[first_val_pos], 
                     xend = df$x[second_val_pos], 
                     y    = df$y[first_val_pos]  + y_offset,
                     yend = df$y[second_val_pos] + y_offset), 
                 arrow = arrow(length = unit(0.02, "npc"), type = "closed")), 

      # Background box
      geom_tile(aes(x = mean(c(df$x[first_val_pos], df$x[second_val_pos])),
                    y = mean(c(df$y[first_val_pos], df$y[second_val_pos])) + y_offset, 
                    width = box_width, height = box_height), 
                fill = "white", color = "black", size = 0.5),

      # Text
      geom_text(aes(x = mean(c(df$x[first_val_pos], df$x[second_val_pos])),
                    y = mean(c(df$y[first_val_pos], df$y[second_val_pos])) + y_offset,
                    label = paste0("CAGR\n", 
                                   df$x[first_val_pos], "-", df$x[second_val_pos], "\n", 
                                   scales::percent((df$y[second_val_pos] / df$y[1]) ^ 
                                                     (1/(df$x[second_val_pos]-df$x[first_val_pos])) - 1))),
                lineheight = 0.8)
  )
}

Шаг 3: Использование в сюжете

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(0, 50))) + # Add 50 y padding
  add_CAGR(df, first_val_pos = 1, second_val_pos = 3, 
           y_offset = 50,
           box_width = 0.7, box_height = 40)

enter image description here

Или то же самое только между первыми двумя барами:

ggplot(df, aes(x, y, label = y)) +
  geom_col() +
  geom_text(vjust = -0.5) +
  scale_y_continuous(expand = expand_scale(add = c(0, 50))) + # Add 50 y padding
  add_CAGR(df, first_val_pos = 1, second_val_pos = 2, 
           y_offset = 50,
           box_width = 0.7, box_height = 40)

enter image description here

...