前回は基本となるオープン・クローズチャートを描きましたが、オープンしているチケットの詳細(優先度、カテゴリなど)が同時に表示されると更に分かりやすいオープン・クローズチャートになります。
Packages and Datasets
本ページではR version 3.4.4 (2018-03-15)の標準パッケージ以外に以下の追加パッケージを用いています。
Package | Version | Description |
---|---|---|
forcats | 0.3.0 | Tools for Working with Categorical Variables (Factors) |
ggplot2 | 3.1.0 | Create Elegant Data Visualisations Using the Grammar of Graphics |
knitr | 1.20 | A General-Purpose Package for Dynamic Report Generation in R |
lubridate | 1.7.4 | Make Dealing with Dates a Little Easier |
psych | 1.8.10 | Procedures for Psychological, Psychometric, and Personality Research |
tidyverse | 1.2.1 | Easily Install and Load the ‘Tidyverse’ |
また、本ページでは以下のデータセットを用いています。
Dataset | Package | Version | Description |
---|---|---|---|
issues | NA | NA | Redmine.org issues |
描画用データの作成
データの確認
オープン・クローズチャートを描くために Redmien公式 から REST API を用いて取得した以下のデータを用います。
id | tracker | status | priority | subject | created_on | closed_on | |
---|---|---|---|---|---|---|---|
1 | 29767 | Patch | New | Normal | Traditional Chinese translation (to r17594) | 2018-10-15 | 2018-06-26 |
2 | 29764 | Feature | New | Normal | new filed ‘Related Issues Notes’ for pair of related issues | 2018-10-13 | NA |
3 | 29763 | Feature | Closed | Normal | Better linux distribution to install redmine | 2018-10-13 | 2018-10-14 |
… | … | NA | NA | NA | NA | NA | NA |
555 | 27877 | Feature | Needs feedback | Normal | Optimze history navigation | 2018-01-02 | NA |
556 | 27876 | Feature | Closed | Normal | add project id to robots.txt | 2018-01-02 | 2018-01-31 |
557 | 27875 | Feature | New | Normal | SQL custom query | 2018-01-02 | NA |
プロジェクト期間の設定
オープン・クローズチャートを描くためには横軸になるプロジェクト期間を設定しなければなりません。今回は2018年にオープンしたチケットデータを取得していますのでプロジェクト期間を以下とします。
(range <- data.frame(start = lubridate::as_date("2018/1/1"),
end = lubridate::as_date("2018/12/31"))) %>%
knitr::kable() # 表示のための処理です
start | end |
---|---|
2018-01-01 | 2018-12-31 |
上記の期間を元に日次のデータを作成しておきます。このデータがグラフの横軸となります。
(cal <- data.frame(date = with(range, seq(start, end, 1)))) %>%
head_tail() # 以下は表示のための処理です
date | |
---|---|
1 | 2018-01-01 |
2 | 2018-01-02 |
3 | 2018-01-03 |
… | NA |
363 | 2018-12-29 |
364 | 2018-12-30 |
365 | 2018-12-31 |
チケット数のカウント
横軸となるプロジェクト期間のデータが作成できましたので、次は縦軸となるチケットのオープン数とクローズ数をカウントし、そこから累積数を求めます。
オープン数
チケットのオープン日はチケット作成日(created_on
)になりますので、作成日で集計するのは前回と同じですが、今回は更に優先度やカテゴリといった情報も含めますので、オープンしているチケット(クローズしていないチケット)のみを集計対象とします
(open <- issues %>%
dplyr::filter(status != "Closed") %>% # クローズしていないチケットのみを取り出します
tidyr::drop_na(created_on) %>% # 念の為に作成日がNAのチケットを取り除きます
dplyr::count(created_on, priority)) %>% # 作成日と優先度で集計します
head_tail() # 表示のための処理です
created_on | priority | n |
---|---|---|
2018-01-02 | Normal | 2 |
2018-01-03 | Normal | 1 |
2018-01-04 | Normal | 1 |
NA | NA | … |
2018-10-11 | Normal | 3 |
2018-10-13 | Normal | 1 |
2018-10-15 | Normal | 1 |
クローズ数
同様にクローズ数はチケット終了日(closed_om
)で集計を行います。ただし、Redmineのチケット・ステータスにはReopen
がありますので、ステータスがClosed
のチケットのみを集計対象にします。クローズチケットは既に終了したチケットですので優先度やカテゴリなどの内訳は見ないこととします。
(close <- issues %>%
dplyr::filter(status == "Closed") %>% # クローズしたチケットのみを取り出します
tidyr::drop_na(closed_on) %>% # 念の為に終了日がNAのチケットを取り除きます
dplyr::count(closed_on)) %>% # 終了日で集計します
head_tail() # 表示のための処理です
closed_on | n |
---|---|
2018-01-03 | 3 |
2018-01-05 | 2 |
2018-01-07 | 2 |
NA | … |
2018-10-11 | 1 |
2018-10-14 | 2 |
2018-10-15 | 2 |
プロジェクト期間との結合
ただし、クローズの最終日以降はこれからの進捗期間とみなし集計対象外とします(なので値は欠損値とします)。また、後で累積を計算しますので進捗期間内の欠損値はチケットなしとしてゼロにしておきます。
(oc_df <- cal %>%
# Openチケット数を結合しMessy Dataに変換します
dplyr::left_join(., open, by = c("date" = "created_on")) %>%
tidyr::spread(key = priority, value = n) %>%
# Closeチケットの数を結合します
dplyr::left_join(., close, by = c("date" = "closed_on")) %>%
dplyr::rename(close = n) %>%
# NAを一括して変換するためにTidy Dataに変換します
tidyr::gather(key = "key", value = "n", -date) %>%
dplyr::mutate(n = dplyr::if_else(date <= dplyr::last(close$closed_on),
dplyr::if_else(!is.na(n), n, 0L), NA_integer_)) %>%
tidyr::spread(key = key, value = n) %>% # Messy Dataに変換します
dplyr::rename(`No Status` = `<NA>`)) %>% # 表示名を変更します
head_tail() # 表示のための処理です
date | No.Status | High | Low | Normal | Urgent | close | |
---|---|---|---|---|---|---|---|
1 | 2018-01-01 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 2018-01-02 | 0 | 0 | 0 | 2 | 0 | 0 |
3 | 2018-01-03 | 0 | 0 | 0 | 1 | 0 | 3 |
… | NA | … | … | … | … | … | … |
363 | 2018-12-29 | NA | NA | NA | NA | NA | NA |
364 | 2018-12-30 | NA | NA | NA | NA | NA | NA |
365 | 2018-12-31 | NA | NA | NA | NA | NA | NA |
累積数の算出
これで、日ごとのオープン数とクローズ数が求められましたので、オープン・クローズチャートを描くために必要な累積オープン数と累積クローズ数を求めます。
(cum_df <- oc_df %>%
dplyr::mutate_if(is.integer, cumsum) ) %>% # 一括して累積数を求めます
head_tail() # 表示のための処理です
date | No.Status | High | Low | Normal | Urgent | close | |
---|---|---|---|---|---|---|---|
1 | 2018-01-01 | 0 | 0 | 0 | 0 | 0 | 0 |
2 | 2018-01-02 | 0 | 0 | 0 | 2 | 0 | 0 |
3 | 2018-01-03 | 0 | 0 | 0 | 3 | 0 | 3 |
… | NA | … | … | … | … | … | … |
363 | 2018-12-29 | NA | NA | NA | NA | NA | NA |
364 | 2018-12-30 | NA | NA | NA | NA | NA | NA |
365 | 2018-12-31 | NA | NA | NA | NA | NA | NA |
このままプロットしても構いませんが、ggplot2
パッケージを利用するのであれば、Tidy Dataに変換しておくことをおすゝめします。Tidy Dataにすることでグルーピング操作や因子水準のを並べ変え操作などが楽になります。
cum_df %>%
# Tidy Dataに変換して因子水準を並べ替えます
tidyr::gather(key = "status", value = n, -date) %>%
dplyr::mutate(status = forcats::fct_relevel(status, "Urgent", "High",
"Normal", "Low", "No Status")) %>%
# 並べ替えた因子水準を利用してグラフを描きます
ggplot2::ggplot(ggplot2::aes(x = date, y = n, fill = status)) +
ggplot2::geom_area() + # 積み上げグラフとして描画します
ggplot2::labs(x = "", y = "累積チケット数",
title = "オープンチケットのみ優先度で層別したオープンクローズチャート") +
ggplot2::scale_fill_brewer(palette = "Spectral")
今回は、取得した全チケット(全てのトラッカー)のオープンチケットのみを優先度で分類してオープン・クローズチャートを描いてみました。
Enjoy!