{"spec_id":"elbow-curve","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\nelbow-curve: Elbow Curve for K-Means Clustering\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 97/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\n\nimport numpy as np\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)\"\nBRAND = \"#009E73\"\nACCENT = \"#C475FD\"\n\n# Data - simulate K-means inertia values for k=1 to k=12\nnp.random.seed(42)\nk_values = np.arange(1, 13)\n\n# Generate realistic inertia values that decrease with k\nbase_inertia = 5000\ninertia = base_inertia * np.exp(-0.25 * (k_values - 1)) + np.random.normal(0, 30, len(k_values))\ninertia = np.maximum(inertia, 100)\ninertia = np.sort(inertia)[::-1]\n\n# Optimal k (elbow point) is around k=4\noptimal_k = 4\noptimal_inertia = inertia[optimal_k - 1]\n\n# Create figure\nfig = go.Figure()\n\n# Main curve with markers\nfig.add_trace(\n    go.Scatter(\n        x=k_values,\n        y=inertia,\n        mode=\"lines+markers\",\n        name=\"Inertia\",\n        line={\"color\": BRAND, \"width\": 4},\n        marker={\"size\": 16, \"color\": BRAND, \"line\": {\"color\": PAGE_BG, \"width\": 2}},\n        hovertemplate=\"k=%{x}<br>Inertia=%{y:.0f}<extra></extra>\",\n    )\n)\n\n# Highlight the elbow point\nfig.add_trace(\n    go.Scatter(\n        x=[optimal_k],\n        y=[optimal_inertia],\n        mode=\"markers\",\n        name=f\"Elbow (k={optimal_k})\",\n        marker={\"size\": 24, \"color\": ACCENT, \"symbol\": \"circle\", \"line\": {\"color\": INK, \"width\": 3}},\n        hovertemplate=f\"Optimal k={optimal_k}<br>Inertia={optimal_inertia:.0f}<extra></extra>\",\n    )\n)\n\n# Add annotation for the elbow point\nfig.add_annotation(\n    x=optimal_k,\n    y=optimal_inertia,\n    text=f\"Elbow Point<br>k = {optimal_k}\",\n    showarrow=True,\n    arrowhead=2,\n    arrowsize=1.5,\n    arrowwidth=2,\n    arrowcolor=INK,\n    ax=80,\n    ay=-80,\n    font={\"size\": 20, \"color\": INK},\n    bgcolor=ELEVATED_BG,\n    bordercolor=INK_SOFT,\n    borderwidth=2,\n    borderpad=8,\n)\n\n# Update layout\nfig.update_layout(\n    title={\"text\": \"elbow-curve · plotly · anyplot.ai\", \"font\": {\"size\": 28, \"color\": INK}, \"x\": 0.5, \"xanchor\": \"center\"},\n    xaxis={\n        \"title\": {\"text\": \"Number of Clusters (k)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"tickmode\": \"linear\",\n        \"tick0\": 1,\n        \"dtick\": 1,\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n    },\n    yaxis={\n        \"title\": {\"text\": \"Within-Cluster Sum of Squares (Inertia)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"showgrid\": True,\n        \"gridcolor\": GRID,\n        \"gridwidth\": 1,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n        \"zerolinecolor\": INK_SOFT,\n    },\n    paper_bgcolor=PAGE_BG,\n    plot_bgcolor=PAGE_BG,\n    showlegend=True,\n    legend={\n        \"x\": 0.95,\n        \"y\": 0.95,\n        \"xanchor\": \"right\",\n        \"yanchor\": \"top\",\n        \"font\": {\"size\": 16, \"color\": INK_SOFT},\n        \"bgcolor\": ELEVATED_BG,\n        \"bordercolor\": INK_SOFT,\n        \"borderwidth\": 1,\n    },\n    margin={\"l\": 120, \"r\": 80, \"t\": 100, \"b\": 100},\n)\n\n# Save as PNG (4800x2700 via scale=3)\noutput_dir = os.path.dirname(os.path.abspath(__file__))\nfig.write_image(os.path.join(output_dir, f\"plot-{THEME}.png\"), width=1600, height=900, scale=3)\n\n# Save interactive HTML\nfig.write_html(os.path.join(output_dir, f\"plot-{THEME}.html\"), include_plotlyjs=\"cdn\")\n"}