From 383592931c51b786bed1d1b8a9651bc4ef443cc7 Mon Sep 17 00:00:00 2001 From: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com> Date: Mon, 23 Feb 2026 23:42:15 +0100 Subject: [PATCH 1/6] =?UTF-8?q?update(density-basic):=20letsplot=20?= =?UTF-8?q?=E2=80=94=20comprehensive=20quality=20review?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Comprehensive quality review: marathon data, ggsave fix, tooltips, trim parameter. --- .../density-basic/implementations/letsplot.py | 51 +++++++++++++------ plots/density-basic/metadata/letsplot.yaml | 18 +++---- 2 files changed, 45 insertions(+), 24 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index d2e6fea4e6..df7e3e9a7c 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,41 +1,62 @@ """ pyplots.ai density-basic: Basic Density Plot -Library: letsplot 4.8.2 | Python 3.13.11 -Quality: 91/100 | Created: 2025-12-23 +Library: letsplot 4.8.2 | Python 3.14 +Quality: /100 | Updated: 2026-02-23 """ import numpy as np +import pandas as pd from lets_plot import * # noqa: F403 -from lets_plot.export import ggsave as export_ggsave LetsPlot.setup_html() # noqa: F405 -# Data - Generate realistic test scores with slight right skew +# Data - Simulated marathon finish times with realistic right skew np.random.seed(42) -scores = np.concatenate( +finish_minutes = np.concatenate( [ - np.random.normal(72, 12, 300), # Main group of students - np.random.normal(90, 5, 100), # High achievers + np.random.normal(240, 25, 350), # Main pack (~4 hour runners) + np.random.normal(200, 15, 100), # Competitive runners (~3:20) + np.random.normal(300, 20, 50), # Casual runners (~5 hours) ] ) +finish_minutes = np.clip(finish_minutes, 140, 400) -# Create plot +df = pd.DataFrame({"time": finish_minutes}) + +# Plot plot = ( - ggplot({"scores": scores}, aes(x="scores")) # noqa: F405 - + geom_density(fill="#306998", color="#306998", alpha=0.6, size=1.5) # noqa: F405 - + labs(x="Test Score", y="Density", title="density-basic · letsplot · pyplots.ai") # noqa: F405 + ggplot(df, aes(x="time")) # noqa: F405 + + geom_density( # noqa: F405 + fill="#306998", + color="#1e4263", + alpha=0.55, + size=1.8, + kernel="gaussian", + adjust=0.85, + trim=True, + tooltips=layer_tooltips() # noqa: F405 + .line("@|@time") + .line("density|@..density.."), + ) + + labs( # noqa: F405 + x="Finish Time (minutes)", y="Density", title="density-basic · letsplot · pyplots.ai" + ) + + scale_x_continuous(breaks=list(range(150, 401, 50))) # noqa: F405 + + scale_y_continuous(expand=[0.02, 0, 0.05, 0]) # noqa: F405 + theme_minimal() # noqa: F405 + theme( # noqa: F405 axis_title=element_text(size=20), # noqa: F405 axis_text=element_text(size=16), # noqa: F405 plot_title=element_text(size=24), # noqa: F405 - panel_grid_major=element_line(color="#cccccc", size=0.5), # noqa: F405 + panel_grid_major_x=element_blank(), # noqa: F405 + panel_grid_major_y=element_line(color="#e0e0e0", size=0.4), # noqa: F405 panel_grid_minor=element_blank(), # noqa: F405 + axis_ticks=element_blank(), # noqa: F405 ) + ggsize(1600, 900) # noqa: F405 ) -# Save PNG (scale 3x for 4800x2700) and HTML -export_ggsave(plot, "plot.png", path=".", scale=3) -export_ggsave(plot, "plot.html", path=".") +# Save PNG (scale 3x for 4800 x 2700 px) and HTML +ggsave(plot, "plot.png", path=".", scale=3) # noqa: F405 +ggsave(plot, "plot.html", path=".") # noqa: F405 diff --git a/plots/density-basic/metadata/letsplot.yaml b/plots/density-basic/metadata/letsplot.yaml index 20cfc6d96f..ab933b23df 100644 --- a/plots/density-basic/metadata/letsplot.yaml +++ b/plots/density-basic/metadata/letsplot.yaml @@ -1,27 +1,27 @@ library: letsplot specification_id: density-basic created: '2025-12-23T10:03:24Z' -updated: '2025-12-23T10:11:02Z' -generated_by: claude-opus-4-5-20251101 +updated: '2026-02-23T22:38:00+00:00' +generated_by: claude-opus-4-6 workflow_run: 20457538654 issue: 0 -python_version: 3.13.11 +python_version: 3.14.3 library_version: 4.8.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.html -quality_score: 91 +quality_score: null impl_tags: dependencies: [] techniques: - - layer-composition - - html-export + - layer-composition + - html-export patterns: - - data-generation + - data-generation dataprep: - - kde + - kde styling: - - alpha-blending + - alpha-blending review: strengths: - Clean ggplot2-style grammar implementation with proper layering From 5be4d9b401f1b5d203ed7926d860ded06e06e266 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 22:46:48 +0000 Subject: [PATCH 2/6] chore(letsplot): update quality score 85 and review feedback for density-basic --- .../density-basic/implementations/letsplot.py | 4 +- plots/density-basic/metadata/letsplot.yaml | 259 ++++++++++-------- 2 files changed, 143 insertions(+), 120 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index df7e3e9a7c..b1161690d6 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,7 +1,7 @@ """ pyplots.ai density-basic: Basic Density Plot -Library: letsplot 4.8.2 | Python 3.14 -Quality: /100 | Updated: 2026-02-23 +Library: letsplot 4.8.2 | Python 3.14.3 +Quality: 85/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/density-basic/metadata/letsplot.yaml b/plots/density-basic/metadata/letsplot.yaml index ab933b23df..dcdc72c6a4 100644 --- a/plots/density-basic/metadata/letsplot.yaml +++ b/plots/density-basic/metadata/letsplot.yaml @@ -1,7 +1,7 @@ library: letsplot specification_id: density-basic created: '2025-12-23T10:03:24Z' -updated: '2026-02-23T22:38:00+00:00' +updated: '2026-02-23T22:46:47Z' generated_by: claude-opus-4-6 workflow_run: 20457538654 issue: 0 @@ -10,155 +10,173 @@ library_version: 4.8.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.html -quality_score: null +quality_score: 85 impl_tags: dependencies: [] techniques: - - layer-composition + - hover-tooltips - html-export patterns: - data-generation - dataprep: - - kde + dataprep: [] styling: - alpha-blending + - grid-styling review: strengths: - - Clean ggplot2-style grammar implementation with proper layering - - Excellent bimodal data generation showing both main distribution and high achievers - - Proper use of theme customization for text sizing and grid styling - - Correct 16:9 aspect ratio with 3x scaling for 4800x2700 output - - Good color choice with appropriate alpha for fill transparency + - Excellent spec compliance with correct density plot, proper title format, and + descriptive axis labels with units + - Realistic, neutral marathon finish time data with multimodal distribution showing + skew and multiple runner groups + - 'Good visual refinement: subtle grid styling, removed ticks/minor grids, y-axis + expand tuning' + - Clean KISS code structure with reproducibility seed and proper letsplot save workflow + - Uses letsplot-distinctive features (layer_tooltips, HTML export) weaknesses: - - Axis labels lack units (e.g., "Test Score (points)" or "Density (probability)") - - Test score values exceeding 100 are unrealistic for typical grading scales - - Could benefit from a rug plot to show individual observations as suggested in - spec notes - image_description: The plot displays a smooth kernel density estimation curve showing - the distribution of test scores. The x-axis shows "Test Score" ranging from approximately - 30 to 120, while the y-axis shows "Density" ranging from 0 to about 0.026. The - density curve is filled with Python blue (#306998) with appropriate transparency, - and the outline is the same color. The distribution is bimodal, with a primary - peak around 75 and a secondary peak around 88, reflecting the mixture of a main - student group and high achievers. The title "density-basic · letsplot · pyplots.ai" - is positioned at the top. The background is clean with subtle gray gridlines on - a minimal theme. The overall layout has good proportions in 16:9 aspect ratio. + - No visual hierarchy or data storytelling - the multimodal distribution story is + not emphasized + - Minor text overlap at bottom-left origin where y-axis 0 collides with x-axis 150 + - Y-axis density values have many decimal places making the left margin slightly + heavy + - Design could be elevated further toward publication quality + image_description: The plot shows a single density curve of marathon finish times + on a white background. The x-axis is labeled "Finish Time (minutes)" ranging from + 150 to approximately 370, and the y-axis is labeled "Density" ranging from 0 to + approximately 0.011. The curve is filled with a semi-transparent Python Blue (#306998) + and outlined with a darker blue (#1e4263). The distribution is right-skewed with + a main peak around 240 minutes and a visible shoulder around 200 minutes representing + competitive runners, then a long tail extending to approximately 370 minutes for + casual runners. The title "density-basic · letsplot · pyplots.ai" appears at the + top left. The background uses a minimal theme with only subtle horizontal gridlines + in light gray. No rug plot is present. There is minor text overlap at the bottom-left + origin where the y-axis "0" collides with the x-axis "150" label. criteria_checklist: visual_quality: - score: 36 - max: 40 + score: 28 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 8 + max: 8 passed: true - comment: Title, axis labels, and tick marks are all clearly readable at appropriate - sizes + comment: 'All font sizes explicitly set: title=24, axis_title=20, axis_text=16. + All text clearly readable.' - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 5 + max: 6 passed: true - comment: No overlapping text elements + comment: Minor overlap at origin where y-axis 0 collides with x-axis 150 tick + label. - id: VQ-03 name: Element Visibility - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Density curve is smooth and well-visible with good fill transparency + comment: Density curve clearly visible with good fill (alpha=0.55) and strong + outline (size=1.8). - id: VQ-04 name: Color Accessibility - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Single color scheme, no accessibility issues + comment: Single series Python Blue with good contrast. No colorblind issues. - id: VQ-05 - name: Layout Balance - score: 5 - max: 5 + name: Layout & Canvas + score: 3 + max: 4 passed: true - comment: Good proportions, no cut-off content + comment: Good canvas utilization. Y-axis density decimal values create slight + left-margin heaviness. - id: VQ-06 - name: Axis Labels - score: 1 - max: 2 - passed: false - comment: Descriptive labels but no units (e.g., "Test Score (points)" would - be better) - - id: VQ-07 - name: Grid & Legend - score: 1 + name: Axis Labels & Title + score: 2 max: 2 + passed: true + comment: X-axis has units (minutes). Y-axis Density is appropriate. + design_excellence: + score: 11 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 5 + max: 8 + passed: true + comment: 'Above defaults: Python Blue with darker outline, minimal theme, + custom grid styling. Thoughtful but not publication-quality.' + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: 'Good refinement: minor grids removed, x-grid removed, subtle y-grid, + ticks removed, y-axis expand tuned.' + - id: DE-03 + name: Data Storytelling + score: 2 + max: 6 passed: false - comment: Minor gridlines disabled which is good, but major grid alpha could - be slightly more subtle + comment: Data displayed without visual hierarchy or emphasis. Viewer must + discover multimodal structure unaided. spec_compliance: - score: 25 - max: 25 + score: 15 + max: 15 items: - id: SC-01 name: Plot Type - score: 8 - max: 8 - passed: true - comment: Correct density/KDE plot - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: Continuous variable correctly mapped to x-axis - - id: SC-03 + comment: Correct KDE/density plot using geom_density(). + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: Smooth curve with fill under curve as suggested in spec - - id: SC-04 - name: Data Range + comment: Smooth density curve, fill with transparency, appropriate bandwidth. + Rug plot optional. + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: All data visible - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: No legend needed for single variable - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: X-axis correctly maps continuous variable, y-axis shows density, + full range visible. + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: 'Correct format: "density-basic · letsplot · pyplots.ai"' + comment: Title follows exact format. No legend needed for single series. data_quality: - score: 18 - max: 20 + score: 14 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 7 - max: 8 + score: 5 + max: 6 passed: true - comment: Shows bimodal distribution demonstrating skewness and multiple peaks, - but no rug plot (optional per spec) + comment: Shows right-skew, multimodality, and long tail. A rug plot would + additionally show individual observations. - id: DQ-02 name: Realistic Context - score: 7 - max: 7 + score: 5 + max: 5 passed: true - comment: Test scores is a perfect real-world scenario for density plots + comment: Marathon finish times are real, neutral, and comprehensible with + three realistic runner groups. - id: DQ-03 name: Appropriate Scale score: 4 - max: 5 - passed: false - comment: Good range (30-120), though some extreme values exceed 100 which - is unusual for test scores + max: 4 + passed: true + comment: 'Realistic marathon times: competitive ~200 min, main pack ~240 min, + casual ~300 min.' code_quality: - score: 9 + score: 10 max: 10 items: - id: CQ-01 @@ -166,42 +184,47 @@ review: score: 3 max: 3 passed: true - comment: Clean imports → data → plot → save structure + comment: Clean Imports-Data-Plot-Save structure with no functions or classes. - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: np.random.seed(42) used + comment: np.random.seed(42) set before data generation. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: Only necessary imports + comment: All imports used. noqa comments appropriate for wildcard import pattern. - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 + name: Code Elegance + score: 2 + max: 2 passed: true - comment: Current API usage + comment: Clean ggplot chain, appropriate complexity, no over-engineering. - id: CQ-05 - name: Output Correct - score: 0 + name: Output & API + score: 1 max: 1 - passed: false - comment: Saves both plot.png and plot.html, but uses export_ggsave from lets_plot.export - instead of standard ggsave - library_features: - score: 3 - max: 5 + passed: true + comment: Saves as plot.png with ggsave() and scale=3. Also exports HTML. + library_mastery: + score: 7 + max: 10 items: - - id: LF-01 - name: Uses distinctive library features + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + passed: true + comment: 'Good ggplot grammar usage following letsplot patterns: aes, geom_density, + labs, scales, theme, ggsize, ggsave.' + - id: LM-02 + name: Distinctive Features score: 3 max: 5 - passed: false - comment: Uses ggplot2 grammar correctly with geom_density, theme_minimal, - and proper ggsize for scaling, but doesn't leverage lets-plot specific interactive - features or advanced density options - verdict: APPROVED + passed: true + comment: Uses layer_tooltips() for interactive hover and HTML export - distinctive + letsplot features. + verdict: REJECTED From fbef3c26088721c27b893d91c5f9f64b13a8284f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 22:53:05 +0000 Subject: [PATCH 3/6] fix(letsplot): address review feedback for density-basic Attempt 1/3 - fixes based on AI review --- .../density-basic/implementations/letsplot.py | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index b1161690d6..cfa1356341 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,7 +1,6 @@ -""" pyplots.ai +"""pyplots.ai density-basic: Basic Density Plot Library: letsplot 4.8.2 | Python 3.14.3 -Quality: 85/100 | Updated: 2026-02-23 """ import numpy as np @@ -24,6 +23,18 @@ df = pd.DataFrame({"time": finish_minutes}) +# Rug data: small vertical ticks at each observation +rug_df = pd.DataFrame({"x": finish_minutes, "y0": 0.0, "y1": 0.0004}) + +# Runner group centroids for storytelling annotations +group_labels = pd.DataFrame( + { + "x": [200, 240, 300], + "y": [0.0123, 0.0123, 0.0123], + "label": ["Competitive (~3:20)", "Main Pack (~4:00)", "Casual (~5:00)"], + } +) + # Plot plot = ( ggplot(df, aes(x="time")) # noqa: F405 @@ -39,11 +50,29 @@ .line("@|@time") .line("density|@..density.."), ) + + geom_segment( # noqa: F405 + data=rug_df, + mapping=aes(x="x", y="y0", xend="x", yend="y1"), # noqa: F405 + color="#1e4263", + alpha=0.15, + size=0.4, + ) + + geom_vline(xintercept=200, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 + + geom_vline(xintercept=240, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 + + geom_vline(xintercept=300, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 + + geom_text( # noqa: F405 + data=group_labels, + mapping=aes(x="x", y="y", label="label"), # noqa: F405 + size=12, + color="#444444", + ) + labs( # noqa: F405 x="Finish Time (minutes)", y="Density", title="density-basic · letsplot · pyplots.ai" ) + scale_x_continuous(breaks=list(range(150, 401, 50))) # noqa: F405 - + scale_y_continuous(expand=[0.02, 0, 0.05, 0]) # noqa: F405 + + scale_y_continuous( # noqa: F405 + breaks=[0.002, 0.004, 0.006, 0.008, 0.010], expand=[0.02, 0, 0.25, 0] + ) + theme_minimal() # noqa: F405 + theme( # noqa: F405 axis_title=element_text(size=20), # noqa: F405 From c9c9d429c3acac55001d1ba8d70d9a9fcab79714 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 22:58:57 +0000 Subject: [PATCH 4/6] chore(letsplot): update quality score 89 and review feedback for density-basic --- .../density-basic/implementations/letsplot.py | 3 +- plots/density-basic/metadata/letsplot.yaml | 137 ++++++++++-------- 2 files changed, 75 insertions(+), 65 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index cfa1356341..e5c2fe6e18 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,6 +1,7 @@ -"""pyplots.ai +""" pyplots.ai density-basic: Basic Density Plot Library: letsplot 4.8.2 | Python 3.14.3 +Quality: 89/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/density-basic/metadata/letsplot.yaml b/plots/density-basic/metadata/letsplot.yaml index dcdc72c6a4..e5fa26f267 100644 --- a/plots/density-basic/metadata/letsplot.yaml +++ b/plots/density-basic/metadata/letsplot.yaml @@ -1,7 +1,7 @@ library: letsplot specification_id: density-basic created: '2025-12-23T10:03:24Z' -updated: '2026-02-23T22:46:47Z' +updated: '2026-02-23T22:58:57Z' generated_by: claude-opus-4-6 workflow_run: 20457538654 issue: 0 @@ -10,10 +10,12 @@ library_version: 4.8.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.html -quality_score: 85 +quality_score: 89 impl_tags: dependencies: [] techniques: + - annotations + - layer-composition - hover-tooltips - html-export patterns: @@ -24,32 +26,35 @@ impl_tags: - grid-styling review: strengths: - - Excellent spec compliance with correct density plot, proper title format, and - descriptive axis labels with units - - Realistic, neutral marathon finish time data with multimodal distribution showing - skew and multiple runner groups - - 'Good visual refinement: subtle grid styling, removed ticks/minor grids, y-axis - expand tuning' - - Clean KISS code structure with reproducibility seed and proper letsplot save workflow - - Uses letsplot-distinctive features (layer_tooltips, HTML export) + - 'Excellent data storytelling improvement: vertical reference lines and group annotations + guide the viewer through three runner populations' + - Full spec compliance with density curve, rug plot, fill transparency, appropriate + bandwidth, and correct title format + - Realistic neutral marathon data with multimodal distribution demonstrating all + density plot features + - 'Clean visual refinement: subtle grid styling, removed ticks, no minor grids, + custom y-axis expand' + - Uses letsplot-distinctive layer_tooltips() for interactive hover and HTML export + - 'Perfect code quality: KISS structure, reproducible seed, clean ggplot chain' weaknesses: - - No visual hierarchy or data storytelling - the multimodal distribution story is - not emphasized - - Minor text overlap at bottom-left origin where y-axis 0 collides with x-axis 150 - - Y-axis density values have many decimal places making the left margin slightly - heavy - - Design could be elevated further toward publication quality + - Top annotations Competitive and Main Pack are slightly crowded due to proximity + (40 data-units apart) + - Design could be further elevated with color-based emphasis to create a stronger + focal point + - Y-axis decimal labels still contribute slight left-margin heaviness image_description: The plot shows a single density curve of marathon finish times - on a white background. The x-axis is labeled "Finish Time (minutes)" ranging from - 150 to approximately 370, and the y-axis is labeled "Density" ranging from 0 to - approximately 0.011. The curve is filled with a semi-transparent Python Blue (#306998) - and outlined with a darker blue (#1e4263). The distribution is right-skewed with - a main peak around 240 minutes and a visible shoulder around 200 minutes representing - competitive runners, then a long tail extending to approximately 370 minutes for - casual runners. The title "density-basic · letsplot · pyplots.ai" appears at the - top left. The background uses a minimal theme with only subtle horizontal gridlines - in light gray. No rug plot is present. There is minor text overlap at the bottom-left - origin where the y-axis "0" collides with the x-axis "150" label. + filled with semi-transparent Python Blue (#306998) and outlined with a darker + blue (#1e4263). The x-axis is labeled "Finish Time (minutes)" ranging from 150 + to ~370, and the y-axis is labeled "Density" with breaks at 0.002, 0.004, 0.006, + 0.008, 0.010. The distribution is right-skewed with a shoulder around 200 minutes + and a dominant peak around 240 minutes, followed by a long tail extending to ~370 + minutes. Three dashed gray vertical reference lines mark group centroids at x=200, + 240, and 300. At the top of the plot, three text annotations read "Competitive + (~3:20)", "Main Pack (~4:00)", and "Casual (~5:00)". A rug plot of small vertical + ticks (subtle, low alpha) runs along the x-axis base showing individual observations. + The title "density-basic · letsplot · pyplots.ai" appears at the top left. The + background uses a minimal theme with subtle horizontal gridlines only, no vertical + gridlines, and no axis ticks. criteria_checklist: visual_quality: score: 28 @@ -61,42 +66,43 @@ review: max: 8 passed: true comment: 'All font sizes explicitly set: title=24, axis_title=20, axis_text=16. - All text clearly readable.' + Group annotations at size=12 readable.' - id: VQ-02 name: No Overlap score: 5 max: 6 passed: true - comment: Minor overlap at origin where y-axis 0 collides with x-axis 150 tick - label. + comment: Competitive and Main Pack annotations slightly crowded at top (40 + data-units apart). Not overlapping but tighter than ideal. - id: VQ-03 name: Element Visibility score: 6 max: 6 passed: true - comment: Density curve clearly visible with good fill (alpha=0.55) and strong - outline (size=1.8). + comment: Density curve perfectly visible with alpha=0.55 fill and size=1.8 + outline. Rug ticks appropriately subtle. - id: VQ-04 name: Color Accessibility score: 4 max: 4 passed: true - comment: Single series Python Blue with good contrast. No colorblind issues. + comment: Single series Python Blue with good contrast. No colorblind issues + with monochromatic scheme. - id: VQ-05 name: Layout & Canvas score: 3 max: 4 passed: true - comment: Good canvas utilization. Y-axis density decimal values create slight - left-margin heaviness. + comment: Good canvas utilization. Minor left-margin heaviness from y-axis + decimal labels. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: X-axis has units (minutes). Y-axis Density is appropriate. + comment: X-axis Finish Time (minutes) has units. Y-axis Density is appropriate. design_excellence: - score: 11 + score: 14 max: 20 items: - id: DE-01 @@ -104,8 +110,8 @@ review: score: 5 max: 8 passed: true - comment: 'Above defaults: Python Blue with darker outline, minimal theme, - custom grid styling. Thoughtful but not publication-quality.' + comment: 'Above defaults: intentional Python Blue palette with darker outline, + multiple info layers, cohesive design. Not quite publication-level.' - id: DE-02 name: Visual Refinement score: 4 @@ -115,11 +121,12 @@ review: ticks removed, y-axis expand tuned.' - id: DE-03 name: Data Storytelling - score: 2 + score: 5 max: 6 - passed: false - comment: Data displayed without visual hierarchy or emphasis. Viewer must - discover multimodal structure unaided. + passed: true + comment: 'Strong storytelling: vertical reference lines and group annotations + guide viewer through three runner populations. Lacks color-based focal point + emphasis.' spec_compliance: score: 15 max: 15 @@ -129,52 +136,53 @@ review: score: 5 max: 5 passed: true - comment: Correct KDE/density plot using geom_density(). + comment: Correct KDE/density plot using geom_density() with gaussian kernel. - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Smooth density curve, fill with transparency, appropriate bandwidth. - Rug plot optional. + comment: Smooth density curve, fill with transparency, rug plot, appropriate + bandwidth, trim. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: X-axis correctly maps continuous variable, y-axis shows density, - full range visible. + comment: X-axis correctly maps continuous variable, y-axis shows density. + Full data range visible. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title follows exact format. No legend needed for single series. + comment: Title density-basic · letsplot · pyplots.ai follows exact format. + No legend needed for single series. data_quality: - score: 14 + score: 15 max: 15 items: - id: DQ-01 name: Feature Coverage - score: 5 + score: 6 max: 6 passed: true - comment: Shows right-skew, multimodality, and long tail. A rug plot would - additionally show individual observations. + comment: Shows right-skew, multimodality, long tail, rug plot for individual + observations. All key density plot features. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: Marathon finish times are real, neutral, and comprehensible with - three realistic runner groups. + comment: 'Marathon finish times: real, neutral, comprehensible. Three runner + groups reflect realistic demographics.' - id: DQ-03 name: Appropriate Scale score: 4 max: 4 passed: true - comment: 'Realistic marathon times: competitive ~200 min, main pack ~240 min, - casual ~300 min.' + comment: Competitive ~200min, main pack ~240min, casual ~300min. All realistic + marathon times. code_quality: score: 10 max: 10 @@ -184,25 +192,26 @@ review: score: 3 max: 3 passed: true - comment: Clean Imports-Data-Plot-Save structure with no functions or classes. + comment: Clean Imports → Data → Plot → Save structure. No functions or classes. - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42) set before data generation. + comment: np.random.seed(42) set before all data generation. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: All imports used. noqa comments appropriate for wildcard import pattern. + comment: numpy, pandas, lets_plot all used. noqa comments appropriate for + wildcard import. - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean ggplot chain, appropriate complexity, no over-engineering. + comment: Clean ggplot chain. Rug via geom_segment is appropriate. No over-engineering. - id: CQ-05 name: Output & API score: 1 @@ -218,13 +227,13 @@ review: score: 4 max: 5 passed: true - comment: 'Good ggplot grammar usage following letsplot patterns: aes, geom_density, - labs, scales, theme, ggsize, ggsave.' + comment: 'Good ggplot grammar: aes(), geom_density() with kernel/adjust/trim, + geom_segment(), geom_vline(), geom_text(), proper scale and theme usage.' - id: LM-02 name: Distinctive Features score: 3 max: 5 passed: true - comment: Uses layer_tooltips() for interactive hover and HTML export - distinctive - letsplot features. + comment: Uses layer_tooltips() with custom line formatting for interactive + hover. HTML export leverages letsplot interactive output. verdict: REJECTED From 77d978ede06d49fbfa36651f209d35253ce1c696 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 23:05:30 +0000 Subject: [PATCH 5/6] fix(letsplot): address review feedback for density-basic Attempt 2/3 - fixes based on AI review --- .../density-basic/implementations/letsplot.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index e5c2fe6e18..2394f60205 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,7 +1,7 @@ -""" pyplots.ai +"""pyplots.ai density-basic: Basic Density Plot Library: letsplot 4.8.2 | Python 3.14.3 -Quality: 89/100 | Updated: 2026-02-23 +Quality: repair-2 | Updated: 2026-02-23 """ import numpy as np @@ -27,11 +27,11 @@ # Rug data: small vertical ticks at each observation rug_df = pd.DataFrame({"x": finish_minutes, "y0": 0.0, "y1": 0.0004}) -# Runner group centroids for storytelling annotations +# Runner group centroids for storytelling annotations (staggered y to avoid crowding) group_labels = pd.DataFrame( { - "x": [200, 240, 300], - "y": [0.0123, 0.0123, 0.0123], + "x": [195, 243, 300], + "y": [0.0131, 0.0119, 0.0131], "label": ["Competitive (~3:20)", "Main Pack (~4:00)", "Casual (~5:00)"], } ) @@ -58,9 +58,9 @@ alpha=0.15, size=0.4, ) - + geom_vline(xintercept=200, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 - + geom_vline(xintercept=240, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 - + geom_vline(xintercept=300, linetype="dashed", color="#888888", alpha=0.5, size=0.6) # noqa: F405 + + geom_vline(xintercept=200, linetype="dashed", color="#1a5276", alpha=0.4, size=0.7) # noqa: F405 + + geom_vline(xintercept=240, linetype="dashed", color="#306998", alpha=0.4, size=0.7) # noqa: F405 + + geom_vline(xintercept=300, linetype="dashed", color="#5d8aa8", alpha=0.4, size=0.7) # noqa: F405 + geom_text( # noqa: F405 data=group_labels, mapping=aes(x="x", y="y", label="label"), # noqa: F405 @@ -68,11 +68,11 @@ color="#444444", ) + labs( # noqa: F405 - x="Finish Time (minutes)", y="Density", title="density-basic · letsplot · pyplots.ai" + x="Finish Time (minutes)", y="Density (×10⁻³)", title="density-basic · letsplot · pyplots.ai" ) + scale_x_continuous(breaks=list(range(150, 401, 50))) # noqa: F405 + scale_y_continuous( # noqa: F405 - breaks=[0.002, 0.004, 0.006, 0.008, 0.010], expand=[0.02, 0, 0.25, 0] + breaks=[0.002, 0.004, 0.006, 0.008, 0.010], labels=["2", "4", "6", "8", "10"], expand=[0.02, 0, 0.38, 0] ) + theme_minimal() # noqa: F405 + theme( # noqa: F405 From 7b920d12ba28d36529df0e0ba25ee6f55d8aac46 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Feb 2026 23:11:17 +0000 Subject: [PATCH 6/6] chore(letsplot): update quality score 91 and review feedback for density-basic --- .../density-basic/implementations/letsplot.py | 4 +- plots/density-basic/metadata/letsplot.yaml | 145 ++++++++---------- 2 files changed, 70 insertions(+), 79 deletions(-) diff --git a/plots/density-basic/implementations/letsplot.py b/plots/density-basic/implementations/letsplot.py index 2394f60205..02a0b17e30 100644 --- a/plots/density-basic/implementations/letsplot.py +++ b/plots/density-basic/implementations/letsplot.py @@ -1,7 +1,7 @@ -"""pyplots.ai +""" pyplots.ai density-basic: Basic Density Plot Library: letsplot 4.8.2 | Python 3.14.3 -Quality: repair-2 | Updated: 2026-02-23 +Quality: 91/100 | Updated: 2026-02-23 """ import numpy as np diff --git a/plots/density-basic/metadata/letsplot.yaml b/plots/density-basic/metadata/letsplot.yaml index e5fa26f267..d5078ccdb3 100644 --- a/plots/density-basic/metadata/letsplot.yaml +++ b/plots/density-basic/metadata/letsplot.yaml @@ -1,7 +1,7 @@ library: letsplot specification_id: density-basic created: '2025-12-23T10:03:24Z' -updated: '2026-02-23T22:58:57Z' +updated: '2026-02-23T23:11:17Z' generated_by: claude-opus-4-6 workflow_run: 20457538654 issue: 0 @@ -10,7 +10,7 @@ library_version: 4.8.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot_thumb.png preview_html: https://storage.googleapis.com/pyplots-images/plots/density-basic/letsplot/plot.html -quality_score: 89 +quality_score: 91 impl_tags: dependencies: [] techniques: @@ -26,35 +26,30 @@ impl_tags: - grid-styling review: strengths: - - 'Excellent data storytelling improvement: vertical reference lines and group annotations - guide the viewer through three runner populations' - - Full spec compliance with density curve, rug plot, fill transparency, appropriate - bandwidth, and correct title format - - Realistic neutral marathon data with multimodal distribution demonstrating all - density plot features - - 'Clean visual refinement: subtle grid styling, removed ticks, no minor grids, - custom y-axis expand' - - Uses letsplot-distinctive layer_tooltips() for interactive hover and HTML export - - 'Perfect code quality: KISS structure, reproducible seed, clean ggplot chain' + - Excellent data storytelling with three annotated marathon runner groups creating + immediate narrative clarity + - Professional monochromatic blue palette with intentional visual hierarchy (curve + > annotations > rug) + - Comprehensive spec coverage including optional rug plot and bandwidth tuning + - Clean y-axis rescaling trick (×10⁻³) improves readability of small density values + - Clever use of layer_tooltips() for interactive hover information weaknesses: - - Top annotations Competitive and Main Pack are slightly crowded due to proximity - (40 data-units apart) - - Design could be further elevated with color-based emphasis to create a stronger - focal point - - Y-axis decimal labels still contribute slight left-margin heaviness - image_description: The plot shows a single density curve of marathon finish times - filled with semi-transparent Python Blue (#306998) and outlined with a darker - blue (#1e4263). The x-axis is labeled "Finish Time (minutes)" ranging from 150 - to ~370, and the y-axis is labeled "Density" with breaks at 0.002, 0.004, 0.006, - 0.008, 0.010. The distribution is right-skewed with a shoulder around 200 minutes - and a dominant peak around 240 minutes, followed by a long tail extending to ~370 - minutes. Three dashed gray vertical reference lines mark group centroids at x=200, - 240, and 300. At the top of the plot, three text annotations read "Competitive - (~3:20)", "Main Pack (~4:00)", and "Casual (~5:00)". A rug plot of small vertical - ticks (subtle, low alpha) runs along the x-axis base showing individual observations. - The title "density-basic · letsplot · pyplots.ai" appears at the top left. The - background uses a minimal theme with subtle horizontal gridlines only, no vertical - gridlines, and no axis ticks. + - Annotation text size (12) is noticeably smaller than axis text — could be increased + for better visual balance + - Rug plot at alpha=0.15 is very subtle and individual marks are hard to distinguish + in dense regions + image_description: 'The plot displays a density (KDE) curve of marathon finish times + ranging from approximately 150 to 370 minutes. The curve is filled with a muted + Python Blue (#306998) at 55% opacity with a darker blue (#1e4263) outline. The + distribution is right-skewed with a main peak around 235-240 minutes. Three vertical + dashed lines mark group centroids at ~200, ~240, and ~300 minutes, each labeled + with text annotations: "Competitive (~3:20)", "Main Pack (~4:00)", and "Casual + (~5:00)". A subtle rug plot of individual observations runs along the x-axis. + The x-axis reads "Finish Time (minutes)" with ticks at 150-350 in increments of + 50. The y-axis reads "Density (×10⁻³)" with scaled labels 2, 4, 6, 8, 10. The + title "density-basic · letsplot · pyplots.ai" appears at the top left. The background + is clean with minimal theme, no x-grid, subtle light-gray y-grid lines, and no + axis ticks or spines.' criteria_checklist: visual_quality: score: 28 @@ -62,71 +57,68 @@ review: items: - id: VQ-01 name: Text Legibility - score: 8 + score: 7 max: 8 passed: true - comment: 'All font sizes explicitly set: title=24, axis_title=20, axis_text=16. - Group annotations at size=12 readable.' + comment: All font sizes explicitly set (title=24, axis_title=20, axis_text=16). + Annotation text at size=12 readable but slightly small. - id: VQ-02 name: No Overlap - score: 5 + score: 6 max: 6 passed: true - comment: Competitive and Main Pack annotations slightly crowded at top (40 - data-units apart). Not overlapping but tighter than ideal. + comment: Annotations staggered at different y-positions. No text collisions. - id: VQ-03 name: Element Visibility - score: 6 + score: 5 max: 6 passed: true - comment: Density curve perfectly visible with alpha=0.55 fill and size=1.8 - outline. Rug ticks appropriately subtle. + comment: Density curve prominent. Rug plot at alpha=0.15 intentionally subtle + but individual marks hard to distinguish in dense regions. - id: VQ-04 name: Color Accessibility score: 4 max: 4 passed: true - comment: Single series Python Blue with good contrast. No colorblind issues - with monochromatic scheme. + comment: Single-series monochromatic blue. No colorblind concerns. Good contrast. - id: VQ-05 name: Layout & Canvas - score: 3 + score: 4 max: 4 passed: true - comment: Good canvas utilization. Minor left-margin heaviness from y-axis - decimal labels. + comment: Plot fills ~65% of 16:9 canvas. Balanced margins. No cut-off. - id: VQ-06 name: Axis Labels & Title score: 2 max: 2 passed: true - comment: X-axis Finish Time (minutes) has units. Y-axis Density is appropriate. + comment: 'Descriptive labels with units: Finish Time (minutes), Density (×10⁻³). + Correct title format.' design_excellence: - score: 14 + score: 16 max: 20 items: - id: DE-01 name: Aesthetic Sophistication - score: 5 + score: 6 max: 8 passed: true - comment: 'Above defaults: intentional Python Blue palette with darker outline, - multiple info layers, cohesive design. Not quite publication-level.' + comment: Cohesive monochromatic blue palette. Intentional visual hierarchy. + Professional look clearly above defaults. - id: DE-02 name: Visual Refinement - score: 4 + score: 5 max: 6 passed: true - comment: 'Good refinement: minor grids removed, x-grid removed, subtle y-grid, - ticks removed, y-axis expand tuned.' + comment: theme_minimal with x-grid removed, subtle y-grid, ticks removed. + Y-axis rescaling trick for readability. - id: DE-03 name: Data Storytelling score: 5 max: 6 passed: true - comment: 'Strong storytelling: vertical reference lines and group annotations - guide viewer through three runner populations. Lacks color-based focal point - emphasis.' + comment: Three labeled runner groups create clear narrative. Dashed reference + lines guide viewer. Right-skewed distribution tells immediate story. spec_compliance: score: 15 max: 15 @@ -136,28 +128,27 @@ review: score: 5 max: 5 passed: true - comment: Correct KDE/density plot using geom_density() with gaussian kernel. + comment: Correct density/KDE plot using geom_density() with Gaussian kernel. - id: SC-02 name: Required Features score: 4 max: 4 passed: true - comment: Smooth density curve, fill with transparency, rug plot, appropriate - bandwidth, trim. + comment: Smooth KDE curve, fill with transparency, rug plot, bandwidth control. + All present. - id: SC-03 name: Data Mapping score: 3 max: 3 passed: true - comment: X-axis correctly maps continuous variable, y-axis shows density. - Full data range visible. + comment: Continuous variable on x-axis, density on y-axis. All data visible. - id: SC-04 name: Title & Legend score: 3 max: 3 passed: true - comment: Title density-basic · letsplot · pyplots.ai follows exact format. - No legend needed for single series. + comment: Title 'density-basic · letsplot · pyplots.ai' correct. No legend + needed for single series. data_quality: score: 15 max: 15 @@ -167,15 +158,15 @@ review: score: 6 max: 6 passed: true - comment: Shows right-skew, multimodality, long tail, rug plot for individual - observations. All key density plot features. + comment: Multimodal distribution shows skewness, multiple modes, and population + substructure. - id: DQ-02 name: Realistic Context score: 5 max: 5 passed: true - comment: 'Marathon finish times: real, neutral, comprehensible. Three runner - groups reflect realistic demographics.' + comment: Marathon finish times - real-world, neutral scenario with three realistic + runner groups. - id: DQ-03 name: Appropriate Scale score: 4 @@ -192,32 +183,32 @@ review: score: 3 max: 3 passed: true - comment: Clean Imports → Data → Plot → Save structure. No functions or classes. + comment: Clean Imports → Data → Plot → Save flow. No functions or classes. - id: CQ-02 name: Reproducibility score: 2 max: 2 passed: true - comment: np.random.seed(42) set before all data generation. + comment: np.random.seed(42) set before random generation. - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: numpy, pandas, lets_plot all used. noqa comments appropriate for - wildcard import. + comment: numpy, pandas, lets_plot all used. No unused imports. - id: CQ-04 name: Code Elegance score: 2 max: 2 passed: true - comment: Clean ggplot chain. Rug via geom_segment is appropriate. No over-engineering. + comment: Clean Pythonic code. Appropriate complexity. Separate DataFrames + for rug and annotations. - id: CQ-05 name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png with ggsave() and scale=3. Also exports HTML. + comment: Saves plot.png via ggsave(scale=3) and plot.html. Current API. library_mastery: score: 7 max: 10 @@ -227,13 +218,13 @@ review: score: 4 max: 5 passed: true - comment: 'Good ggplot grammar: aes(), geom_density() with kernel/adjust/trim, - geom_segment(), geom_vline(), geom_text(), proper scale and theme usage.' + comment: 'Proper ggplot grammar. Uses lets_plot-specific patterns: ggsize, + ggsave(scale=3), LetsPlot.setup_html(). Good scale_y_continuous trick.' - id: LM-02 name: Distinctive Features score: 3 max: 5 passed: true - comment: Uses layer_tooltips() with custom line formatting for interactive - hover. HTML export leverages letsplot interactive output. - verdict: REJECTED + comment: layer_tooltips() with custom format is distinctive to lets_plot. + HTML export leverages interactive capabilities. + verdict: APPROVED