gganimate如何订购有序的酒吧时间序列?

时间:2018-10-03 09:19:45

标签: r animation ggplot2 dplyr gganimate

我有一个时间序列数据,其中我在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年8月”。前几个月所有的x轴都可以基于“ 2018年8月”的订购订单NAME

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 :(得分:8)

要补充@ eipi10的出色答案,我认为在这种情况下,有必要替换geom_bar以提高灵活性。 geom_bar通常对于离散类别非常方便,但是它不能让我们充分利用gganimate柔滑的动画效果。

例如,使用geom_tile,我们可以重新创建与geom_bar相同的外观,但是在x轴上具有流体运动。这有助于保持对每个小节的跟踪,并查看哪些小节的移位最大。我认为这很好地解决了您问题的第二部分。

enter image description here

要执行此操作,我们可以在数据中添加一个新列,该列显示每个月应使用的排序。我们将此顺序保存为双精度而不是整数(使用* 1.0)。当gganimate在位置1和2之间进行动画制作时,这将允许df2 <- df %>% group_by(ACH_DATEyearmon) %>% mutate(ordering = min_rank(DIAG_RATE_65_PLUS) * 1.0) %>% ungroup() 将条形图放置在位置1.25。

geom_tile

现在,我们可以用类似的方式绘制图形,但是使用geom_bar而不是NAME。我想在顶部和轴上都显示geom_text,所以我使用了两个{y}值不同的vjust调用,一个在0处,一个在条形高度处。 coord_cartesian让我们使用文本行单位将每个垂直对齐。

这里的另一个技巧是关闭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) 中的剪辑,该剪辑使底部的文本进入绘图区域的下方,进入通常位于x轴文本的位置。

fill = "gray60"

回到您的第一个问题,这是我通过从geom_tile调用中删除NAME制成的彩色版本。我按照2017年8月的顺序对df2类别进行了排序,因此,正如您所描述的,它们在该类别中看起来是顺序的。

可能存在更好的排序方式,但我通过将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)) 联接到仅按2017年8月排序的表来完成此操作。

enter image description here

Grp_ID_1 / Metric / State / Value
A   Metric1 OH  50
B   Metric1 OH  65
A   Metric1 CA  20
B   Metric1 CA  35

答案 1 :(得分:6)

条形图排序由ggplot完成,不受gganimate的影响。这些小节根据每个DIAG_RATE_65_PLUSACH_DATEyearmon的总和进行排序。下面,我将说明这些条形的排序方式,然后提供代码来创建动画图,并在每一帧中按从低到高的顺序进行排序。

要查看条形的顺序,首先让我们创建一些假数据:

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的{​​{1}}的总和。请注意x轴NAME值的顺序:

NAME

enter image description here

您可以在下面看到,当我们用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)) 显式求和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 的{​​{1}}按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的x值,并为所有帧保持相同的y轴范围。

请注意,我们使用view_follow(fixed_y=TRUE)作为x变量,但是随后运行ACH_DATEyearmon将x标签更改为order值。我将这些标签包括在图中,以便您可以看到它们随每个scale_x_continuous的变化而变化,但是您当然可以像在示例中所做的那样在实际图中将它们删除。

NAME

enter image description here

如果关闭ACH_DATEyearmon,则可以看到“整个”图的样子(当然,可以通过在{{1}之前停止代码来查看完整的非动画图。 }行)。

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') 。请注意,我们必须在coord_flipgeom_barh中切换y和x,并且y轴ggstance值的顺序现在是恒定的:

aes

enter image description here

对于平滑的过渡,@ JonSpring的答案似乎可以很好地处理