From 48c8eb694f3d84ffe81ddc674d6fa7559650b85c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 07:10:14 +0000 Subject: [PATCH 1/5] feat(pygal): implement swarm-basic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 80. Addressed: - Canvas size: 4800x2700 (historical, off-contract) -> 3200x1800 (canonical landscape) - Missing language token in title -> "swarm-basic · python · pygal · anyplot.ai" - Font sizes rescaled to the canonical 3200x1800 pygal table (title=66, label=56, major_label=44, legend=44) - Added subtle Group Mean markers per category (spec explicitly recommends this; previous attempt had removed them) using the theme-adaptive neutral anchor color - Tightened right-side margin to reduce wasted whitespace Kept: custom beeswarm overlap-avoidance algorithm, Imprint palette in canonical order, dual PNG/HTML output, employee-performance-by-department scenario. --- .../implementations/python/pygal.py | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/plots/swarm-basic/implementations/python/pygal.py b/plots/swarm-basic/implementations/python/pygal.py index 2ab09c9660..2a9e2528a1 100644 --- a/plots/swarm-basic/implementations/python/pygal.py +++ b/plots/swarm-basic/implementations/python/pygal.py @@ -1,7 +1,7 @@ -""" anyplot.ai +"""anyplot.ai swarm-basic: Basic Swarm Plot Library: pygal 3.1.0 | Python 3.13.13 -Quality: 80/100 | Updated: 2026-05-05 +Quality: pending | Updated: 2026-07-26 """ import os @@ -11,15 +11,15 @@ from pygal.style import Style -# Theme tokens +# Theme tokens (see prompts/default-style-guide.md "Theme-adaptive Chrome") THEME = os.getenv("ANYPLOT_THEME", "light") PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" INK = "#1A1A17" if THEME == "light" else "#F0EFE8" INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" -IMPRINT = ("#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030", "#2ABCCD", "#954477") +IMPRINT_PALETTE = ("#009E73", "#C475FD", "#4467A3", "#BD8233") -# Data - Employee performance scores by department +# Data - employee performance scores by department np.random.seed(42) categories = ["Engineering", "Marketing", "Sales", "Operations"] data = { @@ -29,40 +29,42 @@ "Operations": np.random.normal(70, 10, 55), } -# Style +# Style - source-pixel sizes for a 3200x1800 canvas (see prompts/library/pygal.md) custom_style = Style( background=PAGE_BG, plot_background=PAGE_BG, foreground=INK, foreground_strong=INK, foreground_subtle=INK_MUTED, - colors=IMPRINT, - title_font_size=72, - label_font_size=48, - major_label_font_size=42, - legend_font_size=42, - tooltip_font_size=36, - opacity=0.85, + colors=IMPRINT_PALETTE + (INK,), # last color reserved for the Group Mean marker + title_font_size=66, + label_font_size=56, + major_label_font_size=44, + legend_font_size=44, + value_font_size=36, + opacity=0.75, opacity_hover=1.0, + stroke_width=2.5, ) # Plot chart = pygal.XY( - width=4800, - height=2700, + width=3200, + height=1800, style=custom_style, - title="swarm-basic · pygal · anyplot.ai", + title="swarm-basic · python · pygal · anyplot.ai", x_title="Department", y_title="Performance Score", show_legend=True, legend_at_bottom=True, stroke=False, - dots_size=12, + dots_size=10, show_x_guides=False, show_y_guides=True, xrange=(0, 5), range=(40, 115), - margin=50, + margin=40, + margin_right=20, ) # Beeswarm algorithm - spreads points horizontally to avoid overlap @@ -105,6 +107,10 @@ chart.add(category, swarm_points) +# Group mean markers - subtle reference points per category (neutral anchor color) +mean_points = [(cat_idx + 1, float(np.mean(values))) for cat_idx, (_, values) in enumerate(data.items())] +chart.add("Group Mean", mean_points, dots_size=20) + # x-axis category labels chart.x_labels = ["", "Engineering", "Marketing", "Sales", "Operations", ""] From 2525f89ece6b672d9406ed32ebefd835751e2eb4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 07:10:23 +0000 Subject: [PATCH 2/5] chore(pygal): add metadata for swarm-basic --- plots/swarm-basic/metadata/python/pygal.yaml | 275 +------------------ 1 file changed, 10 insertions(+), 265 deletions(-) diff --git a/plots/swarm-basic/metadata/python/pygal.yaml b/plots/swarm-basic/metadata/python/pygal.yaml index 6b8fa4c39d..33b47ac853 100644 --- a/plots/swarm-basic/metadata/python/pygal.yaml +++ b/plots/swarm-basic/metadata/python/pygal.yaml @@ -1,276 +1,21 @@ +# Per-library metadata for pygal implementation of swarm-basic +# Auto-generated by impl-generate.yml + library: pygal language: python specification_id: swarm-basic created: '2025-12-23T21:54:47Z' -updated: '2026-05-05T01:30:01Z' +updated: '2026-07-26T07:10:23Z' generated_by: claude-sonnet -workflow_run: 25352188638 +workflow_run: 30192192064 issue: 974 -python_version: 3.13.13 -library_version: 3.1.0 +language_version: 3.13.14 +library_version: 3.1.3 preview_url_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-light.png preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.html -quality_score: 80 +quality_score: null review: - strengths: - - Custom beeswarm algorithm correctly spreads points horizontally using a grid-based - overlap-avoidance strategy - - Correct Okabe-Ito palette in canonical order with brand green (#009E73) as first - series (Engineering) - - All font sizes explicitly set with large values (title=72, labels=48, ticks=42) - for high-resolution canvas - - 'Proper dual output: plot-{THEME}.png and plot-{THEME}.html leveraging pygal''s - interactive capabilities' - - Both light (#FAF8F1) and dark (#1A1A17) themes correctly implemented with full - theme-adaptive chrome - - 'Realistic and neutral domain: employee performance scores by department with - plausible distributions' - - KISS code structure with flat top-level flow; np.random.seed(42) ensures reproducibility - - x-guides disabled, y-guides enabled — appropriate grid choice for a value-axis - chart - weaknesses: - - Mean/median markers per category removed compared to previous attempt — spec explicitly - recommends 'consider adding a subtle mean or median marker for each category'; - their absence is a missed opportunity for data storytelling - - 'Design excellence is limited: no spine removal or chart frame control (pygal''s - default frame remains), limited visual refinement beyond correct colors' - - 'DE-03 data storytelling is weak: all four department distributions are similarly - shaped (normal distributions with slightly different parameters); no focal point - or visual emphasis guides the viewer to an insight' - - Legend at bottom shows department labels but loses the Sales label in the rendered - images (may be a pygal layout/ordering issue) — verify legend ordering matches - data series order - - 'Canvas utilization: some wasted whitespace on the right side of the plot area' - - 'No opacity/alpha tuning per category density: the `opacity=0.85` is global, not - density-adaptive; Sales (40 pts) and Operations (55 pts) have different densities - but same alpha' - image_description: |- - Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) — clearly not pure white, correct theme surface. - Chrome: Title "swarm-basic · pygal · anyplot.ai" is clearly readable in dark ink at the top. Y-axis label "Performance Score" and x-axis label "Department" are visible. Tick labels (40–100 on Y, category names on X) are readable against the light background. All text passes legibility check. - Data: Four colored series — Engineering (#009E73 brand green), Marketing (#D55E00 vermillion), Sales (#0072B2 blue), Operations (#CC79A7 reddish-purple) — in correct Okabe-Ito canonical order. Individual dots are spread horizontally within each category column via the custom beeswarm algorithm. Some dark markers visible at ~y=75 (Marketing) and ~y=71 (Operations) that appear to be Group Mean residuals from a previous implementation run (the current code does not add a Group Mean series). - Legend: Bottom legend shows department labels; legend includes "Group Mean" which does not match the current code — images may reflect a previous implementation run. - Legibility verdict: PASS — all chrome text is readable against the warm off-white background. - - Dark render (plot-dark.png): - Background: Near-black (#1A1A17) — correctly dark, warm near-black, not pure black. - Chrome: Title and axis labels appear in light/white text, clearly visible against the dark background. Tick labels are also light-colored. No dark-on-dark failure detected. Grid lines are subtle dotted horizontal rules. - Data: Data colors are identical to the light render — Engineering green, Marketing vermillion, Sales blue, Operations pink — confirming Okabe-Ito positions 1–4 are theme-invariant. Same white/light residual markers at mean positions visible (from previous implementation). - Legibility verdict: PASS — all text is light-colored on dark background, fully readable. No dark-on-dark failures. - criteria_checklist: - visual_quality: - score: 26 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 7 - max: 8 - passed: true - comment: All font sizes explicitly set (title=72, label=48, major_label=42, - legend=42) — readable in both themes. Minor deduction as the axis label - could be slightly larger for full 4800px canvas impact. - - id: VQ-02 - name: No Overlap - score: 5 - max: 6 - passed: true - comment: Custom beeswarm algorithm successfully prevents most overlap. Minor - crowding in Operations cluster (55 points) but no unreadable stacking. - - id: VQ-03 - name: Element Visibility - score: 5 - max: 6 - passed: true - comment: dots_size=12 is appropriate. Points are clearly visible. Could be - slightly larger for the 4800px canvas but acceptable. - - id: VQ-04 - name: Color Accessibility - score: 2 - max: 2 - passed: true - comment: Okabe-Ito palette is CVD-safe. All four series distinguishable by - hue without relying solely on red/green. - - id: VQ-05 - name: Layout & Canvas - score: 3 - max: 4 - passed: true - comment: Plot area is well-utilized. Some wasted whitespace on the right edge - of the chart. Bottom legend is appropriately placed. - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: 'X: ''Department'', Y: ''Performance Score'' — descriptive and contextually - clear.' - - id: VQ-07 - name: Palette Compliance - score: 2 - max: 2 - passed: true - comment: 'First series (#009E73) is brand green. Okabe-Ito canonical order - maintained. Light background #FAF8F1, dark background #1A1A17. Both renders - are theme-correct with adaptive chrome.' - design_excellence: - score: 10 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 4 - max: 8 - passed: false - comment: Well-configured pygal defaults. Correct colors and clean layout. - Custom beeswarm logic adds sophistication. No exceptional typography or - hierarchy beyond library defaults. - - id: DE-02 - name: Visual Refinement - score: 3 - max: 6 - passed: false - comment: x-guides disabled, y-guides enabled — a good design choice. opacity=0.85 - adds subtle refinement. However, pygal's default frame/border remains; no - spine removal equivalent. - - id: DE-03 - name: Data Storytelling - score: 3 - max: 6 - passed: false - comment: Four departments with visibly different distributions (Engineering - highest, Operations lowest). Some story is apparent. However, no emphasis, - focal point, or mean markers to guide the viewer to the key insight. - spec_compliance: - score: 13 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct swarm/beeswarm plot type implemented with custom horizontal - spread algorithm via pygal.XY. - - id: SC-02 - name: Required Features - score: 3 - max: 4 - passed: true - comment: 'Individual data points shown, horizontal spread to avoid overlap, - color distinguishes categories, clear category grouping. Missing: mean/median - markers per group (spec says ''consider adding a subtle mean or median marker'').' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: 'X-axis: categorical departments. Y-axis: performance score values. - Correct mapping.' - - id: SC-04 - name: Title & Legend - score: 2 - max: 3 - passed: true - comment: Title 'swarm-basic · pygal · anyplot.ai' is correctly formatted. - Legend shows department categories. Images show a 'Group Mean' legend entry - not present in current code — possible image from previous run; legend ordering/completeness - issue flagged. - data_quality: - score: 14 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 5 - max: 6 - passed: true - comment: 'Shows individual points, distributional spread, category differences. - Engineering highest/tightest, Marketing widest spread, Sales most spread, - Operations lowest. Good variation. Minor: all distributions are symmetric - normal; no skewed/bimodal to fully show swarm plot power.' - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Employee performance scores by department — real-world business context, - neutral and non-controversial. - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: Scores 40-100 across departments with realistic means (Engineering - ~82, Marketing ~75, Sales ~78, Operations ~70) and appropriate standard - deviations. - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: 'Flat top-level flow: imports → tokens → data → style → chart config - → beeswarm loop → output.' - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: np.random.seed(42) ensures deterministic data generation. - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: Only os, numpy, pygal, and pygal.style.Style — all used. - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Beeswarm loop complexity is justified by the plot type. No fake UI - elements. Pythonic structure. - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves plot-{THEME}.png via render_to_png and plot-{THEME}.html via - render(). Correct pygal API. - library_mastery: - score: 7 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 4 - max: 5 - passed: true - comment: Uses pygal.XY with Style object correctly. Theme tokens passed through - Style. Dual PNG/HTML output. Creative use of XY chart type for swarm simulation. - - id: LM-02 - name: Distinctive Features - score: 3 - max: 5 - passed: true - comment: HTML interactive output is a distinctive pygal feature leveraged - here. opacity_hover=1.0 uses pygal's hover state. Custom beeswarm via XY - offsets is a clever library-specific pattern. - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - html-export - - hover-tooltips - patterns: - - data-generation - - iteration-over-groups - dataprep: [] - styling: - - alpha-blending + strengths: [] + weaknesses: [] From dd7ce56cedbbbbbc2e3df8e250ac4b7bebdb39bc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 07:15:27 +0000 Subject: [PATCH 3/5] chore(pygal): update quality score 75 and review feedback for swarm-basic --- .../implementations/python/pygal.py | 6 +- plots/swarm-basic/metadata/python/pygal.yaml | 258 +++++++++++++++++- 2 files changed, 254 insertions(+), 10 deletions(-) diff --git a/plots/swarm-basic/implementations/python/pygal.py b/plots/swarm-basic/implementations/python/pygal.py index 2a9e2528a1..5e5507fe18 100644 --- a/plots/swarm-basic/implementations/python/pygal.py +++ b/plots/swarm-basic/implementations/python/pygal.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai swarm-basic: Basic Swarm Plot -Library: pygal 3.1.0 | Python 3.13.13 -Quality: pending | Updated: 2026-07-26 +Library: pygal 3.1.3 | Python 3.13.14 +Quality: 75/100 | Updated: 2026-07-26 """ import os diff --git a/plots/swarm-basic/metadata/python/pygal.yaml b/plots/swarm-basic/metadata/python/pygal.yaml index 33b47ac853..e6d977651d 100644 --- a/plots/swarm-basic/metadata/python/pygal.yaml +++ b/plots/swarm-basic/metadata/python/pygal.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for pygal implementation of swarm-basic -# Auto-generated by impl-generate.yml - library: pygal language: python specification_id: swarm-basic created: '2025-12-23T21:54:47Z' -updated: '2026-07-26T07:10:23Z' +updated: '2026-07-26T07:15:27Z' generated_by: claude-sonnet workflow_run: 30192192064 issue: 974 @@ -15,7 +12,254 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/swarm-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.html -quality_score: null +quality_score: 75 review: - strengths: [] - weaknesses: [] + strengths: + - 'Imprint palette applied correctly: Engineering=#009E73 (first series, brand green) + through to Operations=#BD8233 in canonical order, identical across both themes.' + - 'Theme tokens threaded through consistently — PAGE_BG/INK/INK_MUTED flip correctly + between #FAF8F1/#1A1A17 renders with no dark-on-dark or light-on-light text.' + - Group Mean markers per department are a thoughtful addition that directly satisfies + the spec's 'consider adding a subtle mean/median marker' note and give the plot + a clear comparative focal point. + - Canvas is exactly 3200x1800 with no clipped text at any edge; title, axis titles, + and legend are all fully visible. + - Deterministic data generation via np.random.seed(42); clean imports; correct plot-{theme}.png/.html + output contract for an interactive library. + weaknesses: + - 'Beeswarm collision detection is scaled wrong: point_radius=0.1 and spacing=0.05 + are compared directly against raw y-values, but the value axis spans ~75 units + (range=(40,115)) while a rendered dot (dots_size=10) is roughly 1-1.5 data-units + tall. Because the overlap threshold (2*point_radius+spacing = 0.25) is far smaller + than the dot''s actual on-screen footprint, most points that are visually touching + are never flagged as overlapping and stay at center_x, producing a dense solid-looking + vertical strip (e.g. the Sales column) instead of a fanned beeswarm. Fix by deriving + point_radius/spacing from the actual y-range/dot size (e.g. normalize y to [0,1] + using the chart''s `range` before running the collision loop, or scale point_radius + ~ (range span) * (dots_size in px / plot height in px)).' + - Because of the collision-scale bug, the plot under-delivers on the spec's core + promise ('points spread horizontally to avoid overlap' / 'reveals the full distribution + shape') — large portions of each category render as a single dense column rather + than a true swarm shape. + - Some synthetic performance scores exceed 100 (e.g. ~106-115 in Sales) which reads + oddly for a 'Performance Score' metric typically bounded 0-100 — either clamp/tighten + the normal distribution parameters or make the scale explicit if scores >100 are + intentional. + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (~#FAF8F1), matches the light chrome token. + Chrome: Title "swarm-basic · python · pygal · anyplot.ai" is dark and fully legible; x_title "Department" and y_title "Performance Score" are dark and clear; y-axis tick labels (40-110) and x category labels (Engineering/Marketing/Sales/Operations) are dark and readable; subtle dashed horizontal gridlines are visible without dominating; bottom legend (4 category swatches + Group Mean) is fully legible. + Data: First series (Engineering) is #009E73 brand green, followed by Marketing (purple #C475FD), Sales (blue #4467A3), Operations (brown/amber #BD8233) — matches canonical Imprint order. Large black Group Mean dots sit at each category's average. Points within each category are NOT well spread horizontally — large stretches (especially Sales, mid-range Marketing/Operations) form a dense, mostly single-column vertical stack of touching/overlapping dots rather than a fanned swarm shape. + Legibility verdict: PASS (all text readable; the overlap issue is a data/algorithm quality problem, not a legibility one). + + Dark render (plot-dark.png): + Background: Warm near-black (~#1A1A17), matches the dark chrome token. + Chrome: Title, axis titles, tick labels, and legend are all rendered in light ink (#F0EFE8/#A8A79F tones) and are clearly legible against the dark background — no dark-on-dark failures observed. Gridlines remain subtle but visible. + Data: Same four category colors as the light render (green/purple/blue/brown), confirming Imprint palette identity across themes — only chrome (background, text, gridlines, Group Mean dot color which flips to a light ink tone) changed. Same overlap/clumping pattern as the light render, since it's a data-layout issue independent of theme. + Legibility verdict: PASS (all text readable in dark mode; same overlap weakness as light render). + criteria_checklist: + visual_quality: + score: 24 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: Title, axis titles, tick labels, and legend all clearly readable + in both themes; explicit font sizes throughout the Style object. + - id: VQ-02 + name: No Overlap + score: 3 + max: 6 + passed: false + comment: Beeswarm collision-detection scale mismatch (see weaknesses) leaves + large stretches of points stacked directly on top of each other, especially + in Sales and mid-range Marketing/Operations. + - id: VQ-03 + name: Element Visibility + score: 4 + max: 6 + passed: true + comment: Marker size (10) and opacity (0.75) are reasonable for the data density, + but dense overlapping clusters reduce individual-point distinguishability. + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Imprint palette colors are distinct and CVD-safe; no red-green sole + encoding. + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: Canvas exactly 3200x1800; no clipping; balanced margins; title proportion + expected for the mandated title length. + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: 'Descriptive: ''Department'' / ''Performance Score''.' + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, canonical multi-series order, correct theme + backgrounds, identical data colors across themes.' + design_excellence: + score: 11 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: false + comment: Custom palette and consistent typography, but overlap issue undercuts + overall polish. + - id: DE-02 + name: Visual Refinement + score: 3 + max: 6 + passed: false + comment: Subtle single-axis gridlines and generous margins, but no spine removal + beyond pygal defaults and dense clustering looks unrefined. + - id: DE-03 + name: Data Storytelling + score: 3 + max: 6 + passed: false + comment: Group Mean markers give a nice comparative focal point, but the muted + swarm spread undersells the distribution-shape story that swarm plots exist + to tell. + spec_compliance: + score: 13 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 4 + max: 5 + passed: true + comment: XY chart with manually computed swarm layout is the right approach + for pygal (no native swarm type), but execution partially fails to deliver + a true swarm shape. + - id: SC-02 + name: Required Features + score: 3 + max: 4 + passed: true + comment: Category axis, continuous value axis, color-by-category, and mean + markers all present; horizontal spread-to-avoid-overlap is only partially + achieved. + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: X = Department (categorical), Y = Performance Score (continuous), + all categories shown. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches required format exactly; legend labels match category + names. + data_quality: + score: 12 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 4 + max: 6 + passed: true + comment: Individual points, per-category color, and mean markers present, + but the full distribution shape is obscured where the swarm collapses into + a dense column. + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Employee performance scores by department is a plausible, neutral + scenario within the spec's suggested applications. + - id: DQ-03 + name: Appropriate Scale + score: 3 + max: 4 + passed: true + comment: Most values sit in a sensible 50-100 band, but a handful of points + exceed 100 (up to ~115), which reads oddly for a 'Performance Score'. + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: No functions/classes; flat procedural script. + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42) makes data generation deterministic. + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: Only os, numpy, pygal, pygal.style.Style — all used. + - id: CQ-04 + name: Code Elegance + score: 1 + max: 2 + passed: false + comment: The manual beeswarm collision loop has a units mismatch that prevents + it from doing what it's written to do (see weaknesses). + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Correct plot-{theme}.png + plot-{theme}.html output contract for + pygal. + library_mastery: + score: 6 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: pygal.XY with stroke=False and a fully customized Style object is + idiomatic given pygal has no native swarm chart type. + - id: LM-02 + name: Distinctive Features + score: 2 + max: 5 + passed: false + comment: Generates the interactive HTML export as expected but doesn't otherwise + showcase pygal-distinctive capabilities beyond standard Style/XY usage. + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: + - manual-ticks + - html-export + patterns: + - data-generation + - iteration-over-groups + dataprep: [] + styling: + - alpha-blending From 8939f709eceab610d8ce9b7f7d5f4432aebd8719 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 07:18:48 +0000 Subject: [PATCH 4/5] fix(pygal): address review feedback for swarm-basic Attempt 1/4 - fixes based on AI review --- .../implementations/python/pygal.py | 44 +++++++++++++------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/plots/swarm-basic/implementations/python/pygal.py b/plots/swarm-basic/implementations/python/pygal.py index 5e5507fe18..5d1efdfba4 100644 --- a/plots/swarm-basic/implementations/python/pygal.py +++ b/plots/swarm-basic/implementations/python/pygal.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai swarm-basic: Basic Swarm Plot Library: pygal 3.1.3 | Python 3.13.14 Quality: 75/100 | Updated: 2026-07-26 @@ -19,16 +19,20 @@ IMPRINT_PALETTE = ("#009E73", "#C475FD", "#4467A3", "#BD8233") -# Data - employee performance scores by department +# Data - employee performance scores by department (clamped to a plausible 0-100 scale) np.random.seed(42) categories = ["Engineering", "Marketing", "Sales", "Operations"] data = { - "Engineering": np.random.normal(82, 8, 45), - "Marketing": np.random.normal(75, 12, 50), - "Sales": np.random.normal(78, 15, 40), - "Operations": np.random.normal(70, 10, 55), + "Engineering": np.clip(np.random.normal(82, 7, 45), 0, 100), + "Marketing": np.clip(np.random.normal(75, 9, 50), 0, 100), + "Sales": np.clip(np.random.normal(78, 10, 40), 0, 100), + "Operations": np.clip(np.random.normal(70, 8, 55), 0, 100), } +all_values = np.concatenate(list(data.values())) +Y_MIN = 10 * np.floor(all_values.min() / 10) +Y_MAX = 10 * np.ceil(all_values.max() / 10) + # Style - source-pixel sizes for a 3200x1800 canvas (see prompts/library/pygal.md) custom_style = Style( background=PAGE_BG, @@ -62,16 +66,31 @@ show_x_guides=False, show_y_guides=True, xrange=(0, 5), - range=(40, 115), + range=(Y_MIN, Y_MAX), margin=40, margin_right=20, ) -# Beeswarm algorithm - spreads points horizontally to avoid overlap +# Beeswarm algorithm - spreads points horizontally to avoid overlap. +# Collision thresholds are derived per-axis from the actual rendered dot +# footprint (dots_size in px) against each axis's own data-unit-per-pixel +# scale, so a 10px dot compares correctly whether it's 0.03 x-units wide +# (category axis spans 5 units over ~2900 plot px) or ~0.6 y-units tall +# (value axis spans Y_MAX-Y_MIN over ~1270 plot px) - not one flat number +# for both axes. +PLOT_WIDTH_PX = 2900 +PLOT_HEIGHT_PX = 1270 +DOT_RADIUS_PX = 10 +SPACING_PX = 4 + +x_unit_per_px = 5 / PLOT_WIDTH_PX +y_unit_per_px = (Y_MAX - Y_MIN) / PLOT_HEIGHT_PX +min_dist_x = 2 * DOT_RADIUS_PX * x_unit_per_px + SPACING_PX * x_unit_per_px +min_dist_y = 2 * DOT_RADIUS_PX * y_unit_per_px + SPACING_PX * y_unit_per_px +step_x = DOT_RADIUS_PX * x_unit_per_px + SPACING_PX * x_unit_per_px / 2 + for cat_idx, (category, values) in enumerate(data.items()): center_x = cat_idx + 1 - point_radius = 0.1 - spacing = 0.05 sorted_indices = np.argsort(values) placed = [] @@ -89,8 +108,7 @@ for px, py in placed: dist_y = abs(y - py) dist_x = abs(test_x - px) - min_dist = 2 * point_radius + spacing - if dist_y < min_dist and dist_x < min_dist: + if dist_y < min_dist_y and dist_x < min_dist_x: overlap = True break if not overlap: @@ -100,7 +118,7 @@ direction = -1 else: direction = 1 - offset += point_radius + spacing / 2 + offset += step_x placed.append((x, y)) swarm_points.append((x, y)) From 4f35ab73491449c362008c0338f97e0d76d4093c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 26 Jul 2026 07:28:07 +0000 Subject: [PATCH 5/5] chore(pygal): update quality score 88 and review feedback for swarm-basic --- .../implementations/python/pygal.py | 4 +- plots/swarm-basic/metadata/python/pygal.yaml | 180 +++++++++--------- 2 files changed, 95 insertions(+), 89 deletions(-) diff --git a/plots/swarm-basic/implementations/python/pygal.py b/plots/swarm-basic/implementations/python/pygal.py index 5d1efdfba4..ca48dd7f0d 100644 --- a/plots/swarm-basic/implementations/python/pygal.py +++ b/plots/swarm-basic/implementations/python/pygal.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai swarm-basic: Basic Swarm Plot Library: pygal 3.1.3 | Python 3.13.14 -Quality: 75/100 | Updated: 2026-07-26 +Quality: 88/100 | Updated: 2026-07-26 """ import os diff --git a/plots/swarm-basic/metadata/python/pygal.yaml b/plots/swarm-basic/metadata/python/pygal.yaml index e6d977651d..663e06fc38 100644 --- a/plots/swarm-basic/metadata/python/pygal.yaml +++ b/plots/swarm-basic/metadata/python/pygal.yaml @@ -2,7 +2,7 @@ library: pygal language: python specification_id: swarm-basic created: '2025-12-23T21:54:47Z' -updated: '2026-07-26T07:15:27Z' +updated: '2026-07-26T07:28:06Z' generated_by: claude-sonnet workflow_run: 30192192064 issue: 974 @@ -12,54 +12,62 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/swarm-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/swarm-basic/python/pygal/plot-dark.html -quality_score: 75 +quality_score: 88 review: strengths: - - 'Imprint palette applied correctly: Engineering=#009E73 (first series, brand green) - through to Operations=#BD8233 in canonical order, identical across both themes.' - - 'Theme tokens threaded through consistently — PAGE_BG/INK/INK_MUTED flip correctly - between #FAF8F1/#1A1A17 renders with no dark-on-dark or light-on-light text.' - - Group Mean markers per department are a thoughtful addition that directly satisfies - the spec's 'consider adding a subtle mean/median marker' note and give the plot - a clear comparative focal point. - - Canvas is exactly 3200x1800 with no clipped text at any edge; title, axis titles, - and legend are all fully visible. + - Beeswarm collision algorithm now correctly derives per-axis pixel-to-data-unit + scale (x_unit_per_px / y_unit_per_px) from the actual plot pixel dimensions and + dot radius, fixing the exact units-mismatch bug flagged in the previous review + — independently re-rendered and confirmed to produce a genuine fanned swarm shape + with no dense overlapping columns. + - Performance-score data is now clamped to a plausible 0-100 range via np.clip, + resolving the previous 'values exceed 100' realism issue. + - Imprint palette applied correctly and identically across both themes (Engineering=#009E73 + brand green through Operations=#BD8233 in canonical order); Group Mean markers + give a clear comparative focal point per the spec's suggestion. + - Canvas is exactly 3200x1800 with no clipped text at any edge; theme tokens (PAGE_BG/INK/INK_MUTED) + are threaded through consistently with no dark-on-dark or light-on-light failures. - Deterministic data generation via np.random.seed(42); clean imports; correct plot-{theme}.png/.html - output contract for an interactive library. + output contract for an interactive library; the non-obvious per-axis scaling derivation + is well-commented. weaknesses: - - 'Beeswarm collision detection is scaled wrong: point_radius=0.1 and spacing=0.05 - are compared directly against raw y-values, but the value axis spans ~75 units - (range=(40,115)) while a rendered dot (dots_size=10) is roughly 1-1.5 data-units - tall. Because the overlap threshold (2*point_radius+spacing = 0.25) is far smaller - than the dot''s actual on-screen footprint, most points that are visually touching - are never flagged as overlapping and stay at center_x, producing a dense solid-looking - vertical strip (e.g. the Sales column) instead of a fanned beeswarm. Fix by deriving - point_radius/spacing from the actual y-range/dot size (e.g. normalize y to [0,1] - using the chart''s `range` before running the collision loop, or scale point_radius - ~ (range span) * (dots_size in px / plot height in px)).' - - Because of the collision-scale bug, the plot under-delivers on the spec's core - promise ('points spread horizontally to avoid overlap' / 'reveals the full distribution - shape') — large portions of each category render as a single dense column rather - than a true swarm shape. - - Some synthetic performance scores exceed 100 (e.g. ~106-115 in Sales) which reads - oddly for a 'Performance Score' metric typically bounded 0-100 — either clamp/tighten - the normal distribution parameters or make the scale explicit if scores >100 are - intentional. + - 'PIPELINE ISSUE (not a code defect): the plot_images/plot-light.png and plot-dark.png + supplied to this review step were stale and do not reflect commit 8939f709e. They + show data points above 100, which is mathematically impossible under the current + code''s np.clip(np.random.normal(...), 0, 100) bound, and their y-axis range extends + past the script''s own computed range=(50,100). This proves the images were rendered + from a pre-fix version of the script (before this attempt''s np.clip addition + and beeswarm-scale fix), not the code actually in this PR. I independently re-rendered + plots/swarm-basic/implementations/python/pygal.py in a clean environment with + the exact pinned pygal==3.1.3 and confirmed: (a) values are correctly clamped + to 0-100, and (b) the beeswarm fix produces a genuine fanned distribution with + no unresolved overlap in both themes. The score and checklist below are based + on those freshly-verified renders, not the stale plot_images/ directory. Recommend + the pipeline re-render plot-light.png/plot-dark.png from the current commit — + and confirm impl-merge.yml does the same before GCS promotion — so stale pre-fix + imagery is never published as the production preview.' + - 'LM-02: still fairly generic pygal usage beyond the Style/XY basics and HTML export + — no additional pygal-distinctive feature (e.g. custom tooltip value formatting, + print_values) is showcased.' + - 'DE-01/DE-02: solid and clean, but no extra embellishment (e.g. varied dot sizing, + easing on the swarm silhouette) pushes it into the top design tier.' image_description: |- - Light render (plot-light.png): - Background: Warm off-white (~#FAF8F1), matches the light chrome token. - Chrome: Title "swarm-basic · python · pygal · anyplot.ai" is dark and fully legible; x_title "Department" and y_title "Performance Score" are dark and clear; y-axis tick labels (40-110) and x category labels (Engineering/Marketing/Sales/Operations) are dark and readable; subtle dashed horizontal gridlines are visible without dominating; bottom legend (4 category swatches + Group Mean) is fully legible. - Data: First series (Engineering) is #009E73 brand green, followed by Marketing (purple #C475FD), Sales (blue #4467A3), Operations (brown/amber #BD8233) — matches canonical Imprint order. Large black Group Mean dots sit at each category's average. Points within each category are NOT well spread horizontally — large stretches (especially Sales, mid-range Marketing/Operations) form a dense, mostly single-column vertical stack of touching/overlapping dots rather than a fanned swarm shape. - Legibility verdict: PASS (all text readable; the overlap issue is a data/algorithm quality problem, not a legibility one). + NOTE: The plot_images/plot-light.png and plot-dark.png supplied for this review were determined to be stale (see Weaknesses) — they show data values >100 which is impossible given the current script's np.clip(...,0,100) bound. The descriptions below are of images I independently re-rendered from the exact submitted code (plots/swarm-basic/implementations/python/pygal.py) using the pinned pygal==3.1.3, which is the accurate representation of what this PR's code actually produces. - Dark render (plot-dark.png): - Background: Warm near-black (~#1A1A17), matches the dark chrome token. - Chrome: Title, axis titles, tick labels, and legend are all rendered in light ink (#F0EFE8/#A8A79F tones) and are clearly legible against the dark background — no dark-on-dark failures observed. Gridlines remain subtle but visible. - Data: Same four category colors as the light render (green/purple/blue/brown), confirming Imprint palette identity across themes — only chrome (background, text, gridlines, Group Mean dot color which flips to a light ink tone) changed. Same overlap/clumping pattern as the light render, since it's a data-layout issue independent of theme. - Legibility verdict: PASS (all text readable in dark mode; same overlap weakness as light render). + Light render (re-rendered plot-light.png): + Background: Warm off-white (#FAF8F1), matches the light chrome token. + Chrome: Title "swarm-basic · python · pygal · anyplot.ai" is dark and fully legible, ~58% of plot width; x_title "Department" and y_title "Performance Score" are dark and clear; y-axis tick labels (50-100) and x category labels (Engineering/Marketing/Sales/Operations) are dark and readable; subtle dashed horizontal gridlines are visible without dominating; bottom legend (4 category swatches + Group Mean) is fully legible in a clean two-row layout. + Data: First series (Engineering) is #009E73 brand green, followed by Marketing (purple #C475FD), Sales (blue #4467A3), Operations (brown/amber #BD8233) — matches canonical Imprint order. Large black Group Mean dots sit at each category's average. Points within each category now form a genuine fanned beeswarm shape — wide where the local point density is high (e.g. mid-70s to mid-80s band), narrowing toward the tails — with no unresolved dense overlapping column like the previous attempt. + Legibility verdict: PASS (all text readable; no clipping at any edge). + + Dark render (re-rendered plot-dark.png): + Background: Warm near-black (#1A1A17), matches the dark chrome token. + Chrome: Title, axis titles, tick labels, and legend are all rendered in light ink and are clearly legible against the dark background — no dark-on-dark failures observed. Gridlines remain subtle but visible. + Data: Same four category colors as the light render, confirming Imprint palette identity across themes — only chrome (background, text, gridlines, Group Mean dot color which flips to a light ink tone) changed. Same well-fanned swarm shape as the light render, confirming the fix is theme-independent. + Legibility verdict: PASS (all text readable in dark mode; no dark-on-dark issues). criteria_checklist: visual_quality: - score: 24 + score: 28 max: 30 items: - id: VQ-01 @@ -71,19 +79,19 @@ review: in both themes; explicit font sizes throughout the Style object. - id: VQ-02 name: No Overlap - score: 3 + score: 6 max: 6 - passed: false - comment: Beeswarm collision-detection scale mismatch (see weaknesses) leaves - large stretches of points stacked directly on top of each other, especially - in Sales and mid-range Marketing/Operations. + passed: true + comment: Beeswarm collision-scale bug from the previous attempt is fixed; + points fan out based on local density with no unresolved dense stacking. - id: VQ-03 name: Element Visibility - score: 4 + score: 5 max: 6 passed: true - comment: Marker size (10) and opacity (0.75) are reasonable for the data density, - but dense overlapping clusters reduce individual-point distinguishability. + comment: Marker size (10) and opacity (0.75) are well-suited to the 40-55 + points/category density; a few points in the densest bands lightly touch + neighbors, which is expected/acceptable for a packed beeswarm. - id: VQ-04 name: Color Accessibility score: 2 @@ -112,51 +120,48 @@ review: comment: 'First series #009E73, canonical multi-series order, correct theme backgrounds, identical data colors across themes.' design_excellence: - score: 11 + score: 14 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 6 max: 8 - passed: false - comment: Custom palette and consistent typography, but overlap issue undercuts - overall polish. + passed: true + comment: Custom palette, consistent typography, and now-correct swarm shape + read as polished; no extra embellishment beyond that. - id: DE-02 name: Visual Refinement - score: 3 + score: 4 max: 6 - passed: false - comment: Subtle single-axis gridlines and generous margins, but no spine removal - beyond pygal defaults and dense clustering looks unrefined. + passed: true + comment: Subtle y-axis-only grid and generous margins; no additional spine/frame + refinement beyond pygal defaults. - id: DE-03 name: Data Storytelling - score: 3 + score: 4 max: 6 - passed: false - comment: Group Mean markers give a nice comparative focal point, but the muted - swarm spread undersells the distribution-shape story that swarm plots exist - to tell. + passed: true + comment: Group Mean markers plus a genuinely fanned swarm shape now tell the + distribution story the spec asks for. spec_compliance: - score: 13 + score: 15 max: 15 items: - id: SC-01 name: Plot Type - score: 4 + score: 5 max: 5 passed: true - comment: XY chart with manually computed swarm layout is the right approach - for pygal (no native swarm type), but execution partially fails to deliver - a true swarm shape. + comment: XY chart with a corrected manual swarm layout is the right approach + for pygal (no native swarm type) and now executes correctly. - id: SC-02 name: Required Features - score: 3 + score: 4 max: 4 passed: true - comment: Category axis, continuous value axis, color-by-category, and mean - markers all present; horizontal spread-to-avoid-overlap is only partially - achieved. + comment: Category axis, continuous value axis, color-by-category, mean markers, + and horizontal spread-to-avoid-overlap are all present and working. - id: SC-03 name: Data Mapping score: 3 @@ -172,17 +177,16 @@ review: comment: Title matches required format exactly; legend labels match category names. data_quality: - score: 12 + score: 15 max: 15 items: - id: DQ-01 name: Feature Coverage - score: 4 + score: 6 max: 6 passed: true - comment: Individual points, per-category color, and mean markers present, - but the full distribution shape is obscured where the swarm collapses into - a dense column. + comment: Individual points, per-category color, mean markers, and now a clearly + visible full distribution shape are all present. - id: DQ-02 name: Realistic Context score: 5 @@ -192,13 +196,13 @@ review: scenario within the spec's suggested applications. - id: DQ-03 name: Appropriate Scale - score: 3 + score: 4 max: 4 passed: true - comment: Most values sit in a sensible 50-100 band, but a handful of points - exceed 100 (up to ~115), which reads oddly for a 'Performance Score'. + comment: Values now clamped to a sensible 0-100 'Performance Score' band via + np.clip. code_quality: - score: 9 + score: 10 max: 10 items: - id: CQ-01 @@ -221,11 +225,12 @@ review: comment: Only os, numpy, pygal, pygal.style.Style — all used. - id: CQ-04 name: Code Elegance - score: 1 + score: 2 max: 2 - passed: false - comment: The manual beeswarm collision loop has a units mismatch that prevents - it from doing what it's written to do (see weaknesses). + passed: true + comment: The manual beeswarm collision loop now correctly derives per-axis + pixel-to-data-unit scale, fixing the previous units mismatch, with a clear + comment explaining the derivation. - id: CQ-05 name: Output & API score: 1 @@ -250,8 +255,9 @@ review: max: 5 passed: false comment: Generates the interactive HTML export as expected but doesn't otherwise - showcase pygal-distinctive capabilities beyond standard Style/XY usage. - verdict: REJECTED + showcase pygal-distinctive capabilities (e.g. custom tooltip/value formatting) + beyond standard Style/XY usage. + verdict: APPROVED impl_tags: dependencies: [] techniques: