{"spec_id":"facet-grid","library":"makie","language":"julia","code":"# anyplot.ai\n# facet-grid: Faceted Grid Plot\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 92/100 | Created: 2026-09-05\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 BRAND      = colorant\"#009E73\"\n\n# --- Data ----------------------------------------------------------------\n# Synthetic penguin bill measurements, faceted by species (columns) and sex\n# (rows) — mirrors real Palmer Penguins sexual-dimorphism patterns.\nconst SPECIES = [\"Adelie\", \"Chinstrap\", \"Gentoo\"]\nconst SEXES = [\"Female\", \"Male\"]\nconst N_PER_FACET = 150\n\nconst LENGTH_MEAN = Dict(\"Adelie\" => 38.8, \"Chinstrap\" => 48.8, \"Gentoo\" => 47.5)\nconst LENGTH_SD = Dict(\"Adelie\" => 2.7, \"Chinstrap\" => 3.3, \"Gentoo\" => 3.1)\nconst DEPTH_MEAN = Dict(\"Adelie\" => 18.3, \"Chinstrap\" => 18.4, \"Gentoo\" => 15.0)\nconst DEPTH_SD = Dict(\"Adelie\" => 1.2, \"Chinstrap\" => 1.1, \"Gentoo\" => 1.0)\nconst LENGTH_SEX_OFFSET = 4.0  # males have longer bills on average\nconst DEPTH_SEX_OFFSET = 1.0   # males have deeper bills on average\n\nbill_length = Dict{Tuple{String,String},Vector{Float64}}()\nbill_depth = Dict{Tuple{String,String},Vector{Float64}}()\n\nfor species in SPECIES, sex in SEXES\n    sign = sex == \"Male\" ? 1 : -1\n    bill_length[(species, sex)] =\n        LENGTH_MEAN[species] .+ sign * LENGTH_SEX_OFFSET / 2 .+\n        randn(N_PER_FACET) .* LENGTH_SD[species]\n    bill_depth[(species, sex)] =\n        DEPTH_MEAN[species] .+ sign * DEPTH_SEX_OFFSET / 2 .+\n        randn(N_PER_FACET) .* DEPTH_SD[species]\nend\n\n# --- Plot ------------------------------------------------------------------\nfig = Figure(\n    resolution      = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nn_cols = length(SPECIES)\nn_rows = length(SEXES)\ntitle_row = 1\nstrip_row = 2\nfirst_ax_row = 3\nxlabel_row = first_ax_row + n_rows\nstrip_col = n_cols + 1\nylabel_col = 0\n\nLabel(\n    fig[title_row, 1:n_cols],\n    \"facet-grid · julia · makie · anyplot.ai\";\n    fontsize = 20, color = INK, tellwidth = false,\n)\n\n# Column strips — species\nfor (j, species) in enumerate(SPECIES)\n    Box(fig[strip_row, j]; color = ELEVATED_BG, strokewidth = 0)\n    Label(fig[strip_row, j], species; fontsize = 15, color = INK, tellwidth = false)\nend\n\naxes = Matrix{Axis}(undef, n_rows, n_cols)\n\nfor (i, sex) in enumerate(SEXES)\n    row = first_ax_row + i - 1\n\n    # Row strip — sex\n    Box(fig[row, strip_col]; color = ELEVATED_BG, strokewidth = 0)\n    Label(\n        fig[row, strip_col], sex;\n        fontsize = 15, color = INK, rotation = -pi / 2, tellheight = false,\n    )\n\n    for (j, species) in enumerate(SPECIES)\n        ax = Axis(\n            fig[row, j];\n            backgroundcolor  = PAGE_BG,\n            xticklabelsize   = 13,\n            yticklabelsize   = 13,\n            xticklabelcolor  = INK_SOFT,\n            yticklabelcolor  = INK_SOFT,\n            xtickcolor       = INK_SOFT,\n            ytickcolor       = INK_SOFT,\n            leftspinecolor   = INK_SOFT,\n            bottomspinecolor = INK_SOFT,\n            topspinevisible  = false,\n            rightspinevisible = false,\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        scatter!(\n            ax, bill_length[(species, sex)], bill_depth[(species, sex)];\n            color = BRAND, markersize = 10, alpha = 0.6, strokewidth = 0,\n        )\n        text!(\n            ax, 0.96, 0.96;\n            text = \"n=$(N_PER_FACET)\", space = :relative,\n            align = (:right, :top), fontsize = 11, color = INK_SOFT,\n        )\n\n        j != 1 && hideydecorations!(ax; grid = false)\n        i != n_rows && hidexdecorations!(ax; grid = false)\n\n        axes[i, j] = ax\n    end\nend\n\nlinkxaxes!(axes...)\nlinkyaxes!(axes...)\n\nLabel(\n    fig[xlabel_row, 1:n_cols], \"Bill Length (mm)\";\n    fontsize = 14, color = INK, tellwidth = false,\n)\nLabel(\n    fig[first_ax_row:(first_ax_row + n_rows - 1), ylabel_col], \"Bill Depth (mm)\";\n    fontsize = 14, color = INK, rotation = pi / 2, tellheight = false,\n)\n\nrowsize!(fig.layout, title_row, Relative(0.09))\nrowsize!(fig.layout, strip_row, Relative(0.06))\nrowsize!(fig.layout, xlabel_row, Relative(0.06))\ncolsize!(fig.layout, strip_col, Relative(0.05))\ncolsize!(fig.layout, ylabel_col, Relative(0.05))\ncolgap!(fig.layout, 8)\nrowgap!(fig.layout, 8)\n\n# --- Save --------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}