{"spec_id":"ma-differential-expression","library":"matplotlib","language":"python","code":"\"\"\" anyplot.ai\nma-differential-expression: MA Plot for Differential Expression\nLibrary: matplotlib 3.11.0 | Python 3.13.14\nQuality: 90/100 | Updated: 2026-06-21\n\"\"\"\n\nimport os\nimport sys\n\n\n# Remove the script's own directory from sys.path so that this file (matplotlib.py)\n# doesn't shadow the installed matplotlib package when run from its own directory.\n_here = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if not p or os.path.abspath(p) != _here]\n\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom scipy.interpolate import UnivariateSpline\n\n\n# Theme tokens — Imprint palette (see default-style-guide.md)\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 — semantic assignment for directional expression\nUP_COLOR = \"#009E73\"  # position 1, brand green — upregulated (gain)\nDOWN_COLOR = \"#AE3030\"  # position 5, matte red — downregulated (loss, semantic exception)\nTREND_COLOR = \"#4467A3\"  # position 3, blue — LOESS trend line\n\n# Data\nnp.random.seed(42)\nn_genes = 15000\n\nmean_expression = np.random.exponential(scale=3.0, size=n_genes) + 0.5\nlog_fold_change = np.random.normal(0, 0.4, size=n_genes)\n\nn_up = 400\nn_down = 350\nup_idx = np.random.choice(n_genes, n_up, replace=False)\nremaining = np.setdiff1d(np.arange(n_genes), up_idx)\ndown_idx = np.random.choice(remaining, n_down, replace=False)\n\nlog_fold_change[up_idx] = np.random.normal(2.5, 0.8, n_up)\nlog_fold_change[down_idx] = np.random.normal(-2.5, 0.8, n_down)\n\nsig_mask = np.zeros(n_genes, dtype=bool)\nsig_mask[up_idx] = True\nsig_mask[down_idx] = True\nnonsig_mask = ~sig_mask\n\n# Top genes for labeling — alternating offsets to reduce crowding\ntop_up_idx = up_idx[np.argsort(log_fold_change[up_idx])[-4:]]\ntop_down_idx = down_idx[np.argsort(log_fold_change[down_idx])[:4]]\nlabel_idx = np.concatenate([top_up_idx, top_down_idx])\nlabel_names = [\"BRCA1\", \"TP53\", \"MYC\", \"EGFR\", \"PTEN\", \"RB1\", \"APC\", \"KRAS\"]\nlabel_offsets = [\n    (30, 18),\n    (-42, 15),\n    (30, -18),\n    (-42, -15),  # upregulated: alternate right/left\n    (30, -18),\n    (-42, -15),\n    (30, 18),\n    (-42, 15),  # downregulated: alternate right/left\n]\n\n# Plot — canvas: figsize=(8, 4.5) × dpi=400 → 3200×1800 px (hard contract)\nfig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG)\nax.set_facecolor(PAGE_BG)\n\n# Non-significant background cloud\nax.scatter(\n    mean_expression[nonsig_mask],\n    log_fold_change[nonsig_mask],\n    s=7,\n    alpha=0.10,\n    color=INK_MUTED,\n    edgecolors=\"none\",\n    rasterized=True,\n    label=\"Not significant\",\n    zorder=2,\n)\n\n# Downregulated genes\nax.scatter(\n    mean_expression[down_idx],\n    log_fold_change[down_idx],\n    s=22,\n    alpha=0.55,\n    color=DOWN_COLOR,\n    edgecolors=PAGE_BG,\n    linewidth=0.3,\n    rasterized=True,\n    label=f\"Downregulated (n={n_down})\",\n    zorder=3,\n)\n\n# Upregulated genes\nax.scatter(\n    mean_expression[up_idx],\n    log_fold_change[up_idx],\n    s=22,\n    alpha=0.55,\n    color=UP_COLOR,\n    edgecolors=PAGE_BG,\n    linewidth=0.3,\n    rasterized=True,\n    label=f\"Upregulated (n={n_up})\",\n    zorder=3,\n)\n\n# Reference lines\nax.axhline(y=0, color=INK, linewidth=1.2, alpha=0.85, zorder=1)\nax.axhline(y=1, color=INK_SOFT, linewidth=0.8, linestyle=\"--\", alpha=0.45, zorder=1)\nax.axhline(y=-1, color=INK_SOFT, linewidth=0.8, linestyle=\"--\", alpha=0.45, zorder=1)\n\n# LOESS trend — binned spline approximation over all genes\nsorted_idx = np.argsort(mean_expression)\nx_sorted = mean_expression[sorted_idx]\ny_sorted = log_fold_change[sorted_idx]\n\nbin_count = 80\nbin_edges = np.linspace(x_sorted.min(), np.percentile(x_sorted, 98), bin_count + 1)\nbin_centers, bin_means = [], []\nfor i in range(bin_count):\n    in_bin = (x_sorted >= bin_edges[i]) & (x_sorted < bin_edges[i + 1])\n    if in_bin.sum() > 10:\n        bin_centers.append((bin_edges[i] + bin_edges[i + 1]) / 2)\n        bin_means.append(np.mean(y_sorted[in_bin]))\n\nbin_centers = np.array(bin_centers)\nbin_means = np.array(bin_means)\nspline = UnivariateSpline(bin_centers, bin_means, s=len(bin_centers) * 0.5)\nx_smooth = np.linspace(bin_centers.min(), bin_centers.max(), 200)\ny_smooth = spline(x_smooth)\nax.plot(x_smooth, y_smooth, color=TREND_COLOR, linewidth=2.5, alpha=0.85, label=\"LOESS trend\", zorder=4)\n\n# Gene annotations with connector arrows (arrowprops) and background bbox for readability\nfor gene_idx, name, (dx, dy) in zip(label_idx, label_names, label_offsets, strict=False):\n    ax.annotate(\n        name,\n        xy=(mean_expression[gene_idx], log_fold_change[gene_idx]),\n        xytext=(dx, dy),\n        textcoords=\"offset points\",\n        fontsize=7,\n        fontweight=\"bold\",\n        fontstyle=\"italic\",\n        color=INK,\n        bbox={\"facecolor\": ELEVATED_BG, \"edgecolor\": \"none\", \"alpha\": 0.85, \"pad\": 1.5, \"boxstyle\": \"round,pad=0.2\"},\n        arrowprops={\"arrowstyle\": \"-\", \"color\": INK_SOFT, \"linewidth\": 0.7, \"shrinkA\": 3, \"shrinkB\": 3},\n        zorder=5,\n    )\n\n# Style — font sizes per library guide (3200×1800 canvas)\ntitle = \"ma-differential-expression · python · matplotlib · anyplot.ai\"\nax.set_xlabel(\"Mean Expression (A)\", fontsize=10, color=INK)\nax.set_ylabel(\"Log₂ Fold Change (M)\", fontsize=10, color=INK)\nax.set_title(title, fontsize=12, fontweight=\"medium\", color=INK)\nax.tick_params(axis=\"both\", labelsize=8, colors=INK_SOFT)\nax.spines[\"top\"].set_visible(False)\nax.spines[\"right\"].set_visible(False)\nax.spines[\"left\"].set_color(INK_SOFT)\nax.spines[\"bottom\"].set_color(INK_SOFT)\nax.yaxis.grid(True, alpha=0.15, linewidth=0.6, color=INK)\n\nleg = ax.legend(fontsize=7.5, loc=\"upper right\", framealpha=0.9, edgecolor=INK_SOFT, fancybox=False)\nif leg:\n    leg.get_frame().set_facecolor(ELEVATED_BG)\n    plt.setp(leg.get_texts(), color=INK_SOFT)\n\nfig.subplots_adjust(left=0.09, right=0.97, top=0.93, bottom=0.11)\n\n# Save — bbox_inches must stay default (None) to preserve 3200×1800 canvas\nplt.savefig(f\"plot-{THEME}.png\", dpi=400, facecolor=PAGE_BG)\nplt.close()\n"}