{"spec_id":"swarm-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nswarm-basic: Basic Swarm Plot\nLibrary: plotnine 0.15.7 | Python 3.13.14\nQuality: 89/100 | Updated: 2026-07-26\n\"\"\"\n\nimport sys\n\n\nsys.path.pop(0)  # prevent this file from shadowing the installed plotnine package\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_blank,\n    element_line,\n    element_rect,\n    element_text,\n    geom_line,\n    geom_point,\n    ggplot,\n    labs,\n    scale_color_manual,\n    scale_x_continuous,\n    theme,\n    theme_minimal,\n)\n\n\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nIMPRINT = [\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\"]\n\n# Data - Patient biomarker levels across treatment groups\nnp.random.seed(42)\n\ntreatment_groups = [\"Placebo\", \"Low Dose\", \"Medium Dose\", \"High Dose\"]\n\ndistributions = {\n    \"Placebo\": {\"mean\": 45, \"std\": 12, \"n\": 50},\n    \"Low Dose\": {\"mean\": 55, \"std\": 10, \"n\": 45},\n    \"Medium Dose\": {\"mean\": 68, \"std\": 8, \"n\": 55},\n    \"High Dose\": {\"mean\": 75, \"std\": 6, \"n\": 40},\n}\n\ndata = []\nfor group, params in distributions.items():\n    values = np.random.normal(params[\"mean\"], params[\"std\"], params[\"n\"])\n    values = np.clip(values, 20, 100)\n    data.extend([(group, value) for value in values])\n\ndf = pd.DataFrame(data, columns=[\"treatment\", \"biomarker\"])\ndf[\"treatment\"] = pd.Categorical(df[\"treatment\"], categories=treatment_groups, ordered=True)\ndf[\"x_num\"] = df[\"treatment\"].cat.codes.astype(float)\n\n\n# Deterministic beeswarm packing: sweep points in ascending value order and\n# place each one in the nearest-to-center offset slot (alternating sides)\n# whose most recent occupant already cleared a minimum vertical gap — a slot\n# only frees up once its last point is far enough below the new one, so\n# offsets keep growing in dense stretches instead of every sparse column\n# resetting back to center and stacking near-concentrically with its neighbor.\n# min_gap is fixed to the shared y-axis scale (not each group's own spread)\n# since the marker's on-canvas footprint is the same regardless of group.\ndef beeswarm_offsets(values, min_gap, spacing=0.09):\n    offsets = np.zeros(len(values))\n    slot_last_y = {}  # offset slot (int) -> value of the last point placed there\n    for idx in np.argsort(values):\n        y = values[idx]\n        step = 0\n        while True:\n            for slot in (0,) if step == 0 else (step, -step):\n                last_y = slot_last_y.get(slot)\n                if last_y is None or y - last_y >= min_gap:\n                    offsets[idx] = slot * spacing\n                    slot_last_y[slot] = y\n                    step = None\n                    break\n            if step is None:\n                break\n            step += 1\n    return offsets\n\n\nswarm_min_gap = (df[\"biomarker\"].max() - df[\"biomarker\"].min()) * 0.05\nfor group in treatment_groups:\n    mask = df[\"treatment\"] == group\n    df.loc[mask, \"x_num\"] += beeswarm_offsets(df.loc[mask, \"biomarker\"].to_numpy(), swarm_min_gap)\n\nmedians_df = df.groupby(\"treatment\", observed=True)[\"biomarker\"].median().reset_index()\nmedians_df[\"x_num\"] = medians_df[\"treatment\"].cat.codes.astype(float)\n\n# Plot\nplot = (\n    ggplot(df, aes(x=\"x_num\", y=\"biomarker\", color=\"treatment\"))\n    + geom_point(size=2.2, alpha=0.75)\n    + geom_line(\n        medians_df,\n        aes(x=\"x_num\", y=\"biomarker\", group=1),\n        linetype=\"dashed\",\n        color=INK_SOFT,\n        size=1.0,\n        inherit_aes=False,\n    )\n    + geom_point(medians_df, aes(x=\"x_num\", y=\"biomarker\"), size=6, shape=\"D\", color=INK, inherit_aes=False)\n    + scale_color_manual(values=IMPRINT)\n    + scale_x_continuous(breaks=list(range(len(treatment_groups))), labels=treatment_groups)\n    + labs(x=\"Treatment Group\", y=\"Biomarker Level (ng/mL)\", title=\"swarm-basic · plotnine · anyplot.ai\")\n    + theme_minimal()\n    + theme(\n        figure_size=(8, 4.5),\n        text=element_text(size=7),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_border=element_blank(),\n        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.08),\n        panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.04),\n        axis_ticks_major=element_blank(),\n        axis_title=element_text(color=INK, size=10),\n        axis_text=element_text(color=INK_SOFT, size=8),\n        plot_title=element_text(color=INK, size=13),\n        legend_position=\"none\",\n    )\n)\n\n# Save\nplot.save(f\"plot-{THEME}.png\", dpi=400, width=8, height=4.5, units=\"in\")\n"}