{"spec_id":"area-stacked","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\narea-stacked: Stacked Area Chart\nLibrary: matplotlib 3.11.1 | Python 3.13.15\nQuality: 92/100 | Updated: 2026-08-17\n\"\"\"\n\nimport datetime\nimport os\n\nimport matplotlib.dates as mdates\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.colors import LinearSegmentedColormap\nfrom matplotlib.path import Path\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\"\n\n# Imprint palette (canonical order, positions 1-4)\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data: monthly grid electricity consumption by sector over 3 years (GWh).\n# Each sector follows its own seasonal cycle plus a steady adoption/growth\n# trend, rather than an unstructured random walk.\nnp.random.seed(42)\nn_months = 36\nt = np.arange(n_months)\n\n\ndef month_add(base_date, months):\n    total = base_date.month - 1 + months\n    year = base_date.year + total // 12\n    month = total % 12 + 1\n    return datetime.date(year, month, 1)\n\n\ndates = [month_add(datetime.date(2023, 1, 1), i) for i in range(n_months)]\n\nindustrial = 4200 + 15 * t + 60 * np.sin(2 * np.pi * t / 12 + np.pi) + np.random.normal(0, 30, n_months)\ncommercial = 2900 + 18 * t + 280 * np.sin(2 * np.pi * t / 12) + np.random.normal(0, 45, n_months)\nresidential = 2500 + 10 * t + 520 * np.cos(2 * np.pi * t / 12) + np.random.normal(0, 60, n_months)\ntransportation = 1100 + 22 * t + 130 * np.sin(2 * np.pi * (t - 3) / 12) + np.random.normal(0, 25, n_months)\n\n# Ensure all values stay positive\nindustrial = np.maximum(industrial, 3500)\ncommercial = np.maximum(commercial, 2000)\nresidential = np.maximum(residential, 1500)\ntransportation = np.maximum(transportation, 700)\n\n# Stack largest at bottom for easier reading\ncategories = [\"Industrial\", \"Commercial\", \"Residential\", \"Transportation\"]\ndata = np.vstack([industrial, commercial, residential, transportation])\n\n# Create plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Emphasize scale hierarchy: larger sectors read more opaque, smaller ones\n# lighter, so the eye naturally weights the areas by their magnitude. Built\n# manually (cumsum + fill_between) rather than ax.stackplot() so each layer\n# can carry its own alpha and an edge-stroke boundary; stackplot applies one\n# uniform style to every band and can't express that per-layer hierarchy.\nalphas = [0.88, 0.82, 0.76, 0.70]\ncumulative = np.cumsum(data, axis=0)\nbaseline = np.zeros(n_months)\nfor top, color, alpha, label in zip(cumulative, IMPRINT, alphas, categories, strict=True):\n    ax.fill_between(dates, baseline, top, color=color, alpha=alpha, label=label, linewidth=0)\n    # Thin edge stroke at each layer boundary for stronger definition between areas\n    ax.plot(dates, top, color=color, linewidth=1.3, alpha=1.0)\n    baseline = top\n\n# Transportation (top band) grew fastest in relative terms (small base, steep\n# slope). Rather than adding a second text callout, reinforce that story\n# visually: an alpha-ramped raster clipped to the band's own fill polygon,\n# so the layer itself visibly \"heats up\" left-to-right. Built with the\n# matplotlib clip_path + imshow gradient-fill recipe (a raster masked by a\n# vector Path) — a distinctly matplotlib technique with no equivalent\n# one-liner in fill_between/stackplot.\ntransport_bottom, transport_top = cumulative[2], cumulative[3]\nx_num = mdates.date2num(dates)\nband_path = Path(\n    np.column_stack([np.concatenate([x_num, x_num[::-1]]), np.concatenate([transport_bottom, transport_top[::-1]])])\n)\ngrowth_cmap = LinearSegmentedColormap.from_list(\"growth_highlight\", [f\"{IMPRINT[3]}00\", f\"{IMPRINT[3]}66\"])\ngradient = np.linspace(0, 1, 256).reshape(1, -1)\ngrowth_overlay = ax.imshow(\n    gradient,\n    extent=(x_num[0], x_num[-1], 0, cumulative[-1].max() * 1.22),\n    aspect=\"auto\",\n    cmap=growth_cmap,\n    origin=\"lower\",\n    zorder=2.5,\n)\ngrowth_overlay.set_clip_path(band_path, ax.transData)\n\n# Callout the overall growth story: total consumption across all sectors\ntotal = cumulative[-1]\ngrowth_pct = (total[-1] - total[0]) / total[0] * 100\nax.annotate(\n    f\"+{growth_pct:.0f}% total consumption\\nover 3 years\",\n    xy=(dates[-1], total[-1]),\n    xytext=(month_add(dates[-1], -9), total[-1] + total[-1] * 0.14),\n    fontsize=8.5,\n    color=INK,\n    ha=\"left\",\n    va=\"bottom\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_SOFT, \"lw\": 1.1},\n)\n\n# X-axis formatting: real date values driven by matplotlib's date locator/\n# formatter machinery, rather than hand-picked tick positions/labels.\nax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=[1, 7]))\nax.xaxis.set_major_formatter(mdates.DateFormatter(\"%b %Y\"))\n\n# Labels and styling\nax.set_xlabel(\"Month\", fontsize=10, color=INK)\nax.set_ylabel(\"Electricity Consumption (GWh)\", fontsize=10, color=INK)\nax.set_title(\"area-stacked · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\n\n# Grid\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\nax.set_axisbelow(True)\n\n# Spines\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\n# Legend (borderless, per the Decoration Removal Checklist)\nleg = ax.legend(loc=\"upper left\", fontsize=8, frameon=False)\nif leg:\n    for text in leg.get_texts():\n        text.set_color(INK_SOFT)\n\n# Ensure y-axis starts at zero; extra headroom above the stack for the growth callout\nax.set_ylim(bottom=0, top=cumulative[-1].max() * 1.22)\nax.set_xlim(dates[0], dates[-1])\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}