目的
xy平面上のデータzをプロットするために等高線図を作ります。
Excelのグラフで一応等高線グラフはあるんですが、
下記のようなグリッドのデータが存在する前提の機能のようで使えない場合が多いです。
例えば実験データなどはところどころ抜けがあったり、等間隔のグリッドですらない場合が多いので、xy面内分布を図示するのには使えません。
y1 | y2 | y3 | y4 | |
---|---|---|---|---|
x1 | z11 | z12 | z13 | z14 |
x2 | z21 | z22 | z23 | z24 |
x3 | z31 | z32 | z33 | z34 |
x4 | z41 | z42 | z43 | z44 |
シナリオ
ランダムなx,yとそれに対応するzの計3列からなるデータがあります。
これの等高線図を作ることにします。
(zの値は今回sin^2(x)+cos^3(y)としています。しっかり等高線図を作れているか確認するためにzをx,yの関数としましたが、以下のコードは実際にはzが適当な値でも機能します)
コード
python in excelはセルの数式として=PYを入力することで数式バーがpython コード入力領域へと変化しpythonコードを書けるようになります。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
#データの定義 x,y,z,グラフのタイトル,のセル範囲を設定する
x0=xl("C2:C50")
y0=xl("D2:D50")
z0=xl("E2:E50")
title=xl("A3")
lower_limit=xl("A5")
higher_limit=xl("A7")
#データの加工
x1=x0.to_numpy().flatten()
y1=y0.to_numpy().flatten()
z=z0.to_numpy().flatten()
df=pd.DataFrame({'x':x1,'y':y1,'z':z})
df = df.dropna()
#プロット先を作る
x = np.array(sorted(set(df.x))) # setで重複を除いたのち、ソート
y = np.array(sorted(set(df.y))) # setで重複を除いたのち、ソート
x_fine = np.linspace(x.min(), x.max(), len(x) * 5 - 1) # グリッドを5倍に
y_fine = np.linspace(y.min(), y.max(), len(y) * 5 - 1) # グリッドを5倍に
X, Y = np.meshgrid(x_fine, y_fine)
#Zのプロットを作る
# 不規則なデータを補間してグリッドにマッピング
grid_z = griddata((df['x'], df['y']), df['z'], (X, Y), method='linear')
#形を整える
plt.rcParams["figure.figsize"] = [4,4]
ax = plt.subplot(111) # axesの設定
ctf = ax.contourf(X, Y, grid_z, levels=np.linspace(lower_limit,higher_limit,25),vmin=lower_limit, vmax=higher_limit, cmap="jet") # コンター
colb = plt.colorbar(ctf, pad=0.1, orientation="vertical") # カラーバー
colb.set_label("z", fontname="Arial", fontsize=6) # カラーバーのラベル
plt.title(title, fontsize=10, fontname="Arial", pad=20)
#描画
plt.show()
結果
セルの右クリックメニューで「セルの上にプロットを表示」を選ぶとプロットが出てきます。
いい感じの等高線図ができてます。
(本来のsin^2(x)+cos^3(x)にかなり近いのでうまくいってそうです)
何をしているか雑な解説
描画にmatplotlibを使うとしても、データの等高線を作るにはグリッド形式にしてやる必要があるので、まずグリッドを用意してやり、その後元データからグリッド上にデータを補完するという手順を踏んでいます。
(meshgridのデータの記法は初見だとちょっと混乱しそうな気がしますが、ここでは説明を省きます。)
#グリッドを用意している部分
X, Y = np.meshgrid(x_fine, y_fine)
#グリッド上にデータを保管している部分
grid_z = griddata((df['x'], df['y']), df['z'], (X, Y), method='linear')
おわり
Excelでmatplotlib使えるなんていい時代になりましたね。