{"spec_id":"sankey-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nsankey-basic: Basic Sankey Diagram\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 88/100 | Updated: 2026-07-25\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\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\n\n# Imprint palette keyed by source name (canonical order, position 1 = Coal)\nSOURCE_COLOR = {\"Coal\": \"#009E73\", \"Natural Gas\": \"#C475FD\", \"Nuclear\": \"#4467A3\", \"Renewables\": \"#BD8233\"}\nSOURCE_RGBA = {\n    \"Coal\": \"rgba(0, 158, 115, 0.4)\",\n    \"Natural Gas\": \"rgba(196, 117, 253, 0.4)\",\n    \"Nuclear\": \"rgba(68, 103, 163, 0.4)\",\n    \"Renewables\": \"rgba(189, 130, 51, 0.4)\",\n}\n\n# Node order chosen via barycenter heuristic (avg. position of connected flows,\n# weighted by value) to reduce link crossings versus the default/alphabetical order.\nsources = [\"Coal\", \"Nuclear\", \"Natural Gas\", \"Renewables\"]\ntargets = [\"Industrial\", \"Commercial\", \"Residential\", \"Transportation\"]\nlabels = sources + targets\nlabel_index = {name: i for i, name in enumerate(labels)}\n\nflows = [\n    (\"Coal\", \"Residential\", 2),\n    (\"Coal\", \"Commercial\", 8),\n    (\"Coal\", \"Industrial\", 25),\n    (\"Natural Gas\", \"Residential\", 22),\n    (\"Natural Gas\", \"Commercial\", 18),\n    (\"Natural Gas\", \"Industrial\", 15),\n    (\"Natural Gas\", \"Transportation\", 3),\n    (\"Nuclear\", \"Residential\", 12),\n    (\"Nuclear\", \"Commercial\", 10),\n    (\"Nuclear\", \"Industrial\", 8),\n    (\"Renewables\", \"Residential\", 18),\n    (\"Renewables\", \"Commercial\", 4),\n    (\"Renewables\", \"Industrial\", 2),\n    (\"Renewables\", \"Transportation\", 10),\n]\n\nsource_indices = [label_index[f[0]] for f in flows]\ntarget_indices = [label_index[f[1]] for f in flows]\nvalues = [f[2] for f in flows]\n\n# Source nodes use Imprint colors; target nodes use INK_SOFT\nnode_colors = [SOURCE_COLOR[name] for name in sources] + [INK_SOFT] * len(targets)\nlink_colors = [SOURCE_RGBA[f[0]] for f in flows]\n\n# Rank-ordered y hints (per column) nudge the layout toward the low-crossing\n# order above instead of Plotly's default alphabetical placement.\nRANK_Y = [0.001, 0.34, 0.67, 0.999]\nnode_x = [0.001] * len(sources) + [0.999] * len(targets)\nnode_y = RANK_Y + RANK_Y\n\n# Plot\nfig = go.Figure(\n    data=[\n        go.Sankey(\n            node={\n                \"pad\": 20,\n                \"thickness\": 28,\n                \"line\": {\"color\": PAGE_BG, \"width\": 1},\n                \"label\": labels,\n                \"color\": node_colors,\n                \"x\": node_x,\n                \"y\": node_y,\n                \"hovertemplate\": \"%{label}: %{value} TWh<extra></extra>\",\n            },\n            link={\n                \"source\": source_indices,\n                \"target\": target_indices,\n                \"value\": values,\n                \"color\": link_colors,\n                \"hovertemplate\": \"%{source.label} → %{target.label}: %{value} TWh<extra></extra>\",\n            },\n        )\n    ]\n)\n\nfig.update_layout(\n    autosize=False,\n    title={\n        \"text\": \"Energy Distribution · sankey-basic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 20, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    font={\"size\": 16, \"color\": INK},\n    margin={\"l\": 60, \"r\": 60, \"t\": 90, \"b\": 45},\n    annotations=[\n        {\n            \"text\": \"Flow values in TWh\",\n            \"font\": {\"size\": 11, \"color\": INK_SOFT},\n            \"x\": 0.99,\n            \"y\": -0.06,\n            \"xref\": \"paper\",\n            \"yref\": \"paper\",\n            \"xanchor\": \"right\",\n            \"yanchor\": \"top\",\n            \"showarrow\": False,\n        }\n    ],\n)\n\n# Save\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}