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

/

Wind Rose Charts in Python

Wind Rose Charts in Python

A wind rose (also called a wind rose chart, wind rose plot, or wind rose diagram) summarizes how often observations arrive from each compass direction and how those observations are distributed across speed bands. XY bins the raw direction/speed pairs in Python and renders the result as stacked polar bars.

Use wind_rose() when you have one bearing and one magnitude per observation. If the directional counts are already aggregated, use a radial bar chart instead.

Jump to directional sectors, speed bands, or the input contract.

Create a Wind Rose

Directions are compass bearings in degrees: 0° is north and values increase clockwise. The helper applies that convention automatically:

Each stacked color band counts observations whose speed is above the previous edge and at or below the current edge. The legend labels show those inclusive upper edges.

Choose Directional Sectors

sectors= controls the number of equally sized angular bins and must be at least 3. Each bin is centered on its compass bearing, so a value of exactly 0° belongs to the sector centered on north. Bearings outside 0..360 wrap around the circle.

More sectors reveal directional detail but need more observations to keep each bin stable. Common choices are 8, 12, 16, or 36 sectors, depending on sample size and the directional resolution of the source.

Configure Speed Bands

Pass increasing upper edges through speed_bins=:

The final edge should cover the fastest observation; values above it do not belong to a displayed band. XY removes duplicate edges and orders the remaining values. When speed_bins is omitted, it derives up to four readable bands from the speed quartiles and rounds the top edge upward so every finite observation is covered.

Set Sector Count and Band Edges Together

Lower the sector count when the sample is small or the source records only the eight principal bearings, and pass matching band edges so each petal stays thick enough to read:

Plot a Full Year of Observations

With thousands of records a high sector count resolves the prevailing wind, and narrow speed bands separate calm air from gales — add xy.legend() to place the band labels where you want them:

Follow the Input Contract

  • directions and speeds must have the same length.
  • Each pair describes one observation.
  • Non-finite pairs are dropped together.
  • At least one finite pair must remain.
  • sectors must be 3 or greater.
  • speed_bins must contain at least one edge when supplied.

XY raises ValueError for mismatched arrays, an empty finite dataset, too few sectors, or an empty band definition.

Read and Style the Result

The radial value is a count, not a speed. Each speed band becomes one stacked bar series and takes the next chart palette color. Pass chart keyword props such as title, width, height, padding, class_names, and styles through wind_rose().

The helper authors a degree-based theta axis with north at zero and clockwise rotation, plus an r axis labeled count. Build the equivalent sectors manually with polar_bar_chart() when you need custom pre-binning, non-count radial values, a different angular convention, or component children such as xy.theme(), xy.legend(), and xy.modebar().

Interaction and Export

Wind roses support hover, fixed-minimum radial zoom, reset, and browser/static export through the shared polar renderer. Theta rotation, box zoom, selection, brushing, and crosshairs are not available.

See the polar overview for the full interaction, renderer, annotation, and large-data boundary.

API Reference

xy.wind_rose

A wind rose: directional frequency, stacked by speed band.

Props

PropTypeDescription
directionsArrayLike

Bearings in degrees, one per observation.

speedsArrayLike

Speeds, one per observation.

*children_inComponent

Extra components — an `xy.legend`, or an `xy.tooltip` to replace the default direction/count readout.

sectorsint

Number of angular bins around the circle.

speed_binsOptional[Sequence[float]]

Upper edges of the speed bands. Defaults to four quartile bands derived from the data. Each band takes the next colour from the chart's palette cycle, as stacked series do everywhere else.

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

Are wind directions radians or degrees?

wind_rose() always accepts compass bearings in degrees. It applies north-zero, clockwise theta settings automatically.

What happens when I omit speed_bins?

XY derives up to four bands from the finite speed quartiles and rounds the final edge upward to include the maximum observation.

Why are some observations missing?

Non-finite direction/speed pairs are dropped before the wind rose graph is binned. With authored speed_bins, make sure the final upper edge covers the fastest finite observation.

Built with Reflex