まずは蝋の翼から。

学んだことを書きながら確認・整理するためのメモブログ。こういうことなのかな?といったことをふわっと書いたりしていますが、理解が浅いゆえに的はずれなことも多々あると思うのでツッコミ歓迎

週単位にまとめた時系列データで軸目盛を週初め日付ベースにしたい

事象

表題通り。

データとして、週初めの日付が入っているデータがある。その日付単位でplotをすると軸がdateゆえに目盛が週初め刻みではなく、通常通りの1日刻みとなる。そのため、下記グラフのように欲しい部分(週初め日付)とは別の日付が目盛に表示されてしまい見づらい。

library(dplyr)
library(lubridate)
library(patchwork)

# 時系列データ作る
date_2018 <- seq(as.Date("2018-01-01"), as.Date("2018-04-30"), by = "day")
n <- abs(rnorm(120)) * 100
d <- data.frame(date = date_2018, num = n)

# 日付刻みでplot
g_date <- d %>% 
  ggplot(aes(x=date, y=num)) + 
  geom_point()+ 
  scale_x_date(date_breaks = "1 week") +
  theme(axis.text.x = element_text(angle=45, hjust=1)) +
  labs(title = "date")

# 週刻みでplot
d_week <- d %>% 
  mutate(week = floor_date(date,"week")) %>% #週初めの日にちが入る
  group_by(week) %>% 
  summarise(sum_n = sum(num)) %>% 
  ungroup()

g_week <-
  d_week %>% 
  ggplot(aes(x=week, y=sum_n)) + 
  geom_point()+ 
  scale_x_date(date_breaks = "1 week") +
  theme(axis.text.x = element_text(angle=45, hjust=1))  +
  labs(title = "week")

# =>目盛が週初め日付ではない!!!

g_date / g_week

f:id:chito_ng:20190224152333p:plain

対応

Tokyo.Rのslack r-wakalang.slack.comで質問してみた。 https://r-wakalang.slack.com/archives/C06QP6NJ0/p1550995395050400

回答を要約すると、「scale_x_dateのbreaksに表示したい日付ベクトルを渡せばおk」。
未知だったのですがscale_x_dateでもscale_x_continuousと同様にbreaksにベクトル指定で目盛の指定ができるよう。

また、row_number使い、例えばrow_number % 2 == 1にフィルターをすると2刻みのベクトルが取り出せる。ただし、ここは注意が必要で、取り出しもととなるデータで入ってない週初め日付がない場合その日付のラベルが出ないので、先に取り出しもとデータに対してその期間の全週初め日付を作成しておき、left_joinしておく必要がある。

# 欠損なしplot-------

# 一部欠損週初め日付を作る
d_week2 <- sample_n(d_week,16) 

#ダミー期間を作成
week <- seq(as.Date(min(d_week2$week)), as.Date(max(d_week2$week)), by = "7 days")
week <- as.data.frame(week)
d_week2_full <- left_join(week,d_week2,by="week")#ダミー期間にジョインさせる

break_date_full <- d_week2_full %>% 
  mutate(no = row_number(week)) %>% 
  filter(no %% 2 == 1) %>%  # 2刻み
  pull(week)

# プロット
g1 <- d_week2_full %>% 
  ggplot(aes(x=week, y=sum_n)) + 
  geom_point()+ 
  scale_x_date(
    breaks = break_date,    # 別途用意した日付のベクトルを指定
    # データのweekを指定(d_weekは省略負荷)
    # もしくはseqで該当日付のベクトルを作成したほうがスムーズ
    minor_breaks = d_week$week
  ) +
  theme(axis.text.x = element_text(angle=45, hjust=1))  +
  labs(title = "full date")

# 欠損ありplot-------
break_date_missing <- d_week2 %>% 
  mutate(no = row_number(week)) %>% 
  filter(no %% 2 == 1) %>%  # 2刻み
  pull(week)

# プロット
g2 <- d_week2 %>% 
  ggplot(aes(x=week, y=sum_n)) + 
  geom_point()+ 
  scale_x_date(
    breaks = break_date_missing,    # 別途用意した日付のベクトルを指定
    # データのweekを指定(d_weekは省略負荷)
    # もしくはseqで該当日付のベクトルを作成したほうがスムーズ
    minor_breaks = d_week$week
  ) +
  theme(axis.text.x = element_text(angle=45, hjust=1))  +
  labs(title = "missing date")

g1 / g2

f:id:chito_ng:20190225094344p:plain

できた!

質問に丁寧にお答えいただいたおふたりに感謝。