{"spec_id":"ternary-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nternary-basic: Basic Ternary Plot\nLibrary: plotly 6.9.0 | Python 3.13.14\nQuality: 91/100 | Updated: 2026-08-04\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\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.12)\" if THEME == \"light\" else \"rgba(240,239,232,0.12)\"\n\n# Imprint palette (first series is always #009E73)\nIMPRINT = [\n    \"#009E73\",  # bluish green (brand — primary)\n    \"#C475FD\",  # vermillion (secondary)\n    \"#4467A3\",  # blue (tertiary)\n    \"#BD8233\",  # reddish purple (quaternary)\n]\n\n# Data: three-way market share (leader / challenger / niche player) across\n# four industries, each with a distinct competitive structure. This spreads\n# points across the full simplex — concentrated markets sit near the \"Leader\"\n# vertex, three-way races sit near the centroid, and duopolies sit near the\n# leader-challenger edge — rather than clustering in one corner. Per-point\n# noise is renormalized so the three shares always sum to exactly 100%.\nnp.random.seed(42)\n\nindustries = [\n    (\"Cloud Infrastructure\", 65.0, 25.0, 10.0, \"circle\"),\n    (\"Streaming Video\", 40.0, 35.0, 25.0, \"diamond\"),\n    (\"Ride-Hailing\", 48.0, 45.0, 7.0, \"square\"),\n    (\"Food Delivery\", 30.0, 50.0, 20.0, \"triangle-up\"),\n]\n\nn_per_industry = 11\nleader_all, challenger_all, niche_all, industry_idx = [], [], [], []\nfor idx, (_name, lead0, chal0, niche0, _symbol) in enumerate(industries):\n    lead = np.clip(lead0 + np.random.normal(0, 5.0, n_per_industry), 1, None)\n    chal = np.clip(chal0 + np.random.normal(0, 5.0, n_per_industry), 1, None)\n    niche = np.clip(niche0 + np.random.normal(0, 3.0, n_per_industry), 1, None)\n    total = lead + chal + niche\n    leader_all.append(lead / total * 100)\n    challenger_all.append(chal / total * 100)\n    niche_all.append(niche / total * 100)\n    industry_idx.extend([idx] * n_per_industry)\n\nleader_all = np.concatenate(leader_all)\nchallenger_all = np.concatenate(challenger_all)\nniche_all = np.concatenate(niche_all)\nindustry_idx = np.array(industry_idx)\n\ntitle_text = \"Market Share by Industry · ternary-basic · python · plotly · anyplot.ai\"\ntitle_fontsize = round(16 * min(1.0, 67 / len(title_text)))\n\nfig = go.Figure()\n\n# One trace per industry: color AND marker symbol both encode the group, so\n# the grouping reads even for viewers who can't distinguish the hues.\nfor idx, (name, _lead0, _chal0, _niche0, symbol) in enumerate(industries):\n    mask = industry_idx == idx\n    fig.add_trace(\n        go.Scatterternary(\n            a=leader_all[mask],\n            b=challenger_all[mask],\n            c=niche_all[mask],\n            mode=\"markers\",\n            name=name,\n            marker={\n                \"symbol\": symbol,\n                \"size\": 15,\n                \"color\": IMPRINT[idx],\n                \"opacity\": 0.82,\n                \"line\": {\"width\": 1.5, \"color\": PAGE_BG},\n            },\n            hovertemplate=(\n                \"<b>%{customdata}</b><br>Leader: %{a:.1f}%<br>Challenger: %{b:.1f}%<br>Niche: %{c:.1f}%<extra></extra>\"\n            ),\n            customdata=[name] * int(mask.sum()),\n        )\n    )\n\n# Reference line: the 50% \"majority\" threshold — above it the leader alone\n# controls the market, below it no single player commands a majority. A\n# domain-specific annotation, not just decoration.\nfig.add_trace(\n    go.Scatterternary(\n        a=[50, 50],\n        b=[50, 0],\n        c=[0, 50],\n        mode=\"lines\",\n        line={\"width\": 1.5, \"color\": INK_SOFT, \"dash\": \"dot\"},\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\nfig.add_annotation(\n    text=\"- - - dashed line: 50% majority threshold\",\n    xref=\"paper\",\n    yref=\"paper\",\n    x=0.0,\n    y=0.87,\n    xanchor=\"left\",\n    yanchor=\"bottom\",\n    showarrow=False,\n    font={\"size\": 13, \"color\": INK_SOFT},\n)\n\nfig.update_layout(\n    autosize=False,\n    title={\"text\": title_text, \"font\": {\"size\": title_fontsize, \"color\": INK}, \"x\": 0.5, \"xanchor\": \"center\"},\n    ternary={\n        \"sum\": 100,\n        \"aaxis\": {\n            \"title\": {\"text\": \"Market Leader (%)\", \"font\": {\"size\": 12, \"color\": INK}},\n            \"tickmode\": \"linear\",\n            \"tick0\": 0,\n            \"dtick\": 20,\n            \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n            \"linewidth\": 2,\n            \"linecolor\": INK_SOFT,\n            \"gridwidth\": 1,\n            \"gridcolor\": GRID,\n        },\n        \"baxis\": {\n            \"title\": {\"text\": \"Challenger (%)\", \"font\": {\"size\": 12, \"color\": INK}},\n            \"tickmode\": \"linear\",\n            \"tick0\": 0,\n            \"dtick\": 20,\n            \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n            \"linewidth\": 2,\n            \"linecolor\": INK_SOFT,\n            \"gridwidth\": 1,\n            \"gridcolor\": GRID,\n        },\n        \"caxis\": {\n            \"title\": {\"text\": \"Niche Player (%)\", \"font\": {\"size\": 12, \"color\": INK}},\n            \"tickmode\": \"linear\",\n            \"tick0\": 0,\n            \"dtick\": 20,\n            \"tickfont\": {\"size\": 10, \"color\": INK_SOFT},\n            \"linewidth\": 2,\n            \"linecolor\": INK_SOFT,\n            \"gridwidth\": 1,\n            \"gridcolor\": GRID,\n        },\n        \"bgcolor\": PAGE_BG,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    margin={\"l\": 90, \"r\": 90, \"t\": 100, \"b\": 80},\n    legend={\n        \"title\": {\"text\": \"Industry\", \"font\": {\"size\": 11, \"color\": INK}},\n        \"x\": 0.98,\n        \"y\": 0.02,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"bottom\",\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n        \"font\": {\"color\": INK_SOFT, \"size\": 10},\n    },\n)\n\n# Save outputs — hard target 3200x1800, see prompts/library/plotly.md \"Canvas\"\nfig.write_image(f\"plot-{THEME}.png\", width=800, height=450, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}