{"spec_id":"step-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\nstep-basic: Basic Step Plot\nLibrary: seaborn 0.13.2 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-07-25\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme tokens (Imprint — see prompts/default-style-guide.md)\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\"\nMUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nIMPRINT_PALETTE = [\"#009E73\", \"#C475FD\"]  # brand green, lavender\n\n# Data - warehouse inventory levels held between restock events (13 weekly checks)\nweeks = np.arange(1, 14)\nearbuds_stock = np.array([500, 460, 410, 650, 600, 540, 480, 700, 640, 580, 510, 440, 380])\nspeakers_stock = np.array([320, 290, 250, 210, 480, 430, 380, 330, 280, 520, 460, 400, 340])\n\ndf = pd.DataFrame(\n    {\n        \"Week\": np.concatenate([weeks, weeks]),\n        \"Units in Stock\": np.concatenate([earbuds_stock, speakers_stock]),\n        \"Product\": [\"Wireless Earbuds\"] * len(weeks) + [\"Bluetooth Speakers\"] * len(weeks),\n    }\n)\n\n# Plot\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.12,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Muted fill between the two step curves - highlights the stock differential\n# without competing with the data lines (semantic \"muted\" anchor, not a data color)\nax.fill_between(weeks, earbuds_stock, speakers_stock, step=\"post\", color=MUTED, alpha=0.08, linewidth=0, zorder=1)\n\n# Single hue-mapped lineplot drives both step series and the shared legend\nsns.lineplot(\n    data=df,\n    x=\"Week\",\n    y=\"Units in Stock\",\n    hue=\"Product\",\n    hue_order=[\"Wireless Earbuds\", \"Bluetooth Speakers\"],\n    palette=IMPRINT_PALETTE,\n    drawstyle=\"steps-post\",\n    linewidth=2.5,\n    marker=\"o\",\n    markersize=9,\n    markeredgecolor=PAGE_BG,\n    markeredgewidth=1.5,\n    ax=ax,\n    zorder=3,\n)\n\n# Restock annotation - the single largest jump (Wireless Earbuds week 3->4, +240 units)\n# is the defining moment a step plot exists to show\nax.annotate(\n    \"Restock: +240 units\",\n    xy=(4, 650),\n    xytext=(5.4, 745),\n    fontsize=9,\n    fontweight=\"medium\",\n    color=INK,\n    ha=\"left\",\n    arrowprops={\"arrowstyle\": \"-\", \"color\": INK_SOFT, \"linewidth\": 1},\n)\n\n# Style - title and subtitle anchored to the figure (not the axes) to avoid overlap\nfig.text(\n    0.5,\n    0.965,\n    \"step-basic · python · seaborn · anyplot.ai\",\n    fontsize=12,\n    fontweight=\"medium\",\n    color=INK,\n    ha=\"center\",\n    va=\"top\",\n)\nfig.text(\n    0.5,\n    0.90,\n    \"Warehouse inventory held constant between weekly checks — restocks create the jumps\",\n    fontsize=9,\n    color=INK_SOFT,\n    ha=\"center\",\n    va=\"top\",\n)\nax.set_xlabel(\"Week\", fontsize=10, color=INK)\nax.set_ylabel(\"Units in Stock\", fontsize=10, color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\nax.set_xticks(weeks)\nax.set_ylim(0, 800)\nax.yaxis.grid(True, alpha=0.12, linewidth=0.8, color=INK)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor spine in (\"left\", \"bottom\"):\n    ax.spines[spine].set_color(INK_SOFT)\n\nlegend = ax.legend(fontsize=8, title=None, loc=\"lower left\", frameon=True, handlelength=2.2, markerscale=0.8)\nlegend.get_frame().set_facecolor(ELEVATED_BG)\nlegend.get_frame().set_edgecolor(\"none\")\nlegend.get_frame().set_alpha(0.85)\n\nfig.subplots_adjust(top=0.80, bottom=0.14, left=0.09, right=0.97)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}