THE KEY EMERGES key_renderer.py
Main renderer engine.
Consumes RendererSnapshot objects. Produces visual frames.
One snapshot -> one render update. No more. No less.
GOVERNING CONSTRAINT:
The renderer must reveal the computation, not replace it with a story.
WHAT THIS FILE DOES:
- Builds and maintains a fixed panel layout
- Dispatches each snapshot to the correct stage renderer
- Updates the evidence panel from accumulated history
- Requests text from key_stage_text_runtime (never writes its own)
- Redraws exactly once per snapshot
WHAT THIS FILE NEVER DOES:
- Infer missing state
- Smooth transitions between snapshots
- Add synthetic frames
- Predict future stages
- Bias attention toward success
- Pre-signal failure
- Show the world before WORLD_EVALUATION
- Render the accidental candidate differently from GIE candidate
- Write any text string directly
CHANGES FROM v1 (six warranted revisions):
Change 1 Hard-veto visibility:
Veto count annotation retained for now with explicit comment flagging
the architectural gap. Per-generation veto geometry is not yet in
RendererSnapshot. Long-term fix documented in _render_main_search_distribution.
Change 2 Promotion renders one structure at a time:
Comparison card removed. Promotion is a stage event, not a summary.
Only the most recently promoted structure is shown.
Change 3 World geometry not reconstructed from defaults:
If world_view lacks geometry, renderer logs and renders nothing extra.
No implicit inference. Applies to both world evaluation and contrast stages.
Change 4 Identical candidate styling enforced by code:
CANDIDATE_STYLE constant used for both GIE and accidental candidates.
Palette cannot diverge accidentally. Visual equality is structural.
Change 5 Axis titles controlled by debug_labels flag:
debug_labels=False (default) = no axis titles = public demo mode.
debug_labels=True = titles visible = development mode.
Titles are not part of the sanctioned text layer.
Change 6 Evidence panel shows promotion threshold:
Factual reference line added when threshold is known.
Not interpretation. Helps viewer see why candidates are in surviving band.
from **future** import annotations
import numpy as np
import matplotlib
matplotlib.use(Agg)
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from typing import Any, Dict, List, Optional
from core_types import RendererSnapshot, StageLabel
from key_snapshot_adapters import (
Colors, EvidenceHistory,
extract_signal_views, extract_candidate_distribution,
extract_promoted_views, extract_composition_views,
extract_world_view, extract_contrast_view,
build_polar_profile_geometry, stage_display_label,
)
from key_stage_text_runtime import (
StageTextState, stage_text_for_snapshot
)
#
# Change 4: Single candidate style enforced by code, not convention.
# Both GIE candidate and accidental candidate use exactly this constant.
# A future developer cannot assign different colors by modifying the palette
# because both calls reference this constant, not Colors.* directly.
#
CANDIDATE_STYLE = {
color: Colors.ACTIVE_CANDIDATE,
linewidth: 1.6,
alpha: 0.9,
zorder: 3,
}
#
# Renderer
#
class KeyRenderer:
Main renderer. Consumes RendererSnapshot objects, emits visual frames.
```
Parameters
----------
figsize : matplotlib figure size
dpi : resolution
debug_labels : Change 5. True = show axis titles (development mode).
False = no axis titles (public demo mode).
Axis titles are not part of the sanctioned text layer.
"""
def __init__(self, figsize=(14, 9), dpi=100, debug_labels=False):
self.figsize = figsize
self.dpi = dpi
self.debug_labels = debug_labels
self.fig = None
self.ax_main = None
self.ax_evidence = None
self.ax_meta = None
self.ax_text = None
self.evidence = EvidenceHistory()
self.text_state = StageTextState()
self.last_snapshot: Optional[RendererSnapshot] = None
self.frame_count = 0
# Change 6: track threshold for evidence panel reference line
self._current_threshold: Optional[float] = None
def build_layout(self):
self.fig = plt.figure(
figsize=self.figsize, dpi=self.dpi,
facecolor=Colors.BACKGROUND
)
gs = gridspec.GridSpec(
3, 3, figure=self.fig,
height_ratios=[7, 2, 1],
width_ratios=[4, 1, 2],
hspace=0.08, wspace=0.12,
left=0.04, right=0.97, top=0.96, bottom=0.04
)
self.ax_main = self.fig.add_subplot(gs[0:2, 0:2])
self.ax_evidence = self.fig.add_subplot(gs[0, 2])
self.ax_meta = self.fig.add_subplot(gs[1, 2])
self.ax_text = self.fig.add_subplot(gs[2, :])
for ax in [self.ax_main, self.ax_evidence, self.ax_meta, self.ax_text]:
ax.set_facecolor(Colors.BACKGROUND)
for spine in ax.spines.values():
spine.set_color("#333333")
self.ax_text.set_xticks([])
self.ax_text.set_yticks([])
self.ax_meta.set_xticks([])
self.ax_meta.set_yticks([])
self.fig.suptitle(
"THE KEY EMERGES",
color=Colors.TEXT_OVERLAY, fontsize=11,
fontfamily="monospace", x=0.04, y=0.99, ha="left"
)
def consume_snapshot(self, snapshot: RendererSnapshot):
"""One snapshot -> one render update."""
if self.fig is None:
self.build_layout()
self.evidence.update(snapshot)
text = stage_text_for_snapshot(snapshot, self.text_state)
for ax in [self.ax_main, self.ax_evidence, self.ax_meta, self.ax_text]:
ax.cla()
ax.set_facecolor(Colors.BACKGROUND)
self._render_snapshot(snapshot)
self._render_evidence_panel(snapshot)
self._render_text_overlay(text)
self.last_snapshot = snapshot
self.frame_count += 1
def _render_snapshot(self, snapshot: RendererSnapshot):
stage = snapshot.stage
if stage == StageLabel.SIGNAL_GENERATION:
self._render_main_signal_generation(snapshot)
elif stage in (StageLabel.LENS_SEARCH, StageLabel.SURVIVAL_EVALUATION):
self._render_main_search_distribution(snapshot)
elif stage == StageLabel.PROMOTION:
self._render_main_promotion(snapshot)
elif stage == StageLabel.COMPOSITION_SEARCH:
# Same method reused same visual language as lens search.
# Reuse is the architectural claim made visible.
self._render_main_search_distribution(snapshot)
elif stage in (StageLabel.WORLD_EVALUATION, StageLabel.STATE_TRANSITION):
self._render_main_world(snapshot)
elif stage == StageLabel.CONTRAST_EVALUATION:
self._render_main_contrast(snapshot)
else:
self._render_main_placeholder(snapshot)
# -----------------------------------------------------------------------
# Signal generation
# -----------------------------------------------------------------------
def _render_main_signal_generation(self, snapshot: RendererSnapshot):
"""Raw point clouds only. No connecting lines. Noise visible."""
data = extract_signal_views(snapshot)
ax = self.ax_main
plotted = False
if data["arm1_points"] is not None:
pts = data["arm1_points"]
ax.scatter(pts[:, 0], pts[:, 1],
s=4, color=Colors.ACTIVE_CANDIDATE,
alpha=0.6, linewidths=0)
plotted = True
if data["arm2_points"] is not None:
pts = data["arm2_points"]
ax.scatter(pts[:, 0] + 2.5, pts[:, 1],
s=4, color=Colors.ACTIVE_CANDIDATE,
alpha=0.6, linewidths=0)
plotted = True
if not plotted:
ax.text(0.5, 0.5, "Awaiting signals...",
transform=ax.transAxes, ha="center", va="center",
color=Colors.TEXT_OVERLAY, fontsize=10,
fontfamily="monospace")
_style_main_ax(ax, "Signal generation raw exposures", self.debug_labels)
# -----------------------------------------------------------------------
# Search distribution (REUSED for lens search and composition search)
# -----------------------------------------------------------------------
def _render_main_search_distribution(self, snapshot: RendererSnapshot):
"""
Population distribution for all search stages.
Called identically for LENS_SEARCH and COMPOSITION_SEARCH.
Same visual language for both. This sameness is the architectural
reuse claim made visible without annotation.
CHANGE 1 hard-veto visibility note:
Hard veto is shown only as a count annotation in the veto color.
This is honest but weaker than showing individual eliminations.
The gap: RendererSnapshot carries only a count, not per-candidate
veto geometry. Long-term fix: add a veto_events field to
RendererSnapshot with eliminated candidate scores, allowing
individual red marks at the veto boundary rather than a counter.
Until then, the count is shown in Colors.HARD_VETO to preserve
the visual distinction requirement from KEY visual grammar Section 3.
The two failure types (hard veto, non-surviving) remain distinguishable:
hard veto = red counter, no distribution member.
non-surviving = gray distribution member with visible score.
"""
ax = self.ax_main
if snapshot.stage == StageLabel.COMPOSITION_SEARCH:
data = extract_composition_views(snapshot)
substrate = data.get("substrate_label", "composed structures")
else:
data = extract_candidate_distribution(snapshot)
substrate = "signal points"
all_scores = data["admissible_scores"]
non_surviving = data["non_surviving_scores"]
surviving = data["surviving_scores"]
veto_count = data["veto_count"]
threshold = data["threshold_display"]
gen = data["generation"]
# Change 6: track threshold for evidence panel
if threshold > 0:
self._current_threshold = threshold
if all_scores:
rng_d = np.random.default_rng(gen)
if non_surviving:
ns = np.array(non_surviving)
ax.scatter(
rng_d.uniform(0.1, 0.9, len(ns)), ns,
s=12, color=Colors.NON_SURVIVING,
alpha=0.5, linewidths=0, zorder=2
)
if surviving:
sv = np.array(surviving)
ax.scatter(
np.random.default_rng(gen + 1000).uniform(0.1, 0.9, len(sv)), sv,
s=16, color=Colors.SURVIVING,
alpha=0.75, linewidths=0, zorder=3
)
if threshold > 0:
ax.axhline(y=threshold, color="#444444",
linewidth=0.8, linestyle="--",
alpha=0.6, zorder=1)
# Change 1: veto count in veto color see comment above
if veto_count > 0:
ax.text(0.02, 0.04,
f"{veto_count} hard-vetoed (world constraint)",
transform=ax.transAxes,
color=Colors.HARD_VETO, fontsize=8,
fontfamily="monospace", va="bottom", zorder=5)
if snapshot.promoted_views:
ax.text(0.5, 0.5, "Structure promoted.",
transform=ax.transAxes, ha="center", va="center",
color=Colors.PROMOTED, fontsize=14,
fontfamily="monospace", zorder=6)
ax.set_xlim(0, 1)
ax.set_ylim(-0.05, 1.05)
ax.set_xticks([])
ax.set_ylabel("Invariance score", color=Colors.TEXT_OVERLAY,
fontsize=8, fontfamily="monospace")
ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=7)
# Change 5: title only in debug mode
title = f"Search {substrate} gen {gen}" if self.debug_labels else ""
_style_main_ax(ax, title, self.debug_labels)
# -----------------------------------------------------------------------
# Promotion one structure, one stage event
# -----------------------------------------------------------------------
def _render_main_promotion(self, snapshot: RendererSnapshot):
"""
Population clears. Single promoted structure appears. Discrete.
CHANGE 2: one structure at a time. Only the most recently promoted
structure is shown. Promotion is a stage event, not a comparison card.
Showing both simultaneously would misrepresent the sequential nature
of the two promotion events and imply a comparison that is not
present in the computation at this moment.
"""
ax = self.ax_main
promoted = extract_promoted_views(snapshot)
if not promoted:
_style_main_ax(ax, "Promotion" if self.debug_labels else "",
self.debug_labels)
return
# Change 2: most recent structure only
pv = promoted[-1]
geom = pv.get("geometry")
if geom is not None:
ax.plot(geom[:, 0], geom[:, 1],
color=Colors.PROMOTED, linewidth=1.8,
alpha=0.9, zorder=3)
ax.fill(geom[:, 0], geom[:, 1],
color=Colors.PROMOTED, alpha=0.08, zorder=2)
if self.debug_labels:
arm = pv.get("arm", "")
score = pv.get("score", 0.0)
ax.text(0.02, 0.04, f"{arm} score={score:.3f}",
transform=ax.transAxes, color=Colors.PROMOTED,
fontsize=8, fontfamily="monospace", va="bottom")
ax.set_aspect("equal", adjustable="datalim")
_style_main_ax(ax, "Promoted structure" if self.debug_labels else "",
self.debug_labels)
# -----------------------------------------------------------------------
# World evaluation
# -----------------------------------------------------------------------
def _render_main_world(self, snapshot: RendererSnapshot):
"""
World appears here for the first time. No preview before this stage.
CHANGE 3: world geometry must come from world_view in the snapshot.
If absent, log and render nothing extra. No reconstruction from
defaults. Reconstruction, even from canonical defaults, would be
renderer-side inference the snapshot did not authorize it.
"""
ax = self.ax_main
wv = extract_world_view(snapshot)
if wv is None:
ax.text(0.5, 0.5, "State transition.",
transform=ax.transAxes, ha="center", va="center",
color=Colors.TEXT_OVERLAY, fontsize=14,
fontfamily="monospace")
_style_main_ax(ax, "", self.debug_labels)
return
# Change 3: use snapshot geometry only
wg = wv.get("world_geometry")
if wg is None:
print(" [renderer] world_view missing world_geometry "
"omitting world display. Check snapshot population.")
else:
ax.plot(wg[:, 0], wg[:, 1],
color=Colors.WORLD_GEOMETRY, linewidth=2.0,
alpha=0.85, zorder=2)
cg = wv.get("candidate_geometry")
if cg is not None:
ax.plot(cg[:, 0], cg[:, 1],
color=Colors.PROMOTED, linewidth=1.6,
alpha=0.9, zorder=3)
ax.fill(cg[:, 0], cg[:, 1],
color=Colors.PROMOTED, alpha=0.06, zorder=1)
success = wv.get("success", False)
can_insert = wv.get("can_insert", False)
can_rotate = wv.get("can_rotate", False)
fail_mode = wv.get("failure_mode", "")
if success:
result_text = "A B C constraints satisfied"
result_color = Colors.SURVIVING
elif can_rotate:
result_text = f"A B C: {fail_mode}"
result_color = Colors.NON_SURVIVING
elif can_insert:
result_text = f"A B: {fail_mode}"
result_color = Colors.NON_SURVIVING
else:
result_text = f"A: {fail_mode}"
result_color = Colors.HARD_VETO
ax.text(0.5, 0.04, result_text,
transform=ax.transAxes, ha="center", va="bottom",
color=result_color, fontsize=9, fontfamily="monospace")
ax.set_aspect("equal", adjustable="datalim")
_style_main_ax(ax, "World evaluation" if self.debug_labels else "",
self.debug_labels)
# -----------------------------------------------------------------------
# Contrast branch
# -----------------------------------------------------------------------
def _render_main_contrast(self, snapshot: RendererSnapshot):
ax = self.ax_main
cv = extract_contrast_view(snapshot)
if cv is None:
_style_main_ax(ax, "Contrast" if self.debug_labels else "",
self.debug_labels)
return
pert_gie = cv.get("pert_gie_result")
pert_acc = cv.get("pert_acc_result")
if pert_gie is not None and pert_acc is not None:
self._render_perturbation_test(ax, cv)
else:
self._render_contrast_single(ax, cv)
def _render_contrast_single(self, ax, cv: Dict):
"""
Single contrast candidate.
CHANGE 3: world geometry from snapshot only. No reconstruction.
CHANGE 4: accidental candidate uses CANDIDATE_STYLE identical
to GIE. Failure comes only from the world's response.
"""
wg = cv.get("world_geometry")
if wg is None:
print(" [renderer] contrast_view missing world_geometry omitting.")
else:
ax.plot(wg[:, 0], wg[:, 1],
color=Colors.WORLD_GEOMETRY, linewidth=2.0,
alpha=0.85, zorder=2)
ag = cv.get("accidental_geometry")
if ag is not None:
# Change 4: CANDIDATE_STYLE identical to GIE candidate
ax.plot(ag[:, 0], ag[:, 1],
color=CANDIDATE_STYLE["color"],
linewidth=CANDIDATE_STYLE["linewidth"],
alpha=CANDIDATE_STYLE["alpha"],
zorder=CANDIDATE_STYLE["zorder"])
acc_result = cv.get("accidental_result", {})
if acc_result:
success = acc_result.get("success", False)
fail = acc_result.get("failure_mode", "")
if success:
label, lcolor = "Passed original world.", Colors.SURVIVING
else:
label, lcolor = f"Failed: {fail}", Colors.HARD_VETO
ax.text(0.5, 0.04, label,
transform=ax.transAxes, ha="center", va="bottom",
color=lcolor, fontsize=9, fontfamily="monospace")
ax.set_aspect("equal", adjustable="datalim")
_style_main_ax(ax, "Contrast evaluation" if self.debug_labels else "",
self.debug_labels)
def _render_perturbation_test(self, ax, cv: Dict):
"""
Side-by-side perturbation test.
CHANGE 3: world geometry from snapshot only. No reconstruction.
CHANGE 4: both candidates use CANDIDATE_STYLE. Identical by code.
The only permitted visible difference is the world's response.
"""
delta_phi = cv.get("delta_phi", -0.20)
offset = 3.0
# Change 3: world geometry from snapshot only
wg_left = cv.get("pert_world_geometry_left")
wg_right = cv.get("pert_world_geometry_right")
if wg_left is None or wg_right is None:
print(" [renderer] perturbation world geometry missing omitting.")
# Left: GIE candidate
if wg_left is not None:
ax.plot(wg_left[:, 0], wg_left[:, 1],
color=Colors.WORLD_GEOMETRY, linewidth=1.8,
alpha=0.8, zorder=2)
gie_geom = cv.get("gie_geometry")
if gie_geom is not None:
# Change 4: CANDIDATE_STYLE for GIE
ax.plot(gie_geom[:, 0], gie_geom[:, 1],
color=CANDIDATE_STYLE["color"],
linewidth=CANDIDATE_STYLE["linewidth"],
alpha=CANDIDATE_STYLE["alpha"],
zorder=CANDIDATE_STYLE["zorder"])
pert_gie = cv.get("pert_gie_result", {})
gie_held = pert_gie.get("success", False)
gie_color = Colors.SURVIVING if gie_held else Colors.HARD_VETO
ax.text(-offset * 0.3, -1.7, "GIE",
ha="center", color=gie_color,
fontsize=9, fontfamily="monospace")
ax.text(-offset * 0.3, -1.95,
"held" if gie_held else pert_gie.get("failure_mode", "failed"),
ha="center", color=gie_color, fontsize=8,
fontfamily="monospace")
# Right: accidental candidate
if wg_right is not None:
ax.plot(wg_right[:, 0] + offset, wg_right[:, 1],
color=Colors.WORLD_GEOMETRY, linewidth=1.8,
alpha=0.8, zorder=2)
acc_geom = cv.get("accidental_geometry")
if acc_geom is not None:
# Change 4: identical CANDIDATE_STYLE enforced by code
ax.plot(acc_geom[:, 0] + offset, acc_geom[:, 1],
color=CANDIDATE_STYLE["color"],
linewidth=CANDIDATE_STYLE["linewidth"],
alpha=CANDIDATE_STYLE["alpha"],
zorder=CANDIDATE_STYLE["zorder"])
pert_acc = cv.get("pert_acc_result", {})
acc_held = pert_acc.get("success", False)
acc_color = Colors.SURVIVING if acc_held else Colors.HARD_VETO
ax.text(offset * 0.7, -1.7, "Accidental",
ha="center", color=acc_color,
fontsize=9, fontfamily="monospace")
ax.text(offset * 0.7, -1.95,
"held" if acc_held else pert_acc.get("failure_mode", "failed"),
ha="center", color=acc_color, fontsize=8,
fontfamily="monospace")
ax.axvline(x=offset * 0.5, color="#333333",
linewidth=0.8, linestyle="--", alpha=0.5)
ax.text(0.5, 0.97,
f"World shifted: phi_lock + {delta_phi:.2f} rad",
transform=ax.transAxes, ha="center", va="top",
color=Colors.TEXT_OVERLAY, fontsize=8,
fontfamily="monospace")
ax.set_aspect("equal", adjustable="datalim")
_style_main_ax(ax, "Perturbation test" if self.debug_labels else "",
self.debug_labels)
# -----------------------------------------------------------------------
# Placeholder
# -----------------------------------------------------------------------
def _render_main_placeholder(self, snapshot: RendererSnapshot):
ax = self.ax_main
if self.debug_labels:
ax.text(0.5, 0.5, f"Stage: {snapshot.stage.name}",
transform=ax.transAxes, ha="center", va="center",
color=Colors.TEXT_OVERLAY, fontsize=9,
fontfamily="monospace")
_style_main_ax(ax, "", self.debug_labels)
# -----------------------------------------------------------------------
# Evidence panel
# -----------------------------------------------------------------------
def _render_evidence_panel(self, snapshot: RendererSnapshot):
"""
Secondary evidence panel. Always visible.
Proof that the main panel is honest.
CHANGE 6: promotion threshold shown as factual reference line.
Not interpretation. Gives viewer context for the surviving band.
"""
ax = self.ax_evidence
ev = self.evidence.as_arrays()
gens = ev["generations"]
scores = ev["best_scores"]
vetos = ev["veto_counts"]
promo_gens = ev["promotion_gens"]
if len(gens) == 0:
return
ax.plot(gens, scores,
color=Colors.EVIDENCE_LINE, linewidth=1.0,
alpha=0.85, zorder=3)
if vetos.max() > 0:
veto_scaled = vetos / vetos.max() * 0.25
ax.fill_between(gens, 0, veto_scaled,
color=Colors.EVIDENCE_VETO,
alpha=0.25, zorder=1)
for pg in promo_gens:
ax.axvline(x=pg, color=Colors.PROMOTION_MARKER,
linewidth=0.8, alpha=0.7, linestyle=":",
zorder=4)
# Change 6: threshold reference line factual, not interpretive
if self._current_threshold is not None and self._current_threshold > 0:
ax.axhline(y=self._current_threshold,
color=Colors.PROMOTION_MARKER,
linewidth=0.6, alpha=0.4, linestyle="--",
zorder=2)
ax.text(0.02, self._current_threshold + 0.02,
"threshold",
transform=ax.get_yaxis_transform(),
color=Colors.PROMOTION_MARKER, fontsize=6,
fontfamily="monospace", alpha=0.7)
ax.set_ylim(-0.05, 1.05)
ax.set_xlim(left=0)
ax.set_ylabel("Best score", color=Colors.TEXT_OVERLAY,
fontsize=7, fontfamily="monospace")
ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=6)
for spine in ax.spines.values():
spine.set_color("#333333")
ax_meta = self.ax_meta
gen = snapshot.timestamp_gen
stage = stage_display_label(snapshot.stage)
veto_total = self.evidence.running_veto_total()
for i, line in enumerate([
f"Stage: {stage}",
f"Gen: {gen}",
f"Vetoed: {veto_total}",
f"Frames: {self.frame_count}",
]):
ax_meta.text(0.05, 0.85 - i * 0.22, line,
transform=ax_meta.transAxes,
color=Colors.TEXT_OVERLAY,
fontsize=7, fontfamily="monospace", va="top")
ax_meta.set_xlim(0, 1)
ax_meta.set_ylim(0, 1)
for spine in ax_meta.spines.values():
spine.set_color("#333333")
# -----------------------------------------------------------------------
# Text overlay
# -----------------------------------------------------------------------
def _render_text_overlay(self, text: Optional[str]):
"""One sentence, fixed, hard replacement. Blank when None."""
ax = self.ax_text
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis("off")
if text:
ax.text(0.5, 0.5, text,
transform=ax.transAxes,
ha="center", va="center",
color=Colors.TEXT_OVERLAY,
fontsize=10, fontfamily="monospace",
fontstyle="normal", fontweight="normal")
def redraw(self):
if self.fig is not None:
try:
self.fig.canvas.draw_idle()
self.fig.canvas.flush_events()
except Exception:
pass
```
#
# Utility
#
def _style_main_ax(ax, title: str, show_title: bool):
Consistent main panel styling.
Title shown only when show_title is True (debug mode).
Axis titles are not part of the sanctioned text layer.
ax.set_facecolor(Colors.BACKGROUND)
ax.tick_params(colors=Colors.TEXT_OVERLAY, labelsize=7)
for spine in ax.spines.values():
spine.set_color(#333333)
if show_title and title:
ax.set_title(title, color=Colors.TEXT_OVERLAY, fontsize=8,
fontfamily=monospace, pad=4, loc=left)
#
# Live loop
#
def run_live(renderer: KeyRenderer, snapshot_queue, poll_sleep: float = 0.05):
Poll queue. One update per snapshot. No timer-driven transitions.
plt.ion()
renderer.build_layout()
plt.show()
while True:
try:
snapshot = snapshot_queue.get_nowait()
except Exception:
plt.pause(poll_sleep)
continue
if snapshot is None:
break
renderer.consume_snapshot(snapshot)
renderer.redraw()
plt.pause(0.001)
plt.ioff()
#
# Replay loop
#
def run_replay(renderer: KeyRenderer,
snapshots: List[RendererSnapshot],
step_pause: float = 0.3,
interactive: bool = False):
One snapshot = one frame. No interpolation.
plt.ion()
renderer.build_layout()
plt.show()
for i, snapshot in enumerate(snapshots):
renderer.consume_snapshot(snapshot)
renderer.redraw()
if interactive:
input(f Frame {i+1}/{len(snapshots)} press Enter)
else:
plt.pause(step_pause)
plt.ioff()
print(fReplay complete. {len(snapshots)} frames rendered.)
#
# Headless export
#
def export_frames(renderer: KeyRenderer,
snapshots: List[RendererSnapshot],
output_dir: str = frames):
Export each snapshot as frame_NNNN.png.
import os
os.makedirs(output_dir, exist_ok=True)
for i, snapshot in enumerate(snapshots):
renderer.consume_snapshot(snapshot)
path = os.path.join(output_dir, fframe_{i:04d}.png)
renderer.fig.savefig(path, dpi=renderer.dpi,
facecolor=Colors.BACKGROUND,
bbox_inches=tight)
print(fExported {len(snapshots)} frames to {output_dir}/)
#
# Integration test
#
if **name** == **main**:
import sys
import os
import shutil
```
print("THE KEY EMERGES key_renderer.py (revised) integration test")
print()
sys.path.insert(0, ".")
from signal_model import build_signal_arms
from transform_families import (random_candidate, mutate_candidate,
crossover_candidates)
from invariance_metrics import evaluate_candidate
from world_constraint import DEFAULT_WORLD
from core_types import ArmID, SurvivalConfig, StageLabel as SL
from survival_kernel import (run_survival_kernel, make_threshold_gate,
initialize_population)
from key_stage_text_runtime import StageTextState, stage_text_for_snapshot
stream_1, stream_2, c1, c2 = build_signal_arms(seed=42)
world = DEFAULT_WORLD
rng = np.random.default_rng(0)
snaps = []
def factory(n): return [random_candidate(ArmID.ARM_1, f"c{i}", rng=rng)
for i in range(n)]
def evaluator(c): return evaluate_candidate(c, stream_1, world)
def mutator(c): return mutate_candidate(c, rng=rng)
def xover(a, b, cid): return crossover_candidates(a, b, cid, rng=rng)
config = SurvivalConfig(population_size=20, max_generations=15,
promotion_threshold=0.80,
promotion_stability_gens=3)
gate = make_threshold_gate(0.80, 3)
pop = initialize_population(factory, 20)
result = run_survival_kernel(
pop, evaluator, mutator, xover, gate, config,
SL.LENS_SEARCH, ArmID.ARM_1,
snapshot_callback=snaps.append,
verbose=False
)
print(f"Kernel: {len(snaps)} snapshots, "
f"promoted={result.promoted}, gen={result.promotion_generation}")
# Debug mode titles visible
r_debug = KeyRenderer(figsize=(14, 9), dpi=80, debug_labels=True)
r_debug.build_layout()
if os.path.exists("test_frames_debug"):
shutil.rmtree("test_frames_debug")
export_frames(r_debug, snaps, "test_frames_debug")
print("Debug frames: test_frames_debug/")
# Public mode titles off
r_pub = KeyRenderer(figsize=(14, 9), dpi=80, debug_labels=False)
r_pub.build_layout()
if os.path.exists("test_frames_pub"):
shutil.rmtree("test_frames_pub")
export_frames(r_pub, snaps, "test_frames_pub")
print("Public frames: test_frames_pub/")
# Verify Change 4: identical candidate styles
assert CANDIDATE_STYLE["color"] == Colors.ACTIVE_CANDIDATE, \
"FAIL Change 4: CANDIDATE_STYLE diverged from Colors.ACTIVE_CANDIDATE"
print(f"Change 4 verified: CANDIDATE_STYLE = {CANDIDATE_STYLE['color']}")
# Verify text strings
state = StageTextState()
seen = set()
for snap in snaps:
t = stage_text_for_snapshot(snap, state)
if t and t not in seen:
print(f" text: \"{t}\"")
seen.add(t)
print()
print("PASS key_renderer.py (revised) complete.")
```