diff --git a/plots/polar-bar/implementations/python/letsplot.py b/plots/polar-bar/implementations/python/letsplot.py index e78cb4afca..a45ec00035 100644 --- a/plots/polar-bar/implementations/python/letsplot.py +++ b/plots/polar-bar/implementations/python/letsplot.py @@ -1,9 +1,11 @@ -""" pyplots.ai +""" anyplot.ai polar-bar: Polar Bar Chart (Wind Rose) -Library: letsplot 4.8.2 | Python 3.13.11 -Quality: 92/100 | Created: 2025-12-30 +Library: letsplot 4.9.0 | Python 3.13.13 +Quality: 92/100 | Updated: 2026-05-13 """ +import os + import numpy as np import pandas as pd from lets_plot import ( @@ -11,9 +13,11 @@ aes, coord_polar, element_line, + element_rect, element_text, geom_bar, ggplot, + ggsave, ggsize, labs, scale_fill_manual, @@ -21,45 +25,51 @@ theme, theme_minimal, ) -from lets_plot.export import ggsave LetsPlot.setup_html() -# Data - Wind direction frequency data (8 compass directions) -np.random.seed(42) -directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] +# Theme-adaptive colors +THEME = os.getenv("ANYPLOT_THEME", "light") +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" -# Generate realistic wind frequency data -frequencies = np.array([15, 8, 12, 5, 10, 18, 22, 14]) +# Okabe-Ito palette + adaptive neutral for 8 compass directions +OKABE_ITO = ["#009E73", "#D55E00", "#0072B2", "#CC79A7", "#E69F00", "#56B4E9", "#F0E442"] +NEUTRAL = "#1A1A1A" if THEME == "light" else "#E8E8E0" +DIRECTION_COLORS = OKABE_ITO + [NEUTRAL] -# Create DataFrame - direction as categorical factor +# Data - Monsoon wind pattern (SW-dominant, distinct from westerlies) +directions = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] +frequencies = np.array([3, 5, 6, 12, 28, 35, 6, 5]) + +# Create DataFrame df = pd.DataFrame( {"direction": pd.Categorical(directions, categories=directions, ordered=True), "frequency": frequencies} ) # Create polar bar chart (wind rose) -# Use coord_polar to wrap bars in a circle plot = ( ggplot(df, aes(x="direction", y="frequency", fill="direction")) - + geom_bar(stat="identity", color="white", size=0.8, alpha=0.85, width=0.95) - + coord_polar(start=-np.pi / 8) # Rotate so N is at top - + scale_fill_manual(values=["#306998", "#4A90C2", "#FFD43B", "#F5A623", "#7B68EE", "#9B59B6", "#2ECC71", "#27AE60"]) + + geom_bar(stat="identity", color="white", size=0.5, alpha=0.85, width=0.95) + + coord_polar(start=-np.pi / 8) + + scale_fill_manual(values=DIRECTION_COLORS) + scale_y_continuous(limits=[0, None], expand=[0, 0.5]) - + labs(title="polar-bar · letsplot · pyplots.ai", x="", y="Frequency (%)") + + labs(title="polar-bar · letsplot · anyplot.ai", x="", y="Frequency (%)") + theme_minimal() + theme( - plot_title=element_text(size=24, face="bold"), - axis_title_y=element_text(size=18), - axis_text=element_text(size=14), - legend_position="none", # Hide legend (labels shown around chart) - panel_grid_major=element_line(color="#CCCCCC", size=0.3), + plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), + panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG), + panel_grid_major=element_line(color=INK_SOFT, size=0.3), + plot_title=element_text(size=24, color=INK, face="bold"), + axis_title_y=element_text(size=20, color=INK), + axis_text=element_text(size=16, color=INK_SOFT), + legend_position="none", ) - + ggsize(1200, 1200) # Square for polar chart + + ggsize(1200, 1200) ) -# Save as PNG (scale 3x for high resolution: 3600x3600 for square polar) -ggsave(plot, "plot.png", scale=3, path=".") - -# Save interactive HTML -ggsave(plot, "plot.html", path=".") +# Save as PNG and HTML (theme-suffixed) +ggsave(plot, f"plot-{THEME}.png", scale=3, path=".") +ggsave(plot, f"plot-{THEME}.html", path=".") diff --git a/plots/polar-bar/metadata/python/letsplot.yaml b/plots/polar-bar/metadata/python/letsplot.yaml index d161f6c133..64f52ec7e1 100644 --- a/plots/polar-bar/metadata/python/letsplot.yaml +++ b/plots/polar-bar/metadata/python/letsplot.yaml @@ -1,160 +1,187 @@ library: letsplot +language: python specification_id: polar-bar created: '2025-12-30T16:36:44Z' -updated: '2025-12-30T16:45:26Z' -generated_by: claude-opus-4-5-20251101 -workflow_run: 20601061239 -issue: 0 -python_version: 3.13.11 -library_version: 4.8.2 -preview_url: https://storage.googleapis.com/anyplot-images/plots/polar-bar/letsplot/plot.png -preview_html: https://storage.googleapis.com/anyplot-images/plots/polar-bar/letsplot/plot.html +updated: '2026-05-13T01:30:22Z' +generated_by: claude-haiku +workflow_run: 25772046568 +issue: 2693 +python_version: 3.13.13 +library_version: 4.9.0 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/polar-bar/python/letsplot/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/polar-bar/python/letsplot/plot-dark.png +preview_html_light: https://storage.googleapis.com/anyplot-images/plots/polar-bar/python/letsplot/plot-light.html +preview_html_dark: https://storage.googleapis.com/anyplot-images/plots/polar-bar/python/letsplot/plot-dark.html quality_score: 92 -impl_tags: - dependencies: [] - techniques: - - polar-projection - patterns: - - data-generation - dataprep: [] - styling: [] review: strengths: - - Correct polar bar/wind rose implementation using coord_polar - - Good color differentiation across 8 compass directions - - Clean KISS code structure with proper seed for reproducibility - - Appropriate use of lets-plot grammar of graphics features (geom_bar + coord_polar) - - Well-formatted title following spec-id · library · pyplots.ai convention + - Proper polar coordinate system implementation showing clear directional distribution + - Theme-adaptive design correctly applies light (#FAF8F1 background, dark ink) and + dark (#1A1A17 background, light ink) tokens in both renders + - Excellent text legibility in both themes with no contrast issues—all compass directions, + title, and axis labels clearly readable + - Clean, idiomatic lets_plot code using coord_polar and ggplot grammar patterns + effectively + - Correct Okabe-Ito palette integration with 8 direction colors, maintains color + consistency across themes + - Wind rose format effectively communicates frequency distribution with SW dominance + visually apparent + - White bar edges provide subtle definition without clutter weaknesses: - - Y-axis label shows Frequency (%) but data appears to be absolute counts not percentages - - Direction labels (NE, SE) positioned outside the plot area - could be more integrated - - Consider adding radial gridlines for easier magnitude reading - image_description: 'The plot displays a polar bar chart (wind rose) with 8 compass - directions (N, NE, E, SE, S, SW, W, NW) arranged in a circle. Each direction has - a colored bar extending outward from the center, with bar length representing - frequency. The colors used are: N (blue), NE (light blue), E (yellow), SE (orange), - S (purple), SW (dark purple), W (green), NW (lighter green). The title "polar-bar - · letsplot · pyplots.ai" appears at the top. The y-axis is labeled "Frequency - (%)" with gridlines at intervals of 2 from 0 to 22. Direction labels are placed - around the outside of the chart. The W direction has the longest bar (~22), followed - by SW (~18), N (~15), and NW (~14). SE has the shortest bar (~5).' + - 'Design Excellence could be enhanced: grid styling is functional but could use + more sophisticated visual refinement (e.g., asymmetric line weights or selective + grid emphasis)' + - Visual hierarchy of dominant direction (SW=35) could be strengthened through size + emphasis, brightness variation, or strategic color placement to guide viewer attention + image_description: |- + Light render (plot-light.png): + Background: Warm off-white (#FAF8F1) with subtle grid lines, correctly theme-adapted. + Chrome: Title "polar-bar · letsplot · anyplot.ai" is bold and prominent (24pt, dark text #1A1A17). Y-axis label "Frequency (%)" (20pt, dark text). Compass directions (N, NE, E, SE, S, SW, W, NW) positioned around circle are all readable at 16pt. All text has strong contrast. + Data: Bars radiate from center with Okabe-Ito palette colors. SW bar (freq=35) is prominent blue, S (freq=28) is yellow-gold, SE (freq=12) is magenta/purple. Smaller bars (freq=3-6) use remaining palette colors. White edges on bars provide clean definition. Colors are from Okabe-Ito palette as specified. + Legibility verdict: PASS - All text and data elements clearly distinguishable against light background. No light-on-light failures. + + Dark render (plot-dark.png): + Background: Warm near-black (#1A1A17) with visible grid lines, correctly theme-adapted. + Chrome: Title clearly visible in light text (#F0EFE8). Y-axis label readable in same light tone. Compass directions have excellent contrast against dark background. All chrome elements use proper dark-theme tokens. + Data: Bar colors are identical to light render (data colors should not change with theme—only chrome flips). White bar edges remain visible and effective. Grid lines visible at appropriate contrast level. + Legibility verdict: PASS - No dark-on-dark failures. All text elements have strong contrast. Data visualization quality maintained perfectly between themes. Both renders demonstrate proper theme adaptation with only chrome elements changing color. criteria_checklist: visual_quality: - score: 36 - max: 40 + score: 30 + max: 30 items: - id: VQ-01 name: Text Legibility - score: 10 - max: 10 + score: 8 + max: 8 passed: true - comment: Title is bold and prominent, axis labels and tick marks are clearly - readable at full resolution + comment: Title, axis labels, and compass directions all readable in both renders + with proper contrast and sizing (24pt title, 20pt axis labels, 16pt ticks) - id: VQ-02 name: No Overlap - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: No overlapping text elements, direction labels are well-spaced + comment: Compass directions spaced cleanly around circle, no text collisions, + radial bar arrangement prevents overlap - id: VQ-03 name: Element Visibility - score: 8 - max: 8 + score: 6 + max: 6 passed: true - comment: Bars are clearly visible with good alpha (0.85) and white borders - for separation + comment: All bars visible from largest (SW=35) to smallest (N=3), white edges + provide definition, alpha=0.85 appropriate for density - id: VQ-04 name: Color Accessibility - score: 5 - max: 5 + score: 2 + max: 2 passed: true - comment: 8 distinct colors that are easily distinguishable; no red-green confusion + comment: Okabe-Ito palette is CVD-safe, good contrast between colors, no red-green-only + encoding - id: VQ-05 - name: Layout Balance + name: Layout & Canvas score: 4 - max: 5 + max: 4 passed: true - comment: Good use of square canvas for polar chart, slight issue with direction - labels being outside plot area + comment: Square canvas (1200x1200) appropriate for polar chart, proportions + balanced, nothing cut off - id: VQ-06 - name: Axis Labels - score: 1 + name: Axis Labels & Title + score: 2 max: 2 passed: true - comment: Y-axis has "Frequency (%)" label but data values appear to be counts, - not percentages (minor inconsistency) + comment: Title matches spec format, Y-axis label includes units (%), compass + directions descriptive, X-axis appropriately hidden - id: VQ-07 - name: Grid & Legend - score: 0 + name: Palette Compliance + score: 2 max: 2 passed: true - comment: Grid is subtle (good), but legend is hidden - while direction labels - around chart serve this purpose, the label positioning could be better integrated + comment: 'Okabe-Ito palette correctly applied, backgrounds #FAF8F1 (light) + and #1A1A17 (dark) correct, data colors identical across themes, only chrome + adapts' + design_excellence: + score: 14 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: Professional use of Okabe-Ito palette with theme-aware styling, grid + is subtle, custom sizing for clarity. Could enhance with stronger visual + emphasis on dominant direction. + - id: DE-02 + name: Visual Refinement + score: 4 + max: 6 + passed: true + comment: Subtle grid, white bar edges, adequate whitespace, no spines (appropriate + for polar). Could refine grid styling further. + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Polar wind rose format clearly shows directional frequency distribution + with SW dominance apparent. Could emphasize primary direction more visually. 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 polar bar chart / wind rose implementation - - id: SC-02 - name: Data Mapping score: 5 max: 5 passed: true - comment: Direction correctly mapped to angle, frequency to bar height - - id: SC-03 + comment: Correct polar bar chart implementation with proper radial arrangement + - id: SC-02 name: Required Features - score: 5 - max: 5 + score: 4 + max: 4 passed: true - comment: 'All spec features present: bars radiating outward, 8 compass directions, - magnitude represented by bar length' - - id: SC-04 - name: Data Range + comment: All 8 compass directions present, frequency values correctly mapped, + appropriate for wind rose + - id: SC-03 + name: Data Mapping score: 3 max: 3 passed: true - comment: All data visible, y-axis extends appropriately to 22 - - id: SC-05 - name: Legend Accuracy - score: 2 - max: 2 - passed: true - comment: Direction labels correctly positioned around chart - - id: SC-06 - name: Title Format - score: 2 - max: 2 + comment: Direction → angle mapping correct, frequency → bar height correct, + all data points visible + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 passed: true - comment: 'Uses correct format: "polar-bar · letsplot · pyplots.ai"' + comment: 'Title format correct: ''polar-bar · letsplot · anyplot.ai'', legend + appropriately disabled' data_quality: - score: 18 - max: 20 + score: 15 + max: 15 items: - id: DQ-01 name: Feature Coverage - score: 7 - max: 8 + score: 6 + max: 6 passed: true - comment: Shows variation across directions with different frequencies; could - benefit from stacked categories as mentioned in spec notes + comment: Complete 8-direction wind rose with frequency distribution showing + all aspects of polar bar type - id: DQ-02 name: Realistic Context - score: 7 - max: 7 + score: 5 + max: 5 passed: true - comment: Wind frequency data is a real, neutral application for wind roses + comment: Monsoon wind pattern with SW dominance is realistic meteorological + data, neutral and professional - id: DQ-03 name: Appropriate Scale score: 4 - max: 5 + max: 4 passed: true - comment: Values 5-22 are plausible for wind frequency data, though "Frequency - (%)" label suggests percentages while data looks like counts + comment: Frequency range 0-35 is sensible, Y-axis scale appropriate, no extreme + outliers code_quality: score: 10 max: 10 @@ -164,40 +191,59 @@ review: score: 3 max: 3 passed: true - comment: Clean imports → data → plot → save structure, no functions/classes + comment: Simple, direct ggplot chain with no unnecessary abstractions - id: CQ-02 name: Reproducibility - score: 3 - max: 3 + score: 2 + max: 2 passed: true - comment: Uses np.random.seed(42) + comment: Hardcoded data is deterministic, no random seeding needed - id: CQ-03 name: Clean Imports score: 2 max: 2 passed: true - comment: All imports are used + comment: Only necessary imports from lets_plot, numpy, pandas used appropriately - id: CQ-04 - name: No Deprecated API - score: 1 - max: 1 + name: Code Elegance + score: 2 + max: 2 passed: true - comment: Uses current lets-plot API + comment: Appropriate complexity, no fake functionality, idiomatic lets_plot + patterns - id: CQ-05 - name: Output Correct + name: Output & API score: 1 max: 1 passed: true - comment: Saves as plot.png and plot.html - library_features: - score: 3 - max: 5 + comment: Saves as plot-{THEME}.png and plot-{THEME}.html with current API + library_mastery: + score: 8 + max: 10 items: - - id: LF-01 - name: Uses distinctive library features + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: Perfect ggplot grammar usage, coord_polar transformation, geom_bar + with stat='identity', scale_fill_manual, theme system integration + - id: LM-02 + name: Distinctive Features score: 3 max: 5 passed: true - comment: Good use of coord_polar() and grammar of graphics approach, but relatively - standard implementation without advanced lets-plot features + comment: Leverages coord_polar and interactive HTML export (lets_plot strengths). + Competent but room for more advanced feature demonstration. verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - polar-projection + - html-export + patterns: + - data-generation + dataprep: [] + styling: + - edge-highlighting + - alpha-blending