{"spec_id":"elbow-curve","library":"bokeh","language":"python","code":"\"\"\" anyplot.ai\nelbow-curve: Elbow Curve for K-Means Clustering\nLibrary: bokeh 3.9.0 | Python 3.13.13\nQuality: 93/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\nimport sys\nimport time\nfrom pathlib import Path\n\n\n# Remove local bokeh.py from sys.modules cache if it got loaded\nif \"bokeh\" in sys.modules:\n    del sys.modules[\"bokeh\"]\n\n# Rebuild sys.path to avoid shadowing\nsys.path = [p for p in sys.path if not p.endswith(\"/python\") and p != \"\" and p != \".\"]\n# Re-add site-packages at the front to ensure bokeh package is found first\nimport site\n\n\nfor sp in site.getsitepackages():\n    if sp not in sys.path:\n        sys.path.insert(0, sp)\n\nimport numpy as np\nfrom bokeh.io import output_file, save\nfrom bokeh.models import ColumnDataSource\nfrom bokeh.plotting import figure\nfrom selenium import webdriver\nfrom selenium.webdriver.chrome.options import Options\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\"\n\n# Okabe-Ito palette\nBRAND = \"#009E73\"\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\"]\n\n# Data - Generate realistic K-means inertia values\nnp.random.seed(42)\n\nk_values = np.arange(1, 11)\nbase_inertia = 5000\n\n# Create realistic decreasing inertia with elbow around k=4\ninertia = []\nfor k in k_values:\n    if k == 1:\n        val = base_inertia\n    elif k <= 4:\n        # Sharp decrease before elbow\n        val = base_inertia * (0.35 ** (k - 1)) + np.random.uniform(50, 100)\n    else:\n        # Gradual decrease after elbow (diminishing returns)\n        val = inertia[-1] * 0.85 + np.random.uniform(20, 50)\n    inertia.append(val)\n\ninertia = np.array(inertia)\n\n# Optimal k (elbow point)\noptimal_k = 4\noptimal_inertia = inertia[optimal_k - 1]\n\n# Create ColumnDataSource\nsource = ColumnDataSource(data={\"k\": k_values, \"inertia\": inertia})\n\n# Create figure\np = figure(\n    width=4800,\n    height=2700,\n    title=\"elbow-curve · bokeh · anyplot.ai\",\n    x_axis_label=\"Number of Clusters (k)\",\n    y_axis_label=\"Inertia (Within-Cluster Sum of Squares)\",\n    tools=\"\",\n    toolbar_location=None,\n)\n\n# Plot line and markers\np.line(x=\"k\", y=\"inertia\", source=source, line_width=4, line_color=BRAND, line_alpha=0.8)\np.scatter(\n    x=\"k\",\n    y=\"inertia\",\n    source=source,\n    size=18,\n    fill_color=BRAND,\n    line_color=BRAND,\n    line_width=2,\n    fill_alpha=0.8,\n    legend_label=\"Inertia\",\n)\n\n# Highlight the optimal k with a secondary color\np.scatter(\n    x=[optimal_k],\n    y=[optimal_inertia],\n    size=28,\n    fill_color=IMPRINT[1],  # Vermillion\n    line_color=IMPRINT[1],\n    line_width=3,\n    fill_alpha=0.8,\n    legend_label=f\"Elbow Point (k={optimal_k})\",\n)\n\n# Style title and axes\np.title.text_font_size = \"28pt\"\np.title.text_color = INK\np.title.align = \"center\"\n\np.xaxis.axis_label_text_font_size = \"22pt\"\np.yaxis.axis_label_text_font_size = \"22pt\"\np.xaxis.axis_label_text_color = INK\np.yaxis.axis_label_text_color = INK\n\np.xaxis.major_label_text_font_size = \"18pt\"\np.yaxis.major_label_text_font_size = \"18pt\"\np.xaxis.major_label_text_color = INK_SOFT\np.yaxis.major_label_text_color = INK_SOFT\n\np.xaxis.axis_line_color = INK_SOFT\np.yaxis.axis_line_color = INK_SOFT\np.xaxis.major_tick_line_color = INK_SOFT\np.yaxis.major_tick_line_color = INK_SOFT\n\n# Grid styling\np.xgrid.grid_line_color = INK\np.ygrid.grid_line_color = INK\np.xgrid.grid_line_alpha = 0.10\np.ygrid.grid_line_alpha = 0.10\n\n# Set x-axis to show integer values only\np.xaxis.ticker = list(k_values)\n\n# Legend styling\np.legend.location = \"top_right\"\np.legend.label_text_font_size = \"18pt\"\np.legend.label_text_color = INK_SOFT\np.legend.background_fill_color = ELEVATED_BG\np.legend.border_line_color = INK_SOFT\np.legend.padding = 15\np.legend.margin = 10\n\n# Background styling\np.background_fill_color = PAGE_BG\np.border_fill_color = PAGE_BG\np.outline_line_color = INK_SOFT\n\n# Save HTML and screenshot with Selenium\nhtml_file = Path(f\"plot-{THEME}.html\").resolve()\noutput_file(str(html_file))\nsave(p)\n\nW, H = 4800, 2700\nopts = Options()\nfor arg in (\n    \"--headless=new\",\n    \"--no-sandbox\",\n    \"--disable-dev-shm-usage\",\n    \"--disable-gpu\",\n    f\"--window-size={W},{H}\",\n    \"--hide-scrollbars\",\n):\n    opts.add_argument(arg)\n\ndriver = webdriver.Chrome(options=opts)\ndriver.set_window_size(W, H)\ndriver.get(f\"file://{html_file}\")\ntime.sleep(3)\n\npng_file = Path(f\"plot-{THEME}.png\").resolve()\ndriver.save_screenshot(str(png_file))\ndriver.quit()\n"}