Yugen UI

ScatterChart

ScatterChart shows the relationship between two numeric measures (correlation, clusters, outliers), with bubbles and a trend line when needed.

Markers are ≥ 8px with a 2px surface-colored ring, so overlapping points stay distinct. The tooltip follows the point nearest the pointer (Voronoi-style lookup), so there's no need to hit a small dot. Keyboard: Tab into the chart, then use the arrows to step through the points in X order. size turns points into bubbles whose area (not radius) is proportional to the value; the “Trend” button draws a least-squares line for each group and adds the slope and R² to the accessible description.
Yugen Labs · experimentalThis component is outside SemVer: its API can change in a minor release, and What's new says so. Versioning policy
Price and rating
14 products, 3 groups

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { ScatterChart } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Stores: floor area, revenue and staff

Bubbles

size adds a third dimension: the radius follows the square root, so the area is proportional to the value. Large bubbles are drawn first and small ones sit on top.

Study hours and exam scores

Trend line

defaultTrendLine turns on the linear regression (dashed line) from the start. The slope and R² are read out in the description for screen readers.

Response time

Time axis

x is a Date → time axis. series fixes the order and color of the groups instead of following the order they appear in.

Usage

Do
  • Use scatter when the question is “are these two measures related?”. Don't use it for one series over time (that's LineChart).
  • Keep to ≤ 3 groups: in the all-pairs check, only the first 3 colors stay distinct for color-blind readers. With more, markers change shape automatically, or split into small multiples.
  • Set label so the tooltip and table name each point; give xLabel / yLabel their units.
  • Turn on the trend line when the point is the direction, with R² so readers know how reliable it is.
Don't
  • Don't encode a measure with radius. Bubbles always scale by area, and size doesn't suit negative data.
  • Don't plot thousands of raw points. Sample them or bin them into cells (heatmap) first.
  • Don't add a second Y axis for a group with a different scale.

Props

Prop · TypeDefaultDescription
data / x / yChartDatum[] / string / stringDefault: —X field (number or Date) and Y field (number).
sizestringDefault: —Size field → bubbles (area ∝ value).
maxRadiusnumberDefault: 24Radius of the largest bubble (px); the smallest is 5px (≥ 8px dot + 2px ring).
group / seriesstring / ChartSeries[]Default: —Group field, and the order / labels / colors of the groups. The 9th group and beyond are merged into “Other”.
labelstringDefault: —Point name field (tooltip title, first table column).
xLabel / yLabel / sizeLabelstringDefault: —Measure names in the tooltip, table and description.
xType"number" | "time"Default: autoA Date → time.
xFormatIntl.NumberFormatOptions | Intl.DateTimeFormatOptions | (v) => stringDefault: —X format.
valueFormat / axisFormat / sizeFormatChartNumberFormatDefault: —Format of Y, the Y axis and size.
includeZerobooleanDefault: falseY axis starts at 0.
shapesbooleanDefault: texture or > 3 groupsAlso tells groups apart by marker shape.
trendLine / defaultTrendLine / onTrendLineChangeboolean / boolean / (on) => voidDefault: —Least-squares trend line.
hideTrendTogglebooleanDefault: falseHides the “Trend” button.
legendbooleanDefault: ≥ 2 groupsLegend that toggles groups.
title, description, toolbar, locale, ariaLabel, indexLabel…ChartFramePropsDefault: —Same as BarChart: frame, “Data table” button, texture, animate (off under reduced motion).

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.chart

Key · TypeDefault (English)messagesVi
roleDescriptionstring

aria-roledescription của vùng vẽ.

Default (English)"chart"messagesVi"biểu đồ"
heatmapRoleDescriptionstringDefault (English)"heat map"messagesVi"bản đồ nhiệt"
dataTablestring

Nút bật chế độ bảng của ChartContainer.

Default (English)"Data table"messagesVi"Bảng dữ liệu"
totalstring

Dòng tổng (tooltip, bảng) và nhãn giữa vòng DonutChart.

Default (English)"Total"messagesVi"Tổng"
valuestringDefault (English)"Value"messagesVi"Giá trị"
sharestringDefault (English)"Share"messagesVi"Tỉ lệ"
noDatastringDefault (English)"No data"messagesVi"Không có dữ liệu"
timestring

Tiêu đề cột đầu của bảng (khi không truyền indexLabel).

Default (English)"Time"messagesVi"Thời gian"
categorystringDefault (English)"Category"messagesVi"Danh mục"
groupstringDefault (English)"Group"messagesVi"Nhóm"
namestringDefault (English)"Name"messagesVi"Tên"
otherstring

Nhóm gộp (DonutChart vượt maxSlices, ScatterChart nhóm thứ 9+).

Default (English)"Other"messagesVi"Khác"
trendstring

Nút bật đường xu hướng của ScatterChart.

Default (English)"Trend"messagesVi"Xu hướng"
increasestringDefault (English)"Increase"messagesVi"Tăng"
decreasestringDefault (English)"Decrease"messagesVi"Giảm"
noChangestringDefault (English)"No change"messagesVi"Không đổi"
brushstring

ChartBrush: tên cửa sổ thu phóng, dòng "Đang xem … · n/N mốc", nút đặt lại.

Default (English)"Visible range"messagesVi"Vùng xem"
brushRoleDescriptionstringDefault (English)"zoom window"messagesVi"cửa sổ thu phóng"
brushViewingstringDefault (English)"Showing"messagesVi"Đang xem"
brushPoints(shown: number, total: number) => stringDefault (English)(shown, total) => `${shown}/${total} ${total === 1 ? "point" : "points"}`messagesVi(shown, total) => `${shown}/${total} mốc`
brushResetstringDefault (English)"Reset"messagesVi"Đặt lại"
lineSummary(info: { kind: "line" | "area" | "stacked" | "expand"; points: number; /** Mốc đầu / cuối (chỉ có khi points > 0). */ from?: string; to?: string; series: string[]; }) => string

Mô tả truy cập tự sinh (khi không truyền ariaLabel).

Default (English)Function, see messages.tsmessagesViFunction, see messages.ts
barSummary(info: { horizontal: boolean; stacked: boolean; categories: number; series: string[] }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
donutSummary(info: { groups: number; total: string; largest?: { label: string; share: string } }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
scatterSummary(info: { points: number; x: string; y: string; /** Tên đại lượng kích thước (biểu đồ bong bóng). */ size?: string; /** Tên các nhóm (khi có nhiều nhóm). */ groups?: string[]; trends: { group?: string; slope: string; r2: string }[]; }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
heatmapSummary(info: { rows: number; columns: number; min?: string; max?: string; hasEmpty: boolean }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
sparklineSummary(info: { points: number; first: string; last: string; min: string; max: string }) => stringDefault (English)Function, see messages.tsmessagesVi({ points, first, last, min, max }) => `Xu hướng ${points} điểm: từ ${first} đến ${last}, thấp nhất ${min}, cao nhất ${max}`