{"spec_id":"volcano-basic","library":"makie","language":"julia","code":"# anyplot.ai\n# volcano-basic: Volcano Plot for Statistical Significance\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 91/100 | Created: 2026-09-09\n\nusing CairoMakie\nusing Colors\nusing Random\n\nRandom.seed!(42)\n\n# --- Theme tokens -------------------------------------------------------\nconst THEME       = get(ENV, \"ANYPLOT_THEME\", \"light\")\nconst PAGE_BG     = THEME == \"light\" ? colorant\"#FAF8F1\" : colorant\"#1A1A17\"\nconst ELEVATED_BG = THEME == \"light\" ? colorant\"#FFFDF6\" : colorant\"#242420\"\nconst INK         = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT    = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst MUTED       = THEME == \"light\" ? colorant\"#6B6A63\" : colorant\"#A8A79F\"\n\n# Volcano plots follow a domain-standard convention (Imprint semantic\n# exception): non-significant -> muted, up-regulated -> matte red,\n# down-regulated -> blue.\nconst COLOR_NONSIG = MUTED\nconst COLOR_UP     = colorant\"#AE3030\"\nconst COLOR_DOWN   = colorant\"#4467A3\"\n\n# --- Data: simulated differential gene expression (RNA-seq) -------------\nn_genes = 2200\ngene_names = \"Gene\" .* string.(1:n_genes)\nlog2_fold_change = randn(n_genes) .* 1.3\n# Independent additive noise dominates over the fold-change-linked term so the\n# cloud scatters realistically around the thresholds instead of forming a\n# clean deterministic \"V\" (borderline points land on either side by chance,\n# as in real differential-expression data).\nneg_log10_pvalue = abs.(log2_fold_change .* (1.1 .+ 0.55 .* randn(n_genes))) .+\n                    abs.(randn(n_genes) .* 1.3)\n\nfc_threshold = 1.0\np_threshold = -log10(0.05)\n\nis_up = (log2_fold_change .>= fc_threshold) .& (neg_log10_pvalue .>= p_threshold)\nis_down = (log2_fold_change .<= -fc_threshold) .& (neg_log10_pvalue .>= p_threshold)\nis_nonsig = .!(is_up .| is_down)\n\n# --- Plot -----------------------------------------------------------------\nfig = Figure(resolution = (1600, 900), fontsize = 14, backgroundcolor = PAGE_BG)\n\nax = Axis(\n    fig[1, 1];\n    title = \"volcano-basic · julia · makie · anyplot.ai\",\n    titlesize = 20,\n    titlecolor = INK,\n    xlabel = \"log2(Fold Change)\",\n    ylabel = \"-log10(p-value)\",\n    xlabelsize = 14,\n    ylabelsize = 14,\n    xlabelcolor = INK,\n    ylabelcolor = INK,\n    xticklabelsize = 12,\n    yticklabelsize = 12,\n    xticklabelcolor = INK_SOFT,\n    yticklabelcolor = INK_SOFT,\n    backgroundcolor = PAGE_BG,\n    topspinevisible = false,\n    rightspinevisible = false,\n    leftspinecolor = INK_SOFT,\n    bottomspinecolor = INK_SOFT,\n    xgridcolor = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    ygridcolor = RGBAf(INK.r, INK.g, INK.b, 0.12),\n    xminorgridvisible = false,\n    yminorgridvisible = false,\n)\n\nscatter!(ax, log2_fold_change[is_nonsig], neg_log10_pvalue[is_nonsig];\n    color = (COLOR_NONSIG, 0.45), markersize = 7, strokewidth = 0,\n    label = \"Non-significant\")\nscatter!(ax, log2_fold_change[is_down], neg_log10_pvalue[is_down];\n    color = (COLOR_DOWN, 0.75), markersize = 8, strokewidth = 0,\n    label = \"Down-regulated\")\nscatter!(ax, log2_fold_change[is_up], neg_log10_pvalue[is_up];\n    color = (COLOR_UP, 0.75), markersize = 8, strokewidth = 0,\n    label = \"Up-regulated\")\n\nhlines!(ax, [p_threshold]; color = INK_SOFT, linestyle = :dash, linewidth = 1.5)\nvlines!(ax, [-fc_threshold, fc_threshold]; color = INK_SOFT, linestyle = :dash,\n    linewidth = 1.5)\n\n# Label the top few most-significant up/down genes by name, per the spec's\n# optional annotation suggestion — a distinctive use of Makie's text! recipe.\nn_label = 3\ntop_up = findall(is_up)[sortperm(neg_log10_pvalue[is_up]; rev = true)[1:min(n_label, count(is_up))]]\ntop_down = findall(is_down)[sortperm(neg_log10_pvalue[is_down]; rev = true)[1:min(n_label, count(is_down))]]\n\nfor i in top_up\n    text!(ax, log2_fold_change[i] + 0.08, neg_log10_pvalue[i];\n        text = gene_names[i], color = INK, fontsize = 11, align = (:left, :center))\nend\nfor i in top_down\n    text!(ax, log2_fold_change[i] - 0.08, neg_log10_pvalue[i];\n        text = gene_names[i], color = INK, fontsize = 11, align = (:right, :center))\nend\n\naxislegend(ax; position = :rt, backgroundcolor = ELEVATED_BG,\n    framecolor = INK_SOFT, labelcolor = INK)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}