時系列データを描画したい。パターンとして以下の2つを考える。

  • 株価
    5分刻みで取得した株価データを描画するなど。
  • アクセス数
    nginxのアクセスログのデータから各時間帯でのアクセス数をヒストグラムにするなど。

この記事ではこれらそのものはやらないが、もう少し単純な例で描画してみる。

やりたいこと

  • (時刻, 値)の組の形の時系列データを描画する
    株価など。
  • 大量のタイムスタンプをヒストグラムとして描画する
    アクセス数など。

使うもの

  • Python
    3.7.6で確認。

  • Matplotlib
    3.1.3で確認。

  • pandas
    0.25.3で確認。
    pandasはデータ格納用に使うだけ。
    なおpandas+Matplotlibでdatetimeを扱うときは以下を実行しないと警告が出るようだ。

    from pandas.plotting import register_matplotlib_converters
    register_matplotlib_converters()
    

方法

目盛の設定

例1: (時刻, 値)の組の形の時系列データを描画する

import

import matplotlib.pyplot as plt
from matplotlib import dates as mdates
import pandas as pd
from pandas.plotting import register_matplotlib_converters

データ

0時に0、そこから増加して12時に最大(12)になり、
あとは減少して0時に再び0に戻るというサンプルデータを用意する。
DataFrameに格納しておく。

data = [
    ['2020-01-01 00:00:00', 0],
    ['2020-01-01 01:00:00', 1],
    ['2020-01-01 02:00:00', 2],
    ['2020-01-01 03:00:00', 3],
    ['2020-01-01 04:00:00', 4],
    ['2020-01-01 05:00:00', 5],
    ['2020-01-01 06:00:00', 6],
    ['2020-01-01 07:00:00', 7],
    ['2020-01-01 08:00:00', 8],
    ['2020-01-01 09:00:00', 9],
    ['2020-01-01 10:00:00', 10],
    ['2020-01-01 11:00:00', 11],
    ['2020-01-01 12:00:00', 12],
    ['2020-01-01 13:00:00', 11],
    ['2020-01-01 14:00:00', 10],
    ['2020-01-01 15:00:00', 9],
    ['2020-01-01 16:00:00', 8],
    ['2020-01-01 17:00:00', 7],
    ['2020-01-01 18:00:00', 6],
    ['2020-01-01 19:00:00', 5],
    ['2020-01-01 20:00:00', 4],
    ['2020-01-01 21:00:00', 3],
    ['2020-01-01 22:00:00', 2],
    ['2020-01-01 23:00:00', 1],
    ['2020-01-02 00:00:00', 0],
    ['2020-01-02 01:00:00', 1],
    ['2020-01-02 02:00:00', 2],
    ['2020-01-02 03:00:00', 3],
    ['2020-01-02 04:00:00', 4],
    ['2020-01-02 05:00:00', 5],
    ['2020-01-02 06:00:00', 6],
    ['2020-01-02 07:00:00', 7],
    ['2020-01-02 08:00:00', 8],
    ['2020-01-02 09:00:00', 9],
    ['2020-01-02 10:00:00', 10],
    ['2020-01-02 11:00:00', 11],
    ['2020-01-02 12:00:00', 12],
    ['2020-01-02 13:00:00', 11],
    ['2020-01-02 14:00:00', 10],
    ['2020-01-02 15:00:00', 9],
    ['2020-01-02 16:00:00', 8],
    ['2020-01-02 17:00:00', 7],
    ['2020-01-02 18:00:00', 6],
    ['2020-01-02 19:00:00', 5],
    ['2020-01-02 20:00:00', 4],
    ['2020-01-02 21:00:00', 3],
    ['2020-01-02 22:00:00', 2],
    ['2020-01-02 23:00:00', 1],
    ['2020-01-03 00:00:00', 0],
    ['2020-01-03 01:00:00', 1],
    ['2020-01-03 02:00:00', 2],
    ['2020-01-03 03:00:00', 3],
    ['2020-01-03 04:00:00', 4],
    ['2020-01-03 05:00:00', 5],
    ['2020-01-03 06:00:00', 6],
    ['2020-01-03 07:00:00', 7],
    ['2020-01-03 08:00:00', 8],
    ['2020-01-03 09:00:00', 9],
    ['2020-01-03 10:00:00', 10],
    ['2020-01-03 11:00:00', 11],
    ['2020-01-03 12:00:00', 12],
    ['2020-01-03 13:00:00', 11],
    ['2020-01-03 14:00:00', 10],
    ['2020-01-03 15:00:00', 9],
    ['2020-01-03 16:00:00', 8],
    ['2020-01-03 17:00:00', 7],
    ['2020-01-03 18:00:00', 6],
    ['2020-01-03 19:00:00', 5],
    ['2020-01-03 20:00:00', 4],
    ['2020-01-03 21:00:00', 3],
    ['2020-01-03 22:00:00', 2],
    ['2020-01-03 23:00:00', 1],
]

df = pd.DataFrame(data, columns=['datetime', 'val'])

プロット

# pandasでdatetime扱うため
register_matplotlib_converters()

# フォーマット定義
days = mdates.DayLocator()
hours = mdates.HourLocator()
day_fmt = mdates.DateFormatter('%Y/%m/%d')

# グラフ定義
fig, ax = plt.subplots()
x = pd.to_datetime(df['datetime'], format='%Y-%m-%d %H:%M:%S').to_list()
y = df['val'].to_list()
ax.plot(x, y)
ax.grid()

# フォーマット設定
ax.xaxis.set_major_locator(days)
ax.xaxis.set_minor_locator(hours)
ax.xaxis.set_major_formatter(day_fmt)

# 描画範囲の指定
datetime_min, datetime_max = min(x), max(x)
ax.set_xlim(datetime_min, datetime_max)

# x軸のラベルの回転
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, fontsize=10)

plt.show()

折れ線グラフ

例2: 大量のタイムスタンプをヒストグラムとして描画する

import

import matplotlib.pyplot as plt
from matplotlib import dates as mdates
import pandas as pd
import datetime as dt
import random
from pandas.plotting import register_matplotlib_converters

データ

ヒストグラムを描きたいので、わりと大量にデータを用意する必要がある。
ここでは乱数を用いて、1週間ぶんのタイムスタンプを1000個生成する。
(もっといい方法があるのかもしれないが…。)

# 作成するdatetime数
N = 1000

datetime_from, datetime_to = dt.datetime(2020, 1, 1, 0, 0, 0), dt.datetime(2020, 1, 8, 0, 0, 0)
timestamp_from, timestamp_to = int(datetime_from.timestamp()), int(datetime_to.timestamp())
random_timestamps = [random.randint(timestamp_from, timestamp_to) for _ in range(0, N)]
random_datetimes = [dt.datetime.fromtimestamp(t) for t in random_timestamps]
random_datetimes_str = [dt.strftime("%Y-%m-%d %H:%M:%S") for dt in random_datetimes]

生成したデータはこんなふうになる。

# random_datetimes_str[:10]の結果

['2020-01-06 07:14:19',
 '2020-01-01 13:39:55',
 '2020-01-01 01:37:01',
 '2020-01-02 13:14:58',
 '2020-01-02 22:22:01',
 '2020-01-06 08:08:00',
 '2020-01-05 08:53:54',
 '2020-01-07 03:05:51',
 '2020-01-05 09:19:09',
 '2020-01-04 01:46:38']

プロット

# pandasでdatetime扱うため
register_matplotlib_converters()

# フォーマット定義
days = mdates.DayLocator()
hours = mdates.HourLocator()
day_fmt = mdates.DateFormatter('%Y/%m/%d')

# グラフ定義
fig, ax = plt.subplots()
x = [dt.datetime.strptime(s, "%Y-%m-%d %H:%M:%S") for s in random_datetimes_str]
ax.hist(x, bins=7)

# フォーマット設定
ax.xaxis.set_major_locator(days)
ax.xaxis.set_major_formatter(day_fmt)
ax.xaxis.set_minor_locator(hours)

# 描画範囲の指定
datemin, datemax = min(x), max(x)
ax.set_xlim(datemin, datemax)

ax.grid()

# x軸のラベルの回転
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, fontsize=10)

plt.show()

ヒストグラム

参考