{"spec_id":"step-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nstep-basic: Basic Step Plot\nLibrary: matplotlib 3.11.1 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-07-25\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.colors import to_rgba\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nELEVATED_BG = \"#FFFDF6\" if THEME == \"light\" else \"#242420\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nBRAND = \"#009E73\"  # Imprint palette position 1\n\n# Data - monthly cumulative sales figures\nmonth_labels = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\n\nmonthly_sales = np.array([45, 52, 48, 61, 55, 72, 68, 85, 78, 92, 88, 105])\ncumulative_sales = np.cumsum(monthly_sales)\nedges = np.arange(0, 13)  # 12 month-wide steps: edges[i] -> edges[i+1] holds cumulative_sales[i]\n\n# Milestone the running total crosses mid-year, for a data-storytelling callout\nmilestone = 500\nmilestone_idx = int(np.argmax(cumulative_sales >= milestone))\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# ax.stairs is the distinctive step-plot API (matplotlib >=3.4): a single\n# StepPatch driven by bin-style edges, used once filled (baseline=0) for the\n# area and once outline-only (baseline=None, no bottom edge) for the line.\nax.stairs(cumulative_sales, edges, baseline=0, fill=True, color=BRAND, alpha=0.12)\nax.stairs(cumulative_sales, edges, baseline=None, color=BRAND, linewidth=2.5, label=\"Cumulative Sales\")\n\n# Markers at the start of each step ('post' style: value holds from this point until the next)\n# Semi-opaque brand fill (rather than a raw page-background cutout) keeps markers\n# prominent against the filled area at small/thumbnail scale in both themes.\nax.scatter(\n    edges[:-1],\n    cumulative_sales,\n    s=140,\n    facecolors=to_rgba(BRAND, 0.35),\n    edgecolors=BRAND,\n    linewidth=2,\n    zorder=5,\n    label=\"Monthly Totals\",\n)\n\n# Milestone callout\nax.axhline(milestone, color=INK_SOFT, linewidth=1, linestyle=\"--\", alpha=0.5)\nax.annotate(\n    f\"{milestone}k milestone\\nreached in {month_labels[milestone_idx]}\",\n    xy=(edges[milestone_idx], milestone),\n    xytext=(edges[milestone_idx] - 2.6, milestone + 130),\n    fontsize=8,\n    color=INK,\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"linewidth\": 1},\n    bbox={\"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"boxstyle\": \"round,pad=0.3\", \"alpha\": 0.9},\n)\n\n# Style\nax.set_xlabel(\"Month\", fontsize=10, color=INK)\nax.set_ylabel(\"Cumulative Sales (thousands $)\", fontsize=10, color=INK)\nax.set_title(\"step-basic · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\n\nax.set_xlim(0, 12)\nax.set_ylim(0, cumulative_sales.max() * 1.12)\nax.set_xticks(edges[:-1] + 0.5)\nax.set_xticklabels(month_labels)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\n\nleg = ax.legend(fontsize=8, loc=\"upper left\")\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)  # bbox_inches stays default (None)\n"}