File size: 2,943 Bytes
b4c5ac0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import json
from pathlib import Path
import numpy as np
import matplotlib.pyplot as plt

# ── Config ─────────────────────────────────────────────
LOG_PATH = "./training_logs/reward_log.json"
OUT_PATH = "./plots/component_breakdown_clean.png"

COMPONENTS = [
    "verdict",
    "mutation_type",
    "mutation_point",
    "provenance",
    "source_reliability",
    "brier_penalty",
]

COLORS = {
    "verdict": "#2196F3",
    "mutation_type": "#FF9800",
    "mutation_point": "#4CAF50",
    "provenance": "#9C27B0",
    "source_reliability": "#00BCD4",
    "brier_penalty": "#F44336",
}

# ── EMA smoothing ──────────────────────────────────────
def ema(data, alpha=0.06):
    ema_vals = []
    s = data[0]
    for x in data:
        s = alpha * x + (1 - alpha) * s
        ema_vals.append(s)
    return np.array(ema_vals)

# ── Main ───────────────────────────────────────────────
def main():
    # Load logs
    with open(LOG_PATH) as f:
        logs = json.load(f)

    steps = np.array([r["step"] for r in logs])

    plt.figure(figsize=(10, 6))

    for comp in COMPONENTS:
        values = np.array([r.get(comp, 0) for r in logs])

        # Smooth only (no raw lines → clean plot)
        smooth = ema(values, alpha=0.06)

        plt.plot(
            steps,
            smooth,
            linewidth=1.8,
            label=comp,
            color=COLORS[comp],
        )

    # ── Phase shading ──────────────────────────────────
    max_step = max(steps)

    p1 = max_step * 0.37
    p2 = max_step * 0.75

    plt.axvspan(0, p1, alpha=0.06, color='blue')
    plt.axvspan(p1, p2, alpha=0.06, color='orange')
    plt.axvspan(p2, max_step, alpha=0.06, color='green')

    # ── Labels & styling ───────────────────────────────
    plt.xlabel("Training Step", fontsize=12)
    plt.ylabel("Component Reward", fontsize=12)
    plt.title("ChronoVeritas — Per-Component Reward Breakdown (EMA Smoothed)", fontsize=14)

    plt.legend(loc="upper left", fontsize=9)
    plt.grid(alpha=0.3)

    # Keep penalty visible
    plt.ylim(-0.08, 0.32)

    # ── Save ───────────────────────────────────────────
    Path("./plots").mkdir(exist_ok=True)
    plt.tight_layout()
    plt.savefig(OUT_PATH, dpi=150)

    print(f"✅ Saved plot to: {OUT_PATH}")

# ── Run ───────────────────────────────────────────────
if __name__ == "__main__":
    main()