{"spec_id":"cat-box-strip","library":"makie","language":"julia","code":"# anyplot.ai\n# cat-box-strip: Box Plot with Strip Overlay\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 82/100 | Created: 2026-09-02\n\nusing CairoMakie\nusing Colors\nusing Random\nusing Statistics\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 INK      = THEME == \"light\" ? colorant\"#1A1A17\" : colorant\"#F0EFE8\"\nconst INK_SOFT = THEME == \"light\" ? colorant\"#4A4A44\" : colorant\"#B8B7B0\"\nconst IMPRINT_PALETTE = [\n    colorant\"#009E73\", colorant\"#C475FD\", colorant\"#4467A3\", colorant\"#BD8233\",\n    colorant\"#AE3030\", colorant\"#2ABCCD\", colorant\"#954477\", colorant\"#99B314\",\n]\n\n# --- Data ---------------------------------------------------------------\n# Reaction time (ms) across four caffeine-dose groups in a lab experiment\ngroups = [\"Placebo\", \"50mg\", \"100mg\", \"200mg\"]\ngroup_means = [420.0, 390.0, 355.0, 345.0]\ngroup_sds = [55.0, 48.0, 42.0, 50.0]\ngroup_sizes = [90, 90, 90, 90]\n\ncategory = String[]\nvalue = Float64[]\ngroup_index = Int[]\nfor (i, (g, mu, sigma, n)) in enumerate(zip(groups, group_means, group_sds, group_sizes))\n    append!(category, fill(g, n))\n    append!(value, mu .+ sigma .* randn(n))\n    append!(group_index, fill(i, n))\nend\n\n# --- Plot -----------------------------------------------------------------\nfig = Figure(\n    size            = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"cat-box-strip · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Caffeine Dose\",\n    ylabel             = \"Reaction Time (ms)\",\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    xtickcolor         = INK_SOFT,\n    ytickcolor         = INK_SOFT,\n    xticks             = (1:length(groups), groups),\n    backgroundcolor    = PAGE_BG,\n    topspinevisible     = false,\n    rightspinevisible   = false,\n    leftspinecolor      = INK_SOFT,\n    bottomspinecolor    = INK_SOFT,\n    xgridvisible        = false,\n    ygridcolor          = RGBAf(INK.r, INK.g, INK.b, 0.15),\n)\n\nbox_colors = [RGBAf(c.r, c.g, c.b, 0.35) for c in IMPRINT_PALETTE[1:length(groups)]]\n\nboxplot!(\n    ax, group_index, value;\n    color = box_colors[group_index],\n    strokecolor = IMPRINT_PALETTE[1:length(groups)],\n    strokewidth = 1.5,\n    width = 0.55,\n    show_outliers = false,\n    whiskerwidth = 0.4,\n    gap = 0.0,\n)\n\njitter = (rand(length(value)) .- 0.5) .* 0.28\nscatter!(\n    ax, group_index .+ jitter, value;\n    color = IMPRINT_PALETTE[1:length(groups)][group_index],\n    markersize = 9,\n    strokewidth = 0,\n    alpha = 0.45,\n)\n\n# Median-trend line: a subtle focal cue for the dose-response trend across groups\ngroup_medians = [median(value[group_index .== i]) for i in 1:length(groups)]\ntrend_color = RGBAf(INK.r, INK.g, INK.b, 0.55)\nlines!(ax, 1:length(groups), group_medians; color = trend_color, linewidth = 2, linestyle = :dash)\nscatter!(ax, 1:length(groups), group_medians; color = trend_color, markersize = 11, marker = :diamond, strokewidth = 0)\n\n# --- Save -------------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit = 2)\n"}