{"spec_id":"area-stacked-confidence","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\narea-stacked-confidence: Stacked Area Chart with Confidence Bands\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-18\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\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# Okabe-Ito palette - first series always #009E73\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\nCOLORS = {\"stocks\": IMPRINT[0], \"bonds\": IMPRINT[1], \"commodities\": IMPRINT[2], \"real_estate\": IMPRINT[3]}\n\n# Data - Portfolio allocation over 6 years with confidence bands\nnp.random.seed(42)\n\nquarters = pd.date_range(\"2020-01-01\", periods=24, freq=\"QE\")\nn = len(quarters)\n\n# Base values for each asset class (in % of portfolio)\nstocks_base = np.linspace(45, 50, n) + np.random.randn(n) * 2\nbonds_base = np.linspace(30, 28, n) + np.random.randn(n) * 1.5\ncommodities_base = np.linspace(15, 12, n) + np.random.randn(n) * 1\nreal_estate_base = np.linspace(10, 10, n) + np.random.randn(n) * 0.8\n\n# Uncertainty in allocation estimates (tighter in recent years)\nstocks_uncertainty = np.linspace(4, 2.5, n)\nbonds_uncertainty = np.linspace(3, 2, n)\ncommodities_uncertainty = np.linspace(2.5, 1.5, n)\nreal_estate_uncertainty = np.linspace(2, 1, n)\n\n# Create cumulative stacks for central values (bottom to top: Stocks, Bonds, Commodities, Real Estate)\nstocks_cumsum = stocks_base\nbonds_cumsum = stocks_base + bonds_base\ncommodities_cumsum = stocks_base + bonds_base + commodities_base\nreal_estate_cumsum = stocks_base + bonds_base + commodities_base + real_estate_base\n\n# Confidence bands for each layer (stacked properly)\n# Stocks band (bottom layer)\nstocks_lower = stocks_base - stocks_uncertainty\nstocks_upper = stocks_base + stocks_uncertainty\n\n# Bonds band (cumulative from stocks)\nbonds_lower_cumsum = stocks_cumsum + (bonds_base - bonds_uncertainty)\nbonds_upper_cumsum = stocks_cumsum + (bonds_base + bonds_uncertainty)\n\n# Commodities band (cumulative from bonds)\ncommodities_lower_cumsum = bonds_cumsum + (commodities_base - commodities_uncertainty)\ncommodities_upper_cumsum = bonds_cumsum + (commodities_base + commodities_uncertainty)\n\n# Real Estate band (cumulative from commodities)\nreal_estate_lower_cumsum = commodities_cumsum + (real_estate_base - real_estate_uncertainty)\nreal_estate_upper_cumsum = commodities_cumsum + (real_estate_base + real_estate_uncertainty)\n\n# Set theme\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.10,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Create plot\nfig, ax = plt.subplots(figsize=(16, 9))\n\n# Plot from top to bottom for proper layering (back to front)\n# Real Estate confidence band (top layer, drawn first to be in background)\nax.fill_between(\n    quarters, real_estate_lower_cumsum, real_estate_upper_cumsum, color=COLORS[\"real_estate\"], alpha=0.25, linewidth=0\n)\n\n# Real Estate main area\nax.fill_between(\n    quarters, commodities_cumsum, real_estate_cumsum, color=COLORS[\"real_estate\"], alpha=0.8, label=\"Real Estate\"\n)\n\n# Commodities confidence band\nax.fill_between(\n    quarters, commodities_lower_cumsum, commodities_upper_cumsum, color=COLORS[\"commodities\"], alpha=0.25, linewidth=0\n)\n\n# Commodities main area\nax.fill_between(quarters, bonds_cumsum, commodities_cumsum, color=COLORS[\"commodities\"], alpha=0.8, label=\"Commodities\")\n\n# Bonds confidence band\nax.fill_between(quarters, bonds_lower_cumsum, bonds_upper_cumsum, color=COLORS[\"bonds\"], alpha=0.25, linewidth=0)\n\n# Bonds main area\nax.fill_between(quarters, stocks_cumsum, bonds_cumsum, color=COLORS[\"bonds\"], alpha=0.8, label=\"Bonds\")\n\n# Stocks confidence band\nax.fill_between(quarters, stocks_lower, stocks_upper, color=COLORS[\"stocks\"], alpha=0.25, linewidth=0)\n\n# Stocks main area (bottom layer)\nax.fill_between(quarters, 0, stocks_cumsum, color=COLORS[\"stocks\"], alpha=0.8, label=\"Stocks\")\n\n# Add lines for central values to show boundaries\nax.plot(quarters, stocks_cumsum, color=COLORS[\"stocks\"], linewidth=2, alpha=0.9)\nax.plot(quarters, bonds_cumsum, color=COLORS[\"bonds\"], linewidth=2, alpha=0.9)\nax.plot(quarters, commodities_cumsum, color=COLORS[\"commodities\"], linewidth=2, alpha=0.9)\nax.plot(quarters, real_estate_cumsum, color=COLORS[\"real_estate\"], linewidth=2, alpha=0.9)\n\n# Styling\nax.set_xlabel(\"Quarter\", fontsize=20, color=INK)\nax.set_ylabel(\"Portfolio Allocation (%)\", fontsize=20, color=INK)\nax.set_title(\"area-stacked-confidence · Python · seaborn · anyplot.ai\", fontsize=24, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=16, colors=INK_SOFT)\n\n# Remove top and right spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\n# Legend - reverse order so bottom layer is first in legend\nhandles, labels = ax.get_legend_handles_labels()\nlegend = ax.legend(\n    handles[::-1],\n    labels[::-1],\n    loc=\"upper left\",\n    fontsize=16,\n    title=\"Asset Class\\n(shaded bands = 90% CI)\",\n    title_fontsize=14,\n    framealpha=0.95,\n    facecolor=ELEVATED_BG,\n    edgecolor=INK_SOFT,\n)\nlegend.get_title().set_color(INK)\nfor text in legend.get_texts():\n    text.set_color(INK)\n\n# Grid - y-axis only\nax.yaxis.grid(True, alpha=0.15, linewidth=0.8, color=INK)\nax.set_axisbelow(True)\n\n# Format x-axis dates\nfig.autofmt_xdate(rotation=45)\n\n# Set y-axis to start at 0\nax.set_ylim(bottom=0)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}