{"spec_id":"lift-curve","library":"makie","language":"julia","code":"# anyplot.ai\n# lift-curve: Model Lift Chart\n# Library: makie 0.21.9 | Julia 1.11.9\n# Quality: 87/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 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]\nconst BRAND = IMPRINT_PALETTE[1]\n\n# --- Data --------------------------------------------------------------------\n# Fraud detection: a small fraction of transactions are fraudulent, and a\n# model score concentrates most fraud cases near the top of the ranking.\nn_transactions = 5000\nfraud_rate = 0.08\n\nis_fraud = rand(n_transactions) .< fraud_rate\nmodel_score = ifelse.(is_fraud, randn(n_transactions) .+ 2.8, randn(n_transactions))\n\nranking = sortperm(model_score; rev=true)\nsorted_fraud = is_fraud[ranking]\ncumulative_fraud = cumsum(sorted_fraud)\n\npopulation_pct = (1:n_transactions) ./ n_transactions .* 100\nbaseline_rate = sum(is_fraud) / n_transactions\ncumulative_rate = cumulative_fraud ./ (1:n_transactions)\nlift = cumulative_rate ./ baseline_rate\n\ndecile_idx = round.(Int, (0.1:0.1:1.0) .* n_transactions)\ndecile_pct = population_pct[decile_idx]\ndecile_lift = lift[decile_idx]\n\n# --- Plot ---------------------------------------------------------------------\nfig = Figure(\n    resolution      = (1600, 900),\n    fontsize        = 14,\n    backgroundcolor = PAGE_BG,\n)\n\nax = Axis(\n    fig[1, 1];\n    title              = \"lift-curve · julia · makie · anyplot.ai\",\n    titlesize          = 20,\n    titlecolor         = INK,\n    xlabel             = \"Population Targeted (%)\",\n    ylabel             = \"Cumulative Lift\",\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    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    limits             = (0, 100, 0, nothing),\n)\n\nband!(ax, population_pct, fill(1.0, n_transactions), lift; color=(BRAND, 0.18))\nreference_line = hlines!(ax, [1.0]; color=INK_SOFT, linestyle=:dash, linewidth=2)\nmodel_line = lines!(ax, population_pct, lift; color=BRAND, linewidth=3)\nscatter!(ax, decile_pct, decile_lift; color=BRAND, markersize=16, strokewidth=1.5, strokecolor=PAGE_BG)\n\naxislegend(\n    ax,\n    [model_line, reference_line],\n    [\"Fraud model\", \"Random selection (no lift)\"];\n    position = :rt,\n    labelcolor = INK,\n    backgroundcolor = PAGE_BG,\n    framevisible = false,\n)\n\n# --- Callout annotation ------------------------------------------------------\n# Large leader line + bold text deliberately placed in the open area to the\n# right of the curve, turning otherwise-empty canvas into a focal point.\ncallout_lift = round(decile_lift[1], digits=1)\ncallout_pos = (42.0, 9.5)\narrows!(\n    ax,\n    [callout_pos[1] - 1], [callout_pos[2] - 0.6],\n    [decile_pct[1] - callout_pos[1] + 1], [decile_lift[1] - callout_pos[2] + 0.6];\n    color = INK_SOFT, linewidth = 2.5, arrowsize = 22,\n)\ntext!(\n    ax, callout_pos[1], callout_pos[2];\n    text = \"Top 10% → $(callout_lift)x lift\",\n    color = INK,\n    fontsize = 22,\n    font = :bold,\n    align = (:left, :bottom),\n)\n\n# --- Save -----------------------------------------------------------------\nsave(\"plot-$(THEME).png\", fig; px_per_unit=2)\n"}