From 78bbb11cd64055ab7ab2f3ae80c2d972432a1ced Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:27:26 +0000 Subject: [PATCH 1/4] feat(seaborn): implement windrose-basic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regen from quality 88. Addressed: - canvas contract: figsize was (12,12)/dpi=300 with bbox_inches="tight" (~3550x3550 effective) instead of the mandated 2400x2400 square; now figsize=(6,6)/dpi=400 with no bbox_inches override - title was missing the mandated "python" language token - font sizes rescaled for the corrected (smaller) canvas per the library sizing table, instead of carrying forward the old canvas's values - legend previously relied on bbox_to_anchor=(1.15, 0) to push outside the axes, which only worked because bbox_inches="tight" expanded the saved canvas to include it; now placed inside the axes bounds so nothing is clipped by the fixed-size canvas - moved the radial % label spoke off the default 22.5° position into the near-empty E/SE sector - switched direction bars from gapped (width*0.9) to contiguous petals: the gap between a near-empty sector and its tall dominant neighbor was rendering as a stray line cutting across the chart - library_mastery weakness (LM-02, distinctive seaborn features): added a sns.kdeplot inset showing the overall wind-speed distribution, built via sns.color_palette; kept the matplotlib polar bar structure the review praised (DE-01/DE-02/DE-03, alpha-based dominant-sector emphasis) Strengths preserved unchanged: Okabe-Ito-derived Imprint palette order, alpha hierarchy (0.90 dominant / 0.65 weak sectors), Weibull-distributed speed data, seeded reproducibility. --- .../implementations/python/seaborn.py | 71 +++++++++++-------- 1 file changed, 42 insertions(+), 29 deletions(-) diff --git a/plots/windrose-basic/implementations/python/seaborn.py b/plots/windrose-basic/implementations/python/seaborn.py index ea35fd4f07..11ab209aa7 100644 --- a/plots/windrose-basic/implementations/python/seaborn.py +++ b/plots/windrose-basic/implementations/python/seaborn.py @@ -1,7 +1,7 @@ -""" anyplot.ai +"""anyplot.ai windrose-basic: Wind Rose Chart -Library: seaborn 0.13.2 | Python 3.13.13 -Quality: 88/100 | Updated: 2026-05-07 +Library: seaborn 0.13.2 | Python 3.13.12 +Quality: 88/100 | Updated: 2026-08-05 """ import os @@ -18,8 +18,9 @@ INK = "#1A1A17" if THEME == "light" else "#F0EFE8" INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" -# Okabe-Ito palette for speed ranges (cool to warm progression) -IMPRINT = ["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030"] +# Imprint palette for speed ranges (cool to warm progression), built via +# seaborn's own palette API so downstream seaborn calls (kdeplot) share it. +IMPRINT = sns.color_palette(["#009E73", "#C475FD", "#4467A3", "#BD8233", "#AE3030"]) # Configure seaborn sns.set_theme( @@ -88,10 +89,11 @@ frequencies = frequencies / n_obs * 100 -# Plot -fig = plt.figure(figsize=(12, 12), facecolor=PAGE_BG) -ax = fig.add_subplot(111, projection="polar") - +# Plot: polar wind rose fills the square canvas; legend and a seaborn KDE +# inset sit in the corners that fall outside the circle, which the bars +# (clipped to the radial axis limit) never reach regardless of direction. +fig = plt.figure(figsize=(6, 6), dpi=400, facecolor=PAGE_BG) +ax = fig.add_axes((0.06, 0.06, 0.88, 0.88), projection="polar") ax.set_facecolor(PAGE_BG) ax.set_theta_zero_location("N") ax.set_theta_direction(-1) @@ -103,57 +105,68 @@ dominant_threshold = np.percentile(total_freq, 75) is_dominant = total_freq > dominant_threshold -# Plot stacked bars with Okabe-Ito palette +# Plot stacked bars with the Imprint palette bottoms = np.zeros(n_dir_bins) for j, (label, color) in enumerate(zip(speed_labels, IMPRINT, strict=False)): - # Use full alpha for dominant sectors, reduced for weaker ones alpha_per_sector = np.where(is_dominant, 0.90, 0.65) - - # Plot all sectors in one call, then manually adjust alpha if possible + # Contiguous petals (full dir_width, no inter-sector gap): a gap here would + # leave a thin sliver of background between direction bins that, next to a + # tall dominant sector, reads as a stray line cutting across the chart. bars = ax.bar( theta, frequencies[:, j], - width=dir_width * 0.9, + width=dir_width, bottom=bottoms, color=color, edgecolor=PAGE_BG, - linewidth=0.5, + linewidth=0.7, label=label, - alpha=0.85, ) - - # Adjust individual bar alpha for dominant directions for bar, alpha_val in zip(bars, alpha_per_sector, strict=False): bar.set_alpha(alpha_val) - bottoms += frequencies[:, j] -# Style -ax.set_title("windrose-basic · seaborn · anyplot.ai", fontsize=24, pad=20, fontweight="medium", color=INK) +# Title +ax.set_title("windrose-basic · python · seaborn · anyplot.ai", fontsize=12, pad=16, fontweight="medium", color=INK) max_freq = np.ceil(bottoms.max() / 5) * 5 ax.set_ylim(0, max_freq) ax.set_yticks(np.arange(0, max_freq + 1, 5)) -ax.set_yticklabels([f"{int(y)}%" for y in np.arange(0, max_freq + 1, 5)], fontsize=14, color=INK_SOFT) +ax.set_yticklabels([f"{int(y)}%" for y in np.arange(0, max_freq + 1, 5)], fontsize=9, color=INK_SOFT) +# Move the radial-label spoke into the near-empty E/SE sector so it doesn't +# cut across the dominant, densely colored bars. +ax.set_rlabel_position(112.5) direction_labels = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] ax.set_xticks(np.deg2rad(np.arange(0, 360, 45))) -ax.set_xticklabels(direction_labels, fontsize=18, fontweight="medium", color=INK) +ax.set_xticklabels(direction_labels, fontsize=11, fontweight="medium", color=INK) -# Enhanced grid styling with subtle radial emphasis +# Grid styling ax.grid(True, alpha=0.12, linestyle="-", linewidth=0.8, color=INK_SOFT) for spine in ax.spines.values(): spine.set_color(INK_SOFT) spine.set_linewidth(1.1) -legend = ax.legend( - title="Wind Speed", loc="lower right", bbox_to_anchor=(1.15, 0), fontsize=14, title_fontsize=16, framealpha=0.95 -) +# Legend stays inside the axes bounding box (bottom-right corner, outside the +# circle) so nothing gets clipped by the fixed-size canvas. +legend = ax.legend(title="Wind Speed", loc="lower right", fontsize=9, title_fontsize=10, framealpha=0.95) legend.get_frame().set_facecolor(ELEVATED_BG) legend.get_frame().set_edgecolor(INK_SOFT) legend.get_title().set_color(INK) for text in legend.get_texts(): text.set_color(INK) -plt.tight_layout() -plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG) +# Distinctive seaborn feature: a kernel-density estimate of the overall speed +# distribution, tucked into the opposite (top-left) empty corner. +inset = fig.add_axes((0.05, 0.72, 0.24, 0.20)) +sns.kdeplot(x=speeds, fill=True, color=IMPRINT[0], alpha=0.55, linewidth=1.2, ax=inset) +inset.set_facecolor(PAGE_BG) +inset.set_title("Speed distribution", fontsize=8, color=INK, pad=3) +inset.set_xlabel("Wind speed (m/s)", fontsize=7, color=INK_SOFT) +inset.set_ylabel("") +inset.set_yticks([]) +inset.tick_params(axis="x", labelsize=6, colors=INK_SOFT) +sns.despine(ax=inset, left=True) +inset.spines["bottom"].set_color(INK_SOFT) + +fig.savefig(f"plot-{THEME}.png", dpi=400, facecolor=PAGE_BG) From 57b57c27f9886a930892c65334b59779693e67ca Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:27:44 +0000 Subject: [PATCH 2/4] chore(seaborn): add metadata for windrose-basic --- .../metadata/python/seaborn.yaml | 231 +----------------- 1 file changed, 10 insertions(+), 221 deletions(-) diff --git a/plots/windrose-basic/metadata/python/seaborn.yaml b/plots/windrose-basic/metadata/python/seaborn.yaml index f8332769e0..6096991a0b 100644 --- a/plots/windrose-basic/metadata/python/seaborn.yaml +++ b/plots/windrose-basic/metadata/python/seaborn.yaml @@ -1,232 +1,21 @@ +# Per-library metadata for seaborn implementation of windrose-basic +# Auto-generated by impl-generate.yml + library: seaborn language: python specification_id: windrose-basic created: '2025-12-24T22:16:59Z' -updated: '2026-05-07T03:33:08Z' -generated_by: claude-haiku -workflow_run: 25474192715 +updated: '2026-08-05T15:27:42Z' +generated_by: claude-sonnet +workflow_run: 31018968906 issue: 1880 -python_version: 3.13.13 +language_version: 3.13.14 library_version: 0.13.2 preview_url_light: https://storage.googleapis.com/anyplot-images/plots/windrose-basic/python/seaborn/plot-light.png preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/windrose-basic/python/seaborn/plot-dark.png preview_html_light: null preview_html_dark: null -quality_score: 88 +quality_score: null review: - strengths: - - 'Perfect visual quality: All 8 VQ criteria at maximum with explicit font sizing - and flawless theme adaptation' - - 'Impeccable readability in both themes: Light and dark renders both fully legible - with zero dark-on-dark or light-on-light issues' - - 'Complete spec compliance: All windrose features present and correct with proper - title and legend formatting' - - 'Excellent data quality: Realistic meteorological data with plausible Weibull-distributed - speeds and natural prevailing wind patterns' - - 'Thoughtful design choices: Alpha variation (0.90 dominant, 0.65 weaker) creates - visual hierarchy emphasizing prevailing SW winds' - - 'Clean, reproducible code: Deterministic data generation with explicit seed and - straightforward structure' - - 'Professional presentation: Proper typography hierarchy (24pt/18pt/14pt), balanced - layout, well-positioned legend on elevated background' - weaknesses: - - 'Limited distinctive seaborn features: Wind rose requires custom matplotlib implementation; - seaborn''s role is primarily theming rather than leveraging distinctive plotting - capabilities (FacetGrid, hue patterns, etc.)' - image_description: |- - Light render (plot-light.png): - Background: Warm off-white (#FAF8F1) - Chrome: Title in 24pt dark text, direction labels in 18pt dark, radial labels in 14pt soft gray — all clearly readable - Data: Green (#009E73, 0-3 m/s innermost), orange (#D55E00), blue (#0072B2), pink (#CC79A7), yellow (#E69F00, 15+ m/s outermost); SW sector dominates with full opacity (0.90), weaker sectors at reduced opacity (0.65); stacked composition clearly visible - Legibility verdict: PASS - All text crisp and fully readable; no overlap; contrast excellent - - Dark render (plot-dark.png): - Background: Warm near-black (#1A1A17) - Chrome: Title in light text (#F0EFE8), direction labels in light text, radial labels in soft light gray (#B8B7B0) — all clearly visible against dark background; critically, NO dark-on-dark text failures present - Data: Identical colors to light render (green, orange, blue, pink, yellow in same positions); opacity variation (0.90 dominant, 0.65 weaker) preserved - Legibility verdict: PASS - All elements visible; legend readable on elevated dark background (#242420); theme adaptation flawless; both renders equally readable - criteria_checklist: - visual_quality: - score: 30 - max: 30 - items: - - id: VQ-01 - name: Text Legibility - score: 8 - max: 8 - passed: true - comment: All font sizes explicitly set (24pt, 18pt, 14pt); perfectly readable - in both themes - - id: VQ-02 - name: No Overlap - score: 6 - max: 6 - passed: true - comment: No overlapping text; all labels fully separated - - id: VQ-03 - name: Element Visibility - score: 6 - max: 6 - passed: true - comment: Stacked bars clearly visible; colors distinct; opacity variation - optimal - - id: VQ-04 - name: Color Accessibility - score: 2 - max: 2 - passed: true - comment: Okabe-Ito palette CVD-safe; adequate contrast - - id: VQ-05 - name: Layout & Canvas - score: 4 - max: 4 - passed: true - comment: Polar plot fills canvas beautifully; balanced margins - - id: VQ-06 - name: Axis Labels & Title - score: 2 - max: 2 - passed: true - comment: Title correct; labels descriptive with units - - id: VQ-07 - name: Palette Compliance - score: 2 - max: 2 - passed: true - comment: 'First series #009E73; colors follow Okabe-Ito; backgrounds #FAF8F1 - and #1A1A17; theme-adaptive chrome in both' - design_excellence: - score: 14 - max: 20 - items: - - id: DE-01 - name: Aesthetic Sophistication - score: 5 - max: 8 - passed: true - comment: Thoughtful design with alpha variation; above defaults but not exceptional - - id: DE-02 - name: Visual Refinement - score: 5 - max: 6 - passed: true - comment: Custom grid styling; theme-aware spines; elegant legend frame - - id: DE-03 - name: Data Storytelling - score: 4 - max: 6 - passed: true - comment: Visual hierarchy through opacity guides reader to dominant SW winds - spec_compliance: - score: 15 - max: 15 - items: - - id: SC-01 - name: Plot Type - score: 5 - max: 5 - passed: true - comment: Correct wind rose with 8 directions and 5 speed bins - - id: SC-02 - name: Required Features - score: 4 - max: 4 - passed: true - comment: 'All features present: sectors, bins, stacking, legend, percentages' - - id: SC-03 - name: Data Mapping - score: 3 - max: 3 - passed: true - comment: Polar angle = direction; radial = frequency; all data visible - - id: SC-04 - name: Title & Legend - score: 3 - max: 3 - passed: true - comment: Title and legend correct format - data_quality: - score: 15 - max: 15 - items: - - id: DQ-01 - name: Feature Coverage - score: 6 - max: 6 - passed: true - comment: Shows all aspects of wind rose - - id: DQ-02 - name: Realistic Context - score: 5 - max: 5 - passed: true - comment: Realistic weather data with plausible distributions - - id: DQ-03 - name: Appropriate Scale - score: 4 - max: 4 - passed: true - comment: Wind speeds and proportions physically realistic - code_quality: - score: 10 - max: 10 - items: - - id: CQ-01 - name: KISS Structure - score: 3 - max: 3 - passed: true - comment: 'Linear: imports→data→plot→save' - - id: CQ-02 - name: Reproducibility - score: 2 - max: 2 - passed: true - comment: Seed set (42); fully deterministic - - id: CQ-03 - name: Clean Imports - score: 2 - max: 2 - passed: true - comment: All imports used - - id: CQ-04 - name: Code Elegance - score: 2 - max: 2 - passed: true - comment: Clean, Pythonic, appropriate complexity - - id: CQ-05 - name: Output & API - score: 1 - max: 1 - passed: true - comment: Saves as plot-{THEME}.png - library_mastery: - score: 4 - max: 10 - items: - - id: LM-01 - name: Idiomatic Usage - score: 3 - max: 5 - passed: true - comment: Proper seaborn theming, but wind rose requires matplotlib - - id: LM-02 - name: Distinctive Features - score: 1 - max: 5 - passed: false - comment: Limited distinctive seaborn usage; wind rose necessitates matplotlib - verdict: APPROVED -impl_tags: - dependencies: [] - techniques: - - polar-projection - - manual-ticks - patterns: - - data-generation - - matrix-construction - dataprep: [] - styling: - - grid-styling - - alpha-blending + strengths: [] + weaknesses: [] From 86d617324f673259fa29b02524e41954d55dc38d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:41:28 +0000 Subject: [PATCH 3/4] chore(seaborn): update quality score 80 and review feedback for windrose-basic --- .../implementations/python/seaborn.py | 6 +- .../metadata/python/seaborn.yaml | 245 +++++++++++++++++- 2 files changed, 241 insertions(+), 10 deletions(-) diff --git a/plots/windrose-basic/implementations/python/seaborn.py b/plots/windrose-basic/implementations/python/seaborn.py index 11ab209aa7..acc8180751 100644 --- a/plots/windrose-basic/implementations/python/seaborn.py +++ b/plots/windrose-basic/implementations/python/seaborn.py @@ -1,7 +1,7 @@ -"""anyplot.ai +""" anyplot.ai windrose-basic: Wind Rose Chart -Library: seaborn 0.13.2 | Python 3.13.12 -Quality: 88/100 | Updated: 2026-08-05 +Library: seaborn 0.13.2 | Python 3.13.14 +Quality: 80/100 | Updated: 2026-08-05 """ import os diff --git a/plots/windrose-basic/metadata/python/seaborn.yaml b/plots/windrose-basic/metadata/python/seaborn.yaml index 6096991a0b..657e22f564 100644 --- a/plots/windrose-basic/metadata/python/seaborn.yaml +++ b/plots/windrose-basic/metadata/python/seaborn.yaml @@ -1,11 +1,8 @@ -# Per-library metadata for seaborn implementation of windrose-basic -# Auto-generated by impl-generate.yml - library: seaborn language: python specification_id: windrose-basic created: '2025-12-24T22:16:59Z' -updated: '2026-08-05T15:27:42Z' +updated: '2026-08-05T15:41:27Z' generated_by: claude-sonnet workflow_run: 31018968906 issue: 1880 @@ -15,7 +12,241 @@ preview_url_light: https://storage.googleapis.com/anyplot-images/plots/windrose- preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/windrose-basic/python/seaborn/plot-dark.png preview_html_light: null preview_html_dark: null -quality_score: null +quality_score: 80 review: - strengths: [] - weaknesses: [] + strengths: + - 'Correct wind-rose chart type: 8-sector polar stacked histogram with a realistic + prevailing-SW wind pattern (secondary NE lobe) and Weibull-distributed speeds + per direction' + - Imprint categorical palette applied in exact canonical order across all 5 speed + bins, identical hues in light and dark renders, with fully theme-correct chrome + (background, ticks, legend, grid) in both themes + - 'Genuine data storytelling: alpha emphasis (0.90 vs 0.65) highlights the dominant + >75th-percentile sectors, and the seaborn kdeplot inset adds real distributional + context beyond the rose itself — an idiomatic, distinctive seaborn feature' + - 'Clean, reproducible, KISS-structured code: seed set, only used imports, correct + f''plot-{THEME}.png'' save API, no bbox_inches=''tight'', exact mandated title + string' + - Exact 2400x2400 canvas with no edge clipping on N/S/W/E labels or the outer circle + weaknesses: + - 'The NW compass label is completely hidden behind the opaque ''Speed distribution'' + KDE inset panel (fig.add_axes at (0.05, 0.72, 0.24, 0.20) with an opaque PAGE_BG + facecolor, added after the polar axes so it draws on top and occludes whatever + tick label sits underneath). The SE compass label is likewise crowded out / hidden + by the radial % tick labels (rlabel_position=112.5deg, which sits almost exactly + at the SE bearing) and the adjacent ''Wind Speed'' legend box occupying the same + lower-right corner. Confirmed by pixel-cropping both corners: neither ''NW'' nor + ''SE'' text is visible in either theme, even though N/NE/E/S/SW/W all render cleanly. + 2 of the 8 required compass directions are effectively erased — the code''s comments + assume these corners are ''empty'' but they still carry the fixed compass-label + ring around the full circle. Reposition the inset/legend/rlabel spoke (e.g. shrink + further into the true corner past the label radius, or explicitly check clearance + against the tick-label ring, not just the data wedges) so no compass label is + ever covered.' + - The KDE inset's own tick/label text (fontsize 6-7pt) is noticeably smaller than + the rest of the chart's typography and risks becoming illegible at ~400px mobile + width — bump to ~8-9pt or simplify the tick count. + - No explicit radial-axis title (e.g. 'Frequency (%)') — the '%' suffix on the tick + labels implies it, but an explicit label would remove any ambiguity about what + the radius encodes. + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1), matches spec, not pure white. + Chrome: Title "windrose-basic · python · seaborn · anyplot.ai" in dark ink at top-left of the polar area, compact and fully readable. Compass labels N (top), NE (upper-right), E (right), S (bottom), SW (lower-left), W (left) all render clearly in dark ink against the cream background. Radial percentage ticks (5%-35%) legible in soft grey. Legend "Wind Speed" box (cream fill, dark border) bottom-right, all 5 entries readable. + Data: Stacked polar bars — brand green (0-3 m/s) innermost, then lavender (3-6), blue (6-10), ochre (10-15), matte red (15+ m/s, outermost) — matching Imprint canonical order with #009E73 first. Dominant SW-S sector reaches ~30-35%, secondary N-NE sector reaches ~12-15%, other sectors near-empty. KDE inset (top-left) shows a right-skewed green density curve for overall wind speed. + Legibility verdict: FAIL — pixel-cropping the top-left and lower-right corners confirms the "NW" compass label is completely hidden underneath the opaque KDE inset panel, and the "SE" compass label is hidden/crowded out by the radial tick-label cascade and the adjacent legend box. All other text is readable. + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17), matches spec, not pure black. + Chrome: Title and all visible compass labels (N, NE, E, S, SW, W) render in light ink (#F0EFE8), clearly legible against the dark background — no dark-on-dark failures observed. Radial ticks and legend box use theme-adaptive dark-elevated fill (#242420) with light text, fully readable. Grid lines subtle and visible. + Data: Identical hues to the light render — brand green, lavender, blue, ochre, matte red in the same canonical order and same stacking — confirms only chrome flipped between themes, not data colors. + Legibility verdict: FAIL — same NW/SE compass-label occlusion issue as the light render (KDE inset panel and legend/radial-label cluster cover the same angular positions in both themes, since geometry is theme-independent). All other chrome is theme-correct and legible. + criteria_checklist: + visual_quality: + score: 20 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 6 + max: 8 + passed: true + comment: All font sizes explicitly set and readable in both themes; tiny 6-7pt + inset tick labels are the only borderline-mobile-legibility concern + - id: VQ-02 + name: No Overlap + score: 2 + max: 6 + passed: false + comment: NW compass label fully hidden behind the opaque KDE inset panel; + SE compass label hidden/crowded by the radial tick labels and legend box + occupying the same corner + - id: VQ-03 + name: Element Visibility + score: 5 + max: 6 + passed: true + comment: Stacked bars and KDE fill clearly visible and density-appropriate + (alpha emphasis on dominant sectors) + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Imprint palette provides adequate CVD-safe contrast between adjacent + speed bins + - id: VQ-05 + name: Layout & Canvas + score: 1 + max: 4 + passed: false + comment: Good canvas fill overall, but the inset/legend/rlabel placement collides + with the compass tick-label ring, erasing 2 of 8 direction labels + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: Radial % ticks and inset 'Wind speed (m/s)' label are descriptive + with units + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First series #009E73, canonical Imprint order for all 5 bins, theme-correct + chrome in both renders' + design_excellence: + score: 14 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + comment: Deliberate composition (dominant-sector emphasis, corner-tucked KDE + panel, repositioned radial label spoke) goes beyond a configured default, + though the corner-collision bug undercuts the intentional-hierarchy claim + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + comment: Subtle grid, despined inset, generous margins; the label-occlusion + issue keeps this from 'every detail polished' + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + comment: Alpha emphasis on dominant sectors plus the KDE inset create real + visual hierarchy pointing at the prevailing-wind insight + spec_compliance: + score: 14 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + comment: Correct polar stacked-histogram wind rose + - id: SC-02 + name: Required Features + score: 3 + max: 4 + comment: 8 direction bins, 5 speed bins, N-at-top, legend, radial frequency + % all present, but 2 direction labels are functionally invisible + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + comment: Direction=theta, frequency=radius, speed=stacked color, correctly + mapped + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + comment: Exact mandated title string; legend labels match the speed bins exactly + data_quality: + score: 14 + max: 15 + items: + - id: DQ-01 + name: Feature Coverage + score: 5 + max: 6 + comment: Dominant SW, secondary NE, minor W sectors with full speed-bin stacking, + plus KDE distribution shape + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + comment: Real, neutral meteorological wind-station scenario + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + comment: Weibull-based speeds clipped to a realistic 0-25 m/s range, plausible + frequency percentages + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + comment: Flat script, no functions/classes + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + comment: np.random.seed(42) + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + comment: Only os, matplotlib, numpy, seaborn, all used + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + comment: Appropriately complex, no fake functionality + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + comment: Correct f'plot-{THEME}.png' save, no bbox_inches='tight' + library_mastery: + score: 8 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 4 + max: 5 + comment: sns.set_theme/color_palette/kdeplot/despine used idiomatically; the + core rose itself is necessarily raw matplotlib since seaborn has no windrose + primitive + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + comment: The seaborn kdeplot inset is a genuine distinctive-library feature + tied into the wind rose, though somewhat tacked-on rather than deeply integrated + verdict: REJECTED +impl_tags: + dependencies: [] + techniques: + - polar-projection + - inset-axes + - manual-ticks + patterns: + - data-generation + - matrix-construction + - iteration-over-groups + dataprep: + - binning + - kde + styling: + - alpha-blending + - edge-highlighting + - grid-styling From cf897606fff246755684c48074aa9597241f371f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 5 Aug 2026 15:46:53 +0000 Subject: [PATCH 4/4] fix(seaborn): address review feedback for windrose-basic Attempt 1/4 - fixes based on AI review --- .../implementations/python/seaborn.py | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/plots/windrose-basic/implementations/python/seaborn.py b/plots/windrose-basic/implementations/python/seaborn.py index acc8180751..9b5065996d 100644 --- a/plots/windrose-basic/implementations/python/seaborn.py +++ b/plots/windrose-basic/implementations/python/seaborn.py @@ -1,4 +1,4 @@ -""" anyplot.ai +"""anyplot.ai windrose-basic: Wind Rose Chart Library: seaborn 0.13.2 | Python 3.13.14 Quality: 80/100 | Updated: 2026-08-05 @@ -93,7 +93,10 @@ # inset sit in the corners that fall outside the circle, which the bars # (clipped to the radial axis limit) never reach regardless of direction. fig = plt.figure(figsize=(6, 6), dpi=400, facecolor=PAGE_BG) -ax = fig.add_axes((0.06, 0.06, 0.88, 0.88), projection="polar") +# Axes deliberately smaller than the full canvas (vs. a near-full-bleed square) +# so the compass-label ring (just outside the circle) has real clearance from +# the figure's literal corners before the inset/legend boxes anchored there. +ax = fig.add_axes((0.17, 0.17, 0.66, 0.66), projection="polar") ax.set_facecolor(PAGE_BG) ax.set_theta_zero_location("N") ax.set_theta_direction(-1) @@ -147,9 +150,18 @@ spine.set_color(INK_SOFT) spine.set_linewidth(1.1) -# Legend stays inside the axes bounding box (bottom-right corner, outside the -# circle) so nothing gets clipped by the fixed-size canvas. -legend = ax.legend(title="Wind Speed", loc="lower right", fontsize=9, title_fontsize=10, framealpha=0.95) +# Legend anchored to the figure's literal bottom-right corner (not the axes' +# own bounding box) so it sits well beyond the SE compass-label ring instead +# of overlapping it. +legend = ax.legend( + title="Wind Speed", + loc="lower right", + bbox_to_anchor=(0.99, 0.01), + bbox_transform=fig.transFigure, + fontsize=8, + title_fontsize=9, + framealpha=0.95, +) legend.get_frame().set_facecolor(ELEVATED_BG) legend.get_frame().set_edgecolor(INK_SOFT) legend.get_title().set_color(INK) @@ -157,15 +169,17 @@ text.set_color(INK) # Distinctive seaborn feature: a kernel-density estimate of the overall speed -# distribution, tucked into the opposite (top-left) empty corner. -inset = fig.add_axes((0.05, 0.72, 0.24, 0.20)) +# distribution, tucked fully into the figure's literal top-left corner (past +# the NW compass-label ring, not just past the data wedges) so it never +# occludes the label ring the polar axes draws around its full circle. +inset = fig.add_axes((0.015, 0.815, 0.155, 0.155)) sns.kdeplot(x=speeds, fill=True, color=IMPRINT[0], alpha=0.55, linewidth=1.2, ax=inset) inset.set_facecolor(PAGE_BG) inset.set_title("Speed distribution", fontsize=8, color=INK, pad=3) -inset.set_xlabel("Wind speed (m/s)", fontsize=7, color=INK_SOFT) +inset.set_xlabel("Wind speed (m/s)", fontsize=8, color=INK_SOFT) inset.set_ylabel("") inset.set_yticks([]) -inset.tick_params(axis="x", labelsize=6, colors=INK_SOFT) +inset.tick_params(axis="x", labelsize=8, colors=INK_SOFT) sns.despine(ax=inset, left=True) inset.spines["bottom"].set_color(INK_SOFT)