diff --git a/plots/radar-basic/implementations/python/seaborn.py b/plots/radar-basic/implementations/python/seaborn.py index 1ef53dc2fa..416224458a 100644 --- a/plots/radar-basic/implementations/python/seaborn.py +++ b/plots/radar-basic/implementations/python/seaborn.py @@ -1,13 +1,14 @@ """ anyplot.ai radar-basic: Basic Radar Chart -Library: seaborn 0.13.2 | Python 3.13.13 -Quality: 86/100 | Updated: 2026-04-29 +Library: seaborn 0.13.2 | Python 3.13.14 +Quality: 90/100 | Updated: 2026-07-24 """ import os import matplotlib.pyplot as plt import numpy as np +import pandas as pd import seaborn as sns @@ -37,54 +38,57 @@ }, ) -# Data - Employee performance comparison across competencies -categories = ["Communication", "Technical Skills", "Teamwork", "Leadership", "Problem Solving", "Creativity"] -employee_a_values = [85, 90, 75, 70, 88, 82] # Senior Developer -employee_b_values = [78, 65, 92, 85, 72, 75] # Team Lead +# Data - product attribute comparison (0-100 scale, higher is better on every axis) +categories = ["Price", "Quality", "Durability", "Usability", "Design", "Warranty"] +budget_values = [90, 60, 65, 75, 55, 60] # Budget Model +premium_values = [45, 92, 85, 80, 90, 88] # Premium Model n_vars = len(categories) angles = np.linspace(0, 2 * np.pi, n_vars, endpoint=False).tolist() angles += angles[:1] # Close the polygon -employee_a = employee_a_values + employee_a_values[:1] -employee_b = employee_b_values + employee_b_values[:1] +budget_closed = budget_values + budget_values[:1] +premium_closed = premium_values + premium_values[:1] -# Plot - square canvas for symmetric radar chart (3600x3600 at 300 dpi) -fig, ax = plt.subplots(figsize=(12, 12), subplot_kw={"projection": "polar"}, facecolor=PAGE_BG) -ax.set_facecolor(PAGE_BG) +color_budget = IMPRINT[0] # #009E73 - Budget Model (first series) +color_premium = IMPRINT[1] # #C475FD - Premium Model -color_a = IMPRINT[0] # #009E73 - Senior Developer (first series) -color_b = IMPRINT[1] # #C475FD - Team Lead +# Plot - square canvas for symmetric radar chart (2400x2400 at 400 dpi) +fig = plt.figure(figsize=(6, 6), dpi=400, facecolor=PAGE_BG) +grid = fig.add_gridspec(2, 1, height_ratios=[2.3, 1], hspace=0.4) +ax_radar = fig.add_subplot(grid[0], projection="polar") +ax_bar = fig.add_subplot(grid[1]) +ax_radar.set_facecolor(PAGE_BG) +ax_bar.set_facecolor(PAGE_BG) -ax.fill(angles, employee_a, alpha=0.25, color=color_a) -ax.plot(angles, employee_a, color=color_a, linewidth=3.5, label="Senior Developer") -ax.scatter(angles[:-1], employee_a_values, color=color_a, s=150, zorder=5) +ax_radar.set_theta_offset(np.pi / 2) +ax_radar.set_theta_direction(-1) -ax.fill(angles, employee_b, alpha=0.25, color=color_b) -ax.plot(angles, employee_b, color=color_b, linewidth=3.5, label="Team Lead") -ax.scatter(angles[:-1], employee_b_values, color=color_b, s=150, zorder=5) +ax_radar.fill(angles, budget_closed, alpha=0.25, color=color_budget) +ax_radar.plot(angles, budget_closed, color=color_budget, linewidth=3, label="Budget Model") +ax_radar.scatter(angles[:-1], budget_values, color=color_budget, s=60, zorder=5) -# Style axes -ax.set_xticks(angles[:-1]) -ax.set_xticklabels(categories, fontsize=20, color=INK, fontweight="medium") -ax.set_ylim(0, 100) -ax.set_yticks([20, 40, 60, 80, 100]) -ax.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=16, color=INK_SOFT) +ax_radar.fill(angles, premium_closed, alpha=0.25, color=color_premium) +ax_radar.plot(angles, premium_closed, color=color_premium, linewidth=3, label="Premium Model") +ax_radar.scatter(angles[:-1], premium_values, color=color_premium, s=60, zorder=5) -# Grid and spines -grid_alpha = 0.20 if THEME == "light" else 0.25 -ax.grid(True, alpha=grid_alpha, linestyle="-", linewidth=1.2, color=INK_SOFT) -ax.spines["polar"].set_color(INK_SOFT) -ax.spines["polar"].set_alpha(0.4) +# Style radar axes +ax_radar.set_xticks(angles[:-1]) +ax_radar.set_xticklabels(categories, fontsize=10, color=INK, fontweight="medium") +ax_radar.set_ylim(0, 100) +ax_radar.set_yticks([20, 40, 60, 80, 100]) +ax_radar.set_yticklabels(["20", "40", "60", "80", "100"], fontsize=8, color=INK_SOFT) +ax_radar.set_rlabel_position(180 / n_vars) # move radial ticks into a gap between two spokes -# Title -ax.set_title("radar-basic · seaborn · anyplot.ai", fontsize=26, fontweight="medium", color=INK, pad=40) +grid_alpha = 0.20 if THEME == "light" else 0.25 +ax_radar.grid(True, alpha=grid_alpha, linestyle="-", linewidth=1, color=INK_SOFT) +ax_radar.spines["polar"].set_color(INK_SOFT) +ax_radar.spines["polar"].set_alpha(0.4) -# Legend -legend = ax.legend( +legend = ax_radar.legend( loc="upper right", - bbox_to_anchor=(1.35, 1.15), - fontsize=18, + bbox_to_anchor=(1.32, 1.15), + fontsize=8, framealpha=0.95, facecolor=ELEVATED_BG, edgecolor=INK_SOFT, @@ -92,5 +96,27 @@ for text in legend.get_texts(): text.set_color(INK) +# Companion score breakdown - grouped horizontal bars via seaborn's high-level API +scores = pd.DataFrame( + { + "category": categories * 2, + "value": budget_values + premium_values, + "product": ["Budget Model"] * n_vars + ["Premium Model"] * n_vars, + } +) +sns.barplot( + data=scores, x="value", y="category", hue="product", palette=[color_budget, color_premium], legend=False, ax=ax_bar +) +ax_bar.set_xlabel("Score", fontsize=10, color=INK) +ax_bar.set_ylabel("") +ax_bar.tick_params(axis="both", labelsize=8, colors=INK_SOFT) +ax_bar.set_xlim(0, 100) +ax_bar.xaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK_SOFT) +ax_bar.set_axisbelow(True) +sns.despine(ax=ax_bar) + +# Title +fig.suptitle("radar-basic · python · seaborn · anyplot.ai", fontsize=12, fontweight="medium", color=INK, y=0.97) + # Save -plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG) +plt.savefig(f"plot-{THEME}.png", dpi=400, facecolor=PAGE_BG) diff --git a/plots/radar-basic/metadata/python/seaborn.yaml b/plots/radar-basic/metadata/python/seaborn.yaml index 197903d650..c0d050fef6 100644 --- a/plots/radar-basic/metadata/python/seaborn.yaml +++ b/plots/radar-basic/metadata/python/seaborn.yaml @@ -2,54 +2,51 @@ library: seaborn language: python specification_id: radar-basic created: '2025-12-23T18:32:28Z' -updated: '2026-04-29T17:04:27Z' +updated: '2026-07-24T16:05:44Z' generated_by: claude-sonnet -workflow_run: 25121287681 +workflow_run: 30107103649 issue: 744 -python_version: 3.13.13 +language_version: 3.13.14 library_version: 0.13.2 preview_url_light: https://storage.googleapis.com/anyplot-images/plots/radar-basic/python/seaborn/plot-light.png preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/radar-basic/python/seaborn/plot-dark.png preview_html_light: null preview_html_dark: null -quality_score: 86 +quality_score: 90 review: strengths: - - 'Perfect spec compliance: all required radar chart features (filled polygons, - gridlines, polygon closure, multi-series legend) present and correct' - - 'Excellent data quality: contrasting employee profiles (Senior Developer vs Team - Lead) create a natural, informative narrative ideal for radar charts' - - 'Full theme adaptation: both light and dark renders pass all chrome checks — backgrounds - are #FAF8F1 / #1A1A17, text flips correctly, data colors stay constant' - - 'Correct Okabe-Ito palette with #009E73 as first series and #D55E00 as second' - - Clean KISS code structure with explicitly set font sizes at all levels (title=26pt, - axes=20pt, ticks=16pt, legend=18pt) + - Two-panel composition (radar dominant + companion bar ranking) reinforces the + comparison without diluting the primary radar chart type + - Correct closed-polygon geometry, alpha=0.25 fills, and canonical Imprint palette + order (#009E73 first) + - Clean theme-adaptive chrome - both light and dark renders fully legible, data + colors identical across themes + - Deterministic, realistic budget-vs-premium product dataset weaknesses: - - 'Code/image discrepancy: current seaborn.py only implements the radar chart but - plot_images/ show a combined radar+bar chart with different data values — images - appear to be from a previous run and should be regenerated' - - Library mastery is limited because seaborn's high-level plotting API (sns.barplot, - etc.) is not used for the primary visualization — radar charts require matplotlib's - polar projection directly, so seaborn contributes mainly via sns.set_theme() - - Radial tick labels (20/40/60/80/100) are rendered inside the radar near gridlines, - making them slightly hard to read — repositioning with ax.set_rlabel_position() - to an uncluttered angle would improve legibility + - Radial tick labels (20/40/60/80/100), positioned via set_rlabel_position(180/n_vars) + in the Price-Quality gap, sit close to the Budget Model's descending polygon edge + in that gap - nudge further into the gap or reduce label opacity slightly to fully + clear the line + - Markers (s=60) could be sized slightly larger (e.g. 70-80) given the generous + square canvas and only 6 points per series + - Companion bar chart repeats the same six category labels already shown on the + radar spokes - a reasonable trade-off for numeric-ranking clarity, but adds some + label redundancy image_description: |- Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) — correct, not pure white. - Chrome: Title "radar-basic · seaborn · anyplot.ai" in dark ink — readable. Spoke labels (Communication, Technical Skills, Teamwork, Leadership, Problem Solving, Creativity) in dark ink around perimeter — readable. Radial tick labels (20/40/60/80/100) in INK_SOFT grey — readable though close to gridlines. Legend frame uses ELEVATED_BG (#FFFDF6) — readable. - Data: First series (Senior Developer) = #009E73 (brand green) ✓. Second series (Team Lead) = #D55E00 (vermillion, Okabe-Ito position 2) ✓. Both series rendered as filled transparent polygons (alpha=0.25) with thick lines (3.5) and scatter markers. A companion horizontal bar chart ("Score Breakdown") appears on the right half of the canvas. - Note: Bar chart data values in the image (e.g. Creativity=92 for Senior Developer) differ from current seaborn.py (Creativity=82). Images appear to be from a previous render. + Background: Warm off-white, consistent with #FAF8F1. + Chrome: Title "radar-basic · python · seaborn · anyplot.ai" in dark ink, fully readable. Radar axis category labels (Price, Quality, Durability, Usability, Design, Warranty) in dark ink at outer edge. Radial tick labels (20/40/60/80/100) in soft gray, legend box top-right with dark text on elevated cream background. Bar chart tick labels and "Score" axis label dark/soft-gray, all readable. + Data: Budget Model in #009E73 (green), Premium Model in #C475FD (violet), filled polygons alpha~0.25, closed. Bar chart uses identical colors. Legibility verdict: PASS Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17) — correct, not pure black. - Chrome: Title and all labels rendered in light ink (#F0EFE8-ish) — clearly readable against the dark background. No dark-on-dark failures observed. Grid lines are subtle and visible. Legend frame uses ELEVATED_BG (#242420) dark elevated surface — correct. - Data: Data colors are identical to the light render — Senior Developer is still #009E73 (green) and Team Lead is still #D55E00 (orange). Only chrome flips between themes. Brand green #009E73 is clearly visible on the dark background. + Background: Warm near-black, consistent with #1A1A17. + Chrome: Title, axis category labels, and legend text in light ink - clearly visible. Radial tick labels and bar-axis labels in lighter soft gray. No dark-on-dark issues found. + Data: Same #009E73 green and #C475FD violet as light render, confirmed identical across themes. Legibility verdict: PASS criteria_checklist: visual_quality: - score: 28 + score: 27 max: 30 items: - id: VQ-01 @@ -57,78 +54,71 @@ review: score: 7 max: 8 passed: true - comment: 'All font sizes explicitly set (title=26pt, axes=20pt, ticks=16pt, - legend=18pt). Minor deduction: radial tick labels sit close to gridlines - inside the radar.' + comment: Explicit font sizes throughout, all readable in both themes; radial + tick labels slightly small but legible - id: VQ-02 name: No Overlap - score: 6 + score: 5 max: 6 passed: true - comment: Spoke labels well-distributed around perimeter; no text collisions. + comment: Radial tick labels sit close to Budget Model's descending edge between + Price and Quality spokes - borderline soft overlap - id: VQ-03 name: Element Visibility - score: 6 + score: 5 max: 6 passed: true - comment: Filled polygons (alpha=0.25), linewidth=3.5, s=150 markers — all - clearly visible and well-adapted. + comment: Markers (s=60) and linewidth=3 adequate for sparse 6-point series; + could be slightly larger - id: VQ-04 name: Color Accessibility score: 2 max: 2 passed: true - comment: '#009E73 and #D55E00 have strong luminance contrast; both CVD-safe - Okabe-Ito colours.' + comment: Green/violet pairing avoids red-green confusion axis - id: VQ-05 name: Layout & Canvas - score: 3 + score: 4 max: 4 passed: true - comment: 12x12 square canvas appropriate for radar; corners naturally empty - but overall canvas well-utilised. + comment: Square canvas correct for symmetric radar, gate passed, no cutoff - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: Title follows 'radar-basic · seaborn · anyplot.ai' format; spoke - labels are descriptive category names. + comment: Mandated title format correct, axis categories labeled at outer edge - id: VQ-07 name: Palette Compliance score: 2 max: 2 passed: true - comment: 'First series #009E73 ✓; second #D55E00 (Okabe-Ito pos 2) ✓; backgrounds - #FAF8F1 / #1A1A17 ✓; chrome correctly adapts in both renders ✓.' + comment: 'First series #009E73, second #C475FD, backgrounds correct in both + themes' design_excellence: - score: 13 + score: 15 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 6 max: 8 passed: true - comment: Dual-panel layout (radar + bar chart in rendered images) shows design - thought above defaults. Filled polygons with scatter markers add visual - interest. Not FiveThirtyEight-level but above well-configured default. + comment: Custom rc theme, intentional radar+bar hierarchy, Imprint-consistent + palette - id: DE-02 name: Visual Refinement score: 4 max: 6 passed: true - comment: Grid alpha tuned per theme (0.20 light / 0.25 dark); polar spine - opacity controlled (alpha=0.4); legend placed outside with frame. Good attention - to detail. + comment: Bar panel despined, subtle grid; polar spine only lightly softened - id: DE-03 name: Data Storytelling - score: 4 + score: 5 max: 6 passed: true - comment: Contrasting profiles (tech-strong vs leadership-strong) create a - clear narrative. Dual-panel in rendered images strengthens this by showing - both shape and precise values. + comment: Companion bar chart gives direct numeric ranking alongside radar's + holistic shape comparison spec_compliance: score: 15 max: 15 @@ -138,28 +128,26 @@ review: score: 5 max: 5 passed: true - comment: Correct radar/spider chart using polar projection with filled polygons. + comment: Radar/spider chart dominant, correctly implemented via polar projection - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Filled polygons (alpha=0.25), gridlines at 20/40/60/80/100, axis - labels at outer edge, distinct colours, polygon closure, legend — all present. + comment: Filled polygons alpha~0.25, gridlines at 20/40/60/80/100, axis labels + at outer edge, legend, closed polygon - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: Six axes via np.linspace; 0-100 scale; both series plotted with full - data. + comment: Categories on axes, 0-100 scale, all axes shown - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title exactly 'radar-basic · seaborn · anyplot.ai'; legend labels - 'Senior Developer' and 'Team Lead' match data. + comment: Title matches mandated format; legend labels match data data_quality: score: 15 max: 15 @@ -169,22 +157,20 @@ review: score: 6 max: 6 passed: true - comment: Two series with meaningfully different profiles demonstrate radar - chart's core purpose. + comment: Multi-series, gridlines, closed polygons, distinct colors, legend + all present - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Employee performance comparison is a canonical real-world radar chart - use case; neutral business domain. + comment: Plausible, neutral budget-vs-premium product scenario - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: All values 65-92 on 0-100 scale; plausible for senior developer vs - team lead contrast. + comment: 0-100 scale as recommended by spec code_quality: score: 10 max: 10 @@ -194,60 +180,56 @@ review: score: 3 max: 3 passed: true - comment: 'Linear flow: imports → theme tokens → data → plot → style → save. - No functions or classes.' + comment: Flat script, no functions/classes - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: Fully deterministic hardcoded data; no random seed needed. + comment: Fully deterministic hardcoded data - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: os, matplotlib.pyplot, numpy, seaborn — all four used. + comment: All imports (os, plt, numpy, pandas, seaborn) used - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean and Pythonic. Polygon closure via list concatenation is idiomatic. - No fake functionality. + comment: Appropriate complexity, no fake UI - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot-{THEME}.png with bbox_inches='tight' and explicit facecolor. + comment: Saves plot-{THEME}.png, no bbox_inches='tight', current API library_mastery: - score: 5 + score: 8 max: 10 items: - id: LM-01 name: Idiomatic Usage - score: 3 + score: 4 max: 5 passed: true - comment: sns.set_theme() with full rc dict is correct seaborn theming. Radar - chart rendered via matplotlib polar projection (only option — seaborn has - no radar function), limiting high-level API usage. + comment: Matplotlib polar projection (seaborn has no radar geom) + seaborn + high-level API for companion panel - id: LM-02 name: Distinctive Features - score: 2 + score: 4 max: 5 - passed: false - comment: Bar chart in rendered images suggests seaborn barplot was used in - the version that generated the images. Current code's seaborn contribution - is primarily sns.set_theme() styling. + passed: true + comment: sns.barplot(hue, palette) + sns.despine combination alongside polar + companion verdict: APPROVED impl_tags: dependencies: [] techniques: - polar-projection - manual-ticks - - custom-legend + - subplots patterns: - explicit-figure dataprep: [] diff --git a/prompts/workflow-prompts/impl-generate-claude.md b/prompts/workflow-prompts/impl-generate-claude.md index 8354225f47..7cb9ef013f 100644 --- a/prompts/workflow-prompts/impl-generate-claude.md +++ b/prompts/workflow-prompts/impl-generate-claude.md @@ -167,10 +167,12 @@ Run the implementation **twice**, once per theme. ```bash source .venv/bin/activate cd plots/{SPEC_ID}/implementations/{LANGUAGE} -MPLBACKEND=Agg ANYPLOT_THEME=light python {LIBRARY}.py -MPLBACKEND=Agg ANYPLOT_THEME=dark python {LIBRARY}.py +MPLBACKEND=Agg ANYPLOT_THEME=light python -P {LIBRARY}.py +MPLBACKEND=Agg ANYPLOT_THEME=dark python -P {LIBRARY}.py ``` +> **Why `-P`:** this directory contains one file per library (`matplotlib.py`, `seaborn.py`, `plotly.py`, …). Without `-P` (Python 3.11+ "safe path" flag), Python prepends the script's own directory to `sys.path`, so `import matplotlib.pyplot` inside e.g. `seaborn.py` resolves to the sibling `matplotlib.py` file instead of the real installed package — a `ModuleNotFoundError: 'matplotlib' is not a package` that has nothing to do with your code. `-P` skips that prepend so the real site-packages import wins. + **R (`LANGUAGE=r`)**: ```bash cd plots/{SPEC_ID}/implementations/{LANGUAGE}