Matplotlib を使ったタイムライン可視化の作成

PythonPythonBeginner
今すぐ練習

This tutorial is from open-source community. Access the source code

💡 このチュートリアルは英語版からAIによって翻訳されています。原文を確認するには、 ここをクリックしてください

はじめに

この実験では、Matplotlibのリリース日付を使って簡単なタイムラインを作成する方法を学びます。タイムラインは、時系列順に並んだイベントのシーケンスをグラフィカルに表したものです。タイムラインは日付とテキストのコレクションで作成できます。この例では、Matplotlibの最近のリリース日付を使って簡単なタイムラインを作成する方法を示します。

VMのヒント

VMの起動が完了したら、左上隅をクリックしてノートブックタブに切り替え、Jupyter Notebookを使って練習しましょう。

時々、Jupyter Notebookが読み込み終わるまで数秒待つ必要があります。Jupyter Notebookの制限により、操作の検証を自動化することはできません。

学習中に問題に遭遇した場合は、Labbyにお問い合わせください。セッション後にフィードバックを提供してください。すぐに問題を解決いたします。

データの取得

タイムラインを作成するには、日付や名前などのデータを取得する必要があります。この例では、GitHubからMatplotlibのリリースとその日付を使います。何らかの理由でデータを取得できない場合は、バックアップとして代替データを使います。以下はデータを取得するコードです。

from datetime import datetime

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.dates as mdates

try:
    ## Matplotlibのリリースとその日付のリストを
    ## https://api.github.com/repos/matplotlib/matplotlib/releases から取得しようとする
    import json
    import urllib.request

    url = 'https://api.github.com/repos/matplotlib/matplotlib/releases'
    url += '?per_page=100'
    data = json.loads(urllib.request.urlopen(url, timeout=1).read().decode())

    dates = []
    names = []
    for item in data:
        if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
            dates.append(item['published_at'].split("T")[0])
            names.append(item['tag_name'])
    ## 日付文字列を(例:2014-10-18)datetimeに変換する
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

except Exception:
    ## 上記が失敗した場合、例えばインターネット接続がない場合
    ## 以下のリストを代替として使う
    names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
             'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
             'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
             'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']

    dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
             '2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
             '2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
             '2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
             '2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
             '2014-10-26', '2014-10-18', '2014-08-26']

    ## 日付文字列を(例:2014-10-18)datetimeに変換する
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

ステムプロットの作成

次に、近接するイベントを区別するために、レベルにいくつかの変化を持つステムプロットを作成します。タイムラインの一次元的な性質を視覚的に強調するために、基準線にマーカーを追加します。各イベントに対して、~.Axes.annotateを使用してテキストラベルを追加し、イベント線の先端からポイント単位でオフセットさせます。以下はステムプロットを作成するコードです。

## いくつかの良いレベルを選ぶ
levels = np.tile([-5, 5, -3, 3, -1, 1],
                 int(np.ceil(len(dates)/6)))[:len(dates)]

## グラフを作成し、日付付きのステムプロットを描画する
fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained")
ax.set(title="Matplotlib release dates")

ax.vlines(dates, 0, levels, color="tab:red")  ## 垂直の茎
ax.plot(dates, np.zeros_like(dates), "-o",
        color="k", markerfacecolor="w")  ## 基準線とその上のマーカー

## 線に注釈を付ける
for d, l, r in zip(dates, levels, names):
    ax.annotate(r, xy=(d, l),
                xytext=(-3, np.sign(l)*3), textcoords="offset points",
                horizontalalignment="right",
                verticalalignment="bottom" if l > 0 else "top")

グラフのフォーマット設定

次に、x軸とy軸のラベルを追加し、x軸の主目盛り位置とフォーマッタを設定し、y軸とスパインを削除することでグラフのフォーマットを設定します。以下はグラフのフォーマット設定のコードです。

## 4ヶ月間隔でx軸をフォーマットする
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=4))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")

## y軸とスパインを削除する
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)

ax.margins(y=0.1)
plt.show()

まとめてみる

Matplotlibのリリース日付を使って簡単なタイムラインを作成するための最終コードは以下の通りです。

from datetime import datetime

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.dates as mdates

try:
    ## Matplotlibのリリースとその日付のリストを
    ## https://api.github.com/repos/matplotlib/matplotlib/releases から取得しようとする
    import json
    import urllib.request

    url = 'https://api.github.com/repos/matplotlib/matplotlib/releases'
    url += '?per_page=100'
    data = json.loads(urllib.request.urlopen(url, timeout=1).read().decode())

    dates = []
    names = []
    for item in data:
        if 'rc' not in item['tag_name'] and 'b' not in item['tag_name']:
            dates.append(item['published_at'].split("T")[0])
            names.append(item['tag_name'])
    ## 日付文字列を(例:2014-10-18)datetimeに変換する
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

except Exception:
    ## 上記が失敗した場合、例えばインターネット接続がない場合
    ## 以下のリストを代替として使う
    names = ['v2.2.4', 'v3.0.3', 'v3.0.2', 'v3.0.1', 'v3.0.0', 'v2.2.3',
             'v2.2.2', 'v2.2.1', 'v2.2.0', 'v2.1.2', 'v2.1.1', 'v2.1.0',
             'v2.0.2', 'v2.0.1', 'v2.0.0', 'v1.5.3', 'v1.5.2', 'v1.5.1',
             'v1.5.0', 'v1.4.3', 'v1.4.2', 'v1.4.1', 'v1.4.0']

    dates = ['2019-02-26', '2019-02-26', '2018-11-10', '2018-11-10',
             '2018-09-18', '2018-08-10', '2018-03-17', '2018-03-16',
             '2018-03-06', '2018-01-18', '2017-12-10', '2017-10-07',
             '2017-05-10', '2017-05-02', '2017-01-17', '2016-09-09',
             '2016-07-03', '2016-01-10', '2015-10-29', '2015-02-16',
             '2014-10-26', '2014-10-18', '2014-08-26']

    ## 日付文字列を(例:2014-10-18)datetimeに変換する
    dates = [datetime.strptime(d, "%Y-%m-%d") for d in dates]

## いくつかの良いレベルを選ぶ
levels = np.tile([-5, 5, -3, 3, -1, 1],
                 int(np.ceil(len(dates)/6)))[:len(dates)]

## グラフを作成し、日付付きのステムプロットを描画する
fig, ax = plt.subplots(figsize=(8.8, 4), layout="constrained")
ax.set(title="Matplotlib release dates")

ax.vlines(dates, 0, levels, color="tab:red")  ## 垂直の茎
ax.plot(dates, np.zeros_like(dates), "-o",
        color="k", markerfacecolor="w")  ## 基準線とその上のマーカー

## 線に注釈を付ける
for d, l, r in zip(dates, levels, names):
    ax.annotate(r, xy=(d, l),
                xytext=(-3, np.sign(l)*3), textcoords="offset points",
                horizontalalignment="right",
                verticalalignment="bottom" if l > 0 else "top")

## 4ヶ月間隔でx軸をフォーマットする
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=4))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%b %Y"))
plt.setp(ax.get_xticklabels(), rotation=30, ha="right")

## y軸とスパインを削除する
ax.yaxis.set_visible(False)
ax.spines[["left", "top", "right"]].set_visible(False)

ax.margins(y=0.1)
plt.show()

まとめ

この実験では、Matplotlibのリリース日付を使って簡単なタイムラインを作成する方法を学びました。データの取得方法、ステムプロットの作成方法、グラフのフォーマット設定方法、そしてすべてをまとめる方法を学びました。タイムラインは、時系列順にイベントの任意のシーケンスを視覚化するために使用できます。