{"spec_id":"forest-basic","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nforest-basic: Meta-Analysis Forest Plot\nLibrary: matplotlib 3.10.9 | Python 3.13.13\nQuality: 90/100 | Updated: 2026-05-11\n\"\"\"\n\nimport os\n\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport numpy as np\n\n\n# Theme configuration\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\"\nRULE = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\n\n# Okabe-Ito palette\nOKABE_ITO_1 = \"#009E73\"  # Primary data color (brand green)\nOKABE_ITO_2 = \"#C475FD\"  # Secondary\n\n# Data: Meta-analysis of RCTs comparing treatment efficacy (standardized mean difference)\nstudies = [\n    \"Johnson 2018\",\n    \"Smith 2019\",\n    \"Garcia 2020\",\n    \"Williams 2020\",\n    \"Brown 2021\",\n    \"Davis 2021\",\n    \"Miller 2022\",\n    \"Wilson 2022\",\n    \"Anderson 2023\",\n    \"Taylor 2023\",\n]\n\n# Effect sizes (standardized mean difference) and 95% CIs\neffect_sizes = np.array([-0.45, -0.32, -0.58, -0.21, -0.67, -0.38, -0.52, -0.29, -0.41, -0.55])\nci_lower = np.array([-0.78, -0.61, -0.95, -0.48, -1.02, -0.69, -0.88, -0.56, -0.72, -0.91])\nci_upper = np.array([-0.12, -0.03, -0.21, 0.06, -0.32, -0.07, -0.16, -0.02, -0.10, -0.19])\n\n# Study weights (based on sample size / inverse variance)\nweights = np.array([8.5, 10.2, 7.8, 11.5, 6.9, 9.3, 8.1, 10.8, 9.7, 7.2])\n\n# Pooled estimate (random effects meta-analysis)\npooled_effect = -0.42\npooled_ci_lower = -0.53\npooled_ci_upper = -0.31\n\n# Create figure\nfig, ax = plt.subplots(figsize=(16, 9), facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\nn_studies = len(studies)\ny_positions = np.arange(n_studies, 0, -1)\n\n# Normalize weights for marker sizing (scale between 80 and 300)\nweight_normalized = (weights - weights.min()) / (weights.max() - weights.min())\nmarker_sizes = 80 + weight_normalized * 220\n\n# Plot vertical reference line at null effect (0)\nax.axvline(x=0, color=INK_SOFT, linestyle=\"--\", linewidth=2, alpha=0.7, zorder=1)\n\n# Plot confidence intervals as horizontal lines\nfor y, lower, upper in zip(y_positions, ci_lower, ci_upper, strict=True):\n    ax.hlines(y=y, xmin=lower, xmax=upper, color=OKABE_ITO_1, linewidth=3, zorder=2)\n\n# Plot effect size points\nax.scatter(\n    effect_sizes, y_positions, s=marker_sizes, color=OKABE_ITO_1, edgecolors=ELEVATED_BG, linewidths=1.5, zorder=3\n)\n\n# Plot pooled estimate as diamond\ndiamond_y = 0\ndiamond_height = 0.4\n\n# Create diamond shape using polygon\ndiamond_vertices = np.array(\n    [\n        [pooled_effect, diamond_y + diamond_height],\n        [pooled_ci_upper, diamond_y],\n        [pooled_effect, diamond_y - diamond_height],\n        [pooled_ci_lower, diamond_y],\n    ]\n)\ndiamond_patch = mpatches.Polygon(\n    diamond_vertices, closed=True, facecolor=OKABE_ITO_2, edgecolor=OKABE_ITO_1, linewidth=2.5, zorder=4\n)\nax.add_patch(diamond_patch)\n\n# Add study labels on y-axis\nax.set_yticks(list(y_positions) + [0])\nax.set_yticklabels(studies + [\"Pooled Estimate\"], color=INK_SOFT, fontsize=16)\n\n# Styling\nax.set_xlabel(\"Standardized Mean Difference (95% CI)\", fontsize=20, color=INK)\nax.set_title(\"forest-basic · matplotlib · pyplots.ai\", fontsize=24, color=INK, fontweight=\"medium\")\nax.tick_params(axis=\"x\", labelsize=16, colors=INK_SOFT, length=0)\nax.tick_params(axis=\"y\", length=0)\n\n# Set x-axis limits with padding\nx_min = min(ci_lower.min(), pooled_ci_lower) - 0.15\nx_max = max(ci_upper.max(), pooled_ci_upper) + 0.15\nax.set_xlim(x_min, x_max)\n\n# Set y-axis limits\nax.set_ylim(-0.8, n_studies + 0.8)\n\n# Add subtle grid for x-axis only\nax.grid(True, axis=\"x\", alpha=0.15, linestyle=\"-\", linewidth=0.8, color=INK, zorder=0)\nax.set_axisbelow(True)\n\n# Add annotation for \"Favors Treatment\" and \"Favors Control\"\nax.text(x_min + 0.05, -0.6, \"← Favors Treatment\", fontsize=14, ha=\"left\", va=\"top\", color=INK_MUTED)\nax.text(x_max - 0.05, -0.6, \"Favors Control →\", fontsize=14, ha=\"right\", va=\"top\", color=INK_MUTED)\n\n# Style spines\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_visible(False)\nax.spines[\"bottom\"].set_color(INK_SOFT)\n\nplt.tight_layout()\nplt.savefig(f\"plot-{THEME}.png\", dpi=300, bbox_inches=\"tight\", facecolor=PAGE_BG)\n"}