バグチケットの管理においてチケットの処理状況を可視化するオープン・クローズチャートはチケット管理に必須といえるグラフですが、チケット情報からオープン・クローズチャートを描くには、ちょっとした工夫が必要です。
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 %>%
tidyr::drop_na(created_on) %>%
dplyr::count(created_on)) %>%
# 以下は表示のための処理
head_tail()
created_on | n |
---|---|
2018-01-02 | 4 |
2018-01-03 | 6 |
2018-01-04 | 1 |
NA | … |
2018-10-11 | 3 |
2018-10-13 | 2 |
2018-10-15 | 1 |
クローズ数
同様にクローズ数はチケット終了日(closed_om
)で集計を行います。ただし、Redmineのチケット・ステータスにはReopen
がありますので、ステータスがClosed
のチケットのみを集計対象にします。
(close <- issues %>%
dplyr::filter(status == "Closed") %>%
tidyr::drop_na(closed_on) %>%
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 |
プロジェクト期間との結合
ただし、クローズの最終日以降はこれからの進捗期間とみなし集計対象外とします(なので値は欠損値とします)。また、後で累積を計算しますので進捗期間内の欠損値はチケットなしとしてゼロにしておきます。
(op_df <- cal %>%
dplyr::left_join(., open, by = c("date" = "created_on")) %>%
dplyr::mutate(open = dplyr::if_else(date <= dplyr::last(close$closed_on),
dplyr::if_else(!is.na(n), n, 0L),
NA_integer_)) %>%
dplyr::select(-n) %>%
dplyr::left_join(., close, by = c("date" = "closed_on")) %>%
dplyr::mutate(close = dplyr::if_else(date <= dplyr::last(close$closed_on),
dplyr::if_else(!is.na(n), n, 0L),
NA_integer_)) %>%
dplyr::select(-n)) %>%
# 以下は表示のための処理
head_tail()
date | open | close | |
---|---|---|---|
1 | 2018-01-01 | 0 | 0 |
2 | 2018-01-02 | 4 | 0 |
3 | 2018-01-03 | 6 | 3 |
… | NA | … | … |
363 | 2018-12-29 | NA | NA |
364 | 2018-12-30 | NA | NA |
365 | 2018-12-31 | NA | NA |
累積数の算出
これで、日ごとのオープン数とクローズ数が求められましたので、オープン・クローズチャートを描くために必要な累積オープン数と累積クローズ数を求めます。
(cum_df <- op_df %>%
dplyr::mutate(open = cumsum(open), close = cumsum(close))) %>%
# 以下は表示のための処理
head_tail()
date | open | close | |
---|---|---|---|
1 | 2018-01-01 | 0 | 0 |
2 | 2018-01-02 | 4 | 0 |
3 | 2018-01-03 | 10 | 3 |
… | NA | … | … |
363 | 2018-12-29 | NA | NA |
364 | 2018-12-30 | NA | NA |
365 | 2018-12-31 | NA | NA |
このままプロットしても構いませんが、ggplot2
パッケージを利用するのであれば、Tidy Dataに変換しておくことをおすゝめします。Tidy Dataにすることでグルーピング操作や因子水準のを並べ変え操作などが楽になります。
cum_df %>%
# Tidy Dataに変換
tidyr::gather(key = "status", value = n, -date) %>%
# "open"を先に表示させるために因子水準を設定
dplyr::mutate(status = forcats::fct_inorder(status)) %>%
ggplot2::ggplot(ggplot2::aes(x = date, y = n, fill = status)) +
ggplot2::geom_area(position = "identity", alpha = 0.5) +
ggplot2::labs(x = "", y = "累積チケット数",
title = "全チケットに対するオープン・クローズチャート")
今回は、取得した全チケット(全てのトラッカー)のオープン・クローズチャートを描きましたが、バグ(“Defect”)チケットだけで描きたい場合は集計前にデータをフィルタリングしてください。
Enjoy!