PythonのMatplotlibのグラフに領域を指示して最大値と最小値を取得する
PythonのMatplotlibで描画したグラフに対して、マウスでここからここまでという領域を指定して、その領域内のグラフの最大値と最小値を取得してみます。
目次
マウスで指定した範囲の値を取得する方法
Matplotlibのイベントを利用してマウスの座標を取得し、その座標からグラフの最大値と最小値を計算します。
グラフの生成
今回は、グラフの元になるデータはCSVファイルから読み込むこととします。
そのテスト用のCSVファイルを作るコードは下記です。
import csv
import numpy as np
x = np.arange(0, 10, 0.1)
y1 = np.sin(x)
y2 = np.cos(x)
out = np.concatenate([[x],[y1], [y2]]).transpose().tolist()
out = [list(map(str, i)) for i in out]
with open('test.csv', mode='wt', newline='', encoding='utf-8') as f:
csv_writer = csv.writer(f)
csv_writer.writerows(out)
シンプルなものですが、ndarrayをそのままCSVモジュールで書き出そうとするとうまくいきません。ndarrayのデータ型を文字列に変更しなければなりません。
そこで、このコードではndarrayからリストに変換して、mapメソッドで各要素を文字列にキャストしています。
グラフを表示して最大値と最小値を取得する
では、グラフを表示して最大値と最小値を取得してみます。
import csv
import numpy as np
import matplotlib.pyplot as plt
class LineBuilder:
def __init__(self, line, x, y1, y2, line2):
self.line = line
self.xs = list(line.get_xdata())
self.ys = list(line.get_ydata())
self.x = x
self.y1 = y1
self.y2 = y2
self.line2 = line2
self.xs2 = list(line2.get_xdata())
self.ys2 = list(line2.get_ydata())
self.cid = line.figure.canvas.mpl_connect('button_press_event', self)
self.cid = line.figure.canvas.mpl_connect('button_release_event', self)
def __call__(self, event):
if event.inaxes!=self.line.axes: return
lim = ax.get_ylim()
if event.name == 'button_press_event':
self.xs.append(event.xdata)
self.ys.append(lim[0])
self.xs.append(event.xdata)
self.ys.append(lim[1])
self.line.set_data(self.xs, self.ys)
self.line.figure.canvas.draw()
else:
self.xs.append(None)
self.ys.append(None)
self.xs.append(event.xdata)
self.ys.append(lim[0])
self.xs.append(event.xdata)
self.ys.append(lim[1])
self.line.set_data(self.xs, self.ys)
self.line.figure.canvas.draw()
x_selected = []
y1_selected = []
y2_selected = []
x_min = min(self.xs[-4], self.xs[-1])
x_max = max(self.xs[-4], self.xs[-1])
for i in range(len(x)):
if self.x[i] >= x_min and self.x[i] <= x_max:
x_selected.append(self.x[i])
y1_selected.append(self.y1[i])
y2_selected.append(self.y2[i])
if len(x_selected) > 1:
y1_max_idx = np.argmax(y1_selected)
y2_max_idx = np.argmax(y2_selected)
y1_min_idx = np.argmin(y1_selected)
y2_min_idx = np.argmin(y2_selected)
print('Y1 min: ', x_selected[y1_min_idx], y1_selected[y1_min_idx])
print('Y1 max: ', x_selected[y1_max_idx], y1_selected[y1_max_idx])
print('Y2 min: ', x_selected[y2_min_idx], y2_selected[y2_min_idx])
print('Y2 max: ', x_selected[y2_max_idx], y2_selected[y2_max_idx])
self.xs2 = [x_selected[y1_min_idx]-0.2, x_selected[y1_min_idx]+0.2, None, x_selected[y1_min_idx], x_selected[y1_min_idx]]
self.ys2 = [y1_selected[y1_min_idx], y1_selected[y1_min_idx], None, y1_selected[y1_min_idx]-0.2, y1_selected[y1_min_idx]+0.2]
self.xs2.extend([None, x_selected[y1_max_idx]-0.2, x_selected[y1_max_idx]+0.2, None, x_selected[y1_max_idx], x_selected[y1_max_idx]])
self.ys2.extend([None, y1_selected[y1_max_idx], y1_selected[y1_max_idx], None, y1_selected[y1_max_idx]-0.2, y1_selected[y1_max_idx]+0.2])
self.xs2.extend([None, x_selected[y2_min_idx]-0.2, x_selected[y2_min_idx]+0.2, None, x_selected[y2_min_idx], x_selected[y2_min_idx]])
self.ys2.extend([None, y2_selected[y2_min_idx], y2_selected[y2_min_idx], None, y2_selected[y2_min_idx]-0.2, y2_selected[y2_min_idx]+0.2])
self.xs2.extend([None, x_selected[y2_max_idx]-0.2, x_selected[y2_max_idx]+0.2, None, x_selected[y2_max_idx], x_selected[y2_max_idx]])
self.ys2.extend([None, y2_selected[y2_max_idx], y2_selected[y2_max_idx], None, y2_selected[y2_max_idx]-0.2, y2_selected[y2_max_idx]+0.2])
self.line2.set_data(self.xs2, self.ys2)
self.line2.figure.canvas.draw()
else:
self.xs = []
self.ys = []
self.line.set_data(self.xs, self.ys)
self.line.figure.canvas.draw()
self.xs2 = []
self.ys2 = []
self.line2.set_data(self.xs2, self.ys2)
self.line2.figure.canvas.draw()
self.xs = []
self.ys = []
self.xs2 = []
self.ys2 = []
# ファイル読み込み
fn = 'test.csv'
with open(fn, mode='r', newline='') as f_in:
reader = csv.reader(f_in)
data_array = [row for row in reader]
# 要素を文字列からfloatに変換
data_array = [list(map(float, i)) for i in data_array]
# グラフ描画
np_array = np.array(data_array).transpose()
x = np_array[0]
y1 = np_array[1]
y2 = np_array[2]
fig, ax = plt.subplots()
ax.plot(x, y1)
ax.plot(x, y2)
line, = ax.plot([], [])
line2, = ax.plot([], [])
linebuilder = LineBuilder(line, x, y1, y2, line2)
plt.show()
マウスの左ボタンを押したときに領域選択を開始し、マウスの左ボタンを離したときに領域選択を終了します。
選択した領域内の2つのグラフのそれぞれの最大値と最小値に印を付けて、その座標を標準出力に表示します。
実行するとこのようにグラフの最大値と最小値が得られます。
公開日
広告
Pythonでグラフカテゴリの投稿
- Pythonで3Dグラフを描く
- PythonでGIFアニメを作る(PILでアニメーションファイルを出力編)
- Pythonでグラフのアニメを作る(OpenCVでmp4ファイルを出力編)
- Pythonでグラフのコンテナを作る
- Pythonでグラフを描く
- Pythonでグラフ(Matplotlib)のアニメーションを作る(ArtistAnimation編)
- Pythonでグラフ(Matplotlib)のアニメーションを作る(FuncAnimation編)
- PythonのMatplotlibのグラフに領域を指示して最大値と最小値を取得する
- PythonのMatplotlibのグラフに領域を指示して最大値と最小値を取得する(GUI版)
- PythonのMatplotlibのグラフをNumPy行列に変換してOpenCVやPillowで使う
- Pythonのグラフのひな形