techno_memo

個人用の技術メモ。python・ROS・AI系のソフトウェア・ツールなどの情報を記載

plotlyによる3Dグラフ描画

概要

 pythonのライブラリ plotlyを用いて3Dグラフおよびアニメーションの表示をする方法について記述する

3Dグラフの表示

plotly で3次元の散布図を描画する例を下記に示す。scatter_3dを呼び出し3dxyzの座標を与えればグラフを描画できる。

import plotly.graph_objects as go
import plotly.express as px
import numpy as np
import pandas as pd

x = np.arange(20)
y = np.random.rand(20) *20
z = np.random.rand(20) *5

# plotly expresを使う場合
# df = pd.DataFrame({ 'x_data' : x,
#                     'y_data' : y,
#                     'z_data' : z})
#
#
# fig = px.scatter_3d(df, x='x_data', y='y_data', z='z_data')
# fig.show()

# graph objectを使う場合
fig = go.Figure(data=[go.Scatter3d(x=x,y=y,z=z,mode='markers')])
fig.show()

f:id:sd08419ttic:20211031161028p:plain

散布図ではなく平面図として描画したい場合には、Surfaceを用いる。 Surfaceではxyzの各辺の成分を代入して3D平面をプロットすることができる。

# -*- coding: utf-8 -*-
import plotly
import plotly.graph_objects as go
z=[
    [0.0,0.0,0.0,0.0,0.0]
    ,[0.0,1.0,2.0,3.0,0.0]
    ,[0.0,2.0,10.0,6.0,0.0]
    ,[0.0,1.0,2.0,3.0,0.0]
    ,[0.0,0.0,0.0,0.0,0.0]
]
fig = go.Figure(data=[go.Surface(z=z,x=[-5.0,-2.5,0.0,2.5,5.0],y=[-20,-10.0,0.0,10.0,20.0])])
fig.update_layout(
    title='Surface'
    ,scene=dict(
        xaxis=dict(title='x')
        ,yaxis=dict(title='y')
        ,zaxis=dict(title='z')
    )
)
fig.show()

f:id:sd08419ttic:20211205172442p:plain

複数グラフの描画(画像上に散布図を表示)

上記を組み合わせて複数のグラフを同時に描画することができる。 ここで、3DSurfaceのcolormapとして画像データを出力するようにすると、3D空間に平面として画像を表示しその上にデータをプロットすることができる。

# -*- coding: utf-8 -*-
import plotly
import plotly.graph_objects as go
from PIL import Image
import numpy as np

from PIL import Image
img_as_8bit = lambda x: np.array(Image.fromarray(x).convert('P', palette='WEB', dither=None))
dum_img = Image.fromarray(np.ones((3,3,3), dtype='uint8')).convert('P', palette='WEB')
idx_to_color = np.array(dum_img.getpalette()).reshape((-1, 3))
colorscale=[[i/255.0, "rgb({}, {}, {})".format(*rgb)] for i, rgb in enumerate(idx_to_color)]

im = np.array(Image.open('D:/VS_WS/pytest/image/Mandrill.bmp'))

trace=go.Surface(
        z=np.zeros([256,256])-50,
        surfacecolor=img_as_8bit(im),
        cmin=0, 
        cmax=255,
        hoverinfo= 'none',  #画像の各画素にホバーしたときの説明を非表示にする
        colorscale=colorscale,  
        showscale=False #右のカラーバーを非表示にする
          )
trace2=go.Scatter3d(x=[0, 10, 50, 100, 200],
                   y=[0, 30, 70, 150, 200],
                   z=[0,-10, 30, -20, 10],
                   mode='markers',
                   marker_color='rgba(0, 255, 0, .8)',
                   )

fig = go.Figure(
    data=[trace,trace2],
    layout_title_text="3D Face Mesh",
)

fig.show()
fig.write_html("3Dtry.html")

f:id:sd08419ttic:20211205172807p:plain

参考記事

plotly.com

www.dmysd.net