{"spec_id":"alluvial-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nalluvial-basic: Basic Alluvial Diagram\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-09\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.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data: Browser market share evolution 2015-2024\n# Shows how different browsers have gained/lost market share over time\ntime_points = [\"2015\", \"2018\", \"2021\", \"2024\"]\ncategories = [\"Chrome\", \"Firefox\", \"Safari\", \"Edge\"]\n\n# Node labels and colors\nnode_labels = categories * 4\ncategory_colors = {cat: IMPRINT[i] for i, cat in enumerate(categories)}\nnode_colors = [category_colors[cat] for cat in node_labels]\n\n# X positions: 4 time points evenly spaced\nx_positions = []\nfor t in range(4):\n    x_positions.extend([0.01 + (t / 3) * 0.98] * 4)\n\n# Y positions: 4 categories evenly spaced vertically\ny_positions = [0.15, 0.42, 0.68, 0.92] * 4\n\n# Define flows: realistic browser market share transitions\nflows_data = [\n    # 2015 -> 2018: Chrome growth, Firefox decline\n    (0, 0, 1, 0, 420),  # Chrome stays Chrome\n    (0, 0, 1, 2, 30),  # Chrome to Safari\n    (0, 1, 1, 1, 140),  # Firefox stays Firefox\n    (0, 1, 1, 0, 45),  # Firefox to Chrome\n    (0, 1, 1, 2, 15),  # Firefox to Safari\n    (0, 2, 1, 2, 180),  # Safari stays Safari\n    (0, 2, 1, 0, 50),  # Safari to Chrome\n    (0, 3, 1, 3, 85),  # Edge stays Edge\n    (0, 3, 1, 0, 35),  # Edge to Chrome\n    # 2018 -> 2021: Chrome dominance, Firefox further decline\n    (1, 0, 2, 0, 460),  # Chrome stays Chrome\n    (1, 0, 2, 2, 25),  # Chrome to Safari\n    (1, 0, 2, 3, 15),  # Chrome to Edge\n    (1, 1, 2, 1, 105),  # Firefox stays Firefox\n    (1, 1, 2, 0, 40),  # Firefox to Chrome\n    (1, 1, 2, 2, 15),  # Firefox to Safari\n    (1, 2, 2, 2, 200),  # Safari stays Safari\n    (1, 2, 2, 0, 45),  # Safari to Chrome\n    (1, 3, 2, 3, 95),  # Edge stays Edge\n    (1, 3, 2, 0, 30),  # Edge to Chrome\n    # 2021 -> 2024: Consolidation, Chrome dominance continues\n    (2, 0, 3, 0, 480),  # Chrome stays Chrome\n    (2, 0, 3, 3, 20),  # Chrome to Edge\n    (2, 1, 3, 1, 95),  # Firefox stays Firefox\n    (2, 1, 3, 0, 20),  # Firefox to Chrome\n    (2, 2, 3, 2, 215),  # Safari stays Safari\n    (2, 2, 3, 0, 50),  # Safari to Chrome\n    (2, 3, 3, 3, 110),  # Edge stays Edge\n    (2, 3, 3, 0, 25),  # Edge to Chrome\n]\n\n# Convert to source/target indices\nsources = []\ntargets = []\nvalues = []\nlink_colors = []\n\nfor src_time, src_cat, tgt_time, tgt_cat, value in flows_data:\n    src_idx = src_time * 4 + src_cat\n    tgt_idx = tgt_time * 4 + tgt_cat\n    sources.append(src_idx)\n    targets.append(tgt_idx)\n    values.append(value)\n    # Use source category color with transparency\n    base_color = IMPRINT[src_cat]\n    r = int(base_color[1:3], 16)\n    g = int(base_color[3:5], 16)\n    b = int(base_color[5:7], 16)\n    link_colors.append(f\"rgba({r},{g},{b},0.3)\")\n\n# Create Sankey diagram\nfig = go.Figure(\n    data=[\n        go.Sankey(\n            arrangement=\"snap\",\n            node=dict(\n                pad=35,\n                thickness=40,\n                line=dict(color=INK_SOFT, width=1),\n                label=node_labels,\n                color=node_colors,\n                x=x_positions,\n                y=y_positions,\n                hovertemplate=\"<b>%{label}</b><br>Market Share: %{value:,}%<extra></extra>\",\n            ),\n            link=dict(\n                source=sources,\n                target=targets,\n                value=values,\n                color=link_colors,\n                hovertemplate=\"<b>%{source.label}</b> (%{source.customdata})<br>\"\n                + \"→ <b>%{target.label}</b><br>\"\n                + \"Share: <b>%{value}%</b><extra></extra>\",\n            ),\n        )\n    ]\n)\n\n# Add time point labels\nfor i, year in enumerate(time_points):\n    fig.add_annotation(\n        x=i / 3, y=1.12, text=f\"<b>{year}</b>\", showarrow=False, font=dict(size=26, color=INK), xanchor=\"center\"\n    )\n\n# Add legend\nfor cat, color in category_colors.items():\n    fig.add_trace(\n        go.Scatter(\n            x=[None],\n            y=[None],\n            mode=\"markers\",\n            marker=dict(size=18, color=color, symbol=\"square\"),\n            name=cat,\n            showlegend=True,\n        )\n    )\n\n# Update layout with theme-adaptive colors\nfig.update_layout(\n    title=dict(\n        text=\"Browser Market Share · alluvial-basic · plotly · anyplot.ai\",\n        font=dict(size=32, color=INK),\n        x=0.5,\n        xanchor=\"center\",\n        y=0.98,\n    ),\n    font=dict(size=20, color=INK),\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    margin=dict(l=60, r=60, t=140, b=80),\n    legend=dict(\n        orientation=\"h\",\n        yanchor=\"bottom\",\n        y=-0.08,\n        xanchor=\"center\",\n        x=0.5,\n        font=dict(size=20, color=INK_SOFT),\n        bgcolor=ELEVATED_BG,\n        bordercolor=INK_SOFT,\n        borderwidth=1,\n    ),\n    xaxis=dict(visible=False),\n    yaxis=dict(visible=False),\n)\n\n# Save outputs\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}