Files
oh-my-pi/packages/snapcompact/research/snapcompact_viz_city.py
T
2026-07-15 00:08:50 +02:00

376 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# /// script
# requires-python = ">=3.10"
# dependencies = ["pillow", "numpy"]
# ///
"""Render an isometric activation city from snapcompact heatmap tensors."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Iterable
import numpy as np
from PIL import Image, ImageDraw, ImageFilter, ImageFont
HERE = Path(__file__).resolve().parent
DATA_DIR = HERE / "results" / "tensor-heatmap-paddleocr-q7"
OUT_DIR = HERE / "results" / "agent-viz-city"
BG = (8, 11, 24)
INK = (232, 238, 255)
MUTED = (136, 148, 184)
ANSWER = (255, 94, 117)
ANSWER_HI = (255, 198, 97)
RANDOM = (72, 201, 255)
RANDOM_HI = (127, 246, 213)
ROAD = (21, 28, 52)
GRID = (39, 48, 83)
def font(size: int, bold: bool = False) -> ImageFont.FreeTypeFont | ImageFont.ImageFont:
candidates = [
"/System/Library/Fonts/Supplemental/Arial Bold.ttf"
if bold
else "/System/Library/Fonts/Supplemental/Arial.ttf",
"/System/Library/Fonts/Supplemental/Helvetica Bold.ttf"
if bold
else "/System/Library/Fonts/Supplemental/Helvetica.ttf",
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
if bold
else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
]
for path in candidates:
try:
return ImageFont.truetype(path, size)
except OSError:
pass
return ImageFont.load_default()
def clamp255(v: float) -> int:
return max(0, min(255, int(round(v))))
def mix(
a: tuple[int, int, int], b: tuple[int, int, int], t: float
) -> tuple[int, int, int]:
t = max(0.0, min(1.0, t))
return tuple(clamp255(x + (y - x) * t) for x, y in zip(a, b))
def shade(c: tuple[int, int, int], factor: float) -> tuple[int, int, int]:
return tuple(clamp255(x * factor) for x in c)
def iso(
x: float, y: float, origin: tuple[float, float], tile_w: float, tile_h: float
) -> tuple[float, float]:
ox, oy = origin
return ox + (x - y) * tile_w * 0.5, oy + (x + y) * tile_h * 0.5
def diamond(
cx: float, cy: float, tile_w: float, tile_h: float
) -> list[tuple[float, float]]:
return [
(cx, cy - tile_h * 0.5),
(cx + tile_w * 0.5, cy),
(cx, cy + tile_h * 0.5),
(cx - tile_w * 0.5, cy),
]
def building_faces(
cx: float, cy: float, h: float, tile_w: float, tile_h: float
) -> tuple[
list[tuple[float, float]], list[tuple[float, float]], list[tuple[float, float]]
]:
top = diamond(cx, cy - h, tile_w, tile_h)
right = [top[1], (cx + tile_w * 0.5, cy), (cx, cy + tile_h * 0.5), top[2]]
left = [top[3], top[2], (cx, cy + tile_h * 0.5), (cx - tile_w * 0.5, cy)]
return top, right, left
def draw_soft_line(
draw: ImageDraw.ImageDraw,
pts: Iterable[tuple[float, float]],
fill: tuple[int, int, int],
width: int = 1,
) -> None:
draw.line([(int(x), int(y)) for x, y in pts], fill=fill, width=width)
def draw_district(
draw: ImageDraw.ImageDraw,
values: np.ndarray,
ratios: np.ndarray,
origin: tuple[float, float],
base_color: tuple[int, int, int],
high_color: tuple[int, int, int],
label: str,
scale: float,
ratio_scale: float,
) -> None:
layers, bins = values.shape
tile_w = 9.0
tile_h = 5.0
max_h = 245.0
# Foundation grid and layer streets.
for layer in range(layers):
left = iso(0, layer, origin, tile_w, tile_h)
right = iso(bins - 1, layer, origin, tile_w, tile_h)
draw_soft_line(draw, [left, right], GRID if layer % 3 else (66, 76, 118), 1)
for token in range(0, bins, 10):
near = iso(token, 0, origin, tile_w, tile_h)
far = iso(token, layers - 1, origin, tile_w, tile_h)
draw_soft_line(draw, [near, far], (31, 39, 70), 1)
# Draw far blocks first, near blocks last.
for layer in range(layers - 1, -1, -1):
for token in range(bins - 1, -1, -1):
v = float(values[layer, token])
r = float(ratios[layer, token])
intensity = min(1.0, np.log1p(v) / np.log1p(scale))
h = 8.0 + (intensity**1.65) * max_h
if v <= 0.0:
h = 3.0
cx, cy = iso(token, layer, origin, tile_w, tile_h)
top, right, left = building_faces(cx, cy, h, tile_w * 0.92, tile_h * 0.92)
ratio_t = min(1.0, np.log1p(max(r, 0.0)) / np.log1p(ratio_scale))
c = mix(base_color, high_color, max(intensity * 0.55, ratio_t * 0.85))
draw.polygon(left, fill=shade(c, 0.42))
draw.polygon(right, fill=shade(c, 0.62))
draw.polygon(
top, fill=mix(shade(c, 0.95), (255, 255, 255), intensity * 0.20)
)
if ratio_t > 0.80 or intensity > 0.90:
draw.line(
[(int(x), int(y)) for x, y in top + [top[0]]],
fill=mix(c, (255, 255, 255), 0.25),
width=1,
)
# District label plaque.
x0, y0 = iso(-2, layers + 4, origin, tile_w, tile_h)
x1, y1 = iso(54, layers + 4, origin, tile_w, tile_h)
draw.rounded_rectangle(
(x0 - 26, y0 + 18, x1 + 26, y1 + 64),
radius=14,
fill=(13, 18, 37),
outline=shade(base_color, 0.75),
width=2,
)
draw.text(
(x0 - 8, y0 + 27),
label,
font=font(26, True),
fill=mix(base_color, high_color, 0.55),
)
def draw_legend(
draw: ImageDraw.ImageDraw, summary: dict[str, object], scale: float
) -> None:
draw.text((88, 70), "Snapcompact Activation City", font=font(54, True), fill=INK)
draw.text(
(92, 136),
"729 image tokens → 180 token-bin city blocks · 19 transformer layers → depth streets · building height = activation spike magnitude",
font=font(21),
fill=MUTED,
)
question = (
str(summary.get("question", {}).get("q", ""))
if isinstance(summary.get("question"), dict)
else ""
)
answer = (
str(summary.get("question", {}).get("answer_text", ""))
if isinstance(summary.get("question"), dict)
else ""
)
draw.text(
(92, 173),
f"Question: {question} Gold answer: {answer}",
font=font(20),
fill=(180, 190, 220),
)
ratio = float(summary.get("answer_over_random_delta", 0.0))
draw.rounded_rectangle(
(1738, 72, 2286, 206),
radius=24,
fill=(12, 17, 36),
outline=(50, 60, 99),
width=2,
)
draw.text(
(1772, 96), "Answer-mask / random-mask mean delta", font=font(18), fill=MUTED
)
draw.text((1772, 125), f"{ratio:.2f}×", font=font(52, True), fill=ANSWER_HI)
draw.text(
(1906, 149),
f"common p98 height scale {scale:.1f}",
font=font(17),
fill=(176, 186, 218),
)
y = 1400
draw.rounded_rectangle(
(88, y, 772, y + 96),
radius=18,
fill=(12, 17, 36),
outline=(44, 54, 92),
width=1,
)
draw.text((116, y + 18), "How to read it", font=font(22, True), fill=INK)
draw.text(
(116, y + 52),
"Tall towers mark token/layer bins where masking changed hidden states most.",
font=font(18),
fill=MUTED,
)
draw.rounded_rectangle(
(836, y, 1520, y + 96),
radius=18,
fill=(12, 17, 36),
outline=(44, 54, 92),
width=1,
)
draw.text((864, y + 18), "Districts", font=font(22, True), fill=INK)
draw.text(
(864, y + 52),
"Warm city = answer mask around “2003”; cool city = same-size random mask.",
font=font(18),
fill=MUTED,
)
draw.rounded_rectangle(
(1584, y, 2268, y + 96),
radius=18,
fill=(12, 17, 36),
outline=(44, 54, 92),
width=1,
)
draw.text((1612, y + 18), "Color halos", font=font(22, True), fill=INK)
draw.text(
(1612, y + 52),
"Bright caps emphasize bins with high answer/random activation ratio.",
font=font(18),
fill=MUTED,
)
def render() -> None:
OUT_DIR.mkdir(parents=True, exist_ok=True)
heatmaps = np.load(DATA_DIR / "heatmaps.npz")
summary = json.loads((DATA_DIR / "summary.json").read_text())
answer = np.asarray(heatmaps["answer_binned"], dtype=np.float32)
random = np.asarray(heatmaps["random_binned"], dtype=np.float32)
ratio = np.asarray(heatmaps["ratio_binned"], dtype=np.float32)
if answer.shape != random.shape or answer.shape != ratio.shape:
raise ValueError(
f"expected matching binned shapes, got {answer.shape}, {random.shape}, {ratio.shape}"
)
scale = float(
summary.get("common_delta_scale_p98")
or np.percentile(np.concatenate([answer.ravel(), random.ravel()]), 98)
)
ratio_scale = float(summary.get("ratio_scale_p98") or np.percentile(ratio, 98))
w, h = 2400, 1600
canvas = Image.new("RGB", (w, h), BG)
# Atmospheric glow layer.
glow = Image.new("RGBA", (w, h), (0, 0, 0, 0))
gd = ImageDraw.Draw(glow)
gd.ellipse((90, 250, 1090, 1260), fill=(255, 80, 95, 36))
gd.ellipse((1220, 250, 2250, 1260), fill=(62, 190, 255, 34))
gd.rectangle((0, 1240, w, h), fill=(2, 4, 11, 90))
canvas = Image.alpha_composite(
canvas.convert("RGBA"), glow.filter(ImageFilter.GaussianBlur(58))
).convert("RGB")
draw = ImageDraw.Draw(canvas)
# Basemap plates.
draw.rounded_rectangle(
(52, 244, 1134, 1330),
radius=42,
fill=(9, 14, 30),
outline=(42, 31, 55),
width=2,
)
draw.rounded_rectangle(
(1234, 244, 2316, 1330),
radius=42,
fill=(8, 15, 31),
outline=(24, 50, 70),
width=2,
)
for y in range(312, 1300, 70):
draw.line((70, y, 1116, y), fill=ROAD, width=1)
draw.line((1252, y, 2298, y), fill=ROAD, width=1)
draw_district(
draw,
answer,
ratio,
(252.0, 870.0),
ANSWER,
ANSWER_HI,
"answer-mask district",
scale,
ratio_scale,
)
draw_district(
draw,
random,
ratio,
(1434.0, 870.0),
RANDOM,
RANDOM_HI,
"random-mask district",
scale,
ratio_scale,
)
draw_legend(draw, summary, scale)
# Fine vignette frame.
vignette = Image.new("L", (w, h), 0)
vd = ImageDraw.Draw(vignette)
vd.rectangle((0, 0, w, h), fill=255)
vignette = vignette.filter(ImageFilter.GaussianBlur(42))
frame = Image.new("RGB", (w, h), (0, 0, 0))
canvas = Image.composite(canvas, frame, vignette)
np.savez_compressed(
OUT_DIR / "city_source_data.npz",
answer_binned=answer,
random_binned=random,
ratio_binned=ratio,
common_delta_scale_p98=np.array(scale, dtype=np.float32),
ratio_scale_p98=np.array(ratio_scale, dtype=np.float32),
)
(OUT_DIR / "city_summary.json").write_text(
json.dumps(
{
"source_heatmaps": str(DATA_DIR / "heatmaps.npz"),
"source_summary": str(DATA_DIR / "summary.json"),
"shape": list(answer.shape),
"height_encoding": "log1p(delta) scaled by common_delta_scale_p98",
"districts": {"answer": "answer_binned", "random": "random_binned"},
"ratio_encoding": "bright caps use ratio_binned / ratio_scale_p98",
"answer_over_random_delta": summary.get("answer_over_random_delta"),
},
indent=2,
)
+ "\n"
)
canvas.save(OUT_DIR / "city.png")
if __name__ == "__main__":
render()