{"spec_id":"lift-curve","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nlift-curve: Model Lift Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 84/100 | Updated: 2026-05-10\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\nIMPRINT = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\", \"#2ABCCD\", \"#954477\")\n\n# Data - Simulated customer response prediction\nnp.random.seed(42)\nn_samples = 1000\n\n# Generate realistic model scores and true outcomes\ny_score = np.random.beta(2, 5, n_samples)\nresponse_prob = 0.1 + 0.6 * y_score\ny_true = (np.random.random(n_samples) < response_prob).astype(int)\n\n# Calculate lift curve data\nsorted_indices = np.argsort(y_score)[::-1]\ny_true_sorted = y_true[sorted_indices]\n\n# Calculate cumulative metrics\nn_total = len(y_true)\nn_positive = y_true.sum()\nbaseline_rate = n_positive / n_total\n\n# Calculate lift at decile intervals\ndeciles = list(range(10, 101, 10))\nlift_values = []\n\nfor pct in deciles:\n    n_targeted = int(n_total * pct / 100)\n    positives_captured = y_true_sorted[:n_targeted].sum()\n    model_rate = positives_captured / n_targeted\n    lift = model_rate / baseline_rate if baseline_rate > 0 else 1\n    lift_values.append(lift)\n\n# Create custom style\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_SOFT,\n    colors=IMPRINT,\n    title_font_size=28,\n    label_font_size=22,\n    major_label_font_size=18,\n    legend_font_size=18,\n    value_font_size=16,\n    stroke_width=4,\n)\n\n# Create line chart\nchart = pygal.Line(\n    width=4800,\n    height=2700,\n    style=custom_style,\n    title=\"lift-curve · pygal · anyplot.ai\",\n    x_title=\"Population Targeted (%)\",\n    y_title=\"Lift (Model Rate / Baseline Rate)\",\n    show_dots=True,\n    dots_size=10,\n    stroke_style={\"width\": 5},\n    fill=False,\n    show_x_guides=False,\n    show_y_guides=True,\n    legend_at_bottom=False,\n    range=(0.9, max(lift_values) * 1.1),\n    margin=100,\n)\n\n# X-axis labels at deciles\nchart.x_labels = [f\"{d}%\" for d in deciles]\n\n# Add lift curve with tooltip-friendly data\nchart.add(\"Model Lift\", [{\"value\": v, \"label\": f\"{v:.2f}\"} for v in lift_values])\n\n# Add baseline reference line at y=1\nbaseline = [1.0] * len(deciles)\nchart.add(\"Random (No Lift)\", baseline)\n\n# Save as PNG and HTML\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}