Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/charts/box-plot.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Box Plot in Python
description: Box plot Python charts with xy — compare distributions across groups with quartiles, whiskers, and outliers in a fast, interactive boxplot that pans and zooms.
description: Boxplot Python charts with xy. Compare distributions across groups with quartiles, whiskers, and outliers in a fast, interactive box and whisker plot.
components:
- xy.box_chart
---
Expand Down Expand Up @@ -204,8 +204,9 @@ Pass column names with `data=` instead of arrays when your data is a table.
### How do I make a box plot in Python?

Pass a list of arrays to `xy.box(...)`, one per group, inside
`xy.box_chart(...)` and render it. Quartiles, whiskers, and axes are computed
for the whole box chart automatically.
`xy.box_chart(...)` and render it. That is all a Python box and whisker plot
needs: quartiles, whiskers, and axes are computed for the whole box chart
automatically.

### How do I show outliers on a box plot?

Expand Down
27 changes: 27 additions & 0 deletions docs/charts/contour-plot.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,30 @@ explicit list of values to place contours at exact levels.

Set `dash_negative=True` so contours with negative values are dashed, making the
sign of a signed field easy to read.

### I use a MATLAB contour plot or matplotlib. What is the equivalent?

Matplotlib users can often start by changing the import because `xy.pyplot`
accepts the familiar `contour()` and `contourf()` calls, although unsupported
options may still require changes. For MATLAB, translate the workflow to the
equivalent Python/NumPy syntax shown here:

~~~python
import numpy as np
import xy.pyplot as plt

x = np.linspace(-3, 3, 100)
y = np.linspace(-2.5, 2.5, 90)
xx, yy = np.meshgrid(x, y)
z = np.exp(-(xx**2 + yy**2))

fig, ax = plt.subplots()
ax.contourf(x, y, z, levels=12)
ax.set_xlabel("x")
ax.set_ylabel("y")
plt.show()
~~~

The result is a fully interactive contour chart. See the
[matplotlib compatibility guide](/docs/xy/integrations/matplotlib/) for the
covered surface.
15 changes: 10 additions & 5 deletions docs/charts/pie-chart.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
---
title: Pie and Donut Charts in Python
description: Build polished pie, donut, progress-ring, and gauge blocks in Python with xy and Reflex.
description: Create pie charts and donut charts in Python with xy. Build pie plots, progress rings, and gauge blocks with values, percentages, and custom colors.
components:
- xy.pie_chart
---

# Pie and Donut Charts in Python

A pie chart maps each share to an angular span. A donut uses the same sectors
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](#basic-pie-chart),
[progress rings](#progress-rings), or
[build your own pie block](#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
Expand Down Expand Up @@ -695,9 +700,9 @@ corner-radius, clipping, and partial-sector details.

### Does XY have a dedicated pie mark?

No. Pie and donut geometry 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.
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?

Expand Down
9 changes: 7 additions & 2 deletions docs/charts/polar-chart.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Polar Charts in Python
description: Create polar lines, fields, sectors, and uncertainty charts in Python with xy. Configure partial sectors, categorical angles, holes, log radii, and pyplot polar projections.
description: Create polar charts and polar plots in Python with xy. Configure sectors, categorical angles, holes, log radii, and pyplot polar projections.
components:
- xy.polar_chart
- xy.theta_axis
Expand All @@ -9,11 +9,16 @@ components:

# Polar Charts in Python

A **polar chart** places each observation by an angle (theta, or θ) and a
A **polar chart** (also called a polar plot or polar graph) places each
observation by an angle (theta, or θ) and a
distance from the center (radius, or r). It is a natural fit for cyclic
measurements, directional observations, antenna patterns, radar comparisons,
and wind distributions.

Jump to [a polar line chart](#create-a-polar-line-chart),
[the angular axis](#configure-the-angular-axis), or
[supported marks and limits](#supported-marks-and-current-limits).

XY uses the same composition model as its Cartesian charts. Put `line`,
`scatter`, `area`, `bar`, `column`, `heatmap`, `contour`, or `errorbar` marks
inside `polar_chart()`. Focused helpers build
Expand Down
78 changes: 72 additions & 6 deletions docs/charts/radar-chart.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,20 @@ components:

# Radar Charts in Python

A **radar chart** (or spider chart) compares several measurements across the
same categorical dimensions. XY places the categories at evenly spaced angles,
draws one spoke for each category, and closes every series across the circular
seam.
A **radar chart** (also called a spider chart, spider plot, or radar plot)
compares several measurements across the same categorical dimensions. XY places
the categories at evenly spaced angles, draws one spoke for each category, and
closes every series across the circular seam.

Use radar charts for compact profile comparisons such as product capabilities,
model scores, survey dimensions, and operational health. When the angular
position is itself a measured quantity rather than a category, start with the
[polar chart overview](/docs/xy/charts/polar-chart/) instead.

Jump to [filled areas or outlines](#choose-filled-areas-or-outlines),
[the data contract](#follow-the-radar-data-contract), or
[scale configuration](#configure-the-scale).

## Create a Radar Chart

Pass the category labels first, followed by one `area` or `line` mark per
Expand Down Expand Up @@ -133,6 +137,52 @@ rings, as in the live example. General `polar_chart()` compositions also
accept category strings directly. `radar_chart()` additionally validates that
each series matches the shared category count and closes profiles for you.

## Compare Three Profiles on a Fixed Scale

Overlay one mark per candidate, pin the radial domain and its rings with
`xy.r_axis()`, and rotate the first category to the top with `xy.theta_axis()`
so repeated benchmarks stay directly comparable:

~~~python demo exec
import reflex_xy
import xy

benchmark_axes = ["Latency", "Throughput", "Accuracy", "Cost", "Memory", "Setup"]

radar_scaled = xy.radar_chart(
benchmark_axes,
xy.area(
[78, 92, 88, 61, 74, 95],
name="Engine A",
color="#6e56cf",
line_color="#6e56cf",
opacity=0.25,
),
xy.area(
[64, 55, 90, 72, 58, 80],
name="Engine B",
color="#2563eb",
line_color="#2563eb",
opacity=0.22,
),
xy.area(
[52, 48, 76, 88, 83, 66],
name="Engine C",
color="#f97316",
line_color="#f97316",
opacity=0.22,
),
xy.theta_axis(grid_shape="linear", zero="N", direction="clockwise"),
xy.r_axis(domain=(0.0, 100.0), tick_values=[25, 50, 75, 100], label="score"),
xy.legend(loc="right", title="Engine"),
title="Benchmark profile (0-100)",
)


def radar_scaled_demo():
return reflex_xy.chart(radar_scaled, height="440px")
~~~

## Interaction and Export

Radar charts use the shared polar interaction model: hover, radial-only zoom,
Expand Down Expand Up @@ -160,12 +210,28 @@ A radar chart assigns evenly spaced angles to category labels and closes the
profile automatically. A polar line chart expects explicit numeric angles and
radii.

### How do I build a spider chart in Python?

Call `xy.radar_chart(categories, ...)` with one `xy.area()` or `xy.line()` mark
per series and render it:

~~~python
spider = xy.radar_chart(
["Speed", "Range", "Payload", "Efficiency"],
xy.area([0.9, 0.7, 0.6, 0.8], name="Model A", color="#6e56cf"),
xy.legend(),
)
~~~

The category list drives the spokes, so a spider plot needs no manual angle
math and no repeated closing value.

### How do I draw an unfilled spider chart?

Use `xy.line(values)` for each series, or pass `fill=False` to
`xy.radar_chart()` when the children are area marks.

### Why does my radar chart raise a value-count error?

Each series must have the same number of values as the category list. Add or
remove values so every category has one measurement.
Each series in a radar graph must have the same number of values as the category
list. Add or remove values so every category has one measurement.
13 changes: 9 additions & 4 deletions docs/charts/radial-bar-chart.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
---
title: Radial Bar Charts in Python
description: Build polished radial bar, progress-ring, and semicircular capacity blocks in Python with xy and Reflex.
description: Create radial bar charts in Python with xy. Build radial bar plots, progress rings, gauge charts, and semicircular capacity blocks.
components:
- xy.polar_bar_chart
---

# Radial Bar Charts in Python

A **radial bar chart** encodes each value as an annular sector. The bar's first
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](#basic-radial-bar-chart),
[inner radius and sector geometry](#inner-radius-and-sector-geometry), or
[partial gauges](#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
Expand Down Expand Up @@ -622,8 +627,8 @@ used by the progress-ring blocks above.

## Partial Gauges

Use `sector=(start, end)` for a gauge whose visible arc should expand to fill
the plot box. Rounded sectors, background-colored strokes, gradients, and
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
Comment thread
Alek99 marked this conversation as resolved.
explicit padding work the same way on a partial layout:

~~~python
Expand Down
84 changes: 78 additions & 6 deletions docs/charts/wind-rose.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,20 @@ components:

# Wind Rose Charts in Python

A **wind rose** 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.
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](/docs/xy/charts/radial-bar-chart/) instead.

Jump to [directional sectors](#choose-directional-sectors),
[speed bands](#configure-speed-bands), or
[the input contract](#follow-the-input-contract).

## Create a Wind Rose

Directions are compass bearings in degrees: 0° is north and values increase
Expand Down Expand Up @@ -85,6 +90,72 @@ 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:

~~~python demo exec
import numpy as np
import reflex_xy
import xy

coarse_rng = np.random.default_rng(7)
coarse_directions = np.mod(coarse_rng.normal(270.0, 45.0, 500), 360.0)
coarse_speeds = np.clip(coarse_rng.gamma(shape=2.0, scale=3.0, size=500), 0.3, 17.0)

coarse_rose = xy.wind_rose(
coarse_directions,
coarse_speeds,
sectors=8,
speed_bins=[3, 6, 9, 12, 18],
title="Eight-sector wind rose",
)


def wind_rose_sectors_demo():
return reflex_xy.chart(coarse_rose, height="440px")
~~~

## 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:

~~~python demo exec
import numpy as np
import reflex_xy
import xy

met_rng = np.random.default_rng(2024)
met_directions = np.mod(
np.concatenate(
[
met_rng.normal(240.0, 22.0, 5200),
met_rng.normal(60.0, 40.0, 1800),
met_rng.uniform(0.0, 360.0, 1000),
]
),
360.0,
)
met_speeds = np.clip(met_rng.weibull(2.0, 8000) * 7.5, 0.2, 28.0)

annual_rose = xy.wind_rose(
met_directions,
met_speeds,
xy.legend(loc="right", title="speed (m/s)"),
sectors=32,
speed_bins=[2, 4, 6, 8, 11, 14, 18, 25],
title="Wind rose, 8,000 hourly observations",
)


def wind_rose_annual_demo():
return reflex_xy.chart(annual_rose, height="440px")
~~~

## Follow the Input Contract

- `directions` and `speeds` must have the same length.
Expand Down Expand Up @@ -144,5 +215,6 @@ edge upward to include the maximum observation.

### Why are some observations missing?

Non-finite direction/speed pairs are dropped. With authored `speed_bins`, make
sure the final upper edge covers the fastest finite observation.
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.