{"spec_id":"pyramid-basic","library":"seaborn","language":"python","code":"\"\"\" anyplot.ai\npyramid-basic: Basic Pyramid Chart\nLibrary: seaborn 0.13.2 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-06-16\n\"\"\"\n\nimport os\n\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\n\n\n# Theme-adaptive chrome\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# Imprint palette — canonical order, first series always #009E73.\n# Gender categories carry no widely-shared color expectation, so default to\n# canonical order: Male → brand green, Female → lavender.\nBRAND = \"#009E73\"\nSECOND = \"#C475FD\"\n\n# Data - Population pyramid showing age distribution by gender\nage_groups = [\"0-9\", \"10-19\", \"20-29\", \"30-39\", \"40-49\", \"50-59\", \"60-69\", \"70-79\", \"80+\"]\nmale_population = [4200, 4500, 5100, 5400, 4800, 4200, 3500, 2200, 1100]\nfemale_population = [4000, 4300, 4900, 5200, 4700, 4400, 3800, 2800, 1700]\n\n# Create DataFrame with male values as negative for left-side display\ndf = pd.DataFrame(\n    {\n        \"Age Group\": age_groups * 2,\n        \"Population\": [-m for m in male_population] + female_population,\n        \"Gender\": [\"Male\"] * len(age_groups) + [\"Female\"] * len(age_groups),\n    }\n)\n\nsns.set_theme(\n    style=\"ticks\",\n    rc={\n        \"figure.facecolor\": PAGE_BG,\n        \"axes.facecolor\": PAGE_BG,\n        \"axes.edgecolor\": INK_SOFT,\n        \"axes.labelcolor\": INK,\n        \"text.color\": INK,\n        \"xtick.color\": INK_SOFT,\n        \"ytick.color\": INK_SOFT,\n        \"grid.color\": INK,\n        \"grid.alpha\": 0.15,\n        \"legend.facecolor\": ELEVATED_BG,\n        \"legend.edgecolor\": INK_SOFT,\n    },\n)\n\n# Plot — landscape canvas: 8 x 4.5 in @ 400 dpi → 3200 x 1800 px\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400)\n\nsns.barplot(\n    data=df,\n    y=\"Age Group\",\n    x=\"Population\",\n    hue=\"Gender\",\n    hue_order=[\"Male\", \"Female\"],\n    palette={\"Male\": BRAND, \"Female\": SECOND},\n    ax=ax,\n    dodge=False,\n    orient=\"h\",\n    width=0.8,\n    edgecolor=PAGE_BG,\n    linewidth=0.6,\n)\n\n# Styling\nax.set_xlabel(\"Population (thousands)\", fontsize=10)\nax.set_ylabel(\"Age Group\", fontsize=10)\nax.set_title(\"pyramid-basic · python · seaborn · anyplot.ai\", fontsize=12, fontweight=\"medium\")\nax.tick_params(axis=\"both\", labelsize=9)\n\n# Make x-axis symmetric\nmax_val = max(max(male_population), max(female_population))\nax.set_xlim(-max_val * 1.15, max_val * 1.15)\n\n# Custom x-tick labels to show absolute values\nticks = [-6000, -4000, -2000, 0, 2000, 4000, 6000]\nax.set_xticks(ticks)\nax.set_xticklabels([f\"{abs(t):,}\" for t in ticks])\n\n# Subtle reference line at the central axis (theme-adaptive ink)\nax.axvline(x=0, color=INK, linewidth=1.0, alpha=0.6)\n\n# Grid (x-axis only, subtle solid)\nax.grid(True, axis=\"x\", alpha=0.15, linewidth=0.8)\nax.set_axisbelow(True)\n\n# Clean L-frame — idiomatic seaborn despine\nsns.despine(ax=ax, top=True, right=True)\n\n# Data storytelling: emphasize the female-skewed older cohorts (women\n# outlive men). Female bars extend right (positive width); accent the three\n# oldest with a crisp ink edge, then annotate the crossover.\nfocal_groups = [\"60-69\", \"70-79\", \"80+\"]\nfocal_values = {female_population[age_groups.index(g)] for g in focal_groups}\nfor patch in ax.patches:\n    if patch.get_width() > 0 and round(patch.get_width()) in focal_values:\n        patch.set_edgecolor(INK)\n        patch.set_linewidth(1.4)\n\nfocal_idx = age_groups.index(\"80+\")\nax.annotate(\n    \"Women outlive men —\\nfemale-skewed 60+ cohorts\",\n    xy=(female_population[focal_idx], focal_idx),\n    xytext=(max_val * 0.55, focal_idx - 0.55),\n    fontsize=8.5,\n    color=INK,\n    ha=\"left\",\n    va=\"center\",\n    arrowprops={\"arrowstyle\": \"->\", \"color\": INK, \"lw\": 1.1, \"alpha\": 0.85},\n)\n\n# Legend\nlegend = ax.legend(title=\"Gender\", fontsize=8, title_fontsize=9, loc=\"upper right\")\nlegend.get_frame().set_facecolor(ELEVATED_BG)\nlegend.get_frame().set_edgecolor(INK_SOFT)\nlegend.get_title().set_color(INK)\nfor text in legend.get_texts():\n    text.set_color(INK_SOFT)\n\nfig.subplots_adjust(left=0.08, right=0.97, top=0.92, bottom=0.1)\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\n"}