オープン・クローズチャートを描く
Text Update: 11/22, 2018 (JST)

バグチケットの管理においてチケットの処理状況を可視化するオープン・クローズチャートはチケット管理に必須といえるグラフですが、チケット情報からオープン・クローズチャートを描くには、ちょっとした工夫が必要です。

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!  


CC BY-NC-SA 4.0 , Sampo Suzuki