Как gganimate заказывает временные ряды с заказанным баром? - PullRequest
0 голосов
/ 03 октября 2018

У меня есть временной ряд данных, где я строю графики показателей заболеваемости по оси Y DIAG_RATE_65_PLUS и географические группы для сравнения по оси X NAME в виде простой гистограммы.Моя переменная времени - ACH_DATEyearmon, по которой анимация циклически повторяется, как видно из заголовка.

df %>% ggplot(aes(reorder(NAME, DIAG_RATE_65_PLUS), DIAG_RATE_65_PLUS)) +
  geom_bar(stat = "identity", alpha = 0.66) +
  labs(title='{closest_state}') +
  theme(plot.title = element_text(hjust = 1, size = 22),
        axis.text.x=element_blank()) +
  transition_states(ACH_DATEyearmon, transition_length = 1, state_length = 1) +
  ease_aes('linear')

Я переупорядочил NAME, поэтому он ранжируется по DIAG_RATE_65_PLUS.

Что производит gganimate:

gganimate plot

Теперь у меня есть два вопроса:

1) Как именно gganimate переупорядочиваетданные?Существует общее общее переупорядочение, но каждый месяц не имеет рамок, в которых группы идеально упорядочены по DIAG_RATE_65_PLUS от самых маленьких до самых больших.В идеале, я бы хотел, чтобы последний месяц «Август 2018» был идеально упорядочен.Все предыдущие месяцы могут иметь свою ось X на основе заказанного NAME для «августа 2018 года».

2) Есть ли в gganimate вариант, когда группы «сдвигаются» к своему правильному разряду для каждогомесяц на гистограмме?

Графики для моих запросов комментариев:

https://i.stack.imgur.com/s2UPw.gif https://i.stack.imgur.com/Z1wfd.gif

@ JonSpring

    df %>%
  ggplot(aes(ordering, group = NAME)) +
  geom_tile(aes(y = DIAG_RATE_65_PLUS/2, 
                height = DIAG_RATE_65_PLUS,
                width = 0.9), alpha = 0.9, fill = "gray60") +
  geom_hline(yintercept = (2/3)*25, linetype="dotdash") +
  # text in x-axis (requires clip = "off" in coord_cartesian)
  geom_text(aes(y = 0, label = NAME), hjust = 2) + ## trying different hjust values
  theme(plot.title = element_text(hjust = 1, size = 22),
        axis.ticks.y = element_blank(), ## axis.ticks.y shows the ticks on the flipped x-axis (the now metric), and hides the ticks from the geog layer
        axis.text.y = element_blank()) + ## axis.text.y shows the scale on the flipped x-axis (the now metric), and hides the placeholder "ordered" numbers from the geog layer
  coord_cartesian(clip = "off", expand = FALSE) +
  coord_flip() +
  labs(title='{closest_state}', x = "") +
  transition_states(ACH_DATEyearmon, 
                    transition_length = 2, state_length = 1) +
  ease_aes('cubic-in-out')

При hjust=2 метки не выровнены и перемещаются.

enter image description here

Изменение вышеуказанного кода с помощью hjust=1

enter image description here

@ eipi10

df %>% 
  ggplot(aes(y=NAME, x=DIAG_RATE_65_PLUS)) +
  geom_barh(stat = "identity", alpha = 0.66) +
  geom_hline(yintercept=(2/3)*25, linetype = "dotdash") + #geom_vline(xintercept=(2/3)*25) is incompatible, but geom_hline works, but it's not useful for the plot
  labs(title='{closest_state}') +
  theme(plot.title = element_text(hjust = 1, size = 22)) +
  transition_states(ACH_DATEyearmon, transition_length = 1, state_length = 50) +
  view_follow(fixed_x=TRUE) +
  ease_aes('linear')

Ответы [ 2 ]

0 голосов
/ 04 октября 2018

Чтобы добавить отличный ответ @ eipi10, я думаю, что в этом случае стоит заменить geom_bar для большей гибкости.geom_bar обычно довольно удобен для дискретных категорий, но не позволяет нам в полной мере использовать великолепную плавную анимацию gganimate.

Например, с geom_tile мы можем воссоздать тот же внешний вид, что и geom_bar, но с движением жидкости по оси x.Это помогает визуально отслеживать каждую полосу и видеть, какие полосы меняются в наибольшей степени.Я думаю, что это хорошо подходит ко второй части вашего вопроса.

enter image description here

Чтобы сделать эту работу, мы можем добавить к данным новый столбец, показывающий порядокэто следует использовать каждый месяц.Мы сохраняем этот порядок как двойное, а не целое число (используя * 1.0).Это позволит gganimate разместить бар в позиции 1.25, когда он анимируется между позициями 1 и 2.

df2 <- df %>%
  group_by(ACH_DATEyearmon) %>%
  mutate(ordering = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
  ungroup() 

Теперь мы можем строить график аналогичным образом, но используя geom_tile вместо geom_bar.Я хотел показать NAME как сверху, так и на оси, поэтому я использовал два вызова geom_text с разными значениями y, один в нуле и один на высоте бара.vjust позволяет нам выровнять каждую по вертикали, используя единицы текстовой строки.

Другой трюк здесь - отключить обрезку в coord_cartesian, которая позволяет нижнему тексту проходить ниже области графика в направлении оси Xтекст обычно уходит.

p <- df2 %>%
  ggplot(aes(ordering, group = NAME)) +

  geom_tile(aes(y = DIAG_RATE_65_PLUS/2, 
                height = DIAG_RATE_65_PLUS,
                width = 0.9), alpha = 0.9, fill = "gray60") +
  # text on top of bars
  geom_text(aes(y = DIAG_RATE_65_PLUS, label = NAME), vjust = -0.5) +
  # text in x-axis (requires clip = "off" in coord_cartesian)
  geom_text(aes(y = 0, label = NAME), vjust = 2) +
  coord_cartesian(clip = "off", expand = FALSE) +

  labs(title='{closest_state}', x = "") +
  theme(plot.title = element_text(hjust = 1, size = 22),
        axis.ticks.x = element_blank(),
        axis.text.x  = element_blank()) + 

  transition_states(ACH_DATEyearmon, 
                    transition_length = 2, state_length = 1) +
  ease_aes('cubic-in-out')

animate(p, nframes = 300, fps = 20, width = 400, height = 300)

Возвращаясь к вашему первому вопросу, вот цветная версия, которую я сделал, удалив fill = "gray60" из вызова geom_tile.Я отсортировал категории NAME в порядке августа 2017 года, поэтому они будут выглядеть последовательно для этой категории, как вы описали.

Вероятно, есть лучший способ сделать эту сортировку, но я сделал это, присоединившись к df2 к столу только с заказом на август 2017 года.

enter image description here

Aug_order <- df %>%
  filter(ACH_DATEyearmon == "Aug 2017") %>%
  mutate(Aug_order = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
  select(NAME, Aug_order)

df2 <- df %>%
  group_by(ACH_DATEyearmon) %>%
  mutate(ordering = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>%
  ungroup() %>%
  left_join(Aug_order) %>%
  mutate(NAME = fct_reorder(NAME, -Aug_order))
0 голосов
/ 04 октября 2018

Упорядочение баров выполняется ggplot и не зависит от gganimate.Бары упорядочены по сумме DIAG_RATE_65_PLUS в каждом ACH_DATEyearmon.Ниже я покажу, как упорядочены полосы, а затем предоставлю код для создания анимированного графика с желаемой сортировкой от низкого до высокого в каждом кадре.

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

library(tidyverse)
library(gganimate)
theme_set(theme_classic())

# Fake data
dates = paste(rep(month.abb, each=10), 2017)

set.seed(2)
df = data.frame(NAME=c(replicate(12, sample(LETTERS[1:10]))),
                ACH_DATEyearmon=factor(dates, levels=unique(dates)),
                DIAG_RATE_65_PLUS=c(replicate(12, rnorm(10, 30, 5))))

Теперь давайте сделаем один столбчатый график.Столбцы представляют собой сумму DIAG_RATE_65_PLUS для каждого NAME.Обратите внимание на порядок значений оси x NAME:

df %>% 
  ggplot(aes(reorder(NAME, DIAG_RATE_65_PLUS), DIAG_RATE_65_PLUS)) +
  geom_bar(stat = "identity", alpha = 0.66) +
  labs(title='{closest_state}') +
  theme(plot.title = element_text(hjust = 1, size = 22)) 

enter image description here

Ниже вы можете видеть, что порядок одинаков, когда мы явносумма DIAG_RATE_65_PLUS по NAME и сортировка по сумме:

df %>% group_by(NAME) %>% 
  summarise(DIAG_RATE_65_PLUS = sum(DIAG_RATE_65_PLUS)) %>% 
  arrange(DIAG_RATE_65_PLUS)
   NAME DIAG_RATE_65_PLUS
1     A          336.1271
2     H          345.2369
3     B          346.7151
4     I          350.1480
5     E          356.4333
6     C          367.4768
7     D          368.2225
8     F          368.3765
9     J          368.9655
10    G          387.1523

Теперь мы хотим создать анимацию, которая сортирует NAME по DIAG_RATE_65_PLUS отдельно длякаждый ACH_DATEyearmon.Чтобы сделать это, давайте сначала сгенерируем новый столбец с именем order, который устанавливает желаемый порядок:

df = df %>% 
  arrange(ACH_DATEyearmon, DIAG_RATE_65_PLUS) %>% 
  mutate(order = 1:n())

Теперь мы создадим анимацию.transition_states генерирует кадры для каждого ACH_DATEyearmon.view_follow(fixed_y=TRUE) показывает значения x только для текущего ACH_DATEyearmon и поддерживает одинаковый диапазон оси Y для всех кадров.

Обратите внимание, что мы используем order в качестве переменной x, но затем мы запускаем scale_x_continuous, чтобы изменить x-метки на значения NAME.Я включил эти метки в график, чтобы вы могли видеть, что они меняются с каждым ACH_DATEyearmon, но вы, конечно, можете удалить их на вашем реальном графике, как вы это делали в своем примере.

p = df %>% 
  ggplot(aes(order, DIAG_RATE_65_PLUS)) +
    geom_bar(stat = "identity", alpha = 0.66) +
    labs(title='{closest_state}') +
    theme(plot.title = element_text(hjust = 1, size = 22)) +
    scale_x_continuous(breaks=df$order, labels=df$NAME) +
    transition_states(ACH_DATEyearmon, transition_length = 1, state_length = 50) +
    view_follow(fixed_y=TRUE) +
    ease_aes('linear')

animate(p, nframes=60)

anim_save("test.gif")

enter image description here

Если вы отключите view_follow(), вы сможете увидеть, как выглядит «весь» график (и вы можете, конечно, увидеть полный неанимированный график с помощьюостановка кода перед transition_states).

p = df %>% 
  ggplot(aes(order, DIAG_RATE_65_PLUS)) +
    geom_bar(stat = "identity", alpha = 0.66) +
    labs(title='{closest_state}') +
    theme(plot.title = element_text(hjust = 1, size = 22)) +
    scale_x_continuous(breaks=df$order, labels=df$NAME) +
    transition_states(ACH_DATEyearmon, transition_length = 1, state_length = 50) +
    #view_follow(fixed_y=TRUE) +
    ease_aes('linear')

enter image description here

ОБНОВЛЕНИЕ : Чтобы ответить на ваши вопросы ...

Чтобы упорядочить значения за определенный месяц, превратите данные в коэффициент с уровнями, упорядоченными по этому месяцу.Для построения повернутого графика вместо coord_flip мы будем использовать geom_barh (горизонтальная линейная диаграмма) из пакета ggstance.Обратите внимание, что мы должны переключать y и x в aes и view_follow() и что порядок значений оси y NAME теперь постоянен:

library(ggstance)

# Set NAME order based on August 2017 values
df = df %>% 
  arrange(DIAG_RATE_65_PLUS) %>% 
  mutate(NAME = factor(NAME, levels=unique(NAME[ACH_DATEyearmon=="Aug 2017"])))

p = df %>% 
  ggplot(aes(y=NAME, x=DIAG_RATE_65_PLUS)) +
  geom_barh(stat = "identity", alpha = 0.66) +
  labs(title='{closest_state}') +
  theme(plot.title = element_text(hjust = 1, size = 22)) +
  transition_states(ACH_DATEyearmon, transition_length = 1, state_length = 50) +
  view_follow(fixed_x=TRUE) +
  ease_aes('linear')

animate(p, nframes=60)
anim_save("test3.gif")

enter image description here

Для плавных переходов похоже, что ответ @ JonSpring хорошо с этим справляется.

...