Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 23 additions & 28 deletions plots/venn-labeled-items/implementations/python/letsplot.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
""" anyplot.ai
"""anyplot.ai
venn-labeled-items: Chartgeist-Style Venn Diagram with Labeled Items
Library: letsplot 4.9.0 | Python 3.14.4
Quality: 87/100 | Created: 2026-04-25
Library: letsplot | Python
"""

import os
Expand All @@ -12,7 +11,6 @@
LetsPlot,
aes,
coord_fixed,
element_blank,
element_rect,
geom_polygon,
geom_text,
Expand All @@ -30,10 +28,9 @@
THEME = os.getenv("ANYPLOT_THEME", "light")
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F"

# Okabe-Ito categorical (positions 1, 2, 3)
# Imprint palette positions 1, 2, 3
COLOR_A = "#009E73"
COLOR_B = "#C475FD"
COLOR_C = "#4467A3"
Expand All @@ -60,8 +57,8 @@
("Spreadsheets", 2.05, 0.55),
("Calendar Apps", 1.95, 0.05),
# C — Secretly Loved
("Roller Skating", -0.75, -2.05),
("Soap Operas", 0.75, -2.05),
("Roller Skating", -1.10, -2.10),
("Soap Operas", 1.10, -2.10),
# A ∩ B
("ChatGPT", 0.00, 1.20),
("Smartwatches", 0.00, 0.85),
Expand All @@ -71,16 +68,16 @@
# B ∩ C
("Dolly Parton", 1.05, -0.20),
("Spotify", 1.00, -0.60),
# A ∩ B ∩ C
("Sourdough", 0.00, 0.15),
("TikTok", 0.00, -0.30),
# A ∩ B ∩ C — spread vertically to reduce crowding
("Sourdough", 0.00, 0.30),
("TikTok", 0.00, -0.35),
# outside
("Beige Walls", -3.10, -2.50),
]
items_df = pd.DataFrame(items, columns=["label", "x", "y"])

# Plot
plot = ggplot() + coord_fixed(xlim=[-4.0, 4.0], ylim=[-3.5, 3.5])
# Plot — equal xlim/ylim so coord_fixed fills the square canvas without black bars
plot = ggplot() + coord_fixed(xlim=[-4.0, 4.0], ylim=[-4.0, 4.0])

# Three overlapping circles with semi-transparent fills
for c in circle_meta:
Expand All @@ -90,26 +87,26 @@
aes(x="x", y="y"), data=circle_df, fill=c["color"], color=c["color"], alpha=0.22, size=1.4
)

# Item labels (serif, INK)
plot = plot + geom_text(aes(x="x", y="y", label="label"), data=items_df, size=8, family="serif", color=INK)
# Item labels (serif, INK) — size=9 for legibility on 2400×2400 canvas
plot = plot + geom_text(aes(x="x", y="y", label="label"), data=items_df, size=9, family="serif", color=INK)

# Category names outside each circle, in the circle's color
# Category names outside each circle, centered on their quadrant — hjust=0.5 avoids edge clipping
plot = plot + geom_text(
x=-2.40, y=1.95, label="Overhyped", size=13, family="serif", fontface="bold", color=COLOR_A, hjust=1.0
x=-2.10, y=2.15, label="Overhyped", size=11, family="serif", fontface="bold", color=COLOR_A, hjust=0.5
)
plot = plot + geom_text(
x=2.40, y=1.95, label="Actually Useful", size=13, family="serif", fontface="bold", color=COLOR_B, hjust=0.0
x=2.10, y=2.15, label="Actually Useful", size=11, family="serif", fontface="bold", color=COLOR_B, hjust=0.5
)
plot = plot + geom_text(
x=0.00, y=-2.85, label="Secretly Loved", size=13, family="serif", fontface="bold", color=COLOR_C, hjust=0.5
x=0.00, y=-3.10, label="Secretly Loved", size=11, family="serif", fontface="bold", color=COLOR_C, hjust=0.5
)

# Hint label for the "outside" item cluster
plot = plot + geom_text(
x=-3.10,
y=-2.20,
label="(neither here nor there)",
size=6,
size=7,
family="serif",
fontface="italic",
color=INK_MUTED,
Expand All @@ -118,10 +115,10 @@

# Editorial kicker + canonical anyplot.ai title line
plot = plot + geom_text(
x=0, y=3.20, label="Chartgeist 2026", size=18, family="serif", fontface="bold_italic", color=INK, hjust=0.5
x=0, y=3.50, label="Chartgeist 2026", size=16, family="serif", fontface="bold_italic", color=INK, hjust=0.5
)
plot = plot + geom_text(
x=0, y=2.70, label="venn-labeled-items · letsplot · anyplot.ai", size=7, family="serif", color=INK_MUTED, hjust=0.5
x=0, y=3.00, label="venn-labeled-items · letsplot · anyplot.ai", size=6, family="serif", color=INK_MUTED, hjust=0.5
)

# Theme — gridless editorial background
Expand All @@ -132,14 +129,12 @@
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
legend_position="none",
axis_text=element_blank(),
axis_title=element_blank(),
axis_ticks=element_blank(),
)
)

plot = plot + ggsize(1200, 1200)
# Canvas: 2400×2400 px (square — canonical for symmetric Venn layout)
plot = plot + ggsize(600, 600)

# Save
ggsave(plot, f"plot-{THEME}.png", path=".", scale=3)
# Save PNG and interactive HTML
ggsave(plot, f"plot-{THEME}.png", path=".", scale=4)
ggsave(plot, f"plot-{THEME}.html", path=".")
238 changes: 11 additions & 227 deletions plots/venn-labeled-items/metadata/python/letsplot.yaml
Original file line number Diff line number Diff line change
@@ -1,237 +1,21 @@
# Per-library metadata for letsplot implementation of venn-labeled-items
# Auto-generated by impl-generate.yml

library: letsplot
language: python
specification_id: venn-labeled-items
created: '2026-04-25T05:45:00Z'
updated: '2026-04-25T05:50:27Z'
generated_by: claude-opus
workflow_run: 24923774465
updated: '2026-06-25T11:34:08Z'
generated_by: claude-sonnet
workflow_run: 28166734264
issue: 5364
python_version: 3.14.4
library_version: 4.9.0
language_version: 3.13.14
library_version: 4.10.1
preview_url_light: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/python/letsplot/plot-light.png
preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/python/letsplot/plot-dark.png
preview_html_light: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/python/letsplot/plot-light.html
preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/venn-labeled-items/python/letsplot/plot-dark.html
quality_score: 87
quality_score: null
review:
strengths:
- Full spec compliance — all 7 interior zones plus outside populated with correct
Okabe-Ito fills
- 'Strong editorial aesthetic matching the WIRED Chartgeist spec: bold-italic serif
title, colored category labels outside circles, italic aside for outside zone'
- Correct theme adaptation with INK token for item labels and fixed data colors
across both renders
- Clean deterministic flat-script code with correct high-resolution output via scale=3
weaknesses:
- Item labels are size=8 and hint is size=6, below the ~16pt guideline for a 3600x3600
canvas — increase to size=11 for items and size=8 for hint
- ABC zone has Sourdough/TikTok positioned close together (y=0.15 and y=-0.30) —
minor crowding in triple intersection
- axis_text/axis_title/axis_ticks element_blank calls are redundant after theme_void()
— minor code smell
image_description: |-
Light render (plot-light.png):
Background: Warm off-white #FAF8F1 — correct
Chrome: Title "Chartgeist 2026" bold-italic serif — clearly readable; subtitle "venn-labeled-items · letsplot · anyplot.ai" visible; category labels in Okabe-Ito accent colors outside circles — readable
Data: Three circles in Okabe-Ito positions 1-3 (#009E73, #D55E00, #0072B2) with alpha=0.22; item labels in dark INK (#1A1A17); 17 items across all 7 zones plus outside
Legibility verdict: PASS

Dark render (plot-dark.png):
Background: Warm near-black #1A1A17 — correct
Chrome: Title "Chartgeist 2026" in light INK (#F0EFE8) — readable; subtitle visible; category labels retain Okabe-Ito accent colors — legible on dark surface; no dark-on-dark failures observed
Data: Circle fill colors identical to light render (Okabe-Ito unchanged); item labels adapted to light INK (#F0EFE8) and readable against darkened circle regions
Legibility verdict: PASS
criteria_checklist:
visual_quality:
score: 26
max: 30
items:
- id: VQ-01
name: Text Legibility
score: 6
max: 8
passed: true
comment: Title legible in both themes; item labels (size=8) and hint (size=6)
below ~16pt guideline for 3600x3600 canvas
- id: VQ-02
name: No Overlap
score: 5
max: 6
passed: true
comment: Good distribution; minor crowding in ABC zone (Sourdough/TikTok y=0.15
and y=-0.30)
- id: VQ-03
name: Element Visibility
score: 5
max: 6
passed: true
comment: Circles visible in both themes; alpha=0.22 keeps fills subtle and
readable
- id: VQ-04
name: Color Accessibility
score: 2
max: 2
passed: true
comment: Okabe-Ito CVD-safe palette; no red-green sole signal
- id: VQ-05
name: Layout & Canvas
score: 4
max: 4
passed: true
comment: Square 3600x3600 appropriate for symmetric Venn; generous whitespace;
nothing cut off
- id: VQ-06
name: Axis Labels & Title
score: 2
max: 2
passed: true
comment: Editorial title plus canonical anyplot.ai subtitle present
- id: VQ-07
name: Palette Compliance
score: 2
max: 2
passed: true
comment: 'Correct Okabe-Ito order; backgrounds #FAF8F1/#1A1A17; data colors
identical across themes'
design_excellence:
score: 14
max: 20
items:
- id: DE-01
name: Aesthetic Sophistication
score: 6
max: 8
passed: true
comment: Bold-italic serif headline, colored category labels, witty item selection,
italic outside zone aside — genuine editorial intent
- id: DE-02
name: Visual Refinement
score: 4
max: 6
passed: true
comment: theme_void() removes all chrome cleanly; colored category names create
visual anchoring
- id: DE-03
name: Data Storytelling
score: 4
max: 6
passed: true
comment: WIRED Chartgeist framing creates cultural commentary context; outside
zone with Beige Walls adds satirical punch
spec_compliance:
score: 15
max: 15
items:
- id: SC-01
name: Plot Type
score: 5
max: 5
passed: true
comment: Symmetric three-circle Venn with labeled items
- id: SC-02
name: Required Features
score: 4
max: 4
passed: true
comment: Semi-transparent fills; text-only placement; category names outside;
all zones; outside zone
- id: SC-03
name: Data Mapping
score: 3
max: 3
passed: true
comment: 17 items in all zones; correct zone placement
- id: SC-04
name: Title & Legend
score: 3
max: 3
passed: true
comment: Editorial title + anyplot.ai canonical subtitle; no redundant legend
data_quality:
score: 15
max: 15
items:
- id: DQ-01
name: Feature Coverage
score: 6
max: 6
passed: true
comment: All 7 interior zones plus outside; single zones, pairwise, and triple
intersection represented
- id: DQ-02
name: Realistic Context
score: 5
max: 5
passed: true
comment: Pop-culture tech/media/food domain; neutral relatable items
- id: DQ-03
name: Appropriate Scale
score: 4
max: 4
passed: true
comment: 17 items within 10-25 spec range; sensible coordinate geometry
code_quality:
score: 10
max: 10
items:
- id: CQ-01
name: KISS Structure
score: 3
max: 3
passed: true
comment: Flat script, no functions or classes
- id: CQ-02
name: Reproducibility
score: 2
max: 2
passed: true
comment: Fully deterministic geometric computation
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
comment: All imported names are used
- id: CQ-04
name: Code Elegance
score: 2
max: 2
passed: true
comment: Loop over circle_meta; clean data definition; no fake UI
- id: CQ-05
name: Output & API
score: 1
max: 1
passed: true
comment: Saves plot-{THEME}.png (scale=3) and plot-{THEME}.html
library_mastery:
score: 7
max: 10
items:
- id: LM-01
name: Idiomatic Usage
score: 4
max: 5
passed: true
comment: Correct ggplot grammar; coord_fixed; theme_void + theme layering;
geom_polygon/geom_text
- id: LM-02
name: Distinctive Features
score: 3
max: 5
passed: true
comment: HTML export; LetsPlot.setup_html(); ggsize with scale=3; coord_fixed
verdict: APPROVED
impl_tags:
dependencies: []
techniques:
- layer-composition
- html-export
- annotations
patterns:
- data-generation
- iteration-over-groups
dataprep: []
styling:
- minimal-chrome
- alpha-blending
strengths: []
weaknesses: []