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

/

Radial Bar Charts in Python

Radial Bar Charts in Python

A radial bar chart (also called a radial bar plot or radial bar graph) encodes each value as an annular sector. The bar's first channel is its center angle, its second is its radial height, width controls the angular span, and base controls the inner radius.

Jump to a basic radial bar chart, inner radius and sector geometry, or partial gauges.

The first example keeps that geometry intentionally small. The blocks after it combine XY's exportable sectors with ordinary Reflex layout for center values, legends, rails, and summary statistics. This keeps the visualization reusable without forcing dashboard UI into the chart itself.

Basic Radial Bar Chart

Start with six named values at evenly spaced angles. Each row also carries one shade from the purple palette used throughout these docs:

RADIAL_DATA stays independent of the chart construction, so labels, values, and colors are easy to replace. The named one-bar marks populate the legend, while the authored ticks keep the angular and radial axes easy to read. Pass one scalar width for equal angular spans or a same-length sequence for per-bar spans. Widths must be finite and positive.

Allocation Overview

Small progress rings work well when several categories share one maximum. Each ring below is an explicit muted track plus a colored foreground sector; the table repeats the values for exact lookup:

Annual planTeam allocation
$2.0M planned
44%
Platform
24%
Product
15%
Growth
10%
Operations
7%
Support
44%Platform
$880,000
24%Product
$480,000
15%Growth
$300,000
10%Operations
$200,000
7%Support
$140,000

The rings use a common radial domain and thickness. The percentage controls only the foreground width, while the track remains a complete annulus. The labels and exact dollar values stay in Reflex so the ring geometry can be exported or reused independently.

Training Summary

A hero metric can share a card with compact radial KPIs. Here the primary distance and goal rail lead, while three rings summarize the supporting measurements and the narrow side column preserves quick operational context:

Training summaryWeek 28
24.7km ridden
78% of weekly goal
312m
Elevation
684kJ
Work
82rpm
Cadence
Intervals7
Recovery46 min
Avg speed28.4 km/h

The chart helper owns only a track and foreground arc. The headline, horizontal goal rail, center values, and side statistics are ordinary layout, so they remain easy to restyle without changing the chart payload.

Cache Tiers

Nested semicircular bars can compare several capacities without repeating four separate plots. Every tier starts at the same angle; its foreground width is the used fraction of the shared 180-degree track:

Cache tiersLast 24 hours
Served warm8,420
Revalidated1,140
Evictions386
Purges72
Memory
610/1,000 (61%)
Regional
240/1,000 (24%)
Edge
100/1,000 (10%)
Origin
50/1,000 (5%)

Separate one-bar marks make it straightforward to give every tier a name, gradient, and rounded edge. The sector=(-90.0, 90.0) axis fits the visible semicircle to the available plot box instead of reserving space for the missing half.

Build Your Own Radial Block

  1. Decide whether values control radial height, angular progress, or both.
  2. Author a muted track when every category shares a known maximum.
  3. Keep the track and foreground on the same base and radial height.
  4. Convert a percentage to percentage / 100 × 360 for a full ring, or multiply by the declared partial-sector span.
  5. Hide axes and the native legend when Reflex supplies the surrounding labels.
  6. Keep raw data and derived spans outside the chart construction.

XY does not add a background track or infer a maximum automatically. Explicit track marks make the maximum, thickness, color, and export behavior unambiguous.

Inner Radius and Sector Geometry

base is the inner radial edge, and the bar value is the height above it. A scalar base opens the same hole beneath every bar; a sequence can give each bar its own starting radius:

Filled sectors that cross the visible radial range are clipped at the inner or outer ring. A sector wholly outside the range disappears instead of reflecting through the center.

base= belongs to the mark and may differ per bar. For one chart-wide opening, use r_axis(hole=...) to reserve a display-space inner fraction or r_axis(origin=...) to set a data-space radial origin. hole and origin are mutually exclusive.

A single sector with width=360 on a degree axis (or a full width on a radian axis) and a positive base draws a complete annulus. That is the track used by the progress-ring blocks above.

Partial Gauges

Use sector=(start, end) for a gauge chart whose visible arc should expand to fill the plot box. Rounded sectors, background-colored strokes, gradients, and explicit padding work the same way on a partial layout:

Expand

Use a scalar corner_radius for symmetric rounding. A gradient applies to the whole mark and takes priority over a solid color. Use stroke_width to control the separator or outline in screen pixels. Explicit padding=(top, right, bottom, left) is preserved by the polar layout, so a stable caption or legend band can be reserved without shifting the arc.

Angular Convention

Use xy.theta_axis(unit="degrees") when positions and widths are expressed in degrees. Add zero="N", direction="clockwise" for compass bearings. With the default radian axis, both the center angles and widths must be radians.

On theta_axis(), domain= is a compatibility alias for sector=; pass only one. XY clips marks and ticks to that interval and fits the visible arc to its own bounding box.

Interaction and Export

All live blocks on this page set xy.modebar(show=False) to keep the presentation quiet. Sector hover, radial wheel zoom, double-click reset, and browser/static exports remain available through the shared polar renderer.

Reflex-composed center values, rails, statistics, and custom legends are browser UI. The radial sectors themselves remain part of the XY chart and are preserved in SVG and native raster exports.

See the polar overview for shared axes, interaction, pyplot, large-data, and annotation limits.

API Reference

xy.polar_bar_chart

Radial bars: each bar is an annular sector rather than a rectangle.

Props

PropTypeDescription
*childrenComponent

`bar` marks plus axis/legend children.

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

How do I add gaps between radial bars?

Place bar centers at the full bin spacing and choose a slightly smaller width. For centers 30° apart, width=26 leaves a 4° gap.

How do I create a donut hole?

Set a positive base and choose a bar height that reaches the desired outer radius. Hide both axes for a conventional ring presentation.

Can each sector have a different angular width?

Yes. Pass a width sequence with one finite, positive value per bar.

Built with Reflex