下のグラフは、実際のデータをもとに作成された散布図です。
そして、企業のマーケティングの場で利用されているモノです。
この記事では、上の散布図を作成していきます。
この画像をゴール散布図と呼びます。
本記事の内容
- Pythonで散布図を作成するための環境
- Pandasによるエクセルデータの読み込み
- Matplotlibによる散布図の作成
- Matplotlibによる散布図の微調整
- 完成した散布図のコード
上記の内容に沿って、Pythonで簡単に散布図を作成する方法を説明していきます。
まずは、今回用いた環境の説明からです。
Pythonで散布図を作成するための環境
- Windows 10 Home (バージョン1909)※以下の説明は64bit前提
- Python 3.7.3
- NumPy 1.18.5
- Matplotlib 3.2.1
- Pandas 0.24.2
- xlrd 1.2.0
もし、まだMatplotlibの日本語化対応をしていない場合は、次の記事をご覧ください。
Pandasによるエクセルデータの読み込み
ゴール散布図のデータは、次のURLでダウンロード可能です。
http://j-sda.or.jp/about-jsda/weather/kekka4.php
画面の中央に「元データのダウンロードはこちらから」リンクがあります。
これをクリックすれば、ダウンロードが開始します。
ダウンロードしたファイルは、「DL4.xls」です。
エクセルファイルです。
このエクセルファイルをプログラムから読み込む場所に移動しておきます。
xlrdライブラリのインストール
xlrdは、エクセルを扱うためのライブラリです。
これをインストールすれば、Pandasでエクセルを読むことが可能となります。
xlrdライブラリのインストールは、以下のコマンドで行います。
pip install xlrd
エクセルファイルをPandasで読み込む
エクセルの内容は以下。
では、このExcelファイルを読み込みます。
以下のコードだけで、エクセルファイルを読み込むことができます。
なお、エクセルは最初のシートが対象です。
そのため、 read_excelの引数にsheet_name=0と設定しています。
import pandas as pd df = pd.read_excel('data/DL4.xls', index_col=0) print(df.head())
結果に以下が表示されれば、OK。
年月日 平均気温 販売指数 週別指数 週別気温 0 2014-04-01 13.9 2.263703 NaN NaN 1 2014-04-02 15.2 1.697737 NaN NaN 2 2014-04-03 13.8 1.407450 NaN NaN 3 2014-04-04 15.3 1.209598 NaN NaN 4 2014-04-05 11.4 1.206834 1.227821 13.157143
問題なく読み込めていますね。
Matplotlibによる散布図の作成
散布図の作成方法を具体的に説明していきます。
ただし、今回はゴール画像の一部には対応しません。
その一部とは以下。
- 回帰分析に関する表示(直線とR[二乗]=0.7898)
- 「東京都」の太文字
回帰分析まで対応すると、話が広がり過ぎます。
今回は、あくまで散布図の作成がメインです。
また、太文字に関してはフォントが未対応です。
そのため、太文字にする設定が無効となります。
では、早速、簡単な散布図の作成から行いましょう。
以下のコードで散布図を出力できます。
import pandas as pd import matplotlib.pyplot as plt df = pd.read_excel('data/DL4.xls', sheet_name=0) # 欠損値が一つでも含まれる行を削除 df = df.dropna(how='any') x = df['週別気温'] y = df['週別指数'] # 散布図を描画 plt.scatter(x, y, c=(1.0,0,0))
出力結果は以下。
散布図が、簡単に出ましたね。
では、ここからゴール散布図に見た目を近づけていきます。
以下の記事の内容で対応可能な箇所に変更を加えていきます。
その結果は以下のコード。
import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.read_excel('data/DL4.xls', sheet_name=0) # 欠損値が一つでも含まれる行を削除 df = df.dropna(how='any') x = df['週別気温'] y = df['週別指数'] # 目盛の値 xscale = np.arange(0, 40, 5) yscale = np.arange(0, 3, 2.5) fig = plt.figure(dpi=100, figsize=(4.6,3.8)) fig.suptitle('品目:スポーツ飲料等', fontsize=10, x=0.27, y=0.87) ax = fig.add_subplot(111) ax.yaxis.set_label_coords(-0.07,0.4) # 散布図を描画 plt.scatter(x, y) plt.title("東京都", fontsize=17) plt.xticks(xscale, fontsize=8) plt.yticks(yscale, fontsize=8) plt.xlabel("平均気温(℃)", fontsize=10) plt.ylabel("販\n売\n指\n数", fontsize=10, rotation=0) plt.gca().spines['right'].set_visible(False) plt.subplots_adjust(left=0.1, right=0.98, bottom=0.13, top=0.89) plt.savefig("result1.png", facecolor="white")
実行結果は、以下。
ここまでの対応は、既存の知識で対応できました。
ゴール散布図に到達するには、あと2か所の微調整が必要です。
- 散布図のマーカーを同じ表示にする
- グラフ表示領域の上の枠線を販売指数2.5に設定する
これらの微調整を以下で行っていきます。
Matplotlibによる散布図の微調整
散布図のマーカーを同じ表示にする
マーカーの色を指定
マーカーの色は、引数「c」で行います。
カラーコードを設定可能です。
plt.scatter(x, y, c='#8cd7f8')
この変更を加えた結果。
散布図のマーカーの色が、変わりました。
しかし、アウトラインがまだ不足しています。
アウトラインの設定
アウトラインの設定は、引数「edgecolors」で行います。
カラーコードを設定可能です。
plt.scatter(x, y, c='#00FFFF', edgecolors="#37BAF2")
この変更を加えた結果は以下。
見事にアウトラインが設定されました。
残るは、y軸の最大を2.5にすることですね。
グラフ表示領域の上の枠線を販売指数2.5に設定する
以下のコードを設定します。
plt.ylim(0.0, 2.5)
もし、x軸の表示領域を制限するなら、次も追加。
plt.xlim(0, 35)
現状、x軸・y軸の目盛は、最大値を工夫することで対応しています。
工夫といっても、値を固定しているだけです。
# 目盛の値 xscale = np.arange(0, 40, 5) yscale = np.arange(0, 3, 2.5)
ただ、これだと平均気温40度以上や販売指数3以上にも対応できません。
ありえないのでしょうけども・・・
そのため、データの最大値によって、目盛が自動的に決まるようにした方がよいでしょう。
この修正も含めて、次で最終コードを載せます。
完成した散布図のコード
最終コードです。
import numpy as np import pandas as pd import matplotlib.pyplot as plt df = pd.read_excel('data/DL4.xls', sheet_name=0) # 欠損値が一つでも含まれる行を削除 df = df.dropna(how='any') x = df['週別気温'] y = df['週別指数'] # 目盛の値 x_scale = 5 y_scale = 2.5 xscale = np.arange(0, (max(x)+1)*x_scale, x_scale) yscale = np.arange(0, (max(y)+1)*y_scale, y_scale) fig = plt.figure(dpi=100, figsize=(4.6,3.8)) fig.suptitle('品目:スポーツ飲料等', fontsize=10, x=0.27, y=0.87) ax = fig.add_subplot(111) ax.yaxis.set_label_coords(-0.07,0.4) # 散布図を描画 plt.scatter(x, y, c='#00FFFF', edgecolors="#37BAF2") plt.title("東京都", fontsize=17) plt.xticks(xscale, fontsize=8) plt.yticks(yscale, fontsize=8) plt.xlabel("平均気温(℃)", fontsize=10) plt.ylabel("販\n売\n指\n数", fontsize=10, rotation=0) plt.xlim(0, 35) plt.ylim(0.0, 2.5) plt.gca().spines['right'].set_visible(False) plt.subplots_adjust(left=0.1, right=0.98, bottom=0.13, top=0.89) plt.savefig("result1.png", facecolor="white")
このコードの結果。
ゴール散布図をほぼ実現できました。
対応しないと宣言した部分以外では、次の部分が一致していませんね。
散布図のマーカーが、y軸の最大値で一部非表示になるところです。
ただ、これは最大値で表示が切れる方が正しい姿だと思います。