Scatter
Точечная серия; обе оси числовые по умолчанию (без axes создаются number + number).
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Height and weight' },
series: [{ type: 'scatter', xField: 'height', xName: 'Height', yField: 'weight', yName: 'Weight', name: 'People' }],
axes: [
{ type: 'number', position: 'bottom', title: { text: 'Height, cm' }, nice: false },
{ type: 'number', position: 'left', title: { text: 'Weight, kg' } },
],
legend: { enabled: false },
};
}export function getData() {
return [
{ height: 162, weight: 54 },
{ height: 168, weight: 61 },
{ height: 171, weight: 65 },
{ height: 175, weight: 71 },
{ height: 178, weight: 74 },
{ height: 180, weight: 82 },
{ height: 183, weight: 79 },
{ height: 186, weight: 88 },
{ height: 190, weight: 93 },
{ height: 167, weight: 58 },
{ height: 173, weight: 68 },
{ height: 181, weight: 77 },
];
}Подписи точек
Подпись точки — это её имя и значение, нарисованные одним блоком: та же подпись, что у сектора круговой или стадии воронки. Имя точке даёт labelField; без него подпись — голое значение, как и раньше. layout ставит значение через разделитель ('inline' — по умолчанию) или на свою строку, и у каждой половины свой шрифт:
labelField: 'country',
label: { enabled: true, category: { fontWeight: 'bold' }, value: { type: 'percent' } },Имя точки — значение поля, поэтому то, как оно превращается в текст, — свойство серии: labelName (format или formatter) проговаривает его и для заголовка тултипа, и для подписи, а label.category перекрывает там, где подписи нужно что-то короче.
value.type: 'percent' читает число как долю от суммы: для scatter — от значений y, для bubble — от sizeField, то есть от того, частью чего пузырь и является. label.formatter({ value, datum }) по-прежнему говорит за всю подпись, когда нужен один текст, и имеет приоритет над category/value:
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Scatter with labels on the right' },
series: [
{
type: 'scatter',
xField: 'x',
yField: 'y',
name: 'Points',
label: {
enabled: true,
placement: 'right',
formatter: ({ value, datum }) => `(${datum.x}; ${value})`,
},
},
],
legend: { enabled: false },
};
}export function getData() {
return [
{ x: 12, y: 30 },
{ x: 25, y: 48 },
{ x: 38, y: 22 },
{ x: 47, y: 61 },
{ x: 58, y: 41 },
{ x: 70, y: 72 },
{ x: 81, y: 55 },
];
}Когда точек много
label.minShare оставляет без подписи точки ниже этой доли от суммы, а label.avoidOverlap скрывает те подписи, которым не хватило места. Пузырьковая серия раздаёт место по размеру — крупные пузыри сохраняют подписи, мелочь теряет; у scatter ранжировать нечем, поэтому там выигрывает более ранняя точка:
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'GDP vs Happiness Index' },
subtitle: { text: 'labels go to the bubbles worth naming, biggest first' },
series: [
{
type: 'bubble',
xField: 'gdp',
xName: 'GDP per capita',
yField: 'happiness',
yName: 'Happiness',
labelField: 'country',
name: 'Countries',
sizeField: 'population',
sizeName: 'Population, M',
maxSize: 36,
label: {
enabled: true,
minShare: 0.04,
avoidOverlap: true,
category: { fontWeight: 'bold' },
value: { type: 'percent', color: '#8a8f98' },
},
},
],
axes: [
{ type: 'number', position: 'bottom', title: { text: 'GDP per capita, $K' } },
{ type: 'number', position: 'left', title: { text: 'Happiness Index' } },
],
legend: { enabled: false },
};
}export function getData() {
return [
{ country: 'Russia', gdp: 4.2, happiness: 5.9, population: 144 },
{ country: 'China', gdp: 12.6, happiness: 6.1, population: 1412 },
{ country: 'India', gdp: 2.4, happiness: 5.0, population: 1408 },
{ country: 'USA', gdp: 76.3, happiness: 6.9, population: 332 },
{ country: 'Germany', gdp: 48.7, happiness: 7.0, population: 84 },
{ country: 'Japan', gdp: 34.0, happiness: 6.5, population: 125 },
{ country: 'South Korea', gdp: 51.0, happiness: 6.4, population: 52 },
{ country: 'Brazil', gdp: 9.7, happiness: 6.3, population: 215 },
];
}Формы маркеров
shape: circle, square, diamond, triangle, cross, plus:
import { getData } from './data';
import type { ChartOptions } from 'grafit-charts';
export function createOptions(): ChartOptions {
return {
data: getData(),
title: { text: 'Marker shapes' },
series: [
{ type: 'scatter', xField: 'x', yField: 'alpha', name: 'Group A', shape: 'circle' },
{ type: 'scatter', xField: 'x', yField: 'beta', name: 'Group B', shape: 'diamond' },
{ type: 'scatter', xField: 'x', yField: 'gamma', name: 'Group C', shape: 'triangle' },
],
};
}export function getData() {
const data: Array<Record<string, number>> = [];
const groups = [
{ key: 'alpha', cx: 30, cy: 40 },
{ key: 'beta', cx: 60, cy: 70 },
{ key: 'gamma', cx: 75, cy: 30 },
];
groups.forEach((g, gi) => {
for (let i = 0; i < 14; i++) {
data.push({
x: g.cx + (((i * 13 + gi * 7) % 21) - 10),
[g.key]: g.cy + (((i * 17 + gi * 11) % 19) - 9),
});
}
});
return data;
}Опции
Общие опции всех серий (name, showInLegend, tooltip.renderer, …) — в разделе Общие опции серий.
| Опция | Тип | По умолчанию | Описание |
|---|---|---|---|
xField | string | — | числовые ключи данных |
yField | string | — | числовые ключи данных |
labelField | string | — | ключ имени точки (подпись и заголовок тултипа) |
labelName.format | string | — | как поле имени точки становится текстом: заголовок тултипа и подпись |
labelName.formatter | ({ datum, value }) => string | — | то же, когда строкой формата не выразить |
xName | string | xField | имя значения x в тултипе |
yName | string | yField | имя значения y в тултипе |
shape | MarkerShape | 'circle' | форма маркера |
size | Pixels | 8 | размер маркера |
fill | ColorValue | палитра | заливка |
fillOpacity | Fraction | 0.85 | заливка |
stroke | ColorValue | фон | обводка |
strokeWidth | Pixels | 1 | обводка |
itemStyler | (params) => style | — | пер-точечные стили (fill/stroke/size) по datum |
label.enabled | boolean | false | показать подписи значений |
label.placement | 'top' | 'bottom' | 'left' | 'right' | 'inside' | 'top' | позиция подписи |
label.formatter | ({ value, datum }) => string | — | вся подпись сразу; приоритет над category/value |
label.layout | 'inline' | 'stacked' | 'inline' | значение через разделитель или на своей строке |
label.separator | string | ' · ' | разделитель половин inline-подписи |
label.category.enabled | boolean | true при заданном labelField | имя точки как часть подписи |
label.category.format | string | — | строка формата для поля имени |
label.category.formatter | ({ datum, label, value, share }) => … | — | текст половины с именем |
label.category.* | FontOptions | шрифт подписи | шрифт имени |
label.value.enabled | boolean | true | значение как часть подписи |
label.value.type | 'value' | 'percent' | 'value' | само значение или его доля от суммы |
label.value.format | string | — | строка формата (',.0f', '.1%') |
label.value.formatter | ({ datum, label, value, share }) => … | — | текст половины со значением |
label.value.* | FontOptions | шрифт подписи | шрифт значения |
label.minShare | Fraction | 0 | доля от суммы, начиная с которой точка достойна подписи |
label.avoidOverlap | boolean | false | скрывать подписи, которым не хватило места |
label.fontSize | Pixels | 11 | размер шрифта подписи |
label.fontWeight | string | number | normal | насыщенность |
label.fontFamily | string | шрифт темы | гарнитура |
label.color | ColorValue | foreground; внутри — автоконтраст | цвет текста |
itemStyler получает { datum, index, highlighted, fill, stroke, size } и возвращает частичные стили — так раскрашивают точки по условию без отдельных серий.
Тултип
У точечной серии обе оси — измерения, поэтому значения выводятся подписанными строками: xName: x, yName: y. В заголовке — имя точки, если его даёт labelField, иначе серия (маркер + name). Bubble добавляет строку sizeName: size с долей от суммы размеров — Население, млн: 1412 (37%), как читает свою долю сектор круговой.