時系列データ表現のための主要グラフ技法と実装ガイド

1. ホライズンチャート(地平線図)

機能的特徴:

  • 高圧縮表示:狭い領域で多数の時系列プロットを重ねて可視化できます。各シリーズは色分けまたは線種で区別されます。
  • 変動の把握:時間経過に伴う増減、振動、特定のパターンを明確に捉えることができます。
  • 比較効率:複数のトレンドを同一平面で配置し、相互の関係性を即座に評価可能です。
  • 省スペース設計:大量の時系列データを扱う際にレイアウトスペースを削減する効果があります。

適用的なユースケース:

複数の指標同時追跡が必要な環境向けです。例えば、為替レートの変動、気象観測値のモニタリング、あるいは企業の複数の KPI や生体情報の継続的な監視などにおいて、異常値や相関パターンの特定に役立ちます。

Python による実装ロジック:

import matplotlib.pyplot as plt
import numpy as np

# フォント設定(日本語対応用)
plt.rcParams["font.family"] = ['MS Gothic', 'Yu Gothic', 'Meiryo']

def construct_horizon_view(series_matrix, labels=None, band_count=3, scale_factor=0.4):
    """
    ホライズンチャートを生成する関数

    Args:
        series_matrix: 時系列データの行列(行が系列)
        labels: シリーズごとのラベルリスト
        band_count: 色付けするバンドの段数
        scale_factor: バンドの高さ比率
    """
    num_rows, points_num = series_matrix.shape
    fig, axs = plt.subplots(num_rows, 1, figsize=(15, 2 * num_rows), sharex=True)

    # レイアウト調整(単一行の場合も対処)
    if num_rows == 1:
        axs = [axs]

    # データ範囲の計算
    global_max = np.max(np.abs(series_matrix))
    band_width = global_max / band_count

    # グラデーション色の定義(マイナス側とプラス側)
    color_map = [
        '#ADD8E6', '#87CEEB', '#4682B4',  # プラス側の青系
        '#FFB6C1', '#FF69B4', '#DC143C'   # マイナス側の赤系
    ]

    for row_idx, current_line in enumerate(series_matrix):
        ax = axs[row_idx]
        ax.set_visible_frame(False)
        
        # タイトル設定
        if labels and row_idx < len(labels):
            ax.set_title(f"{labels[row_idx]}", loc='left')

        # バンドの描画
        for b_idx in range(band_count):
            # 正方向の層
            pos_layer = np.clip(current_line - b_idx * band_width, 0, band_width)
            ax.fill_between(
                range(points_num), 
                b_idx * scale_factor, 
                b_idx * scale_factor + (pos_layer * scale_factor / band_width),
                color=color_map[b_idx], alpha=0.85
            )
            
            # 負方向の層
            neg_layer = np.clip(-current_line - b_idx * band_width, 0, band_width)
            ax.fill_between(
                range(points_num),
                -b_idx * scale_factor,
                -b_idx * scale_factor - (neg_layer * scale_factor / band_width),
                color=color_map[b_idx + band_count], alpha=0.85
            )

        ax.set_ylim(-band_count * scale_factor, band_count * scale_factor)
    
    axs[-1].set_xlabel('時点')
    plt.tight_layout()
    return fig

# データセットの構築
np.random.seed(100)
points = 60
rows = 5
t = np.linspace(0, 20, points)
dataset = np.zeros((rows, points))

dataset[0] = np.sin(t) * 2
dataset[1] = np.cos(t) * 2.5
dataset[2] = t * 0.2
dataset[3] = 10 - t * 0.2
dataset[4] = np.random.randn(points) * 0.5

series_labels = ["売上実績", "競合他社推移", "季節性指数", "コスト変動", "誤差補正"]

fig_demo = construct_horizon_view(dataset, series_labels)
# plt.show()

2. ストリーム(河川)グラフ

機能的特徴:

ストリームグラフは中心軸に対して対称的かつ積み重ねられたエリアとして描画されます。「川の流れ」のような形状となり、各セグメントの幅はその時点での量を示します。これにより、全体に対する各カテゴリの割合変化と時間的な移動が直感的に理解できます。

適用的なユースケース:

構成比の変遷を追跡する際に向いています。経済構造の変化分析、交通流量、エネルギー消費のシフト、あるいはプロジェクトリソースの配分変化などを表現するのに有効です。

Python による実装ロジック:

import plotly.graph_objects as go
import pandas as pd

# サンプルデータの準備
raw_data = {
    "年": ["2019", "2020", "2021", "2022"],
    "部門A": [400, 420, 380, 450],
    "部門B": [150, 180, 220, 200],
    "部門C": [100, 120, 150, 160]
}
df = pd.DataFrame(raw_data)

fig_stream = go.Figure()
accumulated_values = df.iloc[:, 1:].cumsum(axis=1)

# 各行(カテゴリ)ごとに領域を追加
for col_idx, col_name in enumerate(df.columns[1:]):
    upper_limit = accumulated_values[col_name] if col_idx > 0 else df[col_name]
    lower_limit = df["年"] if col_idx == 0 else accumulated_values[df.columns[col_idx]]
    
    fig_stream.add_trace(go.Scatter(
        x=df["年"],
        y=upper_limit,
        fill='tonexty',
        mode='lines',
        name=col_name
    ))
    # 下限ライン(目に見えないように透明化して境界を作る)
    fig_stream.add_trace(go.Scatter(
        x=df["年"],
        y=lower_limit,
        fill='toself',
        mode='lines',
        showlegend=False,
        line_color='rgba(255,255,255,0)' 
    ))

fig_stream.update_layout(
    title="部門別構成比の推移",
    hovermode="x unified",
    xaxis_title="年月",
    yaxis_title="数値合計"
)
# fig_stream.show()

3. ウォーターフォールチャート

機能的特徴:

初期値から終了値までの段階的な変動を棒グラフを用いて示します。増加は通常青色、減少は赤色で表現され、中間の項目が最終結果に与える影響を強調します。要因分解分析において非常に強力です。

適用的なユースケース:

予算計画と実績の差分、在庫の増減、キャッシュフローの経路分析などに利用されます。収益、費用、利益といった財務要素の積み上げ計算を行う場合に適しています。

Python による実装ロジック:

import plotly.graph_objects as go

# 在庫管理に関するサンプル
fig_wf = go.Figure(go.Waterfall(
    name="四半期在庫管理表",
    orientation="v",
    measure=["absolute", "relative", "relative", "relative", "total"],
    x=["期初在庫", "仕入れ増", "販売減", "廃棄ロス", "期末在庫"],
    y=[100, 25, -15, -5, 0],
    connector={"line":{"color":"rgb(212, 175, 55)"}},
))

fig_wf.update_layout(
    title="在庫変動サマリー",
    yaxis=dict(title="個数"),
    font_family="YuGothic"
)
# fig_wf.show()

4. キャンドルスティックチャート

機能的特徴:

特定の期間における「始点」「終点」「最高値」「最低値」の 4 つの数値を烛台形状で表現します。本体(レバー)が実心か空欄かで上昇・下降を判別し、ヒゲ部分で極値範囲を可視化します。

適用的なユースケース:

金融市場での株価、為替、先物などの価格変動分析が主用途ですが、日付や温度、生産量など極端な上下幅がある周期性データにも適用可能です。

Python による実装ロジック:

import pandas as pd
import numpy as np
import plotly.graph_objects as go

# 模擬テクニカルデータ生成
dates = pd.date_range(start="2023-01-01", periods=45, freq="D")
base_price = 150.0

volatility = 0.02
drift = 0.001

prices = [base_price]
for _ in range(len(dates)-1):
    next_p = prices[-1] * (1 + np.random.normal(drift, volatility))
    prices.append(next_p)

df_candle = pd.DataFrame({'Date': dates, 'Price': prices})
df_candle['Open'] = df_candle['Price'].shift(1).fillna(base_price)
df_candle['High'] = df_candle['Price'].rolling(3).max().ffill()
df_candle['Low'] = df_candle['Price'].rolling(3).min().ffill()

fig_candle = go.Figure(data=go.Candlestick(
    x=df_candle['Date'],
    open=df_candle['Open'],
    high=df_candle['High'],
    low=df_candle['Low'],
    close=df_candle['Price']
))

fig_candle.update_layout(
    title="株価変動(模拟データ)",
    yaxis_title="単価",
    xaxis_rangeslider_visible=False,
    height=600
)
# fig_candle.show()

5. 折れ線グラフ

機能的特徴:

最も基本的な時系列表現方法です。点を線で結ぶことで連続的な流れを見せ、傾きを通じて成長率や衰退速度を理解させます。複数の系列を重ね合わせる比較機能が優れています。

適用的なユースケース:

GDP 推移、サイト訪問者数の集計、気温の日次変化など、単一の時間軸上に点在する数値の動きを確認する場合に広く使われます。

Python による実装ロジック:

import matplotlib.pyplot as plt
import numpy as np

plt.style.use('seaborn-v0_8')

quarters = ['Q1', 'Q2', 'Q3', 'Q4', 'Q5', 'Q6', 'Q7', 'Q8']
market_a = [120, 135, 140, 155, 160, 175, 180, 190]
market_b = [90, 95, 100, 105, 110, 115, 120, 125]

fig_line, ax_line = plt.subplots(figsize=(10, 5))

ax_line.plot(quarters, market_a, marker='o', label='自社製品', linewidth=2, color='#1f77b4')
ax_line.plot(quarters, market_b, marker='^', label='競合他社', linewidth=2, linestyle='--', color='#d62728')

ax_line.set_title("四半期別市場シェア推移")
ax_line.set_xlabel("期数")
ax_line.set_ylabel("推定値 (万件)")
ax_line.legend(loc="upper left")
ax_line.grid(True, which='both', linestyle='-', alpha=0.3)

plt.tight_layout()
# plt.show()

6. 面積図(スタックア rea)

機能的特徴:

折れ線グラフの下側を塗りつぶすことで、量感が加わります。積み重ね形式をとると、全体総量の中で各要素が占める比率の推移も同時に把握できます。

適用的なユースケース:

予算執行額の推移、サーバーリソースのカテゴリ別利用率、ユーザー属性別の累積カウントなどが挙げられます。

Python による実装ロジック:

import matplotlib.pyplot as plt
import numpy as np

years = list(range(2018, 2024))
group_x = np.random.randint(10, 50, size=len(years))
group_y = np.random.randint(20, 40, size=len(years))
group_z = np.random.randint(5, 30, size=len(years))

fig_area, ax_area = plt.subplots(figsize=(11, 6))

ax_area.stackplot(years, group_x, group_y, group_z, 
                  labels=['北米圏', '欧州圏', 'アジア圏'],
                  alpha=0.7)

ax_area.set_title("地域別貢献度積算図")
ax_area.set_xlabel("年度")
ax_area.set_ylabel("収益率 (%)")
ax_area.legend(loc='upper right')
ax_area.grid(axis='y', linestyle='--', alpha=0.4)

plt.tight_layout()
# plt.show()

7. チャートタイプ比較一覧表

各種時系列表示手法の特性を整理したものです。

種類 主な強み 代表的な用途
ホライズン図 高密度でのトレンド比較が可能 複数指標の同時監視ダッシュボード
ストリームグラフ 全体と部分の比率変化を流動的に表現 市場規模の内訳変遷、交通動向分析
ウォーターフォール プロセス間の増減要因の明確化 損益計算書の作成、目標達成度分解
キャンドル図 極端な値を含むボラティリティの可視化 株式相場の分析、高頻度データ解析
折れ線グラフ シンプルで読み手が慣れている 単純な数値の推移確認
面積図 量の重厚感と構成比の同時表示 資源使用量の履歴、累積統計

タグ: Python matplotlib Plotly TimeSeries Data Visualization

6月11日 16:41 投稿