diff --git a/plots/area-mountain-panorama/implementations/python/matplotlib.py b/plots/area-mountain-panorama/implementations/python/matplotlib.py new file mode 100644 index 0000000000..757388b1c6 --- /dev/null +++ b/plots/area-mountain-panorama/implementations/python/matplotlib.py @@ -0,0 +1,145 @@ +""" anyplot.ai +area-mountain-panorama: Mountain Panorama Profile with Labeled Peaks +Library: matplotlib 3.10.9 | Python 3.14.4 +Quality: 91/100 | Created: 2026-04-25 +""" + +import os + +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.colors import LinearSegmentedColormap + + +# 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" +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" +BRAND = "#009E73" +SKY_TOP = "#E8C8A0" if THEME == "light" else "#252D40" + +# Data — Wallis (Valais) summit panorama, ordered W → E +peaks = [ + ("Weisshorn", 12, 4506), + ("Zinalrothorn", 30, 4221), + ("Ober Gabelhorn", 45, 4063), + ("Dent Blanche", 58, 4358), + ("Dent d'Hérens", 76, 4171), + ("Matterhorn", 92, 4478), + ("Breithorn", 120, 4164), + ("Pollux", 132, 4092), + ("Castor", 139, 4223), + ("Liskamm", 152, 4527), + ("Monte Rosa", 170, 4634), + ("Strahlhorn", 192, 4190), + ("Rimpfischhorn", 204, 4199), + ("Allalinhorn", 215, 4027), + ("Alphubel", 225, 4206), + ("Täschhorn", 236, 4491), + ("Dom", 250, 4545), +] + +# Skyline construction +np.random.seed(42) +angle = np.linspace(0, 262, 2000) + +# Base ridge: smoothed random walk in the 3000–3700 m belt (foothills + minor cols) +walk = np.cumsum(np.random.randn(len(angle)) * 1.5) +sigma_walk = 22 +g = np.arange(-3 * sigma_walk, 3 * sigma_walk + 1) +kernel_walk = np.exp(-(g**2) / (2 * sigma_walk**2)) +walk = np.convolve(walk, kernel_walk / kernel_walk.sum(), mode="same") +walk = (walk - walk.min()) / (walk.max() - walk.min()) +ridge = 3000 + walk * 700 + +# Major summits as Gaussian peaks (max-combined for the visible silhouette) +for _, pos, elev in peaks: + width = 5.5 + (elev - 4000) / 130 + bump = (elev - 2700) * np.exp(-((angle - pos) ** 2) / (2 * width**2)) + ridge = np.maximum(ridge, 2700 + bump) + +# Light final smoothing of the combined ridge +sigma_ridge = 0.8 +g = np.arange(-3, 4) +kernel_ridge = np.exp(-(g**2) / (2 * sigma_ridge**2)) +ridge = np.convolve(ridge, kernel_ridge / kernel_ridge.sum(), mode="same") + +# Plot +fig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG) +ax.set_facecolor(PAGE_BG) + +# Sky gradient above ridgeline (dusk mood: warm peach for light, deep navy for dark) +sky_cmap = LinearSegmentedColormap.from_list("sky", [PAGE_BG, SKY_TOP]) +sky_gradient = np.linspace(0, 1, 256).reshape(-1, 1) +ax.imshow( + sky_gradient, + extent=(0, 262, 2400, 6050), + aspect="auto", + cmap=sky_cmap, + origin="lower", + zorder=1, + interpolation="bilinear", +) + +# Mountain silhouette (covers the lower portion of the gradient — sky stays above ridge) +ax.fill_between(angle, 2400, ridge, color=BRAND, linewidth=0, zorder=2) +ax.plot(angle, ridge, color=BRAND, linewidth=1.0, zorder=3) + +# Peak labels staggered across three vertical levels, with thin leader lines +label_levels = [5050, 5320, 5590] +sorted_peaks = sorted(peaks, key=lambda p: p[1]) +for i, (name, pos, elev) in enumerate(sorted_peaks): + level = label_levels[i % 3] + is_anchor = name == "Matterhorn" + text_color = INK if is_anchor else INK_SOFT + text_weight = "bold" if is_anchor else "regular" + line_color = INK if is_anchor else INK_SOFT + line_alpha = 0.85 if is_anchor else 0.45 + line_width = 1.4 if is_anchor else 0.8 + fsize = 16 if is_anchor else 14 + + ax.plot([pos, pos], [elev + 25, level - 90], color=line_color, linewidth=line_width, alpha=line_alpha, zorder=4) + ax.text( + pos, + level, + f"{name}\n{elev:,} m", + ha="center", + va="bottom", + fontsize=fsize, + fontweight=text_weight, + color=text_color, + linespacing=1.35, + zorder=5, + ) + +# Axes +ax.set_ylim(2500, 6050) +ax.set_xlim(0, 262) +ax.set_ylabel("Elevation (m)", fontsize=20, color=INK) +ax.set_title( + "Wallis Alps · area-mountain-panorama · matplotlib · anyplot.ai", + fontsize=24, + fontweight="medium", + color=INK, + pad=18, +) + +# Compass bearings on x-axis +compass_ticks = [10, 65, 120, 180, 245] +compass_labels = ["W", "SW", "S", "SE", "E"] +ax.set_xticks(compass_ticks) +ax.set_xticklabels(compass_labels, fontsize=16, color=INK_SOFT) +ax.tick_params(axis="x", colors=INK_SOFT, length=0) +ax.tick_params(axis="y", labelsize=16, colors=INK_SOFT) + +ax.spines["top"].set_visible(False) +ax.spines["right"].set_visible(False) +for s in ("left", "bottom"): + ax.spines[s].set_color(INK_SOFT) +ax.yaxis.grid(True, alpha=0.10, linewidth=0.8, color=INK) + +plt.tight_layout() +plt.savefig(f"plot-{THEME}.png", dpi=300, bbox_inches="tight", facecolor=PAGE_BG) diff --git a/plots/area-mountain-panorama/metadata/python/matplotlib.yaml b/plots/area-mountain-panorama/metadata/python/matplotlib.yaml new file mode 100644 index 0000000000..1bea895902 --- /dev/null +++ b/plots/area-mountain-panorama/metadata/python/matplotlib.yaml @@ -0,0 +1,268 @@ +library: matplotlib +language: python +specification_id: area-mountain-panorama +created: '2026-04-25T01:01:05Z' +updated: '2026-04-25T01:23:49Z' +generated_by: claude-opus +workflow_run: 24918592166 +issue: 5365 +python_version: 3.14.4 +library_version: 3.10.9 +preview_url_light: https://storage.googleapis.com/anyplot-images/plots/area-mountain-panorama/python/matplotlib/plot-light.png +preview_url_dark: https://storage.googleapis.com/anyplot-images/plots/area-mountain-panorama/python/matplotlib/plot-dark.png +preview_html_light: null +preview_html_dark: null +quality_score: 91 +review: + strengths: + - Sky gradient (LinearSegmentedColormap + imshow) added in attempt 2 correctly addresses + the prior review's top weakness and genuinely elevates the panoramic mood — theme-adaptive + (warm dusk in light, deep navy in dark) + - gaussian_smooth() function correctly inlined, fixing the KISS violation from attempt + 1 + - Peak label sizes raised to 14pt/16pt — a significant improvement over the previous + 11pt/13pt + - All 17 real Wallis Alps summits with authentic elevations, geographically ordered + W to E + - 'Both themes fully correct: all chrome tokens threaded through, no dark-on-dark + or light-on-light failures' + - Matterhorn focal point (bold, 16pt, 1.4 linewidth leader, 0.85 alpha) is intentional + and effective + weaknesses: + - Non-anchor peak labels at 14pt remain slightly below the 16pt canvas minimum — + raising all labels to 16pt would fully satisfy VQ-01 + - Spec calls for 'dark solid color (photo-like silhouette, evening/dusk feel)' — + brand green is palette-justified but produces a stylized illustration rather than + a dramatic photo-like silhouette; sky gradient partially compensates + - DE-03 could improve with elevation-based visual differentiation (e.g., subtle + highlight on the top 3 summits by elevation) to guide the viewer beyond the Matterhorn + focal point + image_description: |- + Light render (plot-light.png): + Background: warm off-white (#FAF8F1) — correct, not pure white + Chrome: Title "Wallis Alps · area-mountain-panorama · matplotlib · anyplot.ai" in dark ink (#1A1A17) at 24pt, clearly readable; y-axis label "Elevation (m)" in dark ink at 20pt; compass bearing x-ticks (W, SW, S, SE, E) in INK_SOFT (#4A4A44) at 16pt; y-axis tick values in INK_SOFT — all text readable + Data: Sky gradient from #FAF8F1 to warm peach #E8C8A0 above ridgeline (dusk mood); mountain silhouette filled solid brand green (#009E73) from y=2400 to synthetic ridgeline; 17 Wallis Alps peaks annotated at three staggered levels (5050/5320/5590 m) with thin vertical leader lines; Matterhorn in bold 16pt with 1.4 linewidth leader at 0.85 alpha; non-anchor peaks at 14pt regular weight with 0.8 linewidth leader at 0.45 alpha + Legibility verdict: PASS — all text readable against warm off-white background; non-anchor peak labels at 14pt are slightly below the 16pt canvas minimum but remain legible + + Dark render (plot-dark.png): + Background: warm near-black (#1A1A17) — correct, not pure black + Chrome: Title in #F0EFE8 (INK for dark theme) — clearly readable; axis labels and tick labels in #B8B7B0 (INK_SOFT for dark theme) — clearly readable against near-black; leader lines in INK/INK_SOFT tones with appropriate alpha; subtle grid at 10% opacity using INK token; no dark-on-dark text failures + Data: Sky gradient shifts to deep navy (#252D40) above ridgeline (night-alpine mood); mountain silhouette fill is identical brand green (#009E73) — data colors unchanged from light render; annotation labels use INK (#F0EFE8) for Matterhorn and INK_SOFT (#B8B7B0) for non-anchor peaks — readable against #1A1A17 + Legibility verdict: PASS — all text readable against dark background; no dark-on-dark issues; brand green #009E73 remains well-visible on #1A1A17; theme adaptation complete and correct + criteria_checklist: + visual_quality: + score: 28 + max: 30 + items: + - id: VQ-01 + name: Text Legibility + score: 7 + max: 8 + passed: true + comment: Title 24pt, axis label 20pt, ticks 16pt explicitly set; Matterhorn + label 16pt; non-anchor peak labels 14pt — slightly below 16pt canvas minimum + - id: VQ-02 + name: No Overlap + score: 5 + max: 6 + passed: true + comment: 3-level stagger (5050/5320/5590 m) prevents collisions across all + 17 peaks; minor crowding risk in dense W-SW cluster but no visible collisions + in either render + - id: VQ-03 + name: Element Visibility + score: 6 + max: 6 + passed: true + comment: Mountain silhouette prominently visible; sky gradient adds depth; + leader lines at 0.8-1.4 linewidth visible at full resolution + - id: VQ-04 + name: Color Accessibility + score: 2 + max: 2 + passed: true + comment: Single brand green (#009E73) on warm backgrounds — excellent contrast, + CVD-safe + - id: VQ-05 + name: Layout & Canvas + score: 4 + max: 4 + passed: true + comment: 16:9 landscape perfectly suits the panoramic subject; label zone + above 5000 m makes good use of upper canvas + - id: VQ-06 + name: Axis Labels & Title + score: 2 + max: 2 + passed: true + comment: 'Y-axis: ''Elevation (m)'' with units; X-axis: compass bearings (W, + SW, S, SE, E)' + - id: VQ-07 + name: Palette Compliance + score: 2 + max: 2 + passed: true + comment: 'First/only series is #009E73; backgrounds #FAF8F1 (light) / #1A1A17 + (dark); sky gradient uses theme-adaptive PAGE_BG and SKY_TOP (not data colors); + all chrome tokens correctly applied in both renders' + design_excellence: + score: 15 + max: 20 + items: + - id: DE-01 + name: Aesthetic Sophistication + score: 6 + max: 8 + passed: true + comment: 'Strong design: theme-adaptive sky gradient (warm peach dusk in light, + deep navy in dark) elevates panoramic mood; Matterhorn focal point with + intentional bold/opacity hierarchy; composition clearly above configured + defaults' + - id: DE-02 + name: Visual Refinement + score: 5 + max: 6 + passed: true + comment: Top/right spines removed; x-axis tick marks hidden (length=0); y-grid + at 10% opacity; variable leader line alpha (0.45 non-anchor / 0.85 Matterhorn); + sky gradient fills background meaningfully + - id: DE-03 + name: Data Storytelling + score: 4 + max: 6 + passed: true + comment: Sky gradient establishes panorama-from-a-viewpoint narrative; Matterhorn + is clear focal point through bold weight and stronger leader; W to E geographic + sweep provides orientation; elevation-based differentiation between minor + and major summits would push higher + spec_compliance: + score: 14 + max: 15 + items: + - id: SC-01 + name: Plot Type + score: 5 + max: 5 + passed: true + comment: 'Correct: filled area mountain silhouette from angular panoramic + vantage point' + - id: SC-02 + name: Required Features + score: 3 + max: 4 + passed: true + comment: Staggered leader-line annotations, sky gradient (added in attempt + 2), y-axis in meters, compass x-axis, Matterhorn focal point all present; + spec requested 'dark solid color' silhouette but brand green used — palette-rule + justified deviation + - id: SC-03 + name: Data Mapping + score: 3 + max: 3 + passed: true + comment: 'X: horizontal viewing angle 0-262 degrees; Y: elevation in meters; + all 17 Wallis Alps peaks correctly positioned' + - id: SC-04 + name: Title & Legend + score: 3 + max: 3 + passed: true + comment: Title contains 'area-mountain-panorama · matplotlib · 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: Skyline curve with Gaussian peak construction, sky gradient background, + annotated summits with leader lines, staggered labels, compass orientation + — all spec features present + - id: DQ-02 + name: Realistic Context + score: 5 + max: 5 + passed: true + comment: Real Wallis Alps peaks with authentic names and accurate elevations + (Matterhorn 4478 m, Monte Rosa 4634 m, Weisshorn 4506 m, etc.) + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 4 + passed: true + comment: 17 peaks spanning 0-262 degree panorama; elevations 4027-4634 m; + 2500 m lower bound appropriate for high alpine scene + code_quality: + score: 10 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Flat script: imports to tokens to data to ridge construction to + plot to save; gaussian_smooth() function from attempt 1 correctly inlined' + - id: CQ-02 + name: Reproducibility + score: 2 + max: 2 + passed: true + comment: np.random.seed(42) before all random calls + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: os, matplotlib.pyplot, numpy, matplotlib.colors.LinearSegmentedColormap + — all actively used + - id: CQ-04 + name: Code Elegance + score: 2 + max: 2 + passed: true + comment: Clean, readable; Gaussian peak construction with np.maximum is elegant; + no fake UI elements + - id: CQ-05 + name: Output & API + score: 1 + max: 1 + passed: true + comment: Saves as plot-{THEME}.png with facecolor=PAGE_BG; current matplotlib + API + library_mastery: + score: 9 + max: 10 + items: + - id: LM-01 + name: Idiomatic Usage + score: 5 + max: 5 + passed: true + comment: Consistent axes-object API (ax.fill_between, ax.plot, ax.text, ax.imshow); + proper subplot creation; environment-variable theming; tight_layout + bbox_inches='tight' + - id: LM-02 + name: Distinctive Features + score: 4 + max: 5 + passed: true + comment: LinearSegmentedColormap.from_list() for custom sky gradient; ax.imshow() + with custom extent as gradient background layer — sophisticated matplotlib-specific + technique; Gaussian kernel convolution for ridgeline smoothing + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - annotations + - manual-ticks + patterns: + - data-generation + - iteration-over-groups + - explicit-figure + dataprep: [] + styling: + - alpha-blending + - gradient-fill