はじめに
3D散布図やライン・Surfaceを描くとき、「このデータはどの範囲に分布しているのか?」を理解しづらいことがあります。
そこで Bounding Box(境界立方体) を描くと、全体のスケール・外れ値・広がりが一瞬でつかめます。
Plotly では Scatter3d の"線モード"を使うことで、軽量で美しい立方体ガイドが作れます。
この記事でできること
- 3D空間に「立方体ガイド(Bounding Box)」を追加
- 点群やラインの分布範囲を立体的に把握
- 外れ値検知・可視化の文脈で活用
- Colabですぐ動くコードつき
① データ例:3D点群を準備
import plotly.graph_objects as go
import numpy as np
np.random.seed(0)
x, y, z = np.random.randn(3, 300)
この点群を包む「立方体ガイド」を描いていきます。
② Bounding Box を描くための"8頂点"を作成
x, y, z の 最小値/最大値 を使って立方体を定義します。
xmin, xmax = x.min(), x.max()
ymin, ymax = y.min(), y.max()
zmin, zmax = z.min(), z.max()
# 8つの頂点
corners = np.array([
[xmin, ymin, zmin],
[xmin, ymin, zmax],
[xmin, ymax, zmin],
[xmin, ymax, zmax],
[xmax, ymin, zmin],
[xmax, ymin, zmax],
[xmax, ymax, zmin],
[xmax, ymax, zmax],
])
③ Bounding Box の"12本の辺"を結ぶ
立方体には 12 本のエッジ があります。頂点番号を組み合わせて線を引きます。
edges = [
(0,1), (0,2), (0,4),
(3,1), (3,2), (3,7),
(5,1), (5,4), (5,7),
(6,2), (6,4), (6,7)
]
④ Plotly の Scatter3d(mode="lines") で立方体を描画
fig = go.Figure()
# 点群
fig.add_trace(go.Scatter3d(
x=x, y=y, z=z,
mode='markers',
marker=dict(size=3, color=z, colorscale='Viridis', opacity=0.7),
name='Points'
))
# Bounding Box
for e in edges:
xs = [corners[e[0], 0], corners[e[1], 0]]
ys = [corners[e[0], 1], corners[e[1], 1]]
zs = [corners[e[0], 2], corners[e[1], 2]]
fig.add_trace(go.Scatter3d(
x=xs, y=ys, z=zs,
mode='lines',
line=dict(color='black', width=4),
showlegend=False
))
fig.update_layout(
title="3D Scatter with Bounding Box",
scene=dict(aspectmode='data')
)
fig.show()
黒い線で囲まれた立方体が表示され、データの空間的な広がりが直感的に理解できます。
⑤ 軽量な"ワイヤーボックス"にする
見やすさ&軽量化のため、細いグレー線に変更する例:
line_style = dict(color='gray', width=2)
for e in edges:
fig.add_trace(go.Scatter3d(
x=[corners[e[0],0], corners[e[1],0]],
y=[corners[e[0],1], corners[e[1],1]],
z=[corners[e[0],2], corners[e[1],2]],
mode='lines',
line=line_style,
showlegend=False
))
データ可視化時の"補助ガイド"として最適です。
⑥ Bounding Box を"正方立方体"にする(統一スケール)
比率を揃えて 見た目の歪みを防ぐ 方法です。
min〜max を 同じ長さ に揃えます。
min_val = min(xmin, ymin, zmin)
max_val = max(xmax, ymax, zmax)
# Bounding Box の corners も立方体に再計算
corners = np.array([
[min_val, min_val, min_val],
[min_val, min_val, max_val],
[min_val, max_val, min_val],
[min_val, max_val, max_val],
[max_val, min_val, min_val],
[max_val, min_val, max_val],
[max_val, max_val, min_val],
[max_val, max_val, max_val],
])
# 全軸を同じ範囲に揃える(視覚的に正方立方体)
fig.update_layout(
scene=dict(
xaxis=dict(range=[min_val, max_val]),
yaxis=dict(range=[min_val, max_val]),
zaxis=dict(range=[min_val, max_val]),
aspectmode='cube'
)
)
- Bounding Box 自体が「立方体」になる
- 空間が「立方体」に統一されるため違和感がなくなる
- 3D分布比較に便利
⑦ Mesh3d で"透明な立方体Surface"を追加する
Bounding Box を 面付きの透明立方体 にする表現です。
go.Mesh3d を使って立方体の6面(12三角形)を定義します。
# 立方体の6面を12個の三角形で定義
# 各面(下面・上面・前面・後面・左面・右面)を2つの三角形で構成
i = [0, 2, 1, 3, 0, 1, 2, 3, 0, 1, 4, 5]
j = [2, 4, 3, 5, 1, 4, 3, 6, 1, 2, 5, 6]
k = [4, 6, 5, 7, 4, 5, 6, 7, 2, 3, 6, 7]
fig.add_trace(go.Mesh3d(
x=corners[:, 0],
y=corners[:, 1],
z=corners[:, 2],
i=i, j=j, k=k,
opacity=0.1,
color='lightblue',
flatshading=True,
showscale=False
))
特徴:
- 立体感UP
- 視認性アップ
- Surface や点群との相性がよい
- 軽量で確実に立方体が描画される
⑧ 背景・軸を整えて視認性を高める
fig.update_layout(
scene=dict(
xaxis=dict(backgroundcolor='rgb(245,245,245)'),
yaxis=dict(backgroundcolor='rgb(245,245,245)'),
zaxis=dict(backgroundcolor='rgb(250,250,250)'),
aspectmode='data'
)
)
特に線ガイドは背景が明るい方が見やすくなります。
トラブルシュート
| 問題 | 解決方法 |
|---|---|
| Box が歪む |
aspectmode='cube' を使う |
| Box の線が太すぎ |
width を 1〜3 に調整 |
| 点群と色がかぶる |
line.color を gray に |
| スケールが見づらい | 軸範囲を [min_val,max_val] で揃える |
まとめ
Bounding Box を追加すると、3Dデータの分布範囲が直感的に把握できるようになります。
基本は Scatter3d(mode="lines") で12本の線を描くだけで、必要に応じて透明な立方体(Mesh3d)も作成できます。
aspectmode="cube" にすれば歪みのない立方体表示になり、外れ値検知やスケール比較、シミュレーション可視化にも役立ちます。3D空間に“枠”を入れるだけで、データの理解が一段と進みます。





