| |
| """ |
| ICLR-style colored bar charts (clean, English-only): |
| - Colorblind-friendly palette (blue/orange) |
| - No footers/ornaments, minimal grid |
| - Single-column per-dataset figures + two-column triple panel |
| - Values are fractions [0,1]; labels show 2 decimals |
| """ |
|
|
| from pathlib import Path |
| import argparse |
| import matplotlib |
| matplotlib.use("Agg") |
| import matplotlib.pyplot as plt |
| import numpy as np |
|
|
| |
| METRICS = { |
| "s3dis": { |
| "name": "S3DIS", |
| "fp32": {"miou": 0.2052, "macc": 0.2438, "oa": 0.7519}, |
| "quant": {"miou": 0.2420, "macc": 0.3510, "oa": 0.8120}, |
| }, |
| "nuscenes": { |
| "name": "nuScenes", |
| "fp32": {"miou": 0.2598, "macc": 0.3181, "oa": 0.8096}, |
| "quant": {"miou": 0.6264, "macc": 0.7519, "oa": 0.9284}, |
| }, |
| "scannet": { |
| "name": "ScanNet", |
| "fp32": {"miou": 0.1836, "macc": 0.2325, "oa": 0.7150}, |
| "quant": {"miou": 0.1746, "macc": 0.2325, "oa": 0.7150}, |
| }, |
| } |
|
|
| |
| plt.rcParams.update({ |
| "font.family": "serif", |
| "font.serif": ["Times New Roman", "Times", "DejaVu Serif", "STIXGeneral"], |
| "font.size": 9, |
| "axes.labelsize": 9, |
| "xtick.labelsize": 8, |
| "ytick.labelsize": 8, |
| "legend.fontsize": 8, |
| "axes.spines.right": False, |
| "axes.spines.top": False, |
| "axes.linewidth": 0.9, |
| "xtick.direction": "in", |
| "ytick.direction": "in", |
| "grid.color": "#D9D9D9", |
| "grid.linestyle": "--", |
| "grid.linewidth": 0.6, |
| }) |
|
|
| |
| COL_FP32 = "#4C78A8" |
| COL_QUANT = "#F58518" |
| EDGE = "#2E2E2E" |
|
|
| ORDER = [("miou", "mIoU"), ("macc", "mAcc"), ("oa", "Overall Acc")] |
|
|
| def _vals(info): |
| fp32 = info["fp32"]; quant = info["quant"] |
| xs, v1, v2 = [], [], [] |
| for k, lab in ORDER: |
| if (k in fp32) or (k in quant): |
| xs.append(lab) |
| v1.append(fp32.get(k, 0.0)) |
| v2.append(quant.get(k, 0.0)) |
| return xs, np.array(v1, float), np.array(v2, float) |
|
|
| def _annotate(ax, bars, fmt="%.2f", dy=0.012): |
| for r in bars: |
| h = r.get_height() |
| ax.text(r.get_x() + r.get_width()/2, h + dy, fmt % h, |
| ha="center", va="bottom", fontsize=8, color="#1A1A1A") |
|
|
| def draw_single(name, info, out_dir: Path): |
| labels, v_fp32, v_quant = _vals(info) |
| n = len(labels) |
| x = np.arange(n) |
| w = 0.36 |
|
|
| fig = plt.figure(figsize=(3.25, 2.2)) |
| ax = fig.add_subplot(111) |
|
|
| ax.grid(axis="y", zorder=0) |
|
|
| b1 = ax.bar(x - w/2, v_fp32, width=w, color=COL_FP32, edgecolor=EDGE, alpha=0.95, |
| label="FP32 (Baseline)", zorder=2) |
| b2 = ax.bar(x + w/2, v_quant, width=w, color=COL_QUANT, edgecolor=EDGE, alpha=0.95, |
| label="Bi-PTV3 (Ours)", zorder=2) |
|
|
| ax.set_ylabel("Score") |
| ax.set_xticks(x, labels) |
| ax.set_ylim(0.0, 1.0) |
| ax.legend(loc="upper left", frameon=False) |
|
|
| _annotate(ax, b1, fmt="%.2f") |
| _annotate(ax, b2, fmt="%.2f") |
|
|
| out_dir.mkdir(parents=True, exist_ok=True) |
| png = out_dir / f"{name.lower()}_performance_color_0920.png" |
| pdf = out_dir / f"{name.lower()}_performance_color_0920.pdf" |
| plt.tight_layout() |
| plt.savefig(png, dpi=300, bbox_inches="tight") |
| plt.savefig(pdf, dpi=300, bbox_inches="tight") |
| plt.close() |
| print(f"[plot] {png}\n[plot] {pdf}") |
|
|
| def draw_triple_panel(selected_keys, out_path: Path): |
| fig, axes = plt.subplots(1, len(selected_keys), figsize=(6.75, 2.2), sharey=True) |
| for ax, key in zip(axes, selected_keys): |
| info = METRICS[key] |
| labels, v_fp32, v_quant = _vals(info) |
| x = np.arange(len(labels)); w = 0.34 |
|
|
| ax.grid(axis="y", zorder=0) |
| ax.bar(x - w/2, v_fp32, w, color=COL_FP32, edgecolor=EDGE, alpha=0.95, |
| label="FP32 (Baseline)", zorder=2) |
| ax.bar(x + w/2, v_quant, w, color=COL_QUANT, edgecolor=EDGE, alpha=0.95, |
| label="Bi-PTV3 (Ours)", zorder=2) |
|
|
| ax.set_title(info["name"], pad=2, fontsize=9) |
| ax.set_xticks(x, labels) |
| ax.set_ylim(0.0, 1.0) |
| if ax is axes[0]: |
| ax.set_ylabel("Score") |
| |
| for rects in ax.containers: |
| for r in rects: |
| h = r.get_height() |
| ax.text(r.get_x() + r.get_width()/2, h + 0.010, f"{h:.2f}", |
| ha="center", va="bottom", fontsize=7, color="#1A1A1A") |
|
|
| handles, labels = axes[0].get_legend_handles_labels() |
| fig.legend(handles, labels, loc="upper center", ncol=2, frameon=False, bbox_to_anchor=(0.5, 1.08)) |
| plt.tight_layout() |
| out_path.parent.mkdir(parents=True, exist_ok=True) |
| plt.savefig(out_path.with_suffix(".png"), dpi=300, bbox_inches="tight") |
| plt.savefig(out_path.with_suffix(".pdf"), dpi=300, bbox_inches="tight") |
| plt.close() |
| print(f"[plot] {out_path.with_suffix('.png')}\n[plot] {out_path.with_suffix('.pdf')}") |
|
|
| def main(): |
| ap = argparse.ArgumentParser() |
| ap.add_argument("--out-dir", default="exp/summary_0920/plots_0920_pretty") |
| ap.add_argument("--datasets", nargs="*", default=list(METRICS.keys())) |
| args = ap.parse_args() |
|
|
| out_dir = Path(args.out_dir) |
|
|
| |
| for k in args.datasets: |
| if k not in METRICS: |
| print(f"[skip] {k} not found in METRICS") |
| continue |
| draw_single(METRICS[k]["name"], METRICS[k], out_dir) |
|
|
| |
| keys = [k for k in ["s3dis", "nuscenes", "scannet"] if k in args.datasets] |
| if len(keys) >= 2: |
| draw_triple_panel(keys, out_dir / "all_datasets_performance_color_0920") |
|
|
| if __name__ == "__main__": |
| main() |
|
|