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

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

Python+matplotlibの二次元ヒストグラムhist2dでエントリー数が0のビンの色を白くする方法

カラーバーを線形スケールで描画する場合、countsが0のbinを白くする方法は3通りあります。

  1. np.histogram2d でhistデータを作成し plt.pcolormesh で描画する方法
  2. 下限値を白にしたカラーマップを使って plt.hist2d で描画する方法
  3. 端だけに白にしたカラーマップを使って plt.hist2d で描画する方法 (おすすめ)

データ作成部分

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

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 = np.random.normal(3,2,10000) #平均3、標準偏差2、N=10000

普通に描画

hist2dを普通に使うとうまくいかない

_, _, _, im = plt.hist2d(x, y, range=[[-10,10],[-10,10]], bins=[100,100], cmap="viridis")

im.set_clim(0,50) #カラーバーの表示範囲
plt.colorbar(im,label="Counts") #カラーバーを表示しラベルをセット
plt.xlabel("X")
plt.ylabel("Y")
plt.show()

plt.pcolormesh で描画する方法

plt.pcolormesh で描画するときに、0 countsのbinをマスクする。

Z, X, Y = np.histogram2d(x,y,bins=[100,100],range=[[-10,10],[-10,10]])
Z = np.rot90(Z) # np.histogram2dの仕様上必要
Z = np.flipud(Z) # np.histogram2dの仕様上必要

Z_masked = np.ma.masked_where(Z==0,Z)
im = plt.pcolormesh(X,Y,Z_masked,cmap="viridis")

# 以下省略

下限値を白にしたカラーマップを使って plt.hist2d で描画

カラーマップのコピーをcopy.copyで作って、set_underで下限値と色を指定する。コピーを作らないと怒られる。なお、この方法ではカラーバーの下端を0にできない。

import copy

cmap = copy.copy(plt.cm.viridis)
cmap.set_under('w',1) # 下限以下の色を設定

_, _, _, im = plt.hist2d(x, y, range=[[-10,10],[-10,10]], bins=[100,100], cmap=cmap)

im.set_clim(1,50)
# 以下省略

あまり使わないと思うが、上限を超えた場合の色も設定できる。

cmap.set_under('white',1) # 下限以下の色を設定
cmap.set_over('black',10) #上限以上の色を設定

端だけに白にしたカラーマップを使って plt.hist2d で描画

カラーバーの色指定の範囲[0-1]のうち[0-1e-20]を白くする。ただし、カラーバーの下端もわずかに白くなってしまう。カラーマップ viridis は入ってなかった。

import matplotlib._cm
import matplotlib
cdict = dict([(key,tuple([(0.0, 1, 1)] + [(1e-20, val[0][1], val[0][2])] + list(val)[1:])) for key,val in matplotlib._cm.datad["jet"].items()])
cmap = matplotlib.colors.LinearSegmentedColormap('jet2', cdict)

_, _, _, im = plt.hist2d(x, y, range=[[-10,10],[-10,10]], bins=[100,100], cmap=cmap)

# 以下省略

対数で描画

norm=matplotlib.colors.LogNorm()を使って カラーバーを対数スケールで描画する場合、0 countsは未定義になるため、plt.hist2dで普通に描画すればよい。

_, _, _, im = plt.hist2d(x, y, range=[[-10,10],[-10,10]], bins=[100,100], cmap="viridis", norm=matplotlib.colors.LogNorm())

im.set_clim(1,100)
# 以下省略

matplotlibでの色一覧

matplotlib.org

matplotlibでのカラーマップ一覧

https://matplotlib.org/stable/tutorials/colors/colormaps.htmlmatplotlib.org

参照

stackoverflow.com

oceanpython.org

stackoverflow.com

コメント:

CERN ROOTのTH2等だとcountsが0のbinは自動的に白くなるがmatplotlibの場合そうはならないのでなんとかしてほしいと思っている人は多いだろう。