3次元で可視化したい

    構造解析モデルをはじめ、複雑なデータは、分析するために3次元での可視化を行いたい場合があります。そこで今回は、以前ご紹介したPlotlyを用いた3次元描画をしてみたいと思います。なお、今回はJavaScriptではなく、PythonからPlotlyを利用してみます。 Plotlyに関する前回記事はこちら

環境構築

以下のコマンドによりインストールするだけです。
pip install plotly

簡単なサンプル

モデルデータ

簡単な解析モデルデータを描画してみます。今回用意したデータはjson形式であり、節点情報(節点名と座標)および部材情報(部材名と両端節点名)のみが定義されているものとします。
{
    "Node": [
        {
            "Name": "NODE1",
            "X": "0.0",
            "Y": "0.0",
            "Z": "0.0"
        },
        {
            "Name": "NODE2",
            "X": "6.0",
            "Y": "0.0",
            "Z": "0.0"
        },
        {
            "Name": "NODE3",
            "X": "0.0",
            "Y": "6.0",
            "Z": "0.0"
        },
        {
            "Name": "NODE4",
            "X": "6.0",
            "Y": "6.0",
            "Z": "0.0"
        },
        {
            "Name": "NODE5",
            "X": "0.0",
            "Y": "0.0",
            "Z": "6.0"
        },
        {
            "Name": "NODE6",
            "X": "6.0",
            "Y": "0.0",
            "Z": "6.0"
        },
        {
            "Name": "NODE7",
            "X": "0.0",
            "Y": "6.0",
            "Z": "6.0"
        },
        {
            "Name": "NODE8",
            "X": "6.0",
            "Y": "6.0",
            "Z": "6.0"
        }
    ],
    "Beam": [
        {
            "Name": "BEAM1",
            "INode": "NODE1",
            "JNode": "NODE5"
        },
        {
            "Name": "BEAM2",
            "INode": "NODE2",
            "JNode": "NODE6"
        },
        {
            "Name": "BEAM3",
            "INode": "NODE3",
            "JNode": "NODE7"
        },
        {
            "Name": "BEAM4",
            "INode": "NODE4",
            "JNode": "NODE8"
        },
        {
            "Name": "BEAM5",
            "INode": "NODE5",
            "JNode": "NODE6"
        },
        {
            "Name": "BEAM6",
            "INode": "NODE5",
            "JNode": "NODE7"
        },
        {
            "Name": "BEAM7",
            "INode": "NODE7",
            "JNode": "NODE8"
        },
        {
            "Name": "BEAM8",
            "INode": "NODE6",
            "JNode": "NODE8"
        },
        {
            "Name": "BEAM9",
            "INode": "NODE1",
            "JNode": "NODE8"
        }
    ]
}

描画結果

※マウスで視点を操作できます。

サンプルコード

上記のサンプルコードを以下に示します。今回のサンプルデータで3D描画するだけであればもっと簡易に記述することは可能ですが、拡張性や保守性をふまえて、クラス利用や関数の細分化をして記述しています。
import plotly.offline as po
import plotly.graph_objs as go
import sys, os, json
from docopt import docopt

# モデルクラス
class Model:
    def __init__(self, nodes, beams):
        self.Nodes = nodes
        self.Beams = beams

# 節点クラス
class Node:
    def __init__(self, name, x, y, z):
        self.Name = name
        self.X = float(x)
        self.Y = float(y)
        self.Z = float(z)

# 部材クラス
class Beam:
    def __init__(self, name, node_i, node_j):
        self.Name = name
        self.INode = node_i
        self.JNode = node_j

# モデルを生成する
def create_model(path):
    nodes = []
    beams = []
    dic_nodes= {}
    with open(path) as f:
        df = json.load(f)
    # 節点
    for item in df['Node']:
        node = Node(item['Name'], item['X'], item['Y'], item['Z'])
        nodes.append(node)
        dic_nodes[node.Name] = node
    # 部材
    for item in df['Beam']:
        name = item['Name']
        node_i = dic_nodes[item['INode']]
        node_j = dic_nodes[item['JNode']]
        beam = Beam(item['Name'], node_i, node_j)
        beams.append(beam)
    return Model(nodes, beams)

# 部材の描画用オブジェクトを取得する
def get_trace_beam(beam):
    pair_x = [beam.INode.X, beam.JNode.X]
    pair_y = [beam.INode.Y, beam.JNode.Y]
    pair_z = [beam.INode.Z, beam.JNode.Z]
    return go.Scatter3d(x=pair_x, y=pair_y, z=pair_z, name=beam.Name, mode='lines', line_color='blue', showlegend=True)

# 節点の描画用オブジェクトを取得する
def get_trace_node(node):
    x = node.X
    y = node.Y
    z = node.Z
    return go.Scatter3d(x=[x], y=[y], z=[z], mode='markers', marker_color='blue', marker_size=2, name=node.Name, showlegend=True)

# 描画用オブジェクトを取得する
def get_traces(model):
    traces = []
    # Beam
    for beam in model.Beams:
        traces.append(get_trace_beam(beam))
    # Node
    for node in model.Nodes:
        traces.append(get_trace_node(node))
    return traces

# モデルを描画する
def view_model(model, out_file_name):
    traces = get_traces(model)
    fig = go.Figure(data=traces)
    fig['layout']['scene'].update(go.layout.Scene(aspectmode='data'))
    po.plot(fig, filename=out_file_name, auto_open=True)

# メイン
def main(path, out_file_name):
    model = create_model(path)
    view_model(model, out_file_name)

if __name__ == "__main__":
    __doc__ = """
    Usage:
        model_viewer.py 
        model_viewer.py -h | --help
    Options:
        -h --help  show this help message and exit
    """
    args = docopt(__doc__)
    model_data_file_path = args['']
    out_file_name = os.path.splitext(os.path.basename(model_data_file_path))[0]
    main(model_data_file_path, out_file_name)
 

おまけ

以下の記事でご紹介している複雑なモデルを描画してみました。
Pythonのテンプレートエンジンを使って簡単に解析用テキストファイルを作成する

 

まとめ

今回はPythonからPlotlyを活用した3次元描画のご紹介でした。

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です