""" 读 evaluate_masks.py 产出的 CSV, 画箱线图. 每个 sample 一个分数 -> 3 个 metric 各画一个箱体, 合并展示. 另外可选: 同时画 3 张独立子图(--mode separate). 用法: python plot_boxplot.py --csv mask_scores.csv --out_dir plots python plot_boxplot.py --csv mask_scores.csv --out_dir plots --mode separate """ import argparse import os import matplotlib.pyplot as plt import pandas as pd METRICS = ["dice", "iou", "ms_ssim"] COLORS = ["#4C72B0", "#55A868", "#C44E52"] def plot_combined(df, out_dir): os.makedirs(out_dir, exist_ok=True) data = [df[m].dropna().values for m in METRICS] fig, ax = plt.subplots(figsize=(7, 6)) bp = ax.boxplot( data, labels=[m.upper() for m in METRICS], patch_artist=True, showmeans=True, meanprops=dict(marker="D", markerfacecolor="white", markeredgecolor="black", markersize=6), ) for patch, c in zip(bp["boxes"], COLORS): patch.set_facecolor(c) patch.set_alpha(0.6) ax.set_ylabel("score") ax.set_title(f"Per-sample metric distribution (n={len(df)})") ax.grid(axis="y", alpha=0.3) plt.tight_layout() out_path = os.path.join(out_dir, "boxplot_combined.png") plt.savefig(out_path, dpi=150) plt.close() print(f"[saved] {out_path}") def plot_separate(df, out_dir): os.makedirs(out_dir, exist_ok=True) fig, axes = plt.subplots(1, 3, figsize=(15, 5)) for ax, m, c in zip(axes, METRICS, COLORS): vals = df[m].dropna().values bp = ax.boxplot( [vals], labels=[m.upper()], patch_artist=True, showmeans=True, meanprops=dict(marker="D", markerfacecolor="white", markeredgecolor="black", markersize=6), ) bp["boxes"][0].set_facecolor(c) bp["boxes"][0].set_alpha(0.6) ax.set_title(f"{m.upper()} (n={len(vals)})\nmean={vals.mean():.3f} median={pd.Series(vals).median():.3f}") ax.grid(axis="y", alpha=0.3) plt.tight_layout() out_path = os.path.join(out_dir, "boxplot_separate.png") plt.savefig(out_path, dpi=150) plt.close() print(f"[saved] {out_path}") def main(): p = argparse.ArgumentParser() p.add_argument("--csv", required=True) p.add_argument("--out_dir", default="plots") p.add_argument("--mode", choices=["combined", "separate", "both"], default="both") args = p.parse_args() df = pd.read_csv(args.csv) df = df[df["status"] == "ok"].copy() print(f"[info] {len(df)} ok samples") if args.mode in ("combined", "both"): plot_combined(df, args.out_dir) if args.mode in ("separate", "both"): plot_separate(df, args.out_dir) if "dataset_fid" in df.columns: fid = df["dataset_fid"].dropna().unique() if len(fid): print(f"[info] dataset FID = {fid[0]}") if __name__ == "__main__": main() """ python plot_box.py --csv mask_scores.csv --out_dir figs """