From eea9a24d9f7b12606ba0f121c28efe30ce25f818 Mon Sep 17 00:00:00 2001 From: Lars Bogner Date: Wed, 24 Jun 2026 18:18:26 +0200 Subject: [PATCH] Add export script for ETP group-update presentation plots One-off script (like export_validation_plots.py / export_event_observables.py) that writes a 3x3 marginals grid, post_dir/travel_dir norm histograms, and vector-PDF copies of the KL-bars/photon-edep/event-level plots directly into the thesis-presentations repo's images/ folder. Co-Authored-By: Claude Sonnet 4.6 --- analysis/export_presentation_plots.py | 127 ++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 analysis/export_presentation_plots.py diff --git a/analysis/export_presentation_plots.py b/analysis/export_presentation_plots.py new file mode 100644 index 0000000..a8a08dd --- /dev/null +++ b/analysis/export_presentation_plots.py @@ -0,0 +1,127 @@ +"""One-off export of presentation-specific plots for the 2026-06-24 ETP group +update, written directly into the presentation's images/ folder. Not part of +the package; run manually. + +All plots are saved as PDF (vector) except the pairwise scatter plot, which +stays PNG/raster in the .tex (scatter plots with thousands of points blow up +as vector files and gain nothing from being scalable). + +1. Aggregate marginals, split into a 3x3 grid (instead of plot_marginals' + single wide row of 9 columns) for a more manageable slide aspect ratio. +2. post_dir/travel_dir unit-norm histograms only (subset of + plot_constraint_violations). +3. KL bar plot stratified by pdg. +4. Zoomed-in photon edep histogram + CDF. +5. Event-level profiles/histograms/pdg-share plots. +""" + +from pathlib import Path + +import matplotlib.pyplot as plt +import numpy as np + +import giant.analysis as a +from giant.analysis import RAW_TARGET_NAMES, _hist_edges + +FILE = "/home/lars/Programming/giant/pbwo4_10k_9_predicted_local.parquet" +OUT = Path( + "/home/lars/Programming/thesis-presentations/presentations/2026-06-24-group-update/images" +) +PREFIX = "giant-h1024n8d0.1lr3e-4" + + +def savefig(fig, name: str) -> None: + fig.savefig(OUT / f"{PREFIX}-{name}.pdf", bbox_inches="tight") + print("saved", name) + + +print("=== loading sampled SampleCollection ===") +samples = a.load_predicted_local(FILE, sample_frac=0.15) +print("n rows:", len(samples.gen_raw)) + +print("=== marginals, split 3x3 grid ===") +n_rows, n_cols = 3, 3 +fig, axes = plt.subplots(n_rows, n_cols, figsize=(3.6 * n_cols, 2.8 * n_rows)) +for idx, name in enumerate(RAW_TARGET_NAMES): + row, col = divmod(idx, n_cols) + ax = axes[row][col] + real, gen = samples.real_raw[:, idx], samples.gen_raw[:, idx] + edges = _hist_edges(real, gen, bins=50) + ax.hist(real, bins=edges, density=True, histtype="step", label="real") + ax.hist(gen, bins=edges, density=True, histtype="step", label="generated") + ax.set_yscale("log") + ax.set_title(name, fontsize=9) + if idx == 0: + ax.legend(fontsize=7) +fig.tight_layout() +savefig(fig, "marginals-grid") + +print("=== post_dir / travel_dir unit-norm histograms ===") +gen = samples.gen_raw +post_norm = np.linalg.norm(gen[:, 3:6], axis=1) +travel_norm = np.linalg.norm(gen[:, 6:9], axis=1) + +fig, axes = plt.subplots(1, 2, figsize=(8, 3.5)) +for ax, norm, title in [ + (axes[0], post_norm, r"$\|\mathrm{post\_dir}\|$"), + (axes[1], travel_norm, r"$\|\mathrm{travel\_dir}\|$"), +]: + ax.hist(norm, bins=_hist_edges(norm, bins=50), histtype="step") + ax.set_yscale("log") + ax.axvline(1.0, color="k", linestyle="--", linewidth=1) + ax.set_title(title) +fig.tight_layout() +savefig(fig, "direction-norms") + +print("=== KL bars by pdg ===") +fig = a.plot_kl_bars_pl(FILE, group_by="pdg") +savefig(fig, "kl-bars-pdg") + +print("=== photon edep zoom ===") +mask = samples.pdg == 22 +edep_idx = a.RAW_TARGET_NAMES.index("edep") +real = samples.real_raw[mask, edep_idx] +gen = samples.gen_raw[mask, edep_idx] + +fig, axes = plt.subplots(1, 2, figsize=(10, 4)) +bins = np.linspace(0, np.quantile(real, 0.999), 80) +axes[0].hist(real, bins=bins, alpha=0.6, label="real", density=True) +axes[0].hist(gen, bins=bins, alpha=0.6, label="gen", density=True) +axes[0].set_yscale("log") +axes[0].set_xlabel("edep (photons, pdg=22)") +axes[0].legend() +axes[1].hist( + real, bins=bins, alpha=0.6, label="real", density=True, cumulative=True, histtype="step" +) +axes[1].hist( + gen, bins=bins, alpha=0.6, label="gen", density=True, cumulative=True, histtype="step" +) +axes[1].set_xlabel("edep (photons, pdg=22) - CDF") +axes[1].legend() +fig.tight_layout() +savefig(fig, "photon-edep-zoom") + +print("=== event observables ===") +obs = a.compute_event_observables_pl(FILE) + +fig = a.plot_total_energy(obs) +savefig(fig, "event-total-energy") + +fig = a.plot_total_length(obs) +savefig(fig, "event-total-length") + +fig = a.plot_longitudinal_profile(obs) +savefig(fig, "event-longitudinal-profile") + +fig = a.plot_transverse_profile(obs) +savefig(fig, "event-transverse-profile") + +fig = a.plot_shower_max_depth(obs) +savefig(fig, "event-shower-max-depth") + +print("=== pdg length share ===") +pdg_table = a.pdg_contribution_table_pl(FILE) +fig = a.plot_pdg_length_share(pdg_table) +savefig(fig, "pdg-length-share") + +print("DONE")