Basic Funnel Chart — Bokeh

A funnel chart visualizes sequential stages of a process where values progressively decrease from one stage to the next. Each stage is represented as a trapezoidal segment that narrows from top to bottom, making it easy to identify drop-offs between stages. This chart is ideal for tracking conversion rates, sales pipelines, and multi-step processes where understanding stage-to-stage transitions is critical.

Basic Funnel Chart rendered with Bokeh

Python source (Bokeh)

""" anyplot.ai
funnel-basic: Basic Funnel Chart
Library: bokeh 3.9.0 | Python 3.14.4
Quality: 86/100 | Updated: 2026-04-26
"""

from bokeh.io import export_png, output_file, save
from bokeh.models import Label, Legend, LegendItem
from bokeh.plotting import figure


# Data - Sales funnel stages (from spec example)
stages = ["Awareness", "Interest", "Consideration", "Intent", "Purchase"]
values = [1000, 600, 400, 200, 100]

# Colors - distinct for each stage (Python Blue first, then colorblind-safe palette)
colors = ["#306998", "#FFD43B", "#E74C3C", "#9B59B6", "#27AE60"]

# Calculate widths proportional to values (relative to first/largest value)
max_value = values[0]
widths = [v / max_value for v in values]

# Funnel parameters
funnel_height = 2.0  # Total height of funnel
stage_height = funnel_height / len(stages)
center_x = 0.5  # Center of funnel

# Build funnel segments as patches (trapezoids)
# Each segment connects the width at its top to the width at its bottom
segment_coords = []
for i in range(len(stages)):
    top_width = widths[i]
    # Bottom width is next stage width, or 50% of current for last stage
    bottom_width = widths[i + 1] if i < len(stages) - 1 else widths[i] * 0.5

    top_y = funnel_height - i * stage_height
    bottom_y = top_y - stage_height

    # Trapezoid coordinates (clockwise from top-left)
    xs = [
        center_x - top_width / 2,  # top-left
        center_x + top_width / 2,  # top-right
        center_x + bottom_width / 2,  # bottom-right
        center_x - bottom_width / 2,  # bottom-left
    ]
    ys = [top_y, top_y, bottom_y, bottom_y]
    segment_coords.append((xs, ys))

# Create figure (4800 x 2700 px)
p = figure(
    width=4800,
    height=2700,
    title="funnel-basic · bokeh · pyplots.ai",
    x_range=(-0.3, 1.3),
    y_range=(-0.3, 2.3),
    tools="",
    toolbar_location=None,
)

# Draw funnel segments and collect renderers for legend
renderers = []
for (xs, ys), color in zip(segment_coords, colors, strict=True):
    r = p.patch(xs, ys, fill_color=color, line_color="white", line_width=4, alpha=0.9)
    renderers.append(r)

# Add labels on each segment (stage name and value/percentage)
for i, (stage, value) in enumerate(zip(stages, values, strict=True)):
    xs, ys = segment_coords[i]
    # Label position: center of trapezoid
    center_y = (ys[0] + ys[2]) / 2

    # Calculate percentage relative to first stage
    percentage = (value / max_value) * 100

    # Stage name label (dark text for yellow, white for others)
    text_color = "#333333" if colors[i] == "#FFD43B" else "white"
    stage_label = Label(
        x=center_x,
        y=center_y + 0.06,
        text=stage,
        text_font_size="28pt",
        text_font_style="bold",
        text_color=text_color,
        text_align="center",
        text_baseline="middle",
    )
    p.add_layout(stage_label)

    # Value label
    value_label = Label(
        x=center_x,
        y=center_y - 0.06,
        text=f"{value:,} ({percentage:.0f}%)",
        text_font_size="22pt",
        text_color=text_color,
        text_align="center",
        text_baseline="middle",
    )
    p.add_layout(value_label)

# Create legend
legend_items = [LegendItem(label=f"{stages[i]}: {values[i]:,}", renderers=[renderers[i]]) for i in range(len(stages))]
legend = Legend(
    items=legend_items,
    location="center_right",
    label_text_font_size="24pt",
    glyph_width=40,
    glyph_height=40,
    spacing=20,
    padding=30,
    background_fill_alpha=0.9,
    border_line_color="#cccccc",
)
p.add_layout(legend, "right")

# Styling
p.title.text_font_size = "36pt"
p.title.align = "center"

# Hide axes and grid for funnel chart
p.axis.visible = False
p.grid.visible = False
p.outline_line_color = None

# Save outputs
export_png(p, filename="plot.png")

# Also save interactive HTML
output_file("plot.html")
save(p)

Part of Basic Funnel Chart on anyplot.ai.

Other implementations