From 14cecabf61cbda6c349d6fd9fa2a5d173c826848 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 20:47:45 +0000 Subject: [PATCH 1/2] chore(letsplot): add metadata for strip-basic --- .../implementations/python/letsplot.py | 50 +++-- .../strip-basic/metadata/python/letsplot.yaml | 193 ++---------------- 2 files changed, 45 insertions(+), 198 deletions(-) diff --git a/plots/strip-basic/implementations/python/letsplot.py b/plots/strip-basic/implementations/python/letsplot.py index ae2313b17c..f44f3e519e 100644 --- a/plots/strip-basic/implementations/python/letsplot.py +++ b/plots/strip-basic/implementations/python/letsplot.py @@ -1,9 +1,11 @@ -""" pyplots.ai +"""anyplot.ai strip-basic: Basic Strip Plot -Library: letsplot 4.8.2 | Python 3.13.11 -Quality: 96/100 | Created: 2025-12-23 +Library: letsplot | Python 3.13 +Quality: pending | Updated: 2026-05-04 """ +import os + import numpy as np import pandas as pd from lets_plot import ( @@ -11,6 +13,7 @@ aes, element_blank, element_line, + element_rect, element_text, geom_jitter, ggplot, @@ -24,22 +27,25 @@ LetsPlot.setup_html() +# Theme tokens +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" + +BRAND = "#009E73" # Okabe-Ito position 1 + # Data - Survey response scores by department np.random.seed(42) departments = ["Marketing", "Engineering", "Sales", "Support"] data = [] -# Create different distributions for each department -distributions = { - "Marketing": (72, 12), # Mean 72, moderate spread - "Engineering": (78, 8), # Higher mean, tighter distribution - "Sales": (68, 15), # Lower mean, wide spread - "Support": (75, 10), # Medium-high mean, medium spread -} +distributions = {"Marketing": (72, 12), "Engineering": (78, 8), "Sales": (68, 15), "Support": (75, 10)} for dept in departments: - n_points = np.random.randint(25, 45) # 25-44 observations per department + n_points = np.random.randint(25, 45) mean, std = distributions[dept] scores = np.clip(np.random.normal(mean, std, n_points), 40, 100) for score in scores: @@ -50,22 +56,22 @@ # Plot plot = ( ggplot(df, aes(x="Department", y="Score")) - + geom_jitter(color="#306998", size=4, alpha=0.6, width=0.25, height=0, seed=42) - + labs(x="Department", y="Survey Score (points)", title="strip-basic · letsplot · pyplots.ai") + + geom_jitter(color=BRAND, size=4, alpha=0.65, width=0.25, height=0, seed=42) + + labs(x="Department", y="Survey Score (points)", title="strip-basic · letsplot · anyplot.ai") + ggsize(1600, 900) + theme_minimal() + theme( - axis_title=element_text(size=20), - axis_text=element_text(size=16), - plot_title=element_text(size=24), + plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), + panel_background=element_rect(fill=PAGE_BG), + axis_title=element_text(color=INK, size=20), + axis_text=element_text(color=INK_SOFT, size=16), + plot_title=element_text(color=INK, size=24), panel_grid_major_x=element_blank(), panel_grid_minor=element_blank(), - panel_grid_major_y=element_line(color="#cccccc", size=0.5), + panel_grid_major_y=element_line(color=INK_SOFT, size=0.3), ) ) -# Save PNG (scale=3 gives 4800x2700) -ggsave(plot, "plot.png", path=".", scale=3) - -# Save HTML for interactive version -ggsave(plot, "plot.html", path=".") +# Save +ggsave(plot, f"plot-{THEME}.png", path=".", scale=3) +ggsave(plot, f"plot-{THEME}.html", path=".") diff --git a/plots/strip-basic/metadata/python/letsplot.yaml b/plots/strip-basic/metadata/python/letsplot.yaml index 8a5619f02b..4c613cd95e 100644 --- a/plots/strip-basic/metadata/python/letsplot.yaml +++ b/plots/strip-basic/metadata/python/letsplot.yaml @@ -1,180 +1,21 @@ +# Per-library metadata for letsplot implementation of strip-basic +# Auto-generated by impl-generate.yml + library: letsplot +language: python specification_id: strip-basic created: '2025-12-23T21:54:35Z' -updated: '2025-12-23T22:00:53Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 20472387634 -issue: 0 -python_version: 3.13.11 -library_version: 4.8.2 -preview_url: https://storage.googleapis.com/anyplot-images/plots/strip-basic/letsplot/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/strip-basic/letsplot/plot.html -quality_score: 96 -impl_tags: - dependencies: [] - techniques: - - html-export - patterns: - - data-generation - dataprep: [] - styling: - - alpha-blending - - minimal-chrome - - grid-styling +updated: '2026-05-04T20:47:45Z' +generated_by: claude-sonnet +workflow_run: 25342504812 +issue: 975 +python_version: 3.13.13 +library_version: 4.9.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-dark.html +quality_score: null review: - strengths: - - Excellent use of lets-plot ggplot2-style grammar with geom_jitter for strip plot - - Realistic survey score data with distinct distributions per department showing - the plot type strengths - - Clean minimal theme with appropriate grid styling (horizontal only) - - Proper reproducibility with fixed seeds in both numpy and geom_jitter - - Well-calibrated jitter width (0.25) and alpha (0.6) per spec recommendations - weaknesses: - - 'No legend present (minor: single-color plot does not strictly require one)' - - Point size could be slightly larger for better visibility at full 4800x2700 resolution - image_description: 'The plot displays a basic strip plot showing survey scores (40-100 - points) across four departments: Marketing, Engineering, Sales, and Support. Points - are rendered in a muted blue color (#306998) with horizontal jitter (width ~0.25) - and alpha transparency (0.6) to reduce overplotting. The title "strip-basic · - letsplot · pyplots.ai" appears at the top. The plot uses a clean minimal theme - with subtle horizontal gray grid lines and no vertical grid lines. Each department - shows distinct distribution patterns: Engineering clusters higher (80-90), Sales - shows wide spread with outliers near 40, Marketing has moderate spread around - 70-80, and Support ranges from 50-95.' - criteria_checklist: - visual_quality: - score: 36 - max: 40 - items: - - id: VQ-01 - name: Text Legibility - score: 10 - max: 10 - passed: true - comment: All text perfectly readable at full size with appropriate font sizing - - id: VQ-02 - name: No Overlap - score: 8 - max: 8 - passed: true - comment: No overlapping text elements - - id: VQ-03 - name: Element Visibility - score: 7 - max: 8 - passed: true - comment: 'Points well-sized with good alpha, minor: could be slightly larger' - - id: VQ-04 - name: Color Accessibility - score: 5 - max: 5 - passed: true - comment: Single blue color, colorblind-safe - - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 - passed: true - comment: Plot fills canvas appropriately with balanced margins - - id: VQ-06 - name: Axis Labels - score: 1 - max: 2 - passed: true - comment: Y-axis has units "Survey Score (points)", X-axis categorical label - acceptable - - id: VQ-07 - name: Grid & Legend - score: 0 - max: 2 - passed: true - comment: No legend present (not strictly needed for single-color plot) - spec_compliance: - score: 25 - max: 25 - items: - - id: SC-01 - name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct strip plot using geom_jitter - - id: SC-02 - name: Data Mapping - score: 5 - max: 5 - passed: true - comment: Categorical X, continuous Y correctly assigned - - id: SC-03 - name: Required Features - score: 5 - max: 5 - passed: true - comment: Jitter, transparency, individual points all present - - id: SC-04 - name: Data Range - score: 3 - max: 3 - passed: true - comment: Full 40-100 range shown - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: N/A (single color, no legend needed) - - id: SC-06 - name: Title Format - score: 2 - max: 2 - passed: true - comment: 'Correct format: strip-basic · letsplot · pyplots.ai' - data_quality: - score: 20 - max: 20 - items: - - id: DQ-01 - name: Feature Coverage - score: 8 - max: 8 - passed: true - comment: Shows different distributions, spreads, and outliers across departments - - id: DQ-02 - name: Realistic Context - score: 7 - max: 7 - passed: true - comment: Survey scores by department is a real, comprehensible business scenario - - id: DQ-03 - name: Appropriate Scale - score: 5 - max: 5 - passed: true - comment: Scores 40-100 are realistic for survey data - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: Clean imports → data → plot → save structure - - id: CQ-02 - name: Reproducibility - score: 3 - max: 3 - passed: true - comment: Fixed seed in both np.random and geom_jitter - library_features: - score: 5 - max: 5 - items: - - id: LF-01 - name: Uses distinctive library features - score: 5 - max: 5 - passed: true - comment: ggplot grammar, geom_jitter with seed, fine-grained theme control - verdict: APPROVED + strengths: [] + weaknesses: [] From a63c80de519b7b2aa3cd190d89529805adee8804 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 4 May 2026 20:52:41 +0000 Subject: [PATCH 2/2] chore(letsplot): update quality score 84 and review feedback for strip-basic --- .../implementations/python/letsplot.py | 6 +- .../strip-basic/metadata/python/letsplot.yaml | 232 +++++++++++++++++- 2 files changed, 228 insertions(+), 10 deletions(-) diff --git a/plots/strip-basic/implementations/python/letsplot.py b/plots/strip-basic/implementations/python/letsplot.py index f44f3e519e..1e558c0791 100644 --- a/plots/strip-basic/implementations/python/letsplot.py +++ b/plots/strip-basic/implementations/python/letsplot.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai strip-basic: Basic Strip Plot -Library: letsplot | Python 3.13 -Quality: pending | Updated: 2026-05-04 +Library: letsplot 4.9.0 | Python 3.13.13 +Quality: 84/100 | Updated: 2026-05-04 """ import os diff --git a/plots/strip-basic/metadata/python/letsplot.yaml b/plots/strip-basic/metadata/python/letsplot.yaml index 4c613cd95e..312bdf4f0a 100644 --- a/plots/strip-basic/metadata/python/letsplot.yaml +++ b/plots/strip-basic/metadata/python/letsplot.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for letsplot implementation of strip-basic -# Auto-generated by impl-generate.yml - library: letsplot language: python specification_id: strip-basic created: '2025-12-23T21:54:35Z' -updated: '2026-05-04T20:47:45Z' +updated: '2026-05-04T20:52:41Z' generated_by: claude-sonnet workflow_run: 25342504812 issue: 975 @@ -15,7 +12,228 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/strip-bas preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-dark.png preview_html_light: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-light.html preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/strip-basic/python/letsplot/plot-dark.html -quality_score: null +quality_score: 84 review: - strengths: [] - weaknesses: [] + strengths: + - Perfect spec compliance across all four criteria — correct chart type, jitter + parameters, transparency, and title format + - 'Excellent code quality: reproducible seed in both data generation and geom_jitter, + clean linear structure, all imports used' + - Theme-adaptive chrome correctly implemented with all six tokens applied to plot, + panel, axis, and grid + - Both light and dark renders clearly readable with no dark-on-dark or light-on-light + failures + - Realistic, neutral survey data with varied distributions across groups + weaknesses: + - 'Design Excellence is mediocre: no visual storytelling, no reference layers (mean + lines or crossbars per group), all groups receive identical visual treatment' + - 'LM-02 low: no lets-plot-specific features used — geom_jitter is shared with plotnine; + no geom_crossbar, stat_summary, or other distinctive lets-plot capabilities demonstrated' + image_description: |- + Light render (plot-light.png): + Background: Warm off-white #FAF8F1 - correct, not pure white + Chrome: Title "strip-basic · letsplot · anyplot.ai" dark and clearly readable; axis labels "Department" (x) and "Survey Score (points)" (y) in dark INK color; tick labels (Marketing, Engineering, Sales, Support + numeric y-axis values) in muted dark INK_SOFT color + Data: All points in brand green #009E73, size=4, alpha=0.65; horizontal jitter width=0.25 spreads points clearly; 4 categories with ~25-44 points each; range ~40-100; y-axis major grid lines are subtle horizontal lines only + Legibility verdict: PASS - all text clearly readable against off-white background + + Dark render (plot-dark.png): + Background: Near-black #1A1A17 - correct, not pure black + Chrome: Title in near-white INK (#F0EFE8), clearly visible; axis labels in light INK color; tick labels in light-gray INK_SOFT (#B8B7B0), all readable against dark background; no dark-on-dark failures observed + Data: Data points remain identical brand green #009E73, same distribution and jitter as light render - only chrome flipped + Legibility verdict: PASS - all text readable against near-black background + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 8 + max: 8 + passed: true + comment: Title 24pt, axis labels 20pt, tick labels 16pt all explicitly set; + readable in both themes + - id: VQ-02 + name: No Overlap + score: 6 + max: 6 + passed: true + comment: Jitter spreads points well; no text collisions + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Points at size=4, alpha=0.65 are clearly visible; slightly small + for 4800x2700 canvas + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Okabe-Ito green is CVD-safe; single-hue with good contrast + - id: VQ-05 + name: Layout & Canvas + score: 3 + max: 4 + passed: true + comment: Plot fills canvas adequately; minor leftward positioning creates + slightly uneven horizontal balance + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Survey Score (points) includes unit, Department is descriptive + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series is #009E73; backgrounds are #FAF8F1 (light) and #1A1A17 + (dark); chrome adapts correctly' + design_excellence: + score: 10 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 4 + max: 8 + passed: false + comment: Well-configured library default; professional but not exceptional; + missing reference lines or statistical overlays + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: false + comment: X-grid removed, minor grids removed, y-grid subtle 0.3px; solid refinement + but spines not explicitly removed + - id: DE-03 + name: Data Storytelling + score: 2 + max: 6 + passed: false + comment: Distributions with different means shown but no visual hierarchy; + all groups receive equal treatment; viewer must discover story + spec_compliance: + score: 15 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: Strip plot with horizontal jitter width=0.25, in spec-recommended + 0.1-0.3 range + - id: SC-02 + name: Required Features + score: 4 + max: 4 + passed: true + comment: Individual points per category, jitter, transparency alpha=0.65, + 4 categories with 25-44 points each + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: Category on X, continuous Score on Y; all data visible + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title matches strip-basic · letsplot · anyplot.ai; no legend needed + for single-series + data_quality: + score: 15 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 6 + max: 6 + passed: true + comment: Groups show different means AND spreads (Sales sigma=15 vs Engineering + sigma=8); overplotting mitigated by jitter + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Survey response scores across corporate departments — neutral, plausible, + real-world business scenario + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: Scores clipped to [40, 100]; means in 68-78 range; realistic for + employee survey context + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Linear: imports -> seed -> data -> plot -> save; no functions or + classes' + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42) for data generation, seed=42 in geom_jitter + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: All imported symbols are used + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean, idiomatic, appropriate complexity + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves plot-{THEME}.png and plot-{THEME}.html with scale=3 + library_mastery: + score: 6 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: Proper lets-plot ggplot grammar; theme composition correct; not leveraging + full API (no scale_*, no stat_summary) + - id: LM-02 + name: Distinctive Features + score: 2 + max: 5 + passed: false + comment: geom_jitter with seed is nice but shared with plotnine; HTML export + is lets-plot-specific; no geom_crossbar or stat_summary demonstrating unique + capabilities + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: [] + patterns: + - data-generation + - iteration-over-groups + dataprep: [] + styling: + - alpha-blending