{"spec_id":"bar-spine","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nbar-spine: Spine Plot for Two-Variable Proportions\nLibrary: matplotlib 3.11.2 | Python 3.13.15\nQuality: 91/100 | Updated: 2026-09-27\n\"\"\"\n\nimport importlib\nimport os\nimport sys\n\n\n# This file is named matplotlib.py, which shadows the actual matplotlib package.\n# Strip this directory from sys.path before importing matplotlib so Python finds\n# the installed package instead of this script.\n_here = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != _here and p != \"\"]\n\nmpatches = importlib.import_module(\"matplotlib.patches\")\nplt = importlib.import_module(\"matplotlib.pyplot\")\nnp = importlib.import_module(\"numpy\")\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\n_OUT = os.path.dirname(os.path.abspath(__file__))\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# Titanic survival data by passenger class (classic contingency table)\nclasses = [\"1st Class\", \"2nd Class\", \"3rd Class\", \"Crew\"]\nsurvived_counts = np.array([203, 118, 178, 212])\ndied_counts = np.array([122, 167, 528, 673])\nclass_totals = survived_counts + died_counts\n\n# Marginal proportions → bar widths (width encodes class size)\ngrand_total = class_totals.sum()\nbar_widths = class_totals / grand_total\n\n# Conditional proportions within each bar (height encodes survival rate)\nprop_survived = survived_counts / class_totals\nprop_died = died_counts / class_totals\n\n# Left-edge positions for adjacent bars\nx_left = np.concatenate([[0], np.cumsum(bar_widths)[:-1]])\n\n# Colors: Imprint palette positions 1 and 2\nCOLOR_SURVIVED = \"#009E73\"\nCOLOR_DIED = \"#C475FD\"\n\n# Plot\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nsurvived_bars = ax.bar(\n    x_left, prop_survived, width=bar_widths, bottom=0, align=\"edge\", color=COLOR_SURVIVED, linewidth=0\n)\ndied_bars = ax.bar(\n    x_left, prop_died, width=bar_widths, bottom=prop_survived, align=\"edge\", color=COLOR_DIED, linewidth=0\n)\n\n# Thin page-color separators between adjacent bars\nfor x in x_left[1:]:\n    ax.axvline(x, color=PAGE_BG, linewidth=2.5, zorder=5)\n\n# Percentage labels centered within each segment (blank when too small to hold text)\nsurvived_labels = [f\"{p:.0%}\" if p > 0.08 else \"\" for p in prop_survived]\ndied_labels = [f\"{p:.0%}\" if p > 0.08 else \"\" for p in prop_died]\nax.bar_label(\n    survived_bars, labels=survived_labels, label_type=\"center\", fontsize=8, fontweight=\"bold\", color=\"white\", zorder=6\n)\nax.bar_label(died_bars, labels=died_labels, label_type=\"center\", fontsize=8, fontweight=\"bold\", color=\"white\", zorder=6)\n\n# X-axis: centered tick labels under variable-width bars\ncenter_positions = x_left + bar_widths / 2\nax.set_xticks(center_positions)\nax.set_xticklabels(classes, fontsize=8, color=INK_SOFT)\nax.tick_params(axis=\"x\", length=0, labelcolor=INK_SOFT)\n\n# Y-axis: percentage scale\nax.set_yticks([0, 0.25, 0.5, 0.75, 1.0])\nax.set_yticklabels([\"0%\", \"25%\", \"50%\", \"75%\", \"100%\"], fontsize=8, color=INK_SOFT)\nax.tick_params(axis=\"y\", length=0, labelcolor=INK_SOFT)\n\nax.set_xlim(0, 1)\nax.set_ylim(0, 1)\n\n# Annotation: highlight 1st-class survival advantage over crew\ncx_1st = x_left[0] + bar_widths[0] / 2\nax.annotate(\n    f\"1st class: {prop_survived[0]:.0%} survival\\nvs. {prop_survived[-1]:.0%} for crew\",\n    xy=(cx_1st, prop_survived[0]),\n    xytext=(0.28, 0.88),\n    fontsize=7,\n    color=INK_SOFT,\n    ha=\"center\",\n    va=\"bottom\",\n    arrowprops={\"arrowstyle\": \"-|>\", \"color\": INK_SOFT, \"lw\": 1.2},\n    bbox={\"facecolor\": ELEVATED_BG, \"edgecolor\": INK_SOFT, \"alpha\": 0.9, \"boxstyle\": \"round,pad=0.35\"},\n    zorder=7,\n)\n\n# Style\nax.set_xlabel(\"Passenger Class\", fontsize=10, color=INK)\nax.set_ylabel(\"Proportion of Passengers\", fontsize=10, color=INK)\nax.set_title(\"bar-spine · python · matplotlib · anyplot.ai\", fontsize=12, fontweight=\"medium\", color=INK)\n\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\nax.yaxis.grid(True, alpha=0.18, linewidth=0.8, color=INK)\n\n# Legend\nsurvived_patch = mpatches.Patch(color=COLOR_SURVIVED, label=\"Survived\")\ndied_patch = mpatches.Patch(color=COLOR_DIED, label=\"Did Not Survive\")\nleg = ax.legend(handles=[survived_patch, died_patch], fontsize=8, loc=\"upper right\", framealpha=1.0)\nleg.get_frame().set_facecolor(ELEVATED_BG)\nleg.get_frame().set_edgecolor(INK_SOFT)\nplt.setp(leg.get_texts(), color=INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(os.path.join(_OUT, f\"plot-{THEME}.png\"), dpi=400, facecolor=PAGE_BG)\n"}