{"spec_id":"streamgraph-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nstreamgraph-basic: Basic Stream Graph\nLibrary: matplotlib 3.11.1 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.interpolate import make_interp_spline\n\n\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 — first series always #009E73, positions 1-6 in canonical order\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\"]\n\nnp.random.seed(42)\n\nmonths = np.arange(24)\nmonth_labels = [\n    \"Jan'23\",\n    \"Feb'23\",\n    \"Mar'23\",\n    \"Apr'23\",\n    \"May'23\",\n    \"Jun'23\",\n    \"Jul'23\",\n    \"Aug'23\",\n    \"Sep'23\",\n    \"Oct'23\",\n    \"Nov'23\",\n    \"Dec'23\",\n    \"Jan'24\",\n    \"Feb'24\",\n    \"Mar'24\",\n    \"Apr'24\",\n    \"May'24\",\n    \"Jun'24\",\n    \"Jul'24\",\n    \"Aug'24\",\n    \"Sep'24\",\n    \"Oct'24\",\n    \"Nov'24\",\n    \"Dec'24\",\n]\n\n# Monthly streaming hours by music genre — diverse trend patterns\npop = 50 + 10 * np.sin(months / 6) + np.random.randn(24) * 3 + months * 0.3\nrock = 35 + 8 * np.cos(months / 4) + np.random.randn(24) * 2\nhiphop = 25 + months * 0.8 + 5 * np.sin(months / 3) + np.random.randn(24) * 3\nelectronic = 20 + 15 * np.sin((months - 3) / 6 * np.pi) + np.random.randn(24) * 2\njazz = 18 - months * 0.15 + 4 * np.cos(months / 5) + np.random.randn(24) * 1.5\nclassical = 15 + 8 * np.cos(months / 6 * np.pi) + np.random.randn(24) * 1.5\n\ndata_raw = [pop, rock, hiphop, electronic, jazz, classical]\nfor arr in data_raw:\n    np.maximum(arr, 5, out=arr)\n\ncategories = [\"Pop\", \"Rock\", \"Hip-Hop\", \"Electronic\", \"Jazz\", \"Classical\"]\n\n# Cubic spline interpolation → smooth, flowing curves\nmonths_fine = np.linspace(0, 23, 300)\ndata_smooth = np.array([np.maximum(make_interp_spline(months, series, k=3)(months_fine), 1.0) for series in data_raw])\n\n# Inside-out layer ordering (Byron & Wattenberg): the highest-volume genre sits\n# in the visual center with progressively smaller genres flanking it, so the\n# dominant trend (Pop) reads immediately without needing a text callout.\ntotals = data_smooth.sum(axis=1)\nranked = np.argsort(totals)[::-1]\nleft_side, right_side = [], []\nfor rank, idx in enumerate(ranked):\n    (right_side if rank % 2 == 0 else left_side).append(idx)\nstack_order = left_side[::-1] + right_side\n\nstacked_data = data_smooth[stack_order]\nstacked_colors = [IMPRINT[i] for i in stack_order]\nstacked_labels = [categories[i] for i in stack_order]\n\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nax.stackplot(\n    months_fine,\n    stacked_data,\n    labels=stacked_labels,\n    colors=stacked_colors,\n    baseline=\"wiggle\",\n    alpha=0.9,\n    edgecolor=PAGE_BG,\n    linewidth=1.2,\n)\n\ntitle = \"streamgraph-basic · python · matplotlib · anyplot.ai\"\nax.set_title(title, fontsize=12, color=INK, fontweight=\"medium\")\nax.set_xlabel(\"Month (Jan 2023 – Dec 2024)\", fontsize=10, color=INK)\n\ntick_positions = list(range(0, 24, 3))\nax.set_xticks(tick_positions)\nax.set_xticklabels([month_labels[i] for i in tick_positions], fontsize=8)\nax.tick_params(axis=\"x\", colors=INK_SOFT, labelcolor=INK_SOFT)\nax.set_yticks([])\n\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_visible(False)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\nax.set_xlim(months_fine[0], months_fine[-1])\n\n# Legend sits outside the axes (right margin) — the streamgraph fills nearly\n# the full plot height everywhere, so an inside legend would always cover data.\nleg = ax.legend(loc=\"center left\", bbox_to_anchor=(1.01, 0.5), fontsize=8, framealpha=0.9, borderaxespad=0)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\nfig.subplots_adjust(left=0.04, right=0.84, top=0.88, bottom=0.16)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}