Plot win counts stratified by category (game or model).
(
data_by_category: dict[str, list[int]], output_path: Path, *, title: str, by_model: bool = False
)
| 80 | |
| 81 | |
| 82 | def plot_stratified( |
| 83 | data_by_category: dict[str, list[int]], output_path: Path, *, title: str, by_model: bool = False |
| 84 | ) -> None: |
| 85 | """Plot win counts stratified by category (game or model).""" |
| 86 | # Determine category order |
| 87 | if by_model: |
| 88 | # Sort by full model name (including prefix), then strip prefix for display |
| 89 | category_names = sorted(data_by_category.keys()) |
| 90 | else: |
| 91 | category_names = sorted(data_by_category.keys()) |
| 92 | |
| 93 | # Create subplots: 3 columns, no "All" plot |
| 94 | n_plots = len(category_names) |
| 95 | n_cols = 3 |
| 96 | n_rows = (n_plots + n_cols - 1) // n_cols |
| 97 | |
| 98 | # Use 4x4 for all plots |
| 99 | fig, axes = plt.subplots(n_rows, n_cols, figsize=(4 * n_cols, 4 * n_rows)) |
| 100 | axes = axes.flatten() if n_plots > 1 else [axes] |
| 101 | |
| 102 | bins = np.arange(-0.5, 16.5, 1) |
| 103 | |
| 104 | # Plot per category |
| 105 | for idx, category_name in enumerate(category_names): |
| 106 | ax = axes[idx] |
| 107 | counts = data_by_category[category_name] |
| 108 | |
| 109 | ax.hist(counts, bins=bins, edgecolor="black", alpha=0.7, density=True) |
| 110 | ax.set_xlabel("Total number of rounds won (out of 15)", fontproperties=FONT_BOLD, fontsize=12) |
| 111 | ax.set_ylabel("Density", fontproperties=FONT_BOLD, fontsize=12) |
| 112 | |
| 113 | # Set tick labels to also use bold font |
| 114 | for label in ax.get_xticklabels() + ax.get_yticklabels(): |
| 115 | label.set_fontproperties(FONT_BOLD) |
| 116 | |
| 117 | if by_model: |
| 118 | display_name = MODEL_TO_DISPLAY_NAME.get(category_name, category_name) |
| 119 | else: |
| 120 | display_name = category_name.replace("Halite", "Poker") |
| 121 | ax.set_title(display_name, fontproperties=FONT_BOLD, fontsize=14) |
| 122 | ax.set_xticks(range(0, 16)) |
| 123 | |
| 124 | # Add minor ticks on y-axis |
| 125 | ax.yaxis.set_minor_locator(AutoMinorLocator()) |
| 126 | |
| 127 | # Show ticks on all sides, pointing inward |
| 128 | ax.tick_params(top=True, right=True, which="both", direction="in") |
| 129 | |
| 130 | ax.grid(True, alpha=0.3, axis="y") |
| 131 | |
| 132 | # Add stats text only for by_model plots |
| 133 | if by_model: |
| 134 | mean_wc = np.mean(counts) |
| 135 | median_wc = np.median(counts) |
| 136 | stats_text = f"Mean: {mean_wc:.2f}\nMedian: {median_wc:.1f}\nN: {len(counts)}" |
| 137 | ax.text( |
| 138 | 0.5, |
| 139 | 0.93, |