For AI agents: the complete XY documentation index is at llms.txt. Markdown versions are available by appending .md or sending Accept: text/markdown.
Chart Gallery

/

Pie and Donut Charts in Python

Pie and Donut Charts in Python

A pie chart (also called a pie plot or pie graph) maps each share to an angular span. A donut uses the same sectors with a positive inner radius, leaving room for a total, status, or supporting label. In XY, both are compositions of unequal-width bars inside polar_bar_chart(). For the standard composition, use xy.pie_chart(labels, values, hole=...); the examples below use the lower-level bars directly to demonstrate custom sector geometry and dashboard layouts.

Jump to a basic pie chart, progress rings, or build your own pie block.

The first example keeps the chart intentionally small. The examples after it combine XY's exportable sector geometry with ordinary Reflex layout for center labels, legends, captions, and summary rows. That separation keeps the data visualization reusable while the surrounding block remains easy to adapt to a dashboard.

Basic Pie Chart

A filled pie starts with simple label-and-value data. The chart converts each value to an angular width, and base=0 makes every sector reach the center:

PIE_DATA stays independent of the chart geometry, so changing a value updates both its slice and legend percentage. The separate palette uses the same #6e56cf primary purple used throughout these docs.

Market Share

Use a high-contrast donut when the whole is meaningful and every slice needs a compact percentage label. The two-column legend preserves the names and raw values without crowding the ring:

$100BEcosystem value

The slot width remains proportional to the value. A three-pixel background-colored stroke creates a constant screen-space separator; unlike an angular gap, it stays visually even at the inner and outer rim. Text annotations use (theta, radius) coordinates, so their anchors remain attached to the slices in browser and static output.

Progress Rings

A thin annulus can behave like a circular progress bar. Splitting it into 40 rounded dashes gives the display a lighter rhythm than one continuous arc:

User researchWhere the workday leaks
1,240 responses
48%Additional support requests from users.
67%Inaccurate forecasts disrupt planning.

Each visible dash occupies half of a nine-degree slot. The remaining half is the gap, so the track stays evenly spaced without creating transparent data rows.

Revenue Mix

For a smaller category set, pair a rounded donut with a value list. The center answers the primary question while the aligned legend supports exact lookup:

1,284Total orders
Direct$52,400
Marketplace$38,900
Wholesale$24,150
Affiliate$16,300

Rounded corners are available when base is positive. A CSS linear gradient paints each one-slice mark independently, so every segment can keep its own two-color ramp.

Reliability Score

A partial donut becomes a gauge when its angular span represents an ordered scale. Keep the qualitative bands in the ring and repeat them as a linear key for exact threshold lookup:

Delivery Reliability
842

Reliability is excellent

Updated 12 Mar 2026

04506508201000

This example keeps a full circular layout and authors only 240 degrees of colored bars, matching a conventional dashboard gauge. Use theta_axis(sector=(start, end)) instead when the visible arc should expand to fill the plot box.

Build Your Own Pie Block

  1. Normalize values to a full turn (360 degrees or radians).
  2. Use the cumulative midpoint of each slot as the bar angle.
  3. Add a background-colored stroke for a constant-pixel separator, or subtract a small angle from each slot when the gap should scale with the ring.
  4. Give every slice the same base and height.
  5. Hide the axes and compose labels or legends around the chart with Reflex.

Set base=0 for a filled pie. For donuts, a positive base enables rounded sector corners. Per-slice gradients are easiest to express as one single-slice bar mark per category.

Interaction and Export

Pie blocks use the shared polar renderer. These examples set xy.modebar(show=False) to keep the presentation clean. The underlying interactions and APIs remain intact: sector hover, radial wheel zoom, double-click reset, and browser/static exports remain available. A hovered slice reads its own label and value; the layout angle and the constant rim radius stay out of the readout. Center labels and legends composed in Reflex are browser UI; annotations placed with xy.text() are part of the chart and are preserved in SVG and native raster exports.

See Radial bar charts for width, base, corner-radius, clipping, and partial-sector details.

API Reference

xy.pie_chart

A pie or donut: one slice per label, sized by value.

Props

PropTypeDescription
labelsSequence[Any]

One category name per slice.

valuesArrayLike

One non-negative value per slice.

*childrenComponent

Extra components (legend placement, a user tooltip, …).

holefloat

Inner radius fraction; 0 is a full pie, the default is a donut.

padfloat

Gap between neighbouring slices, in PIXELS — constant from the hole to the rim. An angular pad would be `r · dtheta` wide and so taper to nothing toward the centre, which reads as the spacing being applied unevenly across the slice.

colorsOptional[Sequence[str]]

One CSS colour per slice. Defaults to the palette cycle.

corner_radiusfloat

Rounded slice corners, in px.

show_valuesbool

Include the value in the slice's name (legend + tooltip). Dropped for a slice whose value renders identically to its share — percentage-shaped input would otherwise print the same number twice.

show_percentbool

Include the share in the slice's name (legend + tooltip).

titleOptional[str]

Title shown above the plot.

widthint | str

Chart width in pixels or a CSS size such as ``"100%"``.

heightint | str

Chart height in pixels or a CSS size such as ``"100%"``.

paddingUnion[float, Sequence[float], None]

Plot margins, as one value or a sequence of side values. Use zero for an edge-to-edge sparkline.

dataTableLike

Chart-level data used by marks that omit their own ``data``.

class_nameOptional[str]

CSS class applied to the chart container.

class_namesOptional[dict[str, str]]

CSS classes keyed by stable chart DOM slot.

styleOptional[dict[str, StyleValue]]

Inline style overrides for the chart container.

stylesOptional[dict[str, dict[str, StyleValue]]]

Inline style mappings keyed by stable chart DOM slot.

on_hoverOptional[Callable[[dict], None]]

Callback receiving hover event payloads.

on_clickOptional[Callable[[dict], None]]

Callback receiving picked-mark click payloads.

on_brushOptional[Callable[[dict], None]]

Callback receiving brush event payloads.

on_selectOptional[Callable[[Selection], None]]

Callback receiving data-space selections.

on_view_changeOptional[Callable[[dict], None]]

Callback receiving viewport change payloads.

hoverOptional[bool]

Whether pointer movement emits hover events.

clickOptional[bool]

Whether picked marks emit click events.

selectOptional[bool]

Whether shift-drag box selection is enabled.

brushOptional[bool]

Whether brush selection is enabled.

crosshairOptional[bool]

Whether plot-aligned hover guides are shown.

navigationOptional[bool]

Whether browser pan and zoom navigation is enabled.

panOptional[bool]

Whether plain-drag panning is enabled.

pan_axesOptional[tuple[str, ...]]

Declared axis IDs translated by pan gestures.

zoomOptional[bool]

Whether viewport zoom is enabled.

default_drag_actionOptional[DefaultDragAction]

Initial action performed by a plain plot drag.

zoom_axesOptional[tuple[str, ...]]

Declared axis IDs changed by zoom gestures and controls.

zoom_limitsOptional[ZoomLimits]

Minimum and maximum magnification globally or by axis.

wheel_zoomOptional[bool]

Whether wheel and trackpad zoom is available.

box_zoomOptional[bool]

Whether box zoom is available as a drag action.

zoom_buttonsOptional[bool]

Whether modebar Zoom In/Out commands are available.

double_click_resetOptional[bool]

Whether double-click restores ``reset_axes``.

reset_axesOptional[tuple[str, ...]]

Declared axis IDs restored by reset.

link_groupOptional[str]

Identifier used to synchronize charts in the browser.

link_axesOptional[tuple[str, ...]]

Axes synchronized within the link group.

coordsstr

Coordinate system, ``"cartesian"`` (default) or ``"polar"``. Under ``"polar"`` each mark's first channel is the angle and its second is the radius. Prefer ``xy.polar_chart(...)``, which sets this for you.

FAQ

Does XY have a dedicated pie mark?

No. Every pie plot and donut plot on this page is composed from xy.bar() marks inside xy.polar_bar_chart(). This keeps sector styling and export behavior on the same renderer as radial bars.

How do I add space between slices?

For an even screen-space separator, keep the proportional width and add a background-colored stroke with stroke_width=. For an angular gap, pass a slightly smaller per-item width while keeping each slot midpoint unchanged.

How do I round donut slices?

Pass corner_radius= on bars whose base is positive. A filled pie reaches the center and therefore keeps a sharp center vertex.

Built with Reflex