{"spec_id":"bar-grouped","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nbar-grouped: Grouped Bar Chart\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 92/100 | Updated: 2026-08-05\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\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\"\nGRID = \"rgba(26,26,23,0.15)\" if THEME == \"light\" else \"rgba(240,239,232,0.15)\"\n\n# Imprint categorical palette — device types are abstract groups, canonical order applies\nCOLORS = [\"#009E73\", \"#C475FD\", \"#4467A3\"]\n\n# Data: monthly website sessions (thousands) by traffic source, split by device type\ncategories = [\"Organic Search\", \"Direct\", \"Social Media\", \"Paid Search\", \"Referral\"]\ndevices = {\"Desktop\": [420, 210, 96, 185, 132], \"Mobile\": [312, 168, 224, 148, 90], \"Tablet\": [64, 47, 58, 42, 31]}\n\n# Create figure\nfig = go.Figure()\n\nfor i, (device, values) in enumerate(devices.items()):\n    fig.add_trace(\n        go.Bar(\n            name=device,\n            x=categories,\n            y=values,\n            marker={\"color\": COLORS[i], \"line\": {\"color\": PAGE_BG, \"width\": 1.5}},\n            text=values,\n            textposition=\"outside\",\n            textfont={\"size\": 11, \"color\": INK},\n            hovertemplate=(f\"<b>{device}</b><br>Source: %{{x}}<br>Sessions: %{{y}}K<br><extra></extra>\"),\n        )\n    )\n\n# Callout: Social Media is the only source where mobile sessions outpace desktop\nfig.add_annotation(\n    x=\"Social Media\",\n    y=224,\n    text=\"Social skews mobile-first —<br>2.3× desktop sessions\",\n    showarrow=True,\n    arrowhead=2,\n    arrowcolor=INK_SOFT,\n    ax=110,\n    ay=-25,\n    font={\"size\": 11, \"color\": INK},\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=1,\n    borderpad=6,\n)\n\n# Layout\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"bar-grouped · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 19, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Traffic Source\", \"font\": {\"size\": 15, \"color\": INK}},\n        \"tickfont\": {\"size\": 12, \"color\": INK_SOFT},\n        \"showgrid\": False,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Monthly Sessions (thousands)\", \"font\": {\"size\": 15, \"color\": INK}},\n        \"tickfont\": {\"size\": 12, \"color\": INK_SOFT},\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n        \"mirror\": False,\n    },\n    barmode=\"group\",\n    bargap=0.2,\n    bargroupgap=0.1,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    legend={\n        \"font\": {\"size\": 12, \"color\": INK_SOFT},\n        \"bgcolor\": ELEVATED_BG,\n        \"borderwidth\": 0,\n        \"orientation\": \"h\",\n        \"yanchor\": \"bottom\",\n        \"y\": 1.02,\n        \"xanchor\": \"center\",\n        \"x\": 0.5,\n    },\n    margin={\"l\": 90, \"r\": 40, \"t\": 110, \"b\": 70},\n    hovermode=\"x unified\",\n)\n\n# Save outputs\nscript_dir = os.path.dirname(os.path.abspath(__file__))\nfig.write_image(os.path.join(script_dir, f\"plot-{THEME}.png\"), width=800, height=450, scale=4)\nfig.write_html(os.path.join(script_dir, f\"plot-{THEME}.html\"), include_plotlyjs=\"cdn\")\n"}