| 161 | |
| 162 | |
| 163 | def plot_histograms(per_parser_times: Dict[str, np.ndarray], viz_dir: Path) -> None: |
| 164 | # Individual histograms in log-log scale |
| 165 | for parser, times in per_parser_times.items(): |
| 166 | if times.size == 0: |
| 167 | continue |
| 168 | # Keep only strictly positive times for log scale |
| 169 | tpos = times[times > 0] |
| 170 | if tpos.size == 0: |
| 171 | continue |
| 172 | tmin, tmax = float(np.min(tpos)), float(np.max(tpos)) |
| 173 | if tmin <= 0 or not np.isfinite(tmin) or not np.isfinite(tmax) or tmin == tmax: |
| 174 | # Fallback to skip degenerate |
| 175 | continue |
| 176 | bins = np.logspace(np.log10(tmin), np.log10(tmax), 50) |
| 177 | |
| 178 | plt.figure(figsize=(8, 5)) |
| 179 | plt.hist(tpos, bins=bins, color="#1f77b4", alpha=0.8, log=True) |
| 180 | plt.xscale("log") |
| 181 | plt.title(f"Page time histogram (log-log) — {parser} (n={tpos.size})") |
| 182 | plt.xlabel("Seconds per page (log)") |
| 183 | plt.ylabel("Count (log)") |
| 184 | plt.grid(True, alpha=0.3, which="both") |
| 185 | out = viz_dir / f"hist_{safe_name(parser)}.png" |
| 186 | plt.tight_layout() |
| 187 | plt.savefig(out, dpi=150) |
| 188 | plt.close() |
| 189 | |
| 190 | # Superposed histogram across parsers in log-log scale |
| 191 | if len(per_parser_times) >= 2: |
| 192 | all_times = np.concatenate([t[t > 0] for t in per_parser_times.values() if t.size > 0]) |
| 193 | if all_times.size: |
| 194 | tmin, tmax = float(np.min(all_times)), float(np.max(all_times)) |
| 195 | if tmin > 0 and np.isfinite(tmin) and np.isfinite(tmax) and tmin < tmax: |
| 196 | bins = np.logspace(np.log10(tmin), np.log10(tmax), 60) |
| 197 | plt.figure(figsize=(9, 5)) |
| 198 | for parser, times in per_parser_times.items(): |
| 199 | tpos = times[times > 0] |
| 200 | if tpos.size == 0: |
| 201 | continue |
| 202 | plt.hist( |
| 203 | tpos, |
| 204 | bins=bins, |
| 205 | density=True, |
| 206 | alpha=0.45, |
| 207 | label=f"{parser} (n={tpos.size})", |
| 208 | log=True, |
| 209 | ) |
| 210 | plt.xscale("log") |
| 211 | plt.title("Page time histograms (log-log) — overlay") |
| 212 | plt.xlabel("Seconds per page (log)") |
| 213 | plt.ylabel("Density (log)") |
| 214 | plt.legend() |
| 215 | plt.grid(True, alpha=0.3, which="both") |
| 216 | out = viz_dir / "hist_superposed.png" |
| 217 | plt.tight_layout() |
| 218 | plt.savefig(out, dpi=150) |
| 219 | plt.close() |
| 220 | |