この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
データアナリティクス事業本部の鈴木です。
今回は、PlotlyのPython用ライブラリを使って3次元表面を描画する方法をまとめてみました。
Plotlyの公式ドキュメントで3Dプロットを紹介している、『3D Surface Plots』を参考にしています。
ドキュメントでは描画の設定の記載もありますが、この記事ではどのようなインプットをすると3Dプロットができるのかというところを中心にご紹介します。
また、ドキュメントに載っていない関数も描いてみようと思い、1例だけですが別の関数も描いてみました。
検証環境
Jupyter Docker Stacksのdatascience-notebookイメージにPlotlyをインストールして検証しました。バージョンなどは以下になります。
- イメージ:jupyter/datascience-notebook
- Plotly 5.6.0
使い方を確認してみる
ドキュメントに紹介されている2つの例を試してみました。
どちらもplotly.graph_objects.Surfaceを作成し、plotly.graph_objects.Figureに渡して表示する流れになります。
まず、Surface
を配列から作成して、どのようにインスタンスを作るか確認します。
以下のコードを作成し、実行することで、どのような3Dプロットができるか確認します。
# https://plotly.com/python/3d-surface-plots/
# を2022/02/15に改変しました。
import plotly.graph_objects as go
sur = go.Surface(
contours = {
"x": {"show": True, "start": 1.5, "end": 2, "size": 0.04, "color":"white"},
"z": {"show": True, "start": 0.5, "end": 0.8, "size": 0.05}
},
x = [1,2,3,4,5],
y = [1,2,3,4,5],
z = [
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 1],
[0, 1, 0, 1, 0]
])
fig = go.Figure(sur)
fig.update_layout(
scene = {
"xaxis": {"nticks": 20},
"zaxis": {"nticks": 4},
'camera_eye': {"x": 0, "y": -1, "z": 0.5},
"aspectratio": {"x": 1, "y": 1, "z": 0.2}
})
fig.show()
実行すると以下のような3Dプロットが描画されます。3次元でぐるぐる回転させることが可能です。
Surface
のx
とy
に渡した配列と、z
に渡した2次元配列の対応する値が3Dプロットの座標に各々対応しています。
次にpandasのDataFrameから作成する場合も確認しておきます。この場合は、values
で2次元配列にしてから、先ほどと同じようにSurface
に渡す形になります。
# https://plotly.com/python/3d-surface-plots/
# を2022/02/15に改変しました。
import plotly.graph_objects as go
import pandas as pd
# Read data from a csv
z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv', index_col=0)
fig = go.Figure(data=[go.Surface(z=z_data.values)])
fig.update_layout(title='Mt Bruno Elevation', autosize=False,
width=500, height=500,
margin=dict(l=65, r=50, b=65, t=90))
fig.show()
実行すると以下のような3Dプロットが描画されます。
x
およびy
を指定しない場合は、x軸とy軸が0からになります。
オリジナルの例を試してみる
使い方が分かったので、自分でも例を作ってみました。
今回は鞍点がある関数を表示してみました。
以下のように、描画したい関数f
を定義し、適当なx
とy
の範囲でz
の値を計算してSurface
に渡します。
# 表示したい関数
def f(x, y):
return x*x - y*y
# 表示するデータの作成
xs = [x for x in range(-10, 10)]
ys = [y for y in range(-10, 10)]
zs = [[f(x, y) for x in xs] for y in ys]
# 表示
sur = go.Surface(
contours = {
"x": {"show": True, "start": 1.5, "end": 2, "size": 0.04, "color":"white"},
"z": {"show": True, "start": 0.5, "end": 0.8, "size": 0.05}
},
x = xs,
y = ys,
z = zs
)
fig = go.Figure(sur)
fig.update_layout(
scene = {
"xaxis": {"nticks": 20},
"zaxis": {"nticks": 4},
'camera_eye': {"x": 1, "y": -1.5, "z": 1},
"aspectratio": {"x": 1, "y": 1, "z": 1}
},
width=800,
height=800)
fig.show()
実行してみます。
意図した通りに描画することができました。
意図している関数を描く場合は、x
とy
に値を渡し、z
と対応がついている状態になっているか注意が必要です。また、update_layout
でaspectratio
が設定されている場合には、直感と違う形で描写される可能性があるので、1:1:1
にしておくのが無難そうです。
おわりに
今回はPlotlyの公式ドキュメントのうち3Dプロットを紹介している、3D Surface Plotsに記載の例と、それを元に自分で別の例を描画してみました。
Plotlyの3Dプロットを使うと、とても簡単にインタラクティブな3次元表面が描けるので、この関数どんな表面になってるんだっけ?というときにもPythonで気軽に確認できて良いですね。