roverdevkit / scripts /make_architecture_obstacle_crossover_figure.py
jjreif's picture
Deploy roverdevkit @ 2676a67
b3d14e3
Raw
History Blame Contribute Delete
2.13 kB
"""Render architecture obstacle crossover summary figure for the paper."""
from __future__ import annotations
import argparse
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
def _parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser(description=__doc__)
p.add_argument(
"--summary-csv",
type=Path,
default=Path("reports") / "architecture_obstacle_crossover" / "crossover_summary.csv",
)
p.add_argument(
"--out-path",
type=Path,
default=Path("paper") / "figures" / "fig_architecture_obstacle_crossover.png",
)
return p.parse_args()
def main() -> int:
args = _parse_args()
df = pd.read_csv(args.summary_csv)
if df.empty:
raise SystemExit(f"no rows in {args.summary_csv}")
if "front_empty" not in df.columns:
df["front_empty"] = df["n_points"].eq(0)
fig, ax = plt.subplots(figsize=(7.0, 4.0))
for scenario_name, group in df.groupby("scenario_name"):
group = group.sort_values("required_obstacle_height_m")
x_cm = group["required_obstacle_height_m"] * 100.0
y_pct = group["frac_rocker_bogie"] * 100.0
label = scenario_name.replace("_", " ")
ax.plot(x_cm, y_pct, marker="o", label=label)
empty = group[group["front_empty"].fillna(group["n_points"].eq(0))]
if not empty.empty:
ax.plot(
empty["required_obstacle_height_m"] * 100.0,
[0.0] * len(empty),
linestyle="none",
marker="x",
color=ax.lines[-1].get_color(),
markersize=7,
markeredgewidth=1.5,
)
ax.set_xlabel("Required obstacle height (cm)")
ax.set_ylabel("Rocker-bogie share of Pareto set (%)")
ax.set_ylim(-2, 102)
ax.grid(True, alpha=0.3)
ax.legend(fontsize=8, loc="best")
fig.tight_layout()
args.out_path.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(args.out_path, dpi=200)
print(f"wrote {args.out_path}")
return 0
if __name__ == "__main__":
raise SystemExit(main())