From e059308d4814bec6ec1c8c0be159c6a46884e2e9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 Jan 2026 00:53:26 +0000 Subject: [PATCH 1/3] feat(plotnine): implement indicator-sma --- .../indicator-sma/implementations/plotnine.py | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 plots/indicator-sma/implementations/plotnine.py diff --git a/plots/indicator-sma/implementations/plotnine.py b/plots/indicator-sma/implementations/plotnine.py new file mode 100644 index 0000000000..b66ad39b5c --- /dev/null +++ b/plots/indicator-sma/implementations/plotnine.py @@ -0,0 +1,81 @@ +"""pyplots.ai +indicator-sma: Simple Moving Average (SMA) Indicator Chart +Library: plotnine | Python 3.13 +Quality: pending | Created: 2026-01-11 +""" + +import numpy as np +import pandas as pd +from plotnine import ( + aes, + element_line, + element_text, + geom_line, + ggplot, + labs, + scale_color_manual, + scale_x_datetime, + theme, + theme_minimal, +) + + +# Data - Generate realistic stock price data with trend and volatility +np.random.seed(42) +n_days = 300 +dates = pd.date_range("2024-01-01", periods=n_days, freq="B") # Business days + +# Create a price series with trends and mean reversion +base_price = 150 +returns = np.random.normal(0.0003, 0.015, n_days) # Daily returns +# Add some trending behavior +trend = np.sin(np.linspace(0, 3 * np.pi, n_days)) * 0.001 +returns = returns + trend +close = base_price * np.cumprod(1 + returns) + +# Calculate SMAs +df = pd.DataFrame({"date": dates, "close": close}) +df["sma_20"] = df["close"].rolling(window=20).mean() +df["sma_50"] = df["close"].rolling(window=50).mean() +df["sma_200"] = df["close"].rolling(window=200).mean() + +# Reshape data for plotnine (long format for multiple lines with legend) +df_long = pd.melt( + df, id_vars=["date"], value_vars=["close", "sma_20", "sma_50", "sma_200"], var_name="series", value_name="price" +) + +# Rename series for legend +series_labels = {"close": "Price", "sma_20": "SMA 20", "sma_50": "SMA 50", "sma_200": "SMA 200"} +df_long["series"] = df_long["series"].map(series_labels) + +# Set order for legend +series_order = ["Price", "SMA 20", "SMA 50", "SMA 200"] +df_long["series"] = pd.Categorical(df_long["series"], categories=series_order, ordered=True) + +# Define colors matching the other implementations +colors = {"Price": "#306998", "SMA 20": "#FFD43B", "SMA 50": "#E74C3C", "SMA 200": "#2ECC71"} + +# Plot +plot = ( + ggplot(df_long, aes(x="date", y="price", color="series")) + + geom_line(size=1.5, alpha=0.9) + + scale_color_manual(values=colors) + + scale_x_datetime(date_breaks="2 months", date_labels="%b %Y") + + labs(x="Date", y="Price ($)", title="indicator-sma · plotnine · pyplots.ai", color="") + + theme_minimal() + + theme( + figure_size=(16, 9), + plot_title=element_text(size=24, weight="bold"), + axis_title=element_text(size=20), + axis_text=element_text(size=16), + axis_text_x=element_text(rotation=30, ha="right"), + legend_text=element_text(size=16), + legend_position=(0.02, 0.98), + legend_direction="vertical", + panel_grid_major_y=element_line(color="#cccccc", size=0.5, alpha=0.3), + panel_grid_major_x=element_line(alpha=0), + panel_grid_minor=element_line(alpha=0), + ) +) + +plot.save("plot.png", dpi=300) From d60861cd63c33c9c5c581f2b0b651bcf9a481814 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 Jan 2026 00:53:46 +0000 Subject: [PATCH 2/3] chore(plotnine): add metadata for indicator-sma --- plots/indicator-sma/metadata/plotnine.yaml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 plots/indicator-sma/metadata/plotnine.yaml diff --git a/plots/indicator-sma/metadata/plotnine.yaml b/plots/indicator-sma/metadata/plotnine.yaml new file mode 100644 index 0000000000..8b7ff2fffc --- /dev/null +++ b/plots/indicator-sma/metadata/plotnine.yaml @@ -0,0 +1,19 @@ +# Per-library metadata for plotnine implementation of indicator-sma +# Auto-generated by impl-generate.yml + +library: plotnine +specification_id: indicator-sma +created: '2026-01-11T00:53:45Z' +updated: '2026-01-11T00:53:45Z' +generated_by: claude-opus-4-5-20251101 +workflow_run: 20886981190 +issue: 3651 +python_version: 3.13.11 +library_version: 0.15.2 +preview_url: https://storage.googleapis.com/pyplots-images/plots/indicator-sma/plotnine/plot.png +preview_thumb: https://storage.googleapis.com/pyplots-images/plots/indicator-sma/plotnine/plot_thumb.png +preview_html: null +quality_score: null +review: + strengths: [] + weaknesses: [] From 9e1438de2cc05d75e068be46466503adc7804d91 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 Jan 2026 00:56:28 +0000 Subject: [PATCH 3/3] chore(plotnine): update quality score 91 and review feedback for indicator-sma --- .../indicator-sma/implementations/plotnine.py | 6 +- plots/indicator-sma/metadata/plotnine.yaml | 213 +++++++++++++++++- 2 files changed, 209 insertions(+), 10 deletions(-) diff --git a/plots/indicator-sma/implementations/plotnine.py b/plots/indicator-sma/implementations/plotnine.py index b66ad39b5c..e35e8c8f5b 100644 --- a/plots/indicator-sma/implementations/plotnine.py +++ b/plots/indicator-sma/implementations/plotnine.py @@ -1,7 +1,7 @@ -"""pyplots.ai +""" pyplots.ai indicator-sma: Simple Moving Average (SMA) Indicator Chart -Library: plotnine | Python 3.13 -Quality: pending | Created: 2026-01-11 +Library: plotnine 0.15.2 | Python 3.13.11 +Quality: 91/100 | Created: 2026-01-11 """ import numpy as np diff --git a/plots/indicator-sma/metadata/plotnine.yaml b/plots/indicator-sma/metadata/plotnine.yaml index 8b7ff2fffc..b8dd3bcc29 100644 --- a/plots/indicator-sma/metadata/plotnine.yaml +++ b/plots/indicator-sma/metadata/plotnine.yaml @@ -1,10 +1,7 @@ -# Per-library metadata for plotnine implementation of indicator-sma -# Auto-generated by impl-generate.yml - library: plotnine specification_id: indicator-sma created: '2026-01-11T00:53:45Z' -updated: '2026-01-11T00:53:45Z' +updated: '2026-01-11T00:56:27Z' generated_by: claude-opus-4-5-20251101 workflow_run: 20886981190 issue: 3651 @@ -13,7 +10,209 @@ library_version: 0.15.2 preview_url: https://storage.googleapis.com/pyplots-images/plots/indicator-sma/plotnine/plot.png preview_thumb: https://storage.googleapis.com/pyplots-images/plots/indicator-sma/plotnine/plot_thumb.png preview_html: null -quality_score: null +quality_score: 91 review: - strengths: [] - weaknesses: [] + strengths: + - Excellent use of plotnine grammar of graphics with proper long-format data transformation + - Clean color scheme that distinguishes all four series effectively + - Proper title format following the spec-id · library · pyplots.ai convention + - Good handling of date axis with appropriate rotation to prevent overlap + - Realistic synthetic stock price data with visible trend behavior + - All three SMA periods (20, 50, 200) are correctly calculated and displayed + weaknesses: + - Legend could benefit from a background/box for better readability against data + - The SMA 200 line only appears in the final third of the chart due to the 200-day + window requirement + image_description: 'The plot displays a Simple Moving Average (SMA) indicator chart + with a dark blue price line showing daily stock prices over approximately one + year (Jan 2024 - Feb 2025). Three SMA overlay lines are visible: a yellow SMA + 20 (short-term), a red SMA 50 (medium-term), and a green SMA 200 (long-term). + The price fluctuates between roughly $130-$170, showing a downward trend from + Jan-Aug 2024 followed by an upward trend from Oct 2024 onwards. The legend is + positioned in the upper left corner with entries for Price, SMA 20, SMA 50, and + SMA 200. The title follows the correct format "indicator-sma · plotnine · pyplots.ai" + displayed in bold at the top. X-axis shows dates in "Mon YYYY" format with labels + rotated 30 degrees to prevent overlap. Y-axis shows "Price ($)" with values ranging + from 130 to 170. Grid lines are subtle, appearing only on the y-axis with low + opacity. The minimal theme provides a clean background. All four lines are clearly + distinguishable with consistent 1.5 line width and 0.9 alpha transparency.' + criteria_checklist: + visual_quality: + score: 36 + max: 40 + items: + - id: VQ-01 + name: Text Legibility + score: 10 + max: 10 + passed: true + comment: Title is bold (24pt), axis labels (20pt) and tick labels (16pt) are + clearly readable at full resolution + - id: VQ-02 + name: No Overlap + score: 8 + max: 8 + passed: true + comment: No overlapping text elements, date labels rotated 30 degrees to prevent + overlap + - id: VQ-03 + name: Element Visibility + score: 7 + max: 8 + passed: true + comment: Line width of 1.5 and alpha of 0.9 provide good visibility, all four + series clearly distinguishable + - id: VQ-04 + name: Color Accessibility + score: 5 + max: 5 + passed: true + comment: Blue, yellow, red, green color scheme is colorblind-friendly and + provides good contrast + - id: VQ-05 + name: Layout Balance + score: 4 + max: 5 + passed: true + comment: Good canvas utilization, legend well positioned in upper-left, minimal + wasted space + - id: VQ-06 + name: Axis Labels + score: 2 + max: 2 + passed: true + comment: Y-axis has units 'Price ($)', X-axis labeled 'Date' + - id: VQ-07 + name: Grid & Legend + score: 0 + max: 2 + passed: false + comment: Grid is appropriately subtle but legend lacks background frame for + readability against data + spec_compliance: + score: 25 + max: 25 + items: + - id: SC-01 + name: Plot Type + score: 8 + max: 8 + passed: true + comment: Correct line chart with price and three SMA overlays as specified + - id: SC-02 + name: Data Mapping + score: 5 + max: 5 + passed: true + comment: Date on X-axis, price values on Y-axis, all correctly mapped + - id: SC-03 + name: Required Features + score: 5 + max: 5 + passed: true + comment: 'All required features present: price line, 20/50/200-day SMAs, legend + with periods' + - id: SC-04 + name: Data Range + score: 3 + max: 3 + passed: true + comment: All data visible, axes accommodate full range from ~130 to ~170 + - id: SC-05 + name: Legend Accuracy + score: 2 + max: 2 + passed: true + comment: Legend correctly shows 'Price', 'SMA 20', 'SMA 50', 'SMA 200' + - id: SC-06 + name: Title Format + score: 2 + max: 2 + passed: true + comment: Correct format 'indicator-sma · plotnine · pyplots.ai' + data_quality: + score: 18 + max: 20 + items: + - id: DQ-01 + name: Feature Coverage + score: 7 + max: 8 + passed: true + comment: Shows uptrend and downtrend, SMAs crossing, different lag behavior + of each SMA period + - id: DQ-02 + name: Realistic Context + score: 7 + max: 7 + passed: true + comment: Realistic stock price scenario with plausible daily volatility and + price range (~$130-$170) + - id: DQ-03 + name: Appropriate Scale + score: 4 + max: 5 + passed: true + comment: 300 business days is appropriate for showing 200-day SMA; price range + realistic + code_quality: + score: 9 + max: 10 + items: + - id: CQ-01 + name: KISS Structure + score: 3 + max: 3 + passed: true + comment: 'Clean linear structure: imports → data generation → SMA calculation + → reshape → plot → save' + - id: CQ-02 + name: Reproducibility + score: 3 + max: 3 + passed: true + comment: np.random.seed(42) set at the beginning for reproducible data + - id: CQ-03 + name: Clean Imports + score: 2 + max: 2 + passed: true + comment: 'All imports are used: numpy, pandas, and plotnine components' + - id: CQ-04 + name: No Deprecated API + score: 1 + max: 1 + passed: true + comment: Uses current plotnine API + - id: CQ-05 + name: Output Correct + score: 0 + max: 1 + passed: false + comment: Saves as plot.png correctly but minor formatting + library_features: + score: 3 + max: 5 + items: + - id: LF-01 + name: Distinctive Features + score: 3 + max: 5 + passed: true + comment: Uses plotnine's ggplot grammar, theme_minimal, scale_color_manual, + element_text, and proper long-format data transformation with pd.melt which + is idiomatic for plotnine + verdict: APPROVED +impl_tags: + dependencies: [] + techniques: + - layer-composition + patterns: + - data-generation + - wide-to-long + dataprep: + - rolling-window + - time-series + styling: + - alpha-blending + - grid-styling