{"spec_id":"funnel-basic","library":"pygal","language":"python","code":"\"\"\" anyplot.ai\nfunnel-basic: Basic Funnel Chart\nLibrary: pygal 3.1.0 | Python 3.13.13\nQuality: 87/100 | Updated: 2026-06-16\n\"\"\"\n\nimport os\n\nimport pygal\nfrom pygal.style import Style\n\n\n# Theme tokens (see prompts/default-style-guide.md \"Theme-adaptive Chrome\")\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Imprint palette — first series is ALWAYS brand green (#009E73)\nIMPRINT_PALETTE = (\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\", \"#AE3030\")\n\n# Data — sales conversion funnel, stages ordered largest (top) → smallest (bottom)\n# Deterministic data, no random seed needed\nstages = [\"Awareness\", \"Interest\", \"Consideration\", \"Intent\", \"Purchase\"]\nvalues = [1000, 600, 400, 200, 100]\nbase_value = values[0]\n\n# Style — pygal's Style carries every theme token. Font sizes are unitless and\n# render straight onto the 3200-px source grid (see default-style-guide.md\n# \"Why the Native-pixel numbers look so much bigger\").\ncustom_style = Style(\n    background=PAGE_BG,\n    plot_background=PAGE_BG,\n    foreground=INK,\n    foreground_strong=INK,\n    foreground_subtle=INK_MUTED,\n    colors=IMPRINT_PALETTE,\n    title_font_size=66,\n    label_font_size=56,\n    major_label_font_size=44,\n    legend_font_size=48,\n    value_font_size=44,\n    tooltip_font_size=40,\n    opacity=1,\n)\n\n# pygal's Funnel pads its y-box to [-max, +max] while the tallest segment only\n# spans [-max/2, +max/2], so by default the funnel fills just half the plot\n# height. An explicit symmetric range tightens that padding to ~0.6·max, giving\n# the funnel a more commanding vertical presence without clipping any segment.\nfunnel_half = base_value * 0.6\n\n# Plot — pygal's native Funnel chart; each stage is its own series so the\n# segments carry distinct Imprint colors and the legend names every stage.\nchart = pygal.Funnel(\n    width=3200,\n    height=1800,\n    title=\"funnel-basic · python · pygal · anyplot.ai\",\n    style=custom_style,\n    print_values=True,\n    value_formatter=lambda v: f\"{v:,.0f}  ({v / base_value * 100:.0f}%)\",\n    range=(-funnel_half, funnel_half),\n    margin=50,\n    margin_bottom=15,\n    show_legend=True,\n    legend_at_bottom=True,\n    legend_at_bottom_columns=5,\n    legend_box_size=36,\n    show_x_labels=False,\n    show_y_labels=False,\n    show_y_guides=False,\n    truncate_legend=-1,\n)\n\n# Each stage added as a single-value series — the value (and conversion %) is\n# printed on the segment via the value_formatter above.\nfor stage, value in zip(stages, values, strict=True):\n    chart.add(stage, value)\n\n# Save — theme-suffixed PNG (cairosvg) plus interactive HTML (pygal is interactive)\nchart.render_to_png(f\"plot-{THEME}.png\")\nwith open(f\"plot-{THEME}.html\", \"wb\") as f:\n    f.write(chart.render())\n"}