Synthetic LiDAR point cloud
Remote Sensing — building + ground + trees
Example from the compendium of canonical charts
Python Code
"""Remote Sensing — Synthetic LiDAR point cloud (building + ground + trees)."""
import numpy as np
import plotly.graph_objects as go
def generate():
RNG = np.random.default_rng(7)
pts_x, pts_y, pts_z, pts_cls = [], [], [], []
# ── Ground plane (class 2) ────────────────────────────────────────────────────
n_ground = 5000
gx = RNG.uniform(0, 100, n_ground)
gy = RNG.uniform(0, 100, n_ground)
gz = RNG.normal(0, 0.05, n_ground)
pts_x.append(gx); pts_y.append(gy); pts_z.append(gz)
pts_cls.append(np.full(n_ground, 2))
# ── Building (class 6) — rectangular prism 40×40×15 centered at (50,50) ──────
# Walls
n_wall = 1500
for x0, x1, y0, y1 in [(30, 70, 30, 30), (30, 70, 70, 70),
(30, 30, 30, 70), (70, 70, 30, 70)]:
n = n_wall // 4
wx = RNG.uniform(x0, x1, n) if x0 != x1 else np.full(n, x0)
wy = RNG.uniform(y0, y1, n) if y0 != y1 else np.full(n, y0)
wz = RNG.uniform(0, 15, n)
pts_x.append(wx); pts_y.append(wy); pts_z.append(wz)
pts_cls.append(np.full(n, 6))
# Roof
n_roof = 800
rx = RNG.uniform(30, 70, n_roof)
ry = RNG.uniform(30, 70, n_roof)
rz = np.full(n_roof, 15.0) + RNG.normal(0, 0.05, n_roof)
pts_x.append(rx); pts_y.append(ry); pts_z.append(rz)
pts_cls.append(np.full(n_roof, 6))
# ── Trees (class 5) — cones at random positions outside building ──────────────
tree_positions = [(15, 15), (85, 20), (10, 80), (80, 75), (20, 55)]
for tx, ty in tree_positions:
n_tree = 300
h_max = RNG.uniform(6, 12)
tz = RNG.uniform(0, h_max, n_tree)
radius = (h_max - tz) / h_max * 3.0 + RNG.normal(0, 0.2, n_tree)
theta = RNG.uniform(0, 2 * np.pi, n_tree)
tree_x = tx + radius * np.cos(theta)
tree_y = ty + radius * np.sin(theta)
pts_x.append(tree_x); pts_y.append(tree_y); pts_z.append(tz)
pts_cls.append(np.full(n_tree, 5))
X = np.concatenate(pts_x)
Y = np.concatenate(pts_y)
Z = np.concatenate(pts_z)
print(f"Total points: {len(X)}")
fig = go.Figure(go.Scatter3d(
x=X,
y=Y,
z=Z,
mode="markers",
marker=dict(
size=2,
color=Z,
colorscale="earth",
colorbar=dict(title="Elevation (m)", thickness=12),
opacity=0.8,
),
hovertemplate="X: %{x:.1f}m<br>Y: %{y:.1f}m<br>Z: %{z:.1f}m<extra></extra>",
))
fig.update_layout(
scene=dict(
xaxis_title="Easting (m)",
yaxis_title="Northing (m)",
zaxis_title="Elevation (m)",
aspectmode="manual",
aspectratio=dict(x=1.5, y=1.5, z=0.3),
camera=dict(eye=dict(x=1.5, y=-1.8, z=1.2)),
),
)
return fig
if __name__ == "__main__":
generate()
Made with Plotly