Matplotlib スタックプロット – チュートリアルと例題

Python には多くのデータ可視化ライブラリがありますが、Matplotlib はその中でも最も人気のあるライブラリです。Matplotlib の人気の理由はその信頼性と実用性にあり、少ないコードでシンプルなプロットから複雑なプロットまで作成することができます。また、プロットは様々な方法でカスタマイズすることができます。

このチュートリアルでは、Matplotlib で Stack Plots をプロットする方法について説明します。

スタックプロットは、線形データを縦に並べて、それぞれの線形プロットを別のものに重ねてプロットするために使われます。典型的には、累積プロットを生成するために使用されます。

&gt
&gt

データのインポート

Our World in DataにあるCovid-19の予防接種に関するデータセット、特に国ごとの累積予防接種を含むデータセットを使用することにする。

まず、必要なライブラリをすべてインポートすることから始めます。データセットの読み込みと解析のためにPandasを、X軸の値を生成するためにNumpyを、そしてもちろんMatplotlibからPyPlotモジュールをインポートする必要があります。

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np


それでは、これから使う DataFrame を見てみましょう。

dataframe = pd.read_csv("cumulative-covid-vaccinations.csv")
print(dataframe.head(25))


ここでは、Entitytotal_vaccinations に注目します。Date` 機能も使用できますが、予防接種の状況を日ごとに把握するために、最初のエントリを Day 0、最後のエントリを Day N として扱います。

     Entity Code        Date  total_vaccinations
0   Albania  ALB  2021-01-10                   0
1   Albania  ALB  2021-01-12                 128
2   Albania  ALB  2021-01-13                 188
3   Albania  ALB  2021-01-14                 266
4   Albania  ALB  2021-01-15                 308
5   Albania  ALB  2021-01-16                 369
...
16  Albania  ALB  2021-02-22                6728
17  Albania  ALB  2021-02-25               10135
18  Albania  ALB  2021-03-01               14295
19  Albania  ALB  2021-03-03               15793
20  Albania  ALB  2021-03-10               21613
21  Algeria  DZA  2021-01-29                   0
22  Algeria  DZA  2021-01-30                  30
23  Algeria  DZA  2021-02-19               75000
24  Andorra  AND  2021-01-25                 576


このデータセットは、特殊なユースケースであるため、いくつかの前処理が必要です。しかし、前処理をする前に、スタックプロットが一般的にどのようにプロットされるかを知っておこう。

Matplotlib でのスタックプロットの描画

スタックプロットは、複数の線形プロットを重ねて可視化するために使用されます。通常の折れ線グラフでは、X と Y の関係をプロットします。ここでは、複数の Y 特徴を、共有の X 軸上に、1つずつ重ねてプロットします。

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]
y1 = [5, 6, 4, 5, 7]
y2 = [1, 6, 4, 5, 6]
y3 = [1, 1, 2, 3, 2]


fig, ax = plt.subplots()
ax.stackplot(x, y1, y2, y3)
plt.show()


この結果

このように複数のリストを扱うのは少し扱いにくいので、単純に辞書を使って、各特徴 yn を項目とすることができます。

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]


y_values = {
    "y1": [5, 6, 4, 5, 7],
    "y2": [1, 6, 4, 5, 6],
    "y3" : [1, 1, 2, 3, 2]
}


fig, ax = plt.subplots()
ax.stackplot(x, y_values.values())
plt.show()


この結果は

このタイプのプロットは簡単にスタックで迷子になるので、 y_values 辞書から keys()labels 引数に設定して、色にラベルを追加し、プロットに凡例を追加すると本当に便利です。

import matplotlib.pyplot as plt
x = [1, 2, 3, 4, 5]


y_values = {
    "y1": [5, 6, 4, 5, 7],
    "y2": [1, 6, 4, 5, 6],
    "y3" : [1, 1, 2, 3, 2]
}


fig, ax = plt.subplots()
ax.stackplot(x, y_values.values(), labels=y_values.keys())
ax.legend(loc='upper left')
plt.show()


さて、この結果は

注意: これらのリストの長さは同じでなければなりません。y1を3つの値でプロットし、y2` を5つの値でプロットすることはできません。

これでCovid-19のワクチン接種のデータセットができました。このような辞書の形になるようにデータセットを前処理して、一般人口に投与された累積ワクチンをプロットしてみましょう。

まず、データセットを Entitytotal_vaccinations でグループ化しましょう。現在、各 Entity には多数のエントリがあるため、グループ化する必要があります。また、 WorldEuropean Union というエンティティは、単一の累積線をプロットしたい場合に追加する便利なエンティティなので、削除します。

この場合、すでにプロットされている各国の値を1つのエンティティとして含むため、total_vaccinationのカウントが実質2倍以上になります。

dataframe = pd.read_csv("cumulative-covid-vaccinations.csv")
indices = dataframe[(dataframe['Entity'] == 'World') | (dataframe['Entity'] == 'European Union')].index
dataframe.drop(indices, inplace=True)


countries_vaccinations = dataframe.groupby('Entity')['total_vaccinations'].apply(list)


この結果、データセットの形状はまったく異なるものになります。各エントリに Entity/total_vaccinations というエントリがあるのではなく、各 Entity には、これまでの総ワクチン接種数のリストが含まれることになります。

Entity
Albania           [0, 128, 188, 266, 308, 369, 405, 447, 483, 51...
Algeria                                              [0, 30, 75000]
Andorra           [576, 1036, 1291, 1622, 2141, 2390, 2526, 3611...
...
Croatia           [7864, 12285, 13798, 20603, 24985, 30000, 3455...
Cyprus            [3901, 6035, 10226, 17739, 25519, 32837, 44429...
Czechia           [1261, 3560, 7017, 10496, 11813, 12077, 13335,...


では、この Series を辞書に変換して、どのようになるか見てみましょう。

cv_dict = countries_vaccinations.to_dict()
print(cv_dict)


この結果、次のようになる。

{
'Albania': [0, 128, 188, 266, 308, 369, 405, 447, 483, 519, 549, 550, 1127, 1701, 3049, 4177, 6728, 10135, 14295, 15793, 21613], 
'Algeria': [0, 30, 75000], 
'Andorra': [576, 1036, 1291, 1622, 2141, 2390, 2526, 3611, 4914],
...
}


しかし、ここで問題があります。これらのエントリーの形が同じでないと、プロットできないのです。例えば、アルジェリアは3件、アンドラは9件です。そこで、最も多くの値を持つキーと、その値の個数を調べます。

そして、新しい辞書を作成し(元の辞書を繰り返しながら修正することは望ましくありません)、過去の欠落した日ごとに 0 を挿入します(その日の総ワクチン接種数が 0 だったからです)。

max_key, max_value = max(cv_dict.items(), key = lambda x: len(set(x[1])))


cv_dict_full = {}
for k,v in cv_dict.items():
    if len(v) < len(max_value):
        trailing_zeros = [0]*(len(max_value)-len(v))
        cv_dict_full[k] = trailing_zeros+v
    else:
        cv_dict_full[k] = v

print(cv_dict_full)


ここでは、各エントリのリストの長さが、最大長のリストの長さより短いかどうかをチェックするだけである。もしそうなら、それらの差をゼロで加え、その値を元の値のリストに追加する。

さて、この新しい辞書を印刷すると、次のようなものになる。

{
'Albania': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 188, 266, 308, 369, 405, 447, 483, 519, 549, 550, 1127, 1701, 3049, 4177, 6728, 10135, 14295, 15793, 21613],
'Algeria': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 75000],
'Andorra': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 576, 1036, 1291, 1622, 2141, 2390, 2526, 3611, 4914],
...
}


入力値が最も多い国は

print(max_key, len(max_value)) # Canada 90


これでデータセットの準備が完全に整い、以前のスタックプロットと同じようにプロットできるようになりましたので、日数を生成してプロットしてみましょう。

dates = np.arange(0, len(max_value))


fig, ax = plt.subplots()
ax.stackplot(dates, cv_dict_full.values(), labels=cv_dict_full.keys())
ax.legend(loc='upper left', ncol=4)
ax.set_title('Cumulative Covid Vaccinations')
ax.set_xlabel('Day')
ax.set_ylabel('Number of people')


plt.show()


世界の国数が多いので、凡例はかなり詰め込まれます。そこで、少なくともプロットに収まるように4つの列にしました。

結論

このチュートリアルでは、PythonのPandasとMatplotlibフレームワークを使用して、単純なStack Plotsのプロット方法と、データセットの前処理とStack Plotsに合うようにデータをシェイプする方法について説明しました。

もしあなたがデータ可視化に興味があり、何から始めたらよいかわからない場合は、Pythonのデータ可視化に関する書籍の束をチェックしてみてください。

Pythonによるデータ可視化

データビジュアライゼーションで危険な存在になる

30日間無条件返金保証

初級から上級まで

定期的に無料で更新(最新更新は2021年4月)

ボーナスリソースやガイドを更新

Pythonでデータ可視化 MatplotlibとPandasは、Pythonの基礎知識を持つ全くの初心者が、PandasとMatplotlibを使って、単純なプロットからインタラクティブなボタンを持つアニメーションの3Dプロットまで、これらのライブラリで高度な作業をするための強力な基盤を構築できるように設計された書籍です。

本書は、Pythonの基本的な知識を持つ方を対象としています。
PandasとMatplotlibについて知っておく必要があることすべてを教えてくれる詳細なガイドです。

Pythonでデータ可視化」は、Pythonの初級~中級開発者向けの本で、Pandasを使った簡単なデータ操作から、MatplotlibやSeabornといったコアなプロットライブラリを取り上げ、Altairのような宣言的・実験的なライブラリの活用方法まで、幅広くガイドしています。具体的には、11章にわたって、9つのPythonライブラリを取り上げています。Pandas、Matplotlib、Seaborn、Bokeh、Altair、Plotly、GGPlot、GeoPandas、そしてVisPyです。

データビジュアライゼーションのユニークで実用的なガイドとして、あなたがキャリアで使うかもしれない多くのツールを紹介しています。

タイトルとURLをコピーしました