{"spec_id":"dumbbell-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\ndumbbell-basic: Basic Dumbbell Chart\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 91/100 | Created: 2026-06-30\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport numpy as np\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\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — positions 1 and 2\nBEFORE_COLOR = \"#009E73\"  # Imprint position 1 — always first series\nAFTER_COLOR = \"#C475FD\"  # Imprint position 2\n\n# Data: Employee satisfaction scores before/after workplace policy changes\ncategories = [\"Engineering\", \"Marketing\", \"Sales\", \"HR\", \"Finance\", \"Operations\", \"Customer Support\", \"Product\"]\nbefore_scores = [65, 58, 72, 45, 68, 52, 40, 75]\nafter_scores = [82, 71, 78, 73, 75, 68, 62, 88]\n\n# Sort by improvement magnitude (largest at top)\ndiffs = [a - b for a, b in zip(after_scores, before_scores, strict=True)]\norder = np.argsort(diffs)\ncategories = [categories[i] for i in order]\nbefore_scores = [before_scores[i] for i in order]\nafter_scores = [after_scores[i] for i in order]\ndiffs = [diffs[i] for i in order]\n\n# Canonical 3200 × 1800 px landscape canvas — figsize=(8,4.5), dpi=400\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\ny = np.arange(len(categories))\n\n# Connecting lines — width proportional to improvement magnitude for visual storytelling\nmax_diff = max(diffs)\nfor i, (b, a, d) in enumerate(zip(before_scores, after_scores, diffs, strict=True)):\n    lw = 0.8 + 1.6 * d / max_diff  # scales 0.8–2.4 across the improvement range\n    ax.plot([b, a], [i, i], color=INK_SOFT, linewidth=lw, alpha=0.45, zorder=1)\n\n# Dots with Imprint palette; edgecolors=PAGE_BG for theme-adaptive halos\nax.scatter(before_scores, y, s=80, color=BEFORE_COLOR, zorder=3, edgecolors=PAGE_BG, linewidths=1.5)\nax.scatter(after_scores, y, s=80, color=AFTER_COLOR, zorder=3, edgecolors=PAGE_BG, linewidths=1.5)\n\n# Annotate the top and bottom performers to guide the viewer\nfor i in (0, len(categories) - 1):\n    sign = \"+\" if diffs[i] >= 0 else \"\"\n    ax.annotate(\n        f\"{sign}{diffs[i]} pts\",\n        xy=(after_scores[i], i),\n        xytext=(6, 0),\n        textcoords=\"offset points\",\n        fontsize=7,\n        color=INK_MUTED,\n        va=\"center\",\n    )\n\n# Axes\nax.set_yticks(y)\nax.set_yticklabels(categories)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT, labelcolor=INK_SOFT)\nax.set_xlim(28, 108)\n\ntitle = \"dumbbell-basic · python · matplotlib · anyplot.ai\"\ntitle_fs = max(8, round(12 * 67 / len(title))) if len(title) > 67 else 12\nax.set_title(title, fontsize=title_fs, fontweight=\"medium\", color=INK)\nax.set_xlabel(\"Satisfaction Score (0–100)\", fontsize=10, color=INK)\nax.set_ylabel(\"Department\", fontsize=10, color=INK)\n\n# Spines: L-shaped (top + right removed)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nfor s in (\"left\", \"bottom\"):\n    ax.spines[s].set_color(INK_SOFT)\n\n# Subtle x-axis grid\nax.xaxis.grid(True, color=INK, alpha=0.15, linewidth=0.8)\nax.set_axisbelow(True)\n\n# Custom legend handles via empty-data scatter — explicit matplotlib idiom\nh_before = ax.scatter([], [], s=80, color=BEFORE_COLOR, edgecolors=PAGE_BG, linewidths=1.5, label=\"Before\")\nh_after = ax.scatter([], [], s=80, color=AFTER_COLOR, edgecolors=PAGE_BG, linewidths=1.5, label=\"After\")\nleg = ax.legend(handles=[h_before, h_after], fontsize=8, loc=\"lower right\", frameon=True)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nleg.get_frame().set_linewidth(0.8)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\n# Explicit margins — do NOT use bbox_inches='tight' on savefig (shrinks canvas)\nfig.subplots_adjust(left=0.16, right=0.95, top=0.92, bottom=0.13)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}