Maniskill_gen_new / scripts /plot_data_collection_strategies_3d.py
yqi19's picture
Add Maniskill_gen_new data collection codebase with README
7b8502a
Raw
History Blame Contribute Delete
6.66 kB
#!/usr/bin/env python3
"""3D lattice plots (8³ nodes): five standalone PNGs plus one 1×5 row (data_collection_strategies_3d_1x5.png).
Blue = active / sampled, yellow = inactive.
Logical lattice uses origin (0,0,0) for L / Ours joints; points are mapped to plot space with
(x', y', z') = (N-1-ix, N-1-iy, iz)
so the common intersection maps to corner (N-1, N-1, 0). Camera is chosen so that corner reads
as the lower-right of the cube on the page (tune VIEW_ELEV / VIEW_AZIM if needed).
"""
from pathlib import Path
import matplotlib as mpl
import matplotlib.font_manager as fm
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D # noqa: F401 — registers 3d projection
N = 8
# Y arm for "Ours": fewer samples along logical y than full N
OURS_Y_LEN = 5
ACTIVE = "#0072B2"
INACTIVE = "#D4B84A" # slightly deeper yellow/gold (was very pale)
INACTIVE_ALPHA = 0.42
FIG_DIR = Path(__file__).resolve().parents[1] / "figures"
# Camera: tune so the joint corner (plot coords N-1, N-1, 0) projects near the figure's lower-right
VIEW_ELEV = 9
VIEW_AZIM = 22
def _configure_font():
available = {f.name for f in fm.fontManager.ttflist}
mpl.rcParams["font.family"] = "sans-serif"
preferred = ["Helvetica", "Arial", "Liberation Sans", "DejaVu Sans"]
chosen = [n for n in preferred if n in available]
mpl.rcParams["font.sans-serif"] = chosen + ["DejaVu Sans", "sans-serif"]
def lattice_coords():
ix, iy, iz = np.meshgrid(
np.arange(N), np.arange(N), np.arange(N), indexing="ij"
)
return ix.ravel(), iy.ravel(), iz.ravel()
def logical_to_plot(IX, IY, IZ):
"""Map logical indices so joint (0,0,0) → plot (N-1,N-1,0)."""
return (N - 1 - IX, N - 1 - IY, IZ)
def wireframe_cube(ax, m, color="#bfbfbf", lw=0.9):
z0 = [(0, 0, 0), (m, 0, 0), (m, m, 0), (0, m, 0)]
z1 = [(0, 0, m), (m, 0, m), (m, m, m), (0, m, m)]
for i in range(4):
p0, p1 = z0[i], z0[(i + 1) % 4]
ax.plot([p0[0], p1[0]], [p0[1], p1[1]], [p0[2], p1[2]], c=color, lw=lw)
for i in range(4):
p0, p1 = z1[i], z1[(i + 1) % 4]
ax.plot([p0[0], p1[0]], [p0[1], p1[1]], [p0[2], p1[2]], c=color, lw=lw)
for a, b in zip(z0, z1):
ax.plot([a[0], b[0]], [a[1], b[1]], [a[2], b[2]], c=color, lw=lw)
def plot_strategy(
ax,
mask_active: np.ndarray,
title: str,
show_inactive: bool,
*,
compact: bool = False,
):
IX, IY, IZ = lattice_coords()
PX, PY, PZ = logical_to_plot(IX, IY, IZ)
m = N - 1
if compact:
s_in, s_act = 10, 18
title_fs, label_fs = 14, 10
title_pad = -22 # pull subplot titles (Complete, …) down toward the cube
wire_lw = 0.55
lw_scatter = 0.22
labelpad_xy, labelpad_z = -10, -7
else:
s_in, s_act = 24, 42
title_fs, label_fs = 14, 11
title_pad = 2
wire_lw = 0.9
lw_scatter = 0.35
labelpad_xy, labelpad_z = -14, -10
wireframe_cube(ax, m, lw=wire_lw)
if show_inactive:
inactive = ~mask_active
if np.any(inactive):
ax.scatter(
PX[inactive],
PY[inactive],
PZ[inactive],
c=INACTIVE,
s=s_in,
alpha=INACTIVE_ALPHA,
edgecolors="none",
depthshade=True,
)
if np.any(mask_active):
ax.scatter(
PX[mask_active],
PY[mask_active],
PZ[mask_active],
c=ACTIVE,
s=s_act,
alpha=1.0,
edgecolors="black",
linewidths=lw_scatter,
depthshade=True,
)
ax.set_title(title, fontsize=title_fs, fontweight="bold", pad=title_pad)
ticks = np.arange(N)
ax.set_xticks(ticks)
ax.set_yticks(ticks)
ax.set_zticks(ticks)
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.set_zticklabels([])
lim_lo, lim_hi = -0.4, m + 0.4
ax.set_xlim(lim_lo, lim_hi)
ax.set_ylim(lim_lo, lim_hi)
ax.set_zlim(lim_lo, lim_hi)
ax.view_init(elev=VIEW_ELEV, azim=VIEW_AZIM)
ax.set_box_aspect((1, 1, 1))
ax.set_xlabel("Verb", fontsize=label_fs, fontweight="bold", labelpad=labelpad_xy)
ax.set_ylabel("Color", fontsize=label_fs, fontweight="bold", labelpad=labelpad_xy)
ax.set_zlabel("Object", fontsize=label_fs, fontweight="bold", labelpad=labelpad_z)
def build_masks():
IX, IY, IZ = lattice_coords()
complete = np.ones(IX.shape[0], dtype=bool)
rng = np.random.default_rng(0)
n_random = max(1, int(0.09 * N**3))
choice = rng.choice(N**3, size=n_random, replace=False)
random_m = np.zeros(N**3, dtype=bool)
random_m[choice] = True
diagonal = (IX == IY) & (IY == IZ)
L_mask = ((IY == 0) & (IZ == 0)) | ((IX == 0) & (IZ == 0)) | ((IX == 0) & (IY == 0))
x_arm = (IY == 0) & (IZ == 0)
y_arm = (IX == 0) & (IZ == 0) & (IY < OURS_Y_LEN)
diag_arm = (IX == IY) & (IY == IZ)
ours = x_arm | y_arm | diag_arm
return {
"complete": complete,
"random": random_m,
"diagonal": diagonal,
"L": L_mask,
"ours": ours,
}
def main():
FIG_DIR.mkdir(parents=True, exist_ok=True)
_configure_font()
masks = build_masks()
specs = [
("complete", "Complete", False),
("random", "Random", True),
("diagonal", "Diagonal", True),
("L", "L", True),
("ours", "Ours", True),
]
for key, title, show_inactive in specs:
fig = plt.figure(figsize=(7.2, 6.4))
ax = fig.add_subplot(111, projection="3d")
plot_strategy(ax, masks[key], title, show_inactive=show_inactive)
out = FIG_DIR / f"data_collection_strategies_3d_{key}.png"
fig.savefig(
out, dpi=200, bbox_inches="tight", pad_inches=0.03, facecolor="white"
)
plt.close(fig)
print(f"Saved {out}")
# Single row of five 3D panels (same layout idea as data_collection_strategies_1x5.png)
fig_row = plt.figure(figsize=(19.0, 3.95))
for i, (key, title, show_inactive) in enumerate(specs):
ax = fig_row.add_subplot(1, 5, i + 1, projection="3d")
plot_strategy(
ax, masks[key], title, show_inactive=show_inactive, compact=True
)
fig_row.subplots_adjust(left=0.02, right=0.98, top=0.88, bottom=0.06, wspace=-0.18)
out_row = FIG_DIR / "data_collection_strategies_3d_1x5.png"
fig_row.savefig(
out_row, dpi=200, bbox_inches="tight", pad_inches=0.06, facecolor="white"
)
plt.close(fig_row)
print(f"Saved {out_row}")
if __name__ == "__main__":
main()