pimco-charts/app/renderer/annotations.py
DJP a3a38e85d2 Initial commit: PIMCO chart generator with iterative refinement
AI-powered tool that generates publication-quality SVG charts matching
PIMCO's InDesign style. Upload Excel/CSV data, write a plain-English
brief, then iterate with natural language edits until the chart is
exactly right.

- Claude Opus 4.6 interprets briefs into structured ChartSpec JSON
- Deterministic SVG renderer via drawsvg (no visual hallucinations)
- Roboto/Roboto Condensed fonts base64-embedded in SVG
- FastAPI + HTMX web frontend with live preview
- Conversational refinement: "make lines thicker", "change title", etc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:29:47 -05:00

52 lines
1.2 KiB
Python

"""Annotation rendering: ellipses, callouts, labels."""
from __future__ import annotations
from datetime import datetime
import drawsvg as draw
from app.models.style import COLORS
from app.renderer.scale import LinearScale, DateScale
def render_ellipse(
d: draw.Drawing,
x_scale: DateScale,
y_scale: LinearScale,
x_start: datetime,
x_end: datetime,
y_start: float,
y_end: float,
):
"""Render a semi-transparent grey ellipse annotation."""
px_start = x_scale(x_start)
px_end = x_scale(x_end)
py_start = y_scale(y_start)
py_end = y_scale(y_end)
cx = (px_start + px_end) / 2
cy = (py_start + py_end) / 2
rx = abs(px_end - px_start) / 2
ry = abs(py_end - py_start) / 2
d.append(draw.Ellipse(
cx, cy, rx, ry,
fill=COLORS["annotation_ellipse"],
stroke="none",
))
def render_text_label(
d: draw.Drawing,
text: str,
x: float,
y: float,
font_size: float = 11,
color: str | None = None,
):
"""Render a text annotation at a specific position."""
d.append(draw.Text(
text, font_size,
x, y,
font_family="Roboto, sans-serif",
fill=color or COLORS["axis_text"],
dominant_baseline="middle",
))