自分にassignされたGitHubのissuesの数の時系列をPythonで可視化する

# はじめに
GitHubのIssuesを使って個人的にタスク管理をし始めた。自分にassignされたissuesの一覧は https://github.com/issues/assigned で見ることができるが、実際にどの程度処理したのか過去の履歴が見られなかったので、Pythonを使って可視化することにした。

主な実行環境は以下の通り。

- macOS Big Sur 11.1
- conda 4.9.2
- Python 3.7.7
- PyGithub 1.54

# PyGithub
PythonからGitHub APIを叩くには、PyGithubという便利なモジュールが存在するのでこれを使う。インストールは`conda install -c conda-forge pygithub`でよい。

事前の準備としてGitHubのアクセストークンを作成する必要がある。[PyGithubを使って、GitHubの情報を取得してみた](https://dev.classmethod.jp/articles/get-github-info-using-pygithub/)という記事にしたがって、Select Scopesのrepoにチェックを入れてトークンを作成する。

やることとしては、自分にassignされたissuesを取得して、その作成時刻（およびcloseした時刻）を取得すればよい。

詳細は[PyGithubの公式ドキュメント](https://pygithub.readthedocs.io/en/latest/index.html)を参照されたいが、コードのスニペットは以下の通り。

```python
from github import Github

# トークンを用いてGithubオブジェクトを作成
g = Github(token)

# 引数なしのget_userで自分(AuthenticatedUser)を取得する
user = g.get_user()

# get_user_issuesで自分にassignされたclosedなissueのPaginatedListを取得
issues = user.get_user_issues(filter="assigned", state="closed")

# 作成時刻とclose時刻を取得
for issue in issues:
    print(issue.created_at)
    print(issue.closed_at)
```

# 実際のコードと実行結果
過去30日間のissueの数と増減をグラフにした。タイトルには期間内に、及びopen/closedした数も書いておいた。

![issues.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/829116/11c40e94-58df-2ce8-42b9-0b6c5dd52812.png)

```python
from datetime import datetime as dt
from datetime import timedelta
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from github import Github

# 時刻配列の初期化
today = dt.strptime(dt.now().strftime("%Y-%m-%d"), "%Y-%m-%d")

times = []
counts = []
for day in range(-30, 2):
    times.append(today + timedelta(days=day))
    counts.append(0)

times2 = []
increments = []
decrements = []
for day in range(-30, 1):
    times2.append(today + timedelta(days=day) + timedelta(hours=12))
    increments.append(0)
    decrements.append(0)

# GitHubのissuesの取得
token = "" # あなたのトークン
g = Github(token)
user = g.get_user()
for issue in user.get_user_issues(filter="assigned", state="open"):
    created = issue.created_at
    for index, time in enumerate(times):
        if created <= time:
            counts[index] += 1
    for index, time2 in enumerate(times2):
        begin_time = time2 - timedelta(hours=12)
        end_time = time2 + timedelta(hours=12)
        if begin_time <= created and created < end_time:
            increments[index] += 1

for issue in user.get_user_issues(filter="assigned", state="closed"):
    created = issue.created_at
    closed = issue.closed_at
    for index, time in enumerate(times):
        if created <= time and time < closed:
            counts[index] += 1
    for index, time2 in enumerate(times2):
        begin_time = time2 - timedelta(hours=12)
        end_time = time2 + timedelta(hours=12)
        if begin_time <= created and created < end_time:
            increments[index] += 1
        if begin_time <= closed and closed < end_time:
            decrements[index] -= 1

# グラフの描画
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(times, counts, color="black")
ax.bar(times2, increments, color="red")
ax.bar(times2, decrements, color="blue")
ax.xaxis.set_major_formatter(mdates.DateFormatter('%m/%d'))
plt.title(
    f"wm-ytakano's issues (open={np.sum(increments)} closed={np.sum(decrements)})")
plt.grid()
plt.savefig("issues.png")
```