{"spec_id":"elbow-curve","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nelbow-curve: Elbow Curve for K-Means Clustering\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-10\n\"\"\"\n\nimport importlib\nimport os\nimport sys\n\n\n# Work around naming conflict: ensure we import the real pygal package, not this file\nif __name__ == \"__main__\":\n    import pathlib\n\n    _this_file = pathlib.Path(__file__)\n    _parent = _this_file.parent\n    # Remove parent from path to avoid importing this file as pygal\n    if str(_parent) in sys.path:\n        sys.path.remove(str(_parent))\n\npygal = importlib.import_module(\"pygal\")\nStyle = pygal.style.Style\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\nBRAND = \"#009E73\"\nACCENT = \"#C475FD\"\n\n# Document clustering: optimal k determined by elbow curve\n# Represents topic grouping analysis on a text corpus\nk_values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\ninertias = [5200, 2600, 1600, 950, 700, 560, 480, 420, 380, 350]\n\n# Identify elbow point: where the rate of improvement sharply drops\n# Calculate rates of change to find the point where slope flattens\nrates_of_change = [inertias[i] - inertias[i + 1] for i in range(len(inertias) - 1)]\n# The elbow is where the rate of change itself drops significantly\n# k=4 (index 3) shows diminishing returns: 650 → 250 drop\nelbow_k_index = 3  # k=4\nelbow_k = k_values[elbow_k_index]\nelbow_inertia = inertias[elbow_k_index]\n\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=(BRAND, ACCENT),\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=16,\n    value_font_size=14,\n    stroke_width=3,\n)\n\nchart = pygal.XY(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"elbow-curve · pygal · anyplot.ai\",\n    x_title=\"Number of Clusters (k)\",\n    y_title=\"Inertia (Within-cluster Sum of Squares)\",\n    show_legend=False,\n    show_x_guides=False,\n    show_y_guides=True,\n    dots_size=10,\n    stroke_style={\"width\": 3, \"linecap\": \"round\", \"linejoin\": \"round\"},\n    x_labels=k_values,\n    range=(0, max(inertias) * 1.05),\n    explicit_size=True,\n    margin=80,\n)\n\n# Main curve: all data points as continuous line\nelbow_data = [(k, inertia) for k, inertia in zip(k_values, inertias, strict=True)]\nchart.add(\"Inertia\", elbow_data, stroke_style={\"width\": 3}, dots_size=8, show_dots=True)\n\n# Highlight elbow point with distinct marker (larger, accent color)\n# Create a single-point series for the elbow to emphasize it visually\nelbow_highlight = [None] * len(k_values)\nelbow_highlight[elbow_k_index] = (elbow_k, elbow_inertia)\nelbow_highlight_data = [(k, inertia) for i, (k, inertia) in enumerate(elbow_data) if i == elbow_k_index]\nchart.add(\"Optimal k\", elbow_highlight_data, dots_size=16, show_dots=True, stroke=False, fill=False)\n\n# Save as PNG and HTML\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}