Figure font scale and legend placement fix from the writing audit
Declared point sizes are now pre-divided by the 0.70 include scale so the printed sizes are the intended ones, and place_legend scores the same layout save() enforces.
This commit is contained in:
+20
-4
@@ -36,8 +36,19 @@ def f3(x: str) -> str:
|
|||||||
return "--" if math.isnan(v) else f"{v:.3f}"
|
return "--" if math.isnan(v) else f"{v:.3f}"
|
||||||
|
|
||||||
|
|
||||||
def cell(x: str, bold: bool) -> str:
|
def f4(x: str) -> str:
|
||||||
s = f3(x)
|
"""Four decimals, for a column whose values sit against the
|
||||||
|
random-guess level and would otherwise all print as 1.000 while the
|
||||||
|
body quotes their distance from it in units of 1e-4."""
|
||||||
|
try:
|
||||||
|
v = float(x)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return "--"
|
||||||
|
return "--" if math.isnan(v) else f"{v:.4f}"
|
||||||
|
|
||||||
|
|
||||||
|
def cell(x: str, bold: bool, wide: bool = False) -> str:
|
||||||
|
s = f4(x) if wide else f3(x)
|
||||||
if s == "--":
|
if s == "--":
|
||||||
return "--"
|
return "--"
|
||||||
return rf"$\mathbf{{{s}}}$" if bold else f"${s}$"
|
return rf"$\mathbf{{{s}}}$" if bold else f"${s}$"
|
||||||
@@ -59,6 +70,8 @@ def compare_table():
|
|||||||
b = r["scheme"] == "proposed"
|
b = r["scheme"] == "proposed"
|
||||||
if r["scheme"] == "oma_plain" and f3(r["jam0_ser"]) == "--":
|
if r["scheme"] == "oma_plain" and f3(r["jam0_ser"]) == "--":
|
||||||
r["jam0_ser"] = oma_jam
|
r["jam0_ser"] = oma_jam
|
||||||
|
# four decimals would still print 1.0000 here, so the column
|
||||||
|
# stays at three and the caption names the chance level
|
||||||
cells = [cell(r[k], b) for k in
|
cells = [cell(r[k], b) for k in
|
||||||
("legit_ser", "eve_out", "eve_in", "jam0_ser")]
|
("legit_ser", "eve_out", "eve_in", "jam0_ser")]
|
||||||
print(f"{NAME[r['scheme']]} & " + " & ".join(cells) + r" \\")
|
print(f"{NAME[r['scheme']]} & " + " & ".join(cells) + r" \\")
|
||||||
@@ -96,7 +109,8 @@ def refresh_tables():
|
|||||||
f = (lambda t: r"\mathbf{" + t + "}") if b else (lambda t: t)
|
f = (lambda t: r"\mathbf{" + t + "}") if b else (lambda t: t)
|
||||||
print(f"{name} & ${f(format(float(r['legit']), '.3f'))}$ & "
|
print(f"{name} & ${f(format(float(r['legit']), '.3f'))}$ & "
|
||||||
f"${f(format(float(r['eve']), '.4f'))}$ & "
|
f"${f(format(float(r['eve']), '.4f'))}$ & "
|
||||||
f"${f(format(float(r['entropy_bits']), '.1f'))}$~bits" + r" \\")
|
# the unit lives in the header, not in every cell
|
||||||
|
f"${f(format(float(r['entropy_bits']), '.1f'))}$" + r" \\")
|
||||||
print()
|
print()
|
||||||
print("% Table: known plaintext across a refresh (from refresh_kpa.csv)")
|
print("% Table: known plaintext across a refresh (from refresh_kpa.csv)")
|
||||||
rows = {r["n_frames"]: r for r in csv.DictReader(open(DATA / "refresh_kpa.csv"))}
|
rows = {r["n_frames"]: r for r in csv.DictReader(open(DATA / "refresh_kpa.csv"))}
|
||||||
@@ -105,8 +119,10 @@ def refresh_tables():
|
|||||||
+ " & ".join(f"${k}$" for k in keep) + r" \\")
|
+ " & ".join(f"${k}$" for k in keep) + r" \\")
|
||||||
for lbl, key in (("Same block", "ser_same_block"),
|
for lbl, key in (("Same block", "ser_same_block"),
|
||||||
("Next block", "ser_next_block")):
|
("Next block", "ser_next_block")):
|
||||||
|
w = ".4f" if key == "ser_next_block" else ".3f"
|
||||||
print(f"{lbl} & "
|
print(f"{lbl} & "
|
||||||
+ " & ".join(f"${float(rows[k][key]):.3f}$" for k in keep)
|
+ " & ".join("$" + format(float(rows[k][key]), w) + "$"
|
||||||
|
for k in keep)
|
||||||
+ r" \\")
|
+ r" \\")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+27
-14
@@ -34,21 +34,26 @@ FIG.mkdir(exist_ok=True)
|
|||||||
plt.rcParams.update({
|
plt.rcParams.update({
|
||||||
"font.family": "serif",
|
"font.family": "serif",
|
||||||
"font.serif": ["DejaVu Serif", "Times New Roman"],
|
"font.serif": ["DejaVu Serif", "Times New Roman"],
|
||||||
"font.size": 9,
|
# The manuscript includes each result figure at 0.70 of a 3.455 in
|
||||||
"axes.labelsize": 9,
|
# column while the canvas is 3.15 in, a printed scale of 0.768. Every
|
||||||
"legend.fontsize": 6.6,
|
# size below is therefore pre-divided by that scale so the PRINTED
|
||||||
"xtick.labelsize": 8,
|
# sizes are 9 pt labels, 8 pt ticks and a 6.6 pt legend. Change the
|
||||||
"ytick.labelsize": 8,
|
# include width and these must change with it.
|
||||||
|
"font.size": 10.4,
|
||||||
|
"axes.labelsize": 10.4,
|
||||||
|
"legend.fontsize": 7.6,
|
||||||
|
"xtick.labelsize": 9.2,
|
||||||
|
"ytick.labelsize": 9.2,
|
||||||
"axes.grid": True,
|
"axes.grid": True,
|
||||||
"grid.linestyle": "--",
|
"grid.linestyle": "--",
|
||||||
"grid.linewidth": 0.4,
|
"grid.linewidth": 0.4,
|
||||||
"grid.alpha": 0.6,
|
"grid.alpha": 0.6,
|
||||||
"lines.linewidth": 1.3,
|
"lines.linewidth": 1.5,
|
||||||
"lines.markersize": 4.5,
|
"lines.markersize": 5.2,
|
||||||
"figure.figsize": (3.15, 2.36),
|
"figure.figsize": (3.15, 2.36),
|
||||||
"pdf.fonttype": 42,
|
"pdf.fonttype": 42,
|
||||||
})
|
})
|
||||||
AXES_RECT = dict(left=0.185, right=0.965, top=0.955, bottom=0.195)
|
AXES_RECT = dict(left=0.205, right=0.970, top=0.955, bottom=0.215)
|
||||||
|
|
||||||
C_LEGIT = "#c0392b"
|
C_LEGIT = "#c0392b"
|
||||||
C_EVE = "#2c5fa8"
|
C_EVE = "#2c5fa8"
|
||||||
@@ -178,12 +183,18 @@ def main_legit(snr_db="10"):
|
|||||||
def place_legend(ax, cands=("lower left", "center left", "center right",
|
def place_legend(ax, cands=("lower left", "center left", "center right",
|
||||||
"lower center", "upper right", "upper center",
|
"lower center", "upper right", "upper center",
|
||||||
"center", "lower right"),
|
"center", "lower right"),
|
||||||
sizes=(6.6, 6.2, 5.8, 5.4, 5.0)):
|
sizes=(7.6, 7.2, 6.8, 6.4, 6.0)):
|
||||||
"""Choose the location and font size whose box the fewest curve points
|
"""Choose the location and font size whose box the fewest curve points
|
||||||
fall inside, scored on rendered geometry rather than guessed from the
|
fall inside, scored on rendered geometry rather than guessed from the
|
||||||
data. The size sweep is what makes a long label set placeable: a
|
data. The size sweep is what makes a long label set placeable: a
|
||||||
five-entry legend of full scheme names has no clear corner at the
|
five-entry legend of full scheme names has no clear corner at the
|
||||||
default size on every figure."""
|
default size on every figure.
|
||||||
|
|
||||||
|
The axes rectangle is applied first, because save() enforces the same
|
||||||
|
test after applying it. Scoring the default layout and then checking
|
||||||
|
a different one is how a placement that looked clear here failed
|
||||||
|
there."""
|
||||||
|
ax.figure.subplots_adjust(**AXES_RECT)
|
||||||
best = None
|
best = None
|
||||||
for size in sizes:
|
for size in sizes:
|
||||||
for loc in cands:
|
for loc in cands:
|
||||||
@@ -227,8 +238,10 @@ def fig_snr():
|
|||||||
label=LBL["eve_pub"])
|
label=LBL["eve_pub"])
|
||||||
ax.semilogy(x, col(r, "eve_wrong"), color=C_EVE, marker="s", ls="--",
|
ax.semilogy(x, col(r, "eve_wrong"), color=C_EVE, marker="s", ls="--",
|
||||||
label=LBL["eve_key"])
|
label=LBL["eve_key"])
|
||||||
ax.plot(x, col(r, "chance"), color=C_CH, ls="-.", lw=0.9,
|
# the chance level lies within 3.5e-4 of the wrong-key curve, so it is
|
||||||
label=LBL["chance"])
|
# drawn for reference but left out of the legend, which the caption
|
||||||
|
# names instead; five long entries leave this figure no clear corner
|
||||||
|
ax.plot(x, col(r, "chance"), color=C_CH, ls="-.", lw=0.9)
|
||||||
ax.set_xlabel("SNR (dB)")
|
ax.set_xlabel("SNR (dB)")
|
||||||
ax.set_ylabel("SER")
|
ax.set_ylabel("SER")
|
||||||
ax.set_xlim(min(x), max(x))
|
ax.set_xlim(min(x), max(x))
|
||||||
@@ -284,7 +297,7 @@ def fig_jam():
|
|||||||
ax.set_xlabel("JSR (dB)")
|
ax.set_xlabel("JSR (dB)")
|
||||||
ax.set_ylabel("SER")
|
ax.set_ylabel("SER")
|
||||||
ax.set_xlim(min(x), max(x))
|
ax.set_xlim(min(x), max(x))
|
||||||
ax.set_ylim(0.8 * nojam, 1.02)
|
ax.set_ylim(0.0, 1.02) # keep the reference line off the spine
|
||||||
place_legend(ax)
|
place_legend(ax)
|
||||||
save(fig, "fig_sec_jam")
|
save(fig, "fig_sec_jam")
|
||||||
|
|
||||||
@@ -327,7 +340,7 @@ def fig_brute():
|
|||||||
ax.axhline(legit, color=C_OMA, ls=":", lw=0.9, label=LBL["legit"])
|
ax.axhline(legit, color=C_OMA, ls=":", lw=0.9, label=LBL["legit"])
|
||||||
ax.set_xlabel("Number of key guesses $K$")
|
ax.set_xlabel("Number of key guesses $K$")
|
||||||
ax.set_ylabel("Eavesdropper SER")
|
ax.set_ylabel("Eavesdropper SER")
|
||||||
ax.set_ylim(0.8 * legit, 1.05)
|
ax.set_ylim(0.0, 1.05) # keep the reference line off the spine
|
||||||
place_legend(ax)
|
place_legend(ax)
|
||||||
save(fig, "fig_sec_brute")
|
save(fig, "fig_sec_brute")
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user