物理の駅 Physics station by 現役研究者

テクノロジーは共有されてこそ栄える

Python+matplotlib ヒストグラムのbinを直接操作してplt.hist 以外で描写

ヒストグラムのビン(bin)の値を直接操作した後で、ヒストグラムっぽいグラフを作りたいことがあるだろう。 以下では、plt.hist を使った場合と、np.histgramで計算させた、binの位置 X とCounts Y を使って plt.hist 以外で描画する方法を紹介する。

データ作成部分

ここは共通部分なので最初に書くべし。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
x = np.random.normal(0,1,10000) #平均0、標準偏差1、N=10000

普通にplt.histで描画

plt.hist(x, bins=100, range=[-10,10])
plt.xlim(-10,10)
plt.show()

plt.barで描画

棒グラフを描画する plt.bar を使う

Y, X = np.histogram(x, bins=100, range=[-10,10])
plt.bar((X[:-1]+X[1:])*0.5, Y, width=X[1]-X[0])
plt.xlim(-10,10)
plt.ylim(0,None)
plt.show()

plt.fill_betweenで描画

少しトリッキーだが間を塗りつぶせる plt.fill_between を使う

Y, X = np.histogram(x, bins=100, range=[-10,10])
X2 = np.array([e for e in X for _ in range(2)][1:-1])
Y2 = np.array([e for e in Y for _ in range(2)])
plt.fill_between(X2, X2*0, Y2, lw=0)
plt.xlim(-10,10)
plt.ylim(0,None)
plt.show()

普通に plt.hist で枠だけ描画

histtype="step" で 枠(階段)だけ描画できる。

plt.hist(x, bins=100, range=[-10,10], histtype="step", lw=1)
plt.xlim(-10,10)
plt.show()

plt.step で枠だけ描画

Y, X = np.histogram(x, bins=100, range=[-10,10])
plt.step((X[:-1]+X[1:])*0.5, Y, where='mid', lw=1)
plt.xlim(-10,10)
plt.ylim(0,None)
plt.show()

plt.plot で枠だけ描画

少しトリッキーだが、点列を作って plt.plot で描画することもできる

Y, X = np.histogram(x, bins=100, range=[-10,10])
X2 = np.array([e for e in X for _ in range(2)][1:-1])
Y2 = np.array([e for e in Y for _ in range(2)])
plt.plot(X2, Y2, lw=1)
plt.xlim(-10,10)
plt.ylim(0,None)
plt.show()

plt.hist で塗りつぶし+枠を描画

plt.hist で塗りつぶしと枠を両立するには fill="full", histtype="step"とする。

plt.hist(x,bins=100, range=[-10,10], color="tab:cyan", fill="full", histtype="step", lw=1.5, edgecolor="tab:red")
plt.xlim(-10,10)
plt.show()

plt.barplt.step で塗りつぶし+枠を描画

Y, X = np.histogram(x,bins=100, range=[-10,10])
plt.bar((X[:-1]+X[1:])*0.5, Y, width=X[1]-X[0], color="tab:cyan")
plt.step((X[:-1]+X[1:])*0.5, Y, where='mid', lw=1.5, color="tab:red")
plt.xlim(-10,10)
plt.ylim(0,None)
plt.show()

凡例の描画

step+barで擬似ヒストグラムの描画はできるものの、凡例 legend はそのままでは描画できないので、Patch で凡例を作る必要がある。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
x = np.random.normal(0,1,10000) #平均0、標準偏差1、N=10000
Y, X = np.histogram(x, bins=100, range=[-10,10])
Xcenter = (X[:-1]+X[1:])*0.5
X2 = np.array([e for e in X for _ in range(2)][1:-1])
Y2 = np.array([e for e in Y for _ in range(2)])

fig, ax = plt.subplots(ncols=3, nrows=3, figsize=(12,10)) 

ax[0][0].hist(x, bins=100, range=[-10,10], label="hist")
ax[0][1].bar(Xcenter, Y, width=X[1]-X[0], label="bar")
ax[0][2].fill_between(X2, X2*0, Y2, lw=0, label="fill_between")

ax[1][0].hist(x, bins=100, range=[-10,10], histtype="step", lw=1, label="hist+step")
ax[1][1].step(Xcenter, Y, where='mid', lw=1, label="step")
ax[1][2].plot(X2, Y2, lw=1, label="plot")

ax[2][0].hist(x,bins=100, range=[-10,10], color="tab:cyan", fill="full", histtype="step", lw=1.5, edgecolor="tab:red", label="hist")

ax[2][1].bar(Xcenter, Y, width=X[1]-X[0], color="tab:cyan", label="bar")
ax[2][1].step(Xcenter, Y, where='mid', lw=1.5, color="tab:red", label="step")

ax[2][2].bar(Xcenter, Y, width=X[1]-X[0], color="tab:cyan")
ax[2][2].step(Xcenter, Y, where='mid', lw=1.5, color="tab:red")
from matplotlib.patches import Patch
ax[2][2].legend(handles=[Patch(facecolor='tab:cyan', edgecolor='tab:red', lw=1.5, label='bar+step+legend')])

for col in range(3):
    for row in range(3):
        ax[row][col].set_xlim(-10,10)
        ax[row][col].set_ylim(0,None)
        if col==2 and row==2:continue
        ax[row][col].legend()

plt.show()

いろんな方法があるなあ・・・

2次元の場合

phst.hateblo.jp

または、以下の記事の 「plt.pcolormesh で描画する方法」 参照

phst.hateblo.jp