{"spec_id":"volcano-basic","library":"plotnine","language":"python","code":"\"\"\" anyplot.ai\nvolcano-basic: Volcano Plot for Statistical Significance\nLibrary: plotnine 0.15.4 | Python 3.13.13\nQuality: 88/100 | Updated: 2026-05-14\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pandas as pd\nfrom plotnine import (\n    aes,\n    element_line,\n    element_rect,\n    element_text,\n    geom_hline,\n    geom_point,\n    geom_text,\n    geom_vline,\n    ggplot,\n    labs,\n    scale_color_manual,\n    theme,\n    theme_minimal,\n)\n\n\n# Theme tokens\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# Data - simulated differential gene expression results\nnp.random.seed(42)\nn_genes = 500\n\n# Generate log2 fold changes (centered around 0 with some outliers)\nlog2_fold_change = np.concatenate(\n    [\n        np.random.normal(0, 0.8, 400),  # Most genes have small changes\n        np.random.normal(-2.5, 0.5, 50),  # Down-regulated genes\n        np.random.normal(2.5, 0.5, 50),  # Up-regulated genes\n    ]\n)\n\n# Generate p-values with a realistic range (avoiding extreme values)\npvalues = np.concatenate(\n    [\n        np.random.uniform(0.05, 1.0, 400),  # Most genes not significant\n        np.random.uniform(0.0001, 0.01, 50),  # Down-regulated significant\n        np.random.uniform(0.0001, 0.01, 50),  # Up-regulated significant\n    ]\n)\n\nneg_log10_pvalue = -np.log10(pvalues)\n\n# Create gene labels\ngene_labels = [f\"Gene_{i + 1}\" for i in range(n_genes)]\n\n# Determine significance status based on thresholds\nsignificance_threshold = -np.log10(0.05)  # ~1.3\nfold_change_threshold = 1.0\n\nstatus = []\nfor fc, nlp in zip(log2_fold_change, neg_log10_pvalue, strict=True):\n    if nlp > significance_threshold and fc > fold_change_threshold:\n        status.append(\"Up-regulated\")\n    elif nlp > significance_threshold and fc < -fold_change_threshold:\n        status.append(\"Down-regulated\")\n    else:\n        status.append(\"Not significant\")\n\n# Create DataFrame\ndf = pd.DataFrame(\n    {\n        \"log2_fold_change\": log2_fold_change,\n        \"neg_log10_pvalue\": neg_log10_pvalue,\n        \"label\": gene_labels,\n        \"status\": pd.Categorical(status, categories=[\"Down-regulated\", \"Not significant\", \"Up-regulated\"]),\n    }\n)\n\n# Identify top genes to label (top 4 by significance in each direction, better spacing)\ndf_up = df[df[\"status\"] == \"Up-regulated\"].nlargest(3, \"neg_log10_pvalue\")\ndf_down = df[df[\"status\"] == \"Down-regulated\"].nlargest(3, \"neg_log10_pvalue\")\ndf_labels = pd.concat([df_up, df_down])\n\n# Okabe-Ito palette (blue for down, gray for not significant, orange for up)\ncolor_map = {\n    \"Down-regulated\": \"#4467A3\",  # Okabe-Ito blue\n    \"Not significant\": \"#888888\",  # neutral gray\n    \"Up-regulated\": \"#AE3030\",  # Okabe-Ito orange\n}\n\n# Create volcano plot\nplot = (\n    ggplot(df, aes(x=\"log2_fold_change\", y=\"neg_log10_pvalue\", color=\"status\"))\n    + geom_point(size=3, alpha=0.7)\n    + geom_hline(yintercept=significance_threshold, linetype=\"dashed\", color=INK_SOFT, size=0.8)\n    + geom_vline(xintercept=-fold_change_threshold, linetype=\"dashed\", color=INK_SOFT, size=0.8)\n    + geom_vline(xintercept=fold_change_threshold, linetype=\"dashed\", color=INK_SOFT, size=0.8)\n    + geom_text(data=df_labels, mapping=aes(label=\"label\"), size=10, nudge_y=0.4, nudge_x=0.15, color=INK_SOFT)\n    + scale_color_manual(values=color_map)\n    + labs(\n        x=\"Log2 Fold Change\", y=\"-Log10(p-value)\", title=\"volcano-basic · plotnine · anyplot.ai\", color=\"Significance\"\n    )\n    + theme_minimal()\n    + theme(\n        figure_size=(16, 9),\n        plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),\n        panel_background=element_rect(fill=PAGE_BG),\n        panel_grid_major=element_line(color=INK, size=0.3, alpha=0.10, linetype=\"solid\"),\n        panel_grid_minor=element_line(color=INK, size=0.2, alpha=0.05),\n        panel_border=element_rect(color=INK_SOFT, fill=None),\n        axis_title=element_text(size=20, color=INK),\n        axis_text=element_text(size=16, color=INK_SOFT),\n        axis_line=element_line(color=INK_SOFT),\n        plot_title=element_text(size=24, color=INK),\n        text=element_text(size=14),\n        legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),\n        legend_text=element_text(size=16, color=INK_SOFT),\n        legend_title=element_text(size=18, color=INK),\n    )\n)\n\n# Save plot\nplot.save(f\"plot-{THEME}.png\", dpi=300)\n"}