web-dev-qa-db-ja.com

順序付けられたバーの時系列をgananimateはどのように注文しますか?

病気の診断率を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 plot

私には2つの質問があります。

1)gganimateはどの程度正確にデータを並べ替えますか?全体的に一般的な並べ替えがありますが、毎月、グループがDIAG_RATE_65_PLUSで最小から最大に完全に並べられるフレームがありません。理想的には、最後の月である「2018年8月」を完璧に注文していただきたいと思います。過去すべての月は、「2018年8月」のNAMEの順序に基づいてx軸を持つことができます。

2)グループが棒グラフの各月の正しいランクに「シフト」するオプションがgganimateにありますか?

コメントクエリのプロット:

https://i.stack.imgur.com/s2UPw.gifhttps://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')
9
user126082

バーの順序付けはggplotによって行われ、gganimateの影響は受けません。バーは、各_DIAG_RATE_65_PLUS_内の_ACH_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))))
_

次に、単一の棒グラフを作成します。バーは、各NAMEの_DIAG_RATE_65_PLUS_の合計です。 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)は、現在の_ACH_DATEyearmon_のx値のみを表示し、すべてのフレームで同じy軸範囲を維持します。

X変数としてorderを使用していますが、次に_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

[〜#〜] update [〜#〜]:質問に答えるために...

特定の月の値で並べ替えるには、データをその月で並べ替えられたレベルの要素に変換します。 _coord_flip_の代わりに回転したグラフをプロットするには、ggstanceパッケージの_geom_barh_(横棒グラフ)を使用します。 aesview_follow()のyとxを入れ替える必要があり、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の回答がそれをうまく処理しているようです。

8
eipi10

@ eipi10のすばらしい答えに付け加えると、これはgeom_barを置き換えてより柔軟性を高める価値があるケースだと思います。 geom_barは通常、個別のカテゴリには非常に便利ですが、gganimateの滑らかで滑らかなアニメーションの栄光を最大限に活用することはできません。

たとえば、geom_tileを使用すると、geom_barと同じ外観を再作成できますが、x軸の動きは滑らかです。これにより、各バーを視覚的に追跡し、どのバーが最も順序をシフトしているのかを確認できます。これは質問の2番目の部分にうまく対応していると思います。

enter image description here

これを機能させるために、毎月使用する順序を示す新しい列をデータに追加できます。この注文は整数ではなく、doubleとして保存します(using* 1.0を使用)。これにより、gganimateが位置1と2の間でアニメーションしているときに、位置1.25にバーを配置できます。

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

これで、同様の方法でプロットできますが、geom_tileの代わりにgeom_barを使用します。 NAMEを上と軸の両方に表示したかったので、2つのgeom_text呼び出しを使用して、異なるy値(1つはゼロ、もう1つはバーの高さ)を使用しました。 vjustを使用すると、テキスト行単位を使用してそれぞれを垂直方向に配置できます。

ここでのもう1つのトリックは、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年8月の順にソートしたので、あなたが説明したように、それらはそのカテゴリの順番に表示されます。

その並べ替えを行うにはもっと良い方法があるでしょうが、私は2017年8月の順序だけでdf2をテーブルに結合することでそれを行いました。

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))
10
Jon Spring