{"spec_id":"sunburst-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nsunburst-basic: Basic Sunburst Chart\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 94/100 | Updated: 2026-07-26\n\"\"\"\n\nimport os\n\nimport plotly.graph_objects as go\n\n\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_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Off-black / off-white text tokens for on-segment labels — never pure #000/#FFF\nDARK_TEXT = \"#1A1A17\"\nLIGHT_TEXT = \"#F0EFE8\"\n\n\ndef _on_segment_text_color(hex_color):\n    \"\"\"WCAG relative luminance -> pick the off-black or off-white text token.\"\"\"\n    r, g, b = (int(hex_color.lstrip(\"#\")[i : i + 2], 16) / 255 for i in (0, 2, 4))\n\n    def _lin(c):\n        return c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4\n\n    luminance = 0.2126 * _lin(r) + 0.7152 * _lin(g) + 0.0722 * _lin(b)\n    return DARK_TEXT if luminance > 0.45 else LIGHT_TEXT\n\n\nlabels = [\n    \"Company\",\n    \"Engineering\",\n    \"Sales\",\n    \"Marketing\",\n    \"Operations\",\n    \"Backend\",\n    \"Frontend\",\n    \"DevOps\",\n    \"Enterprise\",\n    \"SMB\",\n    \"Digital\",\n    \"Brand\",\n    \"HR\",\n    \"Finance\",\n]\n\nparents = [\n    \"\",\n    \"Company\",\n    \"Company\",\n    \"Company\",\n    \"Company\",\n    \"Engineering\",\n    \"Engineering\",\n    \"Engineering\",\n    \"Sales\",\n    \"Sales\",\n    \"Marketing\",\n    \"Marketing\",\n    \"Operations\",\n    \"Operations\",\n]\n\n# Values in $M — branchvalues=\"total\" so each parent value equals sum of its children\nvalues = [\n    48,  # Company\n    18,  # Engineering — dominant at 37.5% of total\n    15,  # Sales\n    7,  # Marketing\n    8,  # Operations\n    8,  # Backend\n    6,  # Frontend\n    4,  # DevOps\n    10,  # Enterprise\n    5,  # SMB\n    4,  # Digital\n    3,  # Brand\n    3,  # HR\n    5,  # Finance\n]\n\n# Okabe-Ito palette — departments get canonical positions 1-4,\n# teams get lighter/darker variants to preserve family grouping\ncolors = [\n    ELEVATED_BG,  # Company root — adapts cleanly to both light and dark themes\n    \"#009E73\",  # Engineering — Okabe-Ito #1 (dominant: 37.5%)\n    \"#C475FD\",  # Sales — Okabe-Ito #2\n    \"#4467A3\",  # Marketing — Okabe-Ito #3\n    \"#BD8233\",  # Operations — Okabe-Ito #4\n    \"#2DAE89\",  # Backend — lighter green\n    \"#009E73\",  # Frontend — base green\n    \"#007A58\",  # DevOps — darker green\n    \"#D195FE\",  # Enterprise — lighter lavender\n    \"#C475FD\",  # SMB — base lavender\n    \"#6883B6\",  # Digital — lighter blue\n    \"#4467A3\",  # Brand — base blue\n    \"#CC9852\",  # HR — lighter ochre\n    \"#BD8233\",  # Finance — base ochre\n]\n\n# Explicit per-segment text color (WCAG luminance) instead of relying on\n# Plotly's implicit auto-contrast — keeps legibility fully under our control.\ntext_colors = [_on_segment_text_color(c) for c in colors]\n\nfig = go.Figure(\n    go.Sunburst(\n        labels=labels,\n        parents=parents,\n        values=values,\n        branchvalues=\"total\",\n        marker={\"colors\": colors, \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        textfont={\"size\": 13, \"color\": text_colors},\n        insidetextorientation=\"radial\",\n        hovertemplate=\"<b>%{label}</b><br>Budget: $%{value}M<br>%{percentParent:.1%} of %{parent}<extra></extra>\",\n        leaf={\"opacity\": 0.88},\n    )\n)\n\nfig.update_layout(\n    title={\n        \"text\": \"sunburst-basic · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    autosize=False,\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"color\": INK},\n    margin={\"t\": 70, \"l\": 40, \"r\": 40, \"b\": 130},\n)\n\n# Insight annotation — surface Engineering's outsized 37.5% share\nfig.add_annotation(\n    text=\"Engineering leads with 37.5% of total budget — nearly double Sales, the next-largest department\",\n    xref=\"paper\",\n    yref=\"paper\",\n    x=0.5,\n    y=-0.09,\n    xanchor=\"center\",\n    yanchor=\"bottom\",\n    font={\"size\": 11, \"color\": INK_MUTED},\n    showarrow=False,\n)\n\n# Square format — optimal for symmetric radial charts (2400x2400 via width=600 height=600 scale=4)\nfig.write_image(f\"plot-{THEME}.png\", width=600, height=600, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}