{"spec_id":"bar-stacked","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nbar-stacked: Stacked Bar Chart\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 82/100 | Updated: 2026-05-09\n\"\"\"\n\nimport os\nimport sys\nimport time\nfrom pathlib import Path\n\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\n\n\n# Remove current directory from sys.path to avoid shadowing bokeh module\ncurrent_dir = str(Path(__file__).parent.absolute())\nsys.path = [p for p in sys.path if p != current_dir and p != \"\"]\n\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColumnDataSource, HoverTool, Legend, LegendItem\nfrom bokeh.plotting import figure\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\"]\n\n# Data: Monthly energy consumption by source (in gigawatt-hours)\nmonths = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"]\nsources = [\"Solar\", \"Wind\", \"Hydro\", \"Natural Gas\"]\ncolors = IMPRINT\n\ndata = {\n    \"Solar\": [85, 92, 110, 125, 145, 165, 175, 160, 140, 115, 95, 80],\n    \"Wind\": [120, 130, 125, 110, 95, 85, 80, 90, 105, 125, 140, 145],\n    \"Hydro\": [105, 100, 95, 90, 85, 75, 70, 75, 85, 95, 110, 115],\n    \"Natural Gas\": [65, 60, 55, 50, 45, 40, 35, 40, 50, 60, 70, 80],\n}\n\n# Calculate bottom positions for stacking\nbottoms = {src: [0] * len(months) for src in sources}\nrunning_total = [0] * len(months)\nfor src in sources:\n    bottoms[src] = running_total.copy()\n    running_total = [r + v for r, v in zip(running_total, data[src], strict=True)]\n\n# Create figure\np = figure(\n    x_range=months,\n    width=4800,\n    height=2700,\n    title=\"bar-stacked · bokeh · anyplot.ai\",\n    x_axis_label=\"Month\",\n    y_axis_label=\"Energy Production (GWh)\",\n    toolbar_location=None,\n)\n\n# Create stacked bars\nlegend_items = []\nfor src, color in zip(sources, colors, strict=True):\n    source = ColumnDataSource(\n        data={\n            \"x\": months,\n            \"top\": [b + v for b, v in zip(bottoms[src], data[src], strict=True)],\n            \"bottom\": bottoms[src],\n            \"value\": data[src],\n            \"source\": [src] * len(months),\n        }\n    )\n    renderer = p.vbar(\n        x=\"x\", top=\"top\", bottom=\"bottom\", width=0.6, source=source, color=color, line_color=PAGE_BG, line_width=1.5\n    )\n    legend_items.append(LegendItem(label=src, renderers=[renderer]))\n\n    # Add hover tool\n    hover = HoverTool(\n        renderers=[renderer], tooltips=[(\"Month\", \"@x\"), (\"Source\", \"@source\"), (\"Production\", \"@value{0} GWh\")]\n    )\n    p.add_tools(hover)\n\n# Add legend\nlegend = Legend(\n    items=legend_items,\n    location=\"top_right\",\n    label_text_font_size=\"18pt\",\n    spacing=12,\n    padding=15,\n    background_fill_color=ELEVATED_BG,\n    background_fill_alpha=0.95,\n    border_line_color=INK_SOFT,\n    label_text_color=INK_SOFT,\n    glyph_height=28,\n    glyph_width=28,\n)\np.add_layout(legend)\n\n# Style the plot\np.title.text_font_size = \"28pt\"\np.title.text_color = INK\np.xaxis.axis_label_text_font_size = \"22pt\"\np.yaxis.axis_label_text_font_size = \"22pt\"\np.xaxis.axis_label_text_color = INK\np.yaxis.axis_label_text_color = INK\np.xaxis.major_label_text_font_size = \"18pt\"\np.yaxis.major_label_text_font_size = \"18pt\"\np.xaxis.major_label_text_color = INK_SOFT\np.yaxis.major_label_text_color = INK_SOFT\n\n# Grid styling\np.xgrid.grid_line_color = None\np.ygrid.grid_line_alpha = 0.10\np.ygrid.grid_line_color = INK\n\n# Axis styling\np.xaxis.axis_line_color = INK_SOFT\np.yaxis.axis_line_color = INK_SOFT\np.xaxis.major_tick_line_color = INK_SOFT\np.yaxis.major_tick_line_color = INK_SOFT\np.outline_line_color = INK_SOFT\n\n# Plot background\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\n\n# Set y-axis range with padding\np.y_range.start = 0\np.y_range.end = max(running_total) * 1.1\n\n# Determine output directory\nimpl_dir = Path(__file__).parent\nos.chdir(impl_dir)\n\n# Save HTML\noutput_file(f\"plot-{THEME}.html\")\nsave(p)\n\n# Screenshot to PNG with headless Chrome\nW, H = 4800, 2700\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{H}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\ndriver = webdriver.Chrome(options=opts)\ndriver.set_window_size(W, H)\ndriver.get(f\"file://{(impl_dir / f'plot-{THEME}.html').resolve()}\")\ntime.sleep(3)\ndriver.save_screenshot(str(impl_dir / f\"plot-{THEME}.png\"))\ndriver.quit()\n"}