"""Generate the five new revision figures from data/*.json into ../Relevance_TWCOM_R2/fig/. Uniform geometry: 8:6 axes box, shared rcParams, no tight bounding box. """ import json from pathlib import Path import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt import numpy as np HERE = Path(__file__).resolve().parent DATA = HERE / "data" FIG = HERE.parent / "Relevance_TWCOM_R2" / "fig" FIG.mkdir(exist_ok=True) plt.rcParams.update({ "font.size": 9, "axes.labelsize": 10, "axes.titlesize": 10, "legend.fontsize": 7.5, "xtick.labelsize": 8.5, "ytick.labelsize": 8.5, "lines.linewidth": 1.4, "lines.markersize": 4.5, "figure.dpi": 200, "savefig.dpi": 300, "grid.alpha": 0.35, "axes.grid": True, }) AXRECT = [0.17, 0.165, 0.79, 0.80] # single panel 8:6-ish FSIZE = (3.5, 2.75) def newfig(): f = plt.figure(figsize=FSIZE) ax = f.add_axes(AXRECT) return f, ax def save(f, name, axes=None): f.canvas.draw() if axes: for ax in axes: for lbl in [ax.xaxis.label, ax.yaxis.label]: bb = lbl.get_window_extent() fw, fh = f.canvas.get_width_height() assert bb.x0 >= -1 and bb.y0 >= -1 and bb.x1 <= fw + 1 \ and bb.y1 <= fh + 1, f"label clipped in {name}" f.savefig(FIG / name) plt.close(f) print("saved", FIG / name) C = {"ofdma": "#546E7A", "blind": "#8D6E63", "noma": "#E65100", "uwca": "#1565C0", "genie": "#2E7D32", "extra": "#C62828", "aux": "#6A1B9A"} # ---------------------------------------------------------------- fig_fair -- # axes box kept at 2.59 x 2.12 in; panel tags "(a)"/"(b)" BELOW the panels d = json.load(open(DATA / "e1_fair_baselines.json")) snr = d["snr"] FH = 3.10 # taller canvas for below-axis tags AXH = 2.12 / FH AXB = 0.86 / FH f = plt.figure(figsize=(7.1, FH)) axs = [f.add_axes([0.115, AXB, 0.365, AXH]), f.add_axes([0.615, AXB, 0.365, AXH])] for ax, sc, ttl in zip(axs, ["HIGH", "MIX"], ["(a) HIGH", "(b) MIX"]): v = d["scenarios"][sc] ax.semilogy(snr, v["ofdma"]["ser"], "s--", color=C["ofdma"], label="OFDMA") ax.semilogy(snr, v["lmmse_blind"]["ser"], "v-", color=C["blind"], markevery=(1, 2), label="LMMSE-blind") ax.semilogy(snr, v["noma"]["ser"], "^-.", color=C["noma"], label="NOMA-SIC") ax.semilogy(snr, v["uwca"]["ser"], "o-", color=C["uwca"], label="UWCA (prop.)") ax.semilogy(snr, v["lmmse_genie"]["ser"], "d:", color=C["genie"], label="LMMSE-genie") ax.set_xlabel("SNR (dB)") ax.set_ylabel("SER") ax.set_xlim(0, 20) ax.text(0.5, -0.31, ttl, transform=ax.transAxes, ha="center", va="top", fontsize=10) axs[1].legend(loc="lower left", framealpha=0.9, fontsize=7) save(f, "fig_fair.pdf", axs) # -------------------------------------------------------------- fig_resorth -- d = json.load(open(DATA / "e6_residual_orth.json")) snr = d["snr"] f, ax = newfig() ax.plot(snr, d["uwca"]["rho_input"], "k--", label=r"input $\rho(\mathbf{e}_u,\mathbf{e}_v)$") ax.plot(snr, d["uwca"]["rho_decoded"], "o-", color=C["uwca"], label=r"UWCA decoded $\rho(\hat{\mathbf{e}}_u,\hat{\mathbf{e}}_v)$") ax.plot(snr, d["uwca"]["rho_residual"], "s-", color=C["extra"], label=r"UWCA residual $\rho(\mathbf{r}_u,\mathbf{r}_v)$") ax.plot(snr, d["ofdma"]["rho_decoded"], "^:", color=C["ofdma"], label=r"OFDMA decoded") ax.set_xlabel("SNR (dB)") ax.set_ylabel("Pearson correlation") ax.set_xlim(0, 20) ax.set_ylim(-0.05, 0.62) ax.legend(loc="upper right", framealpha=0.9, fontsize=6.8) save(f, "fig_resorth.pdf", [ax]) # --------------------------------------------------------------- fig_phase2 -- d = json.load(open(DATA / "e2_phase_iui.json")) sg = d["sigma_phi_deg"] f, ax = newfig() sty = {"complexI_zerotrain": ("o-", C["uwca"], "mismatch-trained"), "complexI_augtrain": ("s--", C["genie"], "phase-augmented"), "complexIQ_iqtrain": ("^:", C["extra"], "two-rail (I/Q)")} for key, (mk, col, lab) in sty.items(): ax.plot(sg, d["curves"][key]["10.0"]["ser"], mk, color=col, label=lab) for key, (mk, col, lab) in sty.items(): ax.plot(sg, d["curves"][key]["20.0"]["ser"], mk, color=col, alpha=0.45, label="_nolegend_") ax.annotate("10 dB", xy=(1.5, 0.29), fontsize=8) ax.annotate("20 dB", xy=(1.5, 0.135), fontsize=8) ax.set_xlabel(r"phase residual $\sigma_\varphi$ (deg)") ax.set_ylabel("SER") ax.set_ylim(0.0, 0.45) ax.legend(loc="upper left", framealpha=0.9, fontsize=7) save(f, "fig_phase2.pdf", [ax]) # ---------------------------------------------------------------- fig_async -- d = json.load(open(DATA / "e4_v3_async.json")) dm = d["dmax"] f, ax = newfig() cur = d["curves"] ax.plot(dm, [a[0] for a in cur["uwca_uncorrected"]["10.0"]], "o--", color=C["uwca"], alpha=0.5, label="UWCA, uncorrected") ax.plot(dm, [a[0] for a in cur["ofdma_uncorrected"]["10.0"]], "s--", color=C["ofdma"], alpha=0.5, label="OFDMA, uncorrected") ax.plot(dm, [a[0] for a in cur["uwca_corrected"]["10.0"]], "o-", color=C["uwca"], label="UWCA, realigned") ax.plot(dm, [a[0] for a in cur["ofdma_corrected"]["10.0"]], "s-", color=C["ofdma"], label="OFDMA, realigned") ax.plot(dm, [a[0] for a in cur["uwca_corrected_err20"]["10.0"]], "^-.", color=C["extra"], label="UWCA, realigned (20% est. err.)") ax.set_xlabel(r"maximum timing offset $\Delta$ (symbols)") ax.set_ylabel("SER") ax.set_ylim(0, 1.05) ax.legend(loc="lower right", ncol=2, framealpha=0.9, fontsize=6.0) save(f, "fig_async.pdf", [ax]) # ------------------------------------------------------------- fig_dynusers -- d = json.load(open(DATA / "e3_dynamic_users.json")) ks = d["k"] f = plt.figure(figsize=FSIZE) ax = f.add_axes([0.20, 0.165, 0.76, 0.80]) ax.plot(ks, [a[1] for a in d["fixed8"]["10.0"]], "o-", color=C["uwca"], label="single model, 10 dB") ax.plot(ks, [a[1] for a in d["fixed8"]["20.0"]], "o--", color=C["uwca"], alpha=0.5, label="single model, 20 dB") ok = sorted(int(k) for k in d["oracle"]) ax.plot(ok, [d["oracle"][str(k)]["10.0"][1] for k in ok], "s", ls="none", color=C["extra"], label="per-count retrained, 10 dB") ax.plot(ok, [d["oracle"][str(k)]["20.0"][1] for k in ok], "s", ls="none", mfc="none", color=C["extra"], label="per-count retrained, 20 dB") ax.set_xlabel(r"number of active users $|\mathcal{A}|$") ax.set_ylabel(r"mean cosine $\bar{c}$") ax.set_ylim(0.28, 0.47) ax.legend(loc="upper left", framealpha=0.9, fontsize=6.8) save(f, "fig_dynusers.pdf", [ax]) print("ALL FIGURES DONE")