{"spec_id":"band-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nband-basic: Basic Band Plot\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-29\n\"\"\"\n\nimport os\n\nimport matplotlib.colors as mcolors\nimport matplotlib.patheffects as pe\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom matplotlib.patches import Patch\n\n\n# Theme tokens (Imprint palette + theme-adaptive chrome)\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — first series always #009E73\nBAND_COLOR = \"#009E73\"  # Imprint position 1 — confidence band\nLINE_COLOR = \"#C475FD\"  # Imprint position 2 — center forecast line\n\n# Data - 30-day temperature forecast with asymmetric 95% confidence interval\nnp.random.seed(42)\ndays = np.arange(1, 31)\n\n# Central forecast: seasonal warming with slight upward trend\ntemp_forecast = 12 + 6 * np.sin(np.pi * days / 30) + 0.1 * days\n\n# Asymmetric uncertainty: upper tail wider (warm-bias in extended-range forecasts)\nuncertainty_base = 0.8 + 0.12 * days\ntemp_lower = temp_forecast - uncertainty_base * 0.7  # narrower lower tail\ntemp_upper = temp_forecast + uncertainty_base * 1.3  # wider upper tail\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Gradient band using pcolormesh with gouraud shading\nband_rgb = mcolors.to_rgb(BAND_COLOR)\nx_fine = np.linspace(days[0], days[-1], 300)\nc_fine = np.interp(x_fine, days, temp_forecast)\nlo_fine = np.interp(x_fine, days, temp_lower)\nhi_fine = np.interp(x_fine, days, temp_upper)\n\nn_vert = 100\nX = np.tile(x_fine, (n_vert, 1))\nY = np.zeros((n_vert, len(x_fine)))\nC = np.zeros((n_vert, len(x_fine)))\n\nfor j in range(len(x_fine)):\n    Y[:, j] = np.linspace(lo_fine[j], hi_fine[j], n_vert)\n    hw = (hi_fine[j] - lo_fine[j]) / 2\n    C[:, j] = 1 - np.abs(Y[:, j] - c_fine[j]) / hw\n\ncmap = mcolors.LinearSegmentedColormap.from_list(\"ci\", [(*band_rgb, 0.02), (*band_rgb, 0.22), (*band_rgb, 0.45)])\nax.pcolormesh(X, Y, C, cmap=cmap, shading=\"gouraud\", rasterized=True, zorder=1)\n\n# Boundary dashed lines\nax.plot(days, temp_lower, color=BAND_COLOR, lw=1.5, ls=\"--\", alpha=0.65, zorder=2)\nax.plot(days, temp_upper, color=BAND_COLOR, lw=1.5, ls=\"--\", alpha=0.65, zorder=2)\n\n# Center forecast line with glow effect\nax.plot(\n    days,\n    temp_forecast,\n    color=LINE_COLOR,\n    linewidth=2.5,\n    zorder=3,\n    path_effects=[pe.Stroke(linewidth=5, foreground=LINE_COLOR, alpha=0.2), pe.Normal()],\n)\n\n# Annotation: threshold where forecast uncertainty becomes large\nthreshold_idx = int(np.argmax(uncertainty_base > 3.0))\nax.annotate(\n    \"Uncertainty exceeds ±3°C\",\n    xy=(days[threshold_idx], temp_lower[threshold_idx]),\n    xytext=(days[threshold_idx] + 4, temp_lower[threshold_idx] - 1.5),\n    fontsize=8,\n    color=INK_SOFT,\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK_MUTED, \"lw\": 1.2, \"connectionstyle\": \"arc3,rad=0.2\"},\n    bbox={\"boxstyle\": \"round,pad=0.4\", \"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.9},\n    zorder=4,\n)\n\n# Legend\nlegend_handles = [\n    Patch(facecolor=BAND_COLOR, alpha=0.35, edgecolor=BAND_COLOR, label=\"95% Confidence Interval\"),\n    plt.Line2D([0], [0], color=LINE_COLOR, linewidth=2.5, label=\"Forecast Mean\"),\n]\nleg = ax.legend(handles=legend_handles, fontsize=8, loc=\"upper left\")\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    leg.get_frame().set_edgecolor(INK_SOFT)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Style\ntitle = \"band-basic · python · matplotlib · anyplot.ai\"\nn = len(title)\ntitle_fontsize = max(8, round(12 * 67 / n)) if n > 67 else 12\n\nax.set_xlabel(\"Day of Month\", fontsize=10, color=INK)\nax.set_ylabel(\"Temperature (°C)\", fontsize=10, color=INK)\nax.set_title(title, fontsize=title_fontsize, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}