summaryrefslogtreecommitdiff
path: root/viz/gen_fig3.py
diff options
context:
space:
mode:
Diffstat (limited to 'viz/gen_fig3.py')
-rw-r--r--viz/gen_fig3.py37
1 files changed, 37 insertions, 0 deletions
diff --git a/viz/gen_fig3.py b/viz/gen_fig3.py
new file mode 100644
index 0000000..6cdbbbb
--- /dev/null
+++ b/viz/gen_fig3.py
@@ -0,0 +1,37 @@
+import matplotlib.pyplot as plt
+import numpy as np
+
+fig, ax = plt.subplots(figsize=(8, 5), dpi=300)
+
+categories = ['Random Slicing\n(58% sliced words)', 'Clean Boundaries\n(0% sliced words)']
+ratios = [1.471, 1.311]
+ci_lower = [1.368, 1.258]
+ci_upper = [1.529, 1.402]
+
+errors = [
+ [ratios[0] - ci_lower[0], ratios[1] - ci_lower[1]],
+ [ci_upper[0] - ratios[0], ci_upper[1] - ratios[1]]
+]
+
+x = np.arange(len(categories))
+bars = ax.bar(x, ratios, yerr=errors, capsize=8, color=['#f59e0b', '#10b981'], width=0.45, alpha=0.9, ecolor='#1e293b')
+
+ax.axhline(1.0, color='#ef4444', linestyle='--', linewidth=1.5, label='Baseline (Ratio = 1.0, No Signal)')
+ax.set_ylabel('Middle-Layer Norm Ratio (@ / #)', fontsize=12, fontweight='bold')
+ax.set_title('Synthetic Frequency-Matched Pair Control (@ vs # at 0.1% Freq)', fontsize=13, fontweight='bold', pad=15)
+ax.set_xticks(x)
+ax.set_xticklabels(categories, fontsize=11, fontweight='bold')
+ax.set_ylim(0.8, 1.7)
+ax.grid(True, linestyle=':', alpha=0.6)
+ax.legend(loc='upper right', frameon=True)
+
+for bar, r, l, u in zip(bars, ratios, ci_lower, ci_upper):
+ ax.annotate(f'Ratio: {r:.2f}x\n95% CI: [{l:.2f}, {u:.2f}]',
+ xy=(bar.get_x() + bar.get_width() / 2, u),
+ xytext=(0, 8), textcoords="offset points",
+ ha='center', va='bottom', fontsize=10, fontweight='bold',
+ bbox=dict(boxstyle='round,pad=0.3', facecolor='white', alpha=0.8, edgecolor='none'))
+
+plt.tight_layout()
+plt.savefig('docs/assets/fig3_synthetic_pair.png', dpi=300)
+print("Saved Fig 3")