今回はPythonのPlotly
のgo
(plotly.graph_objects
)のgo.Heatmap
を使ってヒートマップを作成する方法を解説する。
ヒートマップとは行と列(xとy)のある表形式のデータの各セルの値の大小を色分けしたグラフのこと。2次元配列に色を追加し3次元でデータを見ることができる。
本記事ではgo.Heatmap
でのヒートマップの作成方法やレイアウトの変更方法、各セルにテキストを追加する方法などを解説する。
Python環境は以下。
- Python 3.10.8
- numpy 1.24.0
- plotly 5.11.0
- plotly-orca 3.4.2
参考になるサイト
Plotly公式
本記事のコード全文
下準備のimport
import plotly.graph_objects as go
import plotly.io as pio
import numpy as np
import datetime
まずは下準備としてのimport
関連。今回はgo
のgo.Heatmap
を使用するのでgo
をimport
。また、数値計算や時間を使うのでnumpy
とdatetime
もimport
。
go
よりも簡単にシンプルなグラフを作成できるpxについては以下の記事があるので参考にしていただきたい。
-
【Plotlyで散布図】px.scatterのグラフの描き方まとめ
これからPloltyで動くグラフを作りたい、もっとグラフをキ ...
続きを見る
-
【Plotlyで折れ線グラフ】px.lineでLine Plotを作成する
Plotlyの散布図(scatter plot)はわかったけど線のプロット(line plot){ ...
続きを見る
また、go
を使った散布図や折れ線グラフ(go.Scatter
)の書き方については以下の記事で詳しく解説している。
-
【Plotlyで散布図】go.Scatterのグラフの描き方まとめ
これからPloltyで動くグラフを作りたい、もっとグラフをキ ...
続きを見る
-
【Plotlyで折れ線グラフ】go.ScatterでLine Plotを作成する
今回はPlotlyのgo.Scatterを使って折れ線グラフを作成する。px(plotly.express ...
続きを見る
go.Heatmapで2次元配列のヒートマップを作成
本記事ではgo.Heatmap
を使用し2次元配列からヒートマップを作成するが、ここではまず初めに簡単にヒートマップを作成する方法を紹介する。
2次元配列を渡すだけでグラフ化可能
まずはシンプルに2次元配列を渡してヒートマップを作成した。go.Heatmap
の引数z
に2次元配列を渡すだけで簡単にヒートマップを作成できる。
カラースケールやカラーバーについては後ほどカスタムする。
import plotly.graph_objects as go
import plotly.io as pio
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(data=go.Heatmap(z=z))
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_simple_heatmap"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
配列の順番を逆にしてヒートマップと合わせる
ただし、このままだと2次元配列z
の並びとヒートマップの並びが上下逆になってしまう。慣れると問題ないが、初めのうちは混乱するかもしれない。
配列の順番を変更してもいいのであれば、予め配列を[::-1]
で縦方向に逆転させることで混乱を防ぐことが可能だ。
import plotly.graph_objects as go
import plotly.io as pio
# 配列の順番を逆にしてとヒートマップの描画の順番と合わせる
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(z)
# [[1, 2], [4, nan, 6], [None, 8, 9]]
# 配列の順番を逆にする
print(z[::-1])
# [[None, 8, 9], [4, nan, 6], [1, 2]]
fig = go.Figure(data=go.Heatmap(z=z[::-1]))
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_array_reversed"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップの軸の順番を逆にして配列と合わせる
一方でデータの順番は変更したくない場合は、縦軸の方向を逆にすることで配列とヒートマップの並びを同じにすることが可能だ。ただし、座標(0, 0)
の位置が左下から左上に移動することに注意。
import plotly.graph_objects as go
import plotly.io as pio
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(z)
# [[1, 2], [4, nan, 6], [None, 8, 9]]
fig = go.Figure(data=go.Heatmap(z=z))
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
# y軸の軸を反転させ左上を(0, 0)にする
fig.update_layout(yaxis=dict(autorange="reversed"))
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_axis_reversed"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
NoneとNaNと空文字はNaNになる
配列の中には数値だけではなくNone
やNaN
といった欠損値が含まれる場合がある。欠損値を含む配列でヒートマップを作成すると何もない状態としてグラフ化される。
None
も空文字の””
もNaN
として扱われ、デフォルトではホバー機能もオフになる。ホバーはgo.Heatmap
の引数hoverongaps=True
にすることで表示することが可能だ。
import plotly.graph_objects as go
import plotly.io as pio
import numpy as np
# NoneとNaNと空文字の入った2次元配列でヒートマップを作成
z = [
[1, 2, ""],
[4, np.nan, 6],
[None, 8, 9]
]
fig = go.Figure(
data=go.Heatmap(
z=z,
hoverongaps=True # TrueにするとNaN部分のホバーを表示
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_none_nan_brank"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
NaNを数値に置き換える
NaN
としてヒートマップに表示されないセルは一目で欠損値としてわかるが、他のセルと同様に値を持たせることも可能。こうすることでヒートマップの見た目を損なうことなく欠損値と正常値を区別できる。
配列をnumpy
の2次元配列に変換後、np.isnan
でNaN
の箇所だけ別の数値に置き換えてヒートマップを作成すればいい。None
などがある場合は先にこれらをNaNに置き換える。
ここでは欠損値を-1
にし濃い青色として表示するようにした。
import plotly.graph_objects as go
import plotly.io as pio
import numpy as np
# NaNを数値に置き換える
# 置き換えるために予めnumpyの2次元配列として定義
z = np.array([
[1, 2, np.nan],
[4, np.nan, 6],
[np.nan, 8, 9]
])
print(z)
# [[ 1. 2. nan]
# [ 4. nan 6.]
# [nan 8. 9.]]
# NaNを-1に置換
z[np.isnan(z)] = -1
print(z)
# [[ 1. 2. -1.]
# [ 4. -1. 6.]
# [-1. 8. 9.]]
fig = go.Figure(data=go.Heatmap(z=z))
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_replace_nan"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップのレイアウトを変更
go.Heatmap
を使ったヒートマップを作成できたので、ここではヒートマップのグラフのレイアウトを変更する方法を紹介。
colorscalesでカラースケールを変更
go.Heatmap
はデフォルトでは青から紫、黄色と変わるグラデーションのカラースケールを採用。しかし時には白黒や上のグラフのようにレインボーにしたい時もあるだろう。
その時はgo.Heatmap
の引数colorscale
でカラースケールを指定すると簡単にヒートマップの色合いを変更できる。ここでは’jet’
を選択し青から赤に変わるカラースケールとした。
import plotly.graph_objects as go
import plotly.io as pio
# カラースケールを変更
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(
data=go.Heatmap(
z=z,
colorscale='jet' # カラースケールをjetに変更
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_colorscale"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
colorbarでカラーバーのレイアウトを変更
go.Heatmap
ではグラフ化した時点でカラーバーは表示されるが、このカラーバーを編集することも可能だ。
上のグラフでは引数colorbar
でカラーバーの長さや枠線の色、カラーバーで表示する最大値・最小値を変更した。
import plotly.graph_objects as go
import plotly.io as pio
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(
data=go.Heatmap(
z=z,
colorbar=dict(
len=0.8, # カラーバーの長さを0.8に(デフォルトは1)
outlinecolor='white', # カラーバーの枠線の色
outlinewidth=2, # カラーバーの枠線の太さ
bordercolor='gray', # カラーバーとラベルを含むカラーバー自体の枠線の色
borderwidth=1, # カラーバーとラベルを含むカラーバー自体の枠線の太さ
title=dict(
text='bar', # カラーバーのタイトル
side='right', # カラーバーのタイトルをつける位置(デフォルトはtop)
),
)
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_colorbar"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
orientationでカラーバーを水平方向に配置
go.Heatmap
のデフォルトではカラーバーは縦向きに配置されるが、水平方向に配置することも可能だ。go.Heatmap
の引数colorbar
の引数orientation=”h”
を指定することでカラーバーを横向きにできる。ただし、初期位置が上になるが、ここでは位置を下に変更した。
カラーバーを横長にすることでヒートマップの微妙な色の違いをより詳細に知ることが可能だ。
import plotly.graph_objects as go
import plotly.io as pio
# カラーバーを水平方向に配置
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(
data=go.Heatmap(
z=z,
#カラーバーを水平にしつつカラーバーの位置を下に変更
colorbar=dict(orientation="h", y=-0, yanchor="top"),
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_orientation_h"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
カラーバーの指数の表示を変更
大きい値を持つ配列をグラフ化すると自動で指数の表示をしてくれるが、引数exponentformat
でカラーバーの指数部分の表示を変更できる。
exponentformat
で指定できる書式は以下の6種類。必要に応じて使い分けてほしい。
none
: 指数表示なしe
: 1e3の形式E
: 1E3の形式power
: 1×10^3の形式(TEX表記)SI
: 1kの形式B
: 1kの形式(デフォルト)
import plotly.graph_objects as go
import plotly.io as pio
# カラーバーの指数表示を変更
z = [
[1e3, 2e3, 3e3],
[4e4, 5e4, 6e4],
[7e5, 8e5, 9e5]
]
print(z)
# [[1000.0, 2000.0, 3000.0], [40000.0, 50000.0, 60000.0], [700000.0, 800000.0, 900000.0]]
# 指数のフォーマット
exponentformats = ("none", "e", "E", "power", "SI", "B")
for exponentformat in exponentformats:
fig = go.Figure(
data=go.Heatmap(
z=z,
colorbar=dict(
exponentformat=exponentformat
)
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
# eとEは同ファイルと認識されることがあるので回避用
if exponentformat == "E":
exponentformat += exponentformat
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_exponentformat_{exponentformat}"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップに凡例を追加
ヒートマップはグラフなので凡例をつけられ、go.Heatmap
の引数showlegend=True
とするだけでデータの凡例を表示できる。
ただし、そのままの状態だと凡例とカラーバーがかぶるので凡例の位置をズラすかカラーバーの長さを短くするなどの工夫が必要になる。
import plotly.graph_objects as go
import plotly.io as pio
# 凡例を追加
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(
data=go.Heatmap(
z=z,
showlegend=True # 凡例を表示
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_showlegend"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップのグリッドの比率を変更
go.Heatmap
ではデフォルトで表示している画面の比率に応じてグラフの幅と高さを自動調節してくれる。ただ、このせいでヒートマップの各セルが長方形になることもしばしば。
レイアウトのyaxis
の引数scaleanchor='x’
でx
と同じスケールになるように設定することで、常にセルを正方形に保つことが可能だ。
ただし、この場合は表示する画面のアスペクト比によっては左右に余白が生じることに注意。
import plotly.graph_objects as go
import plotly.io as pio
# ヒートマップのマス目の比率を変更
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure( data=go.Heatmap(z=z))
# マス目をxと同じスケールにする
fig.update_layout(yaxis=dict(scaleanchor='x'))
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_scaleanchor"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップのx軸とy軸を変更
ここまではヒートマップの横軸と縦軸は座標の役割として数字を使用したが、横軸と縦軸を文字列などに変更することも可能だ。
横軸ラベルと縦軸ラベルを文字列にする
横軸と縦軸の値を指定するにはシンプルにgo.Heatmap
の引数x
とy
にそれぞれ表示したい内容を指定すればいい。
ここではそれぞれ文字列を指定したが、x
, y
で指定する要素の個数とz
の行・列の個数が異なる場合、その行・列は表示されなくなるので注意。
import plotly.graph_objects as go
import plotly.io as pio
# 軸ラベルを文字列にする
fig = go.Figure(
data=go.Heatmap(
z=[[1, None, 30, 50, 1], [20, 1, 60, 80, 30], [30, 60, 1, -10, 20]],
x=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
y=['Morning', 'Afternoon', 'Evening'],
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_label_string"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
横軸をDatetimeにする
横軸を時間軸にすることも可能だ。時間軸にする場合もgo.Heatmap
の引数x
に時間の配列を渡すだけでいい。
import plotly.graph_objects as go
import plotly.io as pio
import numpy as np
# 横軸を時間単位にする
np.random.seed(1)
programmers = ['Alex', 'Nicole', 'Sara', 'Etienne', 'Chelsea', 'Jody', 'Marianne']
base = datetime.datetime.today()
dates = base - np.arange(180) * datetime.timedelta(days=1)
print(dates)
# [datetime.datetime(2023, 4, 22, 18, 44, 21, 391056)
# datetime.datetime(2023, 4, 21, 18, 44, 21, 391056)
# datetime.datetime(2023, 4, 20, 18, 44, 21, 391056)
# ...
# datetime.datetime(2022, 10, 27, 18, 44, 21, 391056)
# datetime.datetime(2022, 10, 26, 18, 44, 21, 391056)
# datetime.datetime(2022, 10, 25, 18, 44, 21, 391056)]
z = np.random.poisson(size=(len(programmers), len(dates)))
print(z)
# [[1 0 0 ... 2 0 0]
# [0 0 1 ... 2 1 1]
# [2 2 1 ... 2 0 1]
# ...
# [2 0 1 ... 0 2 1]
# [1 1 2 ... 2 1 1]
# [1 1 1 ... 0 0 2]]
fig = go.Figure(data=go.Heatmap(z=z, x=dates, y=programmers,))
fig.update_layout(
title='GitHub commits per day', # グラフタイトル
xaxis_nticks=36 # 横軸の目盛数
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_label_datetime"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
ヒートマップ上にテキストを追加
ヒートマップは通常の線のグラフとは異なり面のグラフだ。なので、この面の上にテキストを表示することも多々あるだろう。ここではヒートマップ上にテキストを表示する方法を解説する。
各セル上にテキストを追加
各セル上にテキストを表示するには引数text
とtexttemplate
を使用。texttemplate
を省略すると次に紹介するようにマウスオーバー時のホバー内容にだけテキストが反映されるので注意。
ここでは文字列の配列を指定したが、各数値をそのままテキストにすると直感的に各セルの値がわかるので有効だ。
import plotly.graph_objects as go
import plotly.io as pio
# 各グリッド上にテキストを追加
z = [[1, 20, 30],
[20, 1, 60],
[30, 60, 1]]
text = [['one', 'twenty', 'thirty'],
['twenty', 'one', 'sixty'],
['thirty', 'sixty', 'one']]
fig = go.Figure(
data=go.Heatmap(
z=z,
text=text, # 追加するテキスト
texttemplate="%{text}", # ホバーに追加する文字
textfont={"size": 20}
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_text"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
マウスホバーのテキストだけ追加
texttemplate
を省略しtext
だけ指定することで各セルにマウスオーバーした時のホバー内容にだけテキストを追加することが可能だ。
ホバー内容はデフォルトでx
, y
, z
の値で、これらの下にテキストが追加される。
import plotly.graph_objects as go
import plotly.io as pio
# マウスホバーのテキストだけ変更
z = [[1, 20, 30],
[20, 1, 60],
[30, 60, 1]]
text = [['one', 'twenty', 'thirty'],
['twenty', 'one', 'sixty'],
['thirty', 'sixty', 'one']]
# texttemplateを消せばホバーだけにテキストを追加可能
fig = go.Figure(
data=go.Heatmap(
z=z,
text=text, # 追加するテキスト
textfont={"size": 20}
)
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_add_hover_text"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
各セルのサイズが異なるヒートマップ
ここまでは各セルのサイズが同じヒートマップを作成したが、ここでは各セルのサイズが異なるヒートマップを作成した。
x
, y
の値を基準点として非等間隔で指定することで、セルのサイズが異なるヒートマップができる。
上のグラフでは各基準点x
, y
をgo.Scatterでグラフ化したので参考にしてほしい。go.Scatterは以下の記事で解説している。
-
【Plotlyで散布図】go.Scatterのグラフの描き方まとめ
これからPloltyで動くグラフを作りたい、もっとグラフをキ ...
続きを見る
import plotly.graph_objects as go
import plotly.io as pio
# グリッドのアスペクト比を変える
# グリッドの基準点
x = [0, 0.5, 0.6, 1]
y = [0, 0.1, 0.2, 1]
z = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
fig = go.Figure(
data=[
go.Heatmap(x=x, y=y, z=z,),
# x, yの点をプロット
go.Scatter(
x=x, y=y, mode="markers",
marker=dict(color="white", size=15)
)
]
)
# グラフ全体とホバーのフォントサイズ変更
fig.update_layout(font_size=20, hoverlabel_font_size=20)
fig.show()
# グラフ保存
prefix = 'go-heatmap' # 保存ファイル名の接頭辞
save_name = f"{prefix}_aspect"
pio.orca.config.executable = '/Applications/orca.app/Contents/MacOS/orca'
pio.write_html(fig, f"{save_name}.html")
pio.write_image(fig, f"{save_name}.png")
各セルの値をホバーできるヒートマップ
今回はPlotly
のgo.Heatmap
でヒートマップを作成する方法を紹介した。Plotly
のグラフなので各セルの値をマウスオーバーで確認でき、拡大縮小や位置の移動も自由だ。
データ数が多く細かいセルになりがちなヒートマップをよりわかりやすく自由度高くグラフ化するためにも本記事で紹介したgo.Heatmap
をぜひ使いこなしてほしい。