| import matplotlib.pyplot as plt | |
| from typing import Dict, List, Tuple | |
| def plot_telemetry( | |
| metrics_log: Dict[str, List[float]], | |
| k_floor: float = 0.5, | |
| c_floor: float = 0.3, | |
| s_floor: float = 0.5, | |
| ) -> Tuple[plt.Figure, List[plt.Axes]]: | |
| """Plot K, C, S metrics over time with cluster transitions. | |
| Args: | |
| metrics_log: Dictionary with keys ``negentropy``, ``lz_complexity``, | |
| ``symbiosis_score`` and optional ``clusters`` listing cluster | |
| assignments per step. | |
| k_floor: Threshold for negentropy (K). | |
| c_floor: Threshold for LZ complexity (C). | |
| s_floor: Threshold for symbiosis score (S). | |
| Returns: | |
| (figure, axes) tuple for further customization or saving. | |
| """ | |
| steps = list(range(len(metrics_log.get("negentropy", [])))) | |
| fig, axes = plt.subplots(3, 1, sharex=True, figsize=(10, 6)) | |
| metrics = [ | |
| ("negentropy", k_floor, "K"), | |
| ("lz_complexity", c_floor, "C"), | |
| ("symbiosis_score", s_floor, "S"), | |
| ] | |
| for ax, (key, floor, label) in zip(axes, metrics): | |
| values = metrics_log.get(key, []) | |
| ax.plot(steps, values, label=label) | |
| ax.axhline(floor, color="r", linestyle="--", linewidth=1) | |
| violations = [i for i, v in enumerate(values) if v < floor] | |
| if violations: | |
| ax.scatter( | |
| [steps[i] for i in violations], | |
| [values[i] for i in violations], | |
| color="r", | |
| zorder=5, | |
| label="violation", | |
| ) | |
| ax.set_ylabel(label) | |
| ax.legend(loc="upper right") | |
| clusters = metrics_log.get("clusters") | |
| if clusters is not None: | |
| prev = clusters[0] | |
| for t, c in enumerate(clusters): | |
| if t > 0 and c != prev: | |
| for ax in axes: | |
| ax.axvline(t, color="gray", linestyle=":", alpha=0.5) | |
| prev = c | |
| axes[-1].set_xlabel("step") | |
| plt.tight_layout() | |
| return fig, axes | |