{"spec_id":"bar-stacked","library":"altair","language":"python","code":"\"\"\" anyplot.ai\nbar-stacked: Stacked Bar Chart\nLibrary: altair 6.1.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\n\nimport altair as alt\nimport pandas as pd\n\n\n# Theme tokens (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\"\n\n# Okabe-Ito palette: first series is ALWAYS #009E73\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data: Quarterly sales by product category\ndata = pd.DataFrame(\n    {\n        \"Quarter\": [\"Q1\", \"Q1\", \"Q1\", \"Q1\", \"Q2\", \"Q2\", \"Q2\", \"Q2\", \"Q3\", \"Q3\", \"Q3\", \"Q3\", \"Q4\", \"Q4\", \"Q4\", \"Q4\"],\n        \"Product\": [\n            \"Electronics\",\n            \"Clothing\",\n            \"Home & Garden\",\n            \"Sports\",\n            \"Electronics\",\n            \"Clothing\",\n            \"Home & Garden\",\n            \"Sports\",\n            \"Electronics\",\n            \"Clothing\",\n            \"Home & Garden\",\n            \"Sports\",\n            \"Electronics\",\n            \"Clothing\",\n            \"Home & Garden\",\n            \"Sports\",\n        ],\n        \"Sales\": [85, 62, 45, 38, 92, 71, 52, 44, 78, 65, 48, 41, 110, 88, 68, 55],\n    }\n)\n\n# Define category order (largest at bottom) and apply Okabe-Ito colors\ncategory_order = [\"Electronics\", \"Clothing\", \"Home & Garden\", \"Sports\"]\norder_map = {cat: i for i, cat in enumerate(category_order)}\ndata[\"color_order\"] = data[\"Product\"].map(order_map)\n\n# Calculate totals for labels above stacks\ntotals = data.groupby(\"Quarter\")[\"Sales\"].sum().reset_index()\ntotals.columns = [\"Quarter\", \"Total\"]\n\n# Create stacked bar chart\nbars = (\n    alt.Chart(data)\n    .mark_bar(stroke=PAGE_BG, strokeWidth=2)\n    .encode(\n        x=alt.X(\"Quarter:O\", title=\"Quarter\", axis=alt.Axis(labelFontSize=18, titleFontSize=22, labelAngle=0)),\n        y=alt.Y(\"sum(Sales):Q\", title=\"Sales (Thousands USD)\", axis=alt.Axis(labelFontSize=18, titleFontSize=22)),\n        color=alt.Color(\n            \"Product:N\",\n            title=\"Product Category\",\n            scale=alt.Scale(domain=category_order, range=IMPRINT),\n            legend=alt.Legend(\n                titleFontSize=18, labelFontSize=16, symbolSize=300, orient=\"right\", titlePadding=10, labelLimit=150\n            ),\n        ),\n        order=alt.Order(\"color_order:Q\", sort=\"ascending\"),\n        tooltip=[\"Quarter:O\", \"Product:N\", alt.Tooltip(\"Sales:Q\", title=\"Sales (K USD)\")],\n    )\n)\n\n# Add total value labels above each stack\ntext = (\n    alt.Chart(totals)\n    .mark_text(fontSize=18, fontWeight=\"bold\", dy=-12, color=INK)\n    .encode(x=alt.X(\"Quarter:O\"), y=alt.Y(\"Total:Q\"), text=alt.Text(\"Total:Q\", format=\".0f\"))\n)\n\n# Combine bars and labels\nchart = (\n    (bars + text)\n    .properties(\n        width=1600,\n        height=900,\n        background=PAGE_BG,\n        title=alt.Title(\"bar-stacked · altair · anyplot.ai\", fontSize=28, anchor=\"middle\"),\n    )\n    .configure_view(fill=PAGE_BG, stroke=INK_SOFT, strokeWidth=0)\n    .configure_axis(\n        domainColor=INK_SOFT, tickColor=INK_SOFT, gridColor=INK, gridOpacity=0.15, labelColor=INK_SOFT, titleColor=INK\n    )\n    .configure_title(color=INK)\n    .configure_legend(fillColor=ELEVATED_BG, strokeColor=INK_SOFT, labelColor=INK_SOFT, titleColor=INK)\n)\n\n# Save as PNG and HTML with theme-suffixed filenames\nchart.save(f\"plot-{THEME}.png\", scale_factor=3.0)\nchart.save(f\"plot-{THEME}.html\")\n"}