Линейные графики в Nivo ожидают строго определённую структуру данных,
которая напрямую влияет на корректность построения осей, интерполяцию
значений и поведение tooltip’ов. Библиотека @nivo/line не
ограничивается одним форматом: допускается несколько моделей
представления данных, но каждая из них должна соответствовать внутренним
правилам маппинга x и y.
Основная модель, используемая в большинстве случаев, представляет данные как массив серий. Каждая серия — это отдельная линия на графике.
const data = [
{
id: "temperature",
data: [
{ x: 0, y: 12 },
{ x: 1, y: 15 },
{ x: 2, y: 14 }
]
}
];
Ключевые элементы структуры:
id — уникальный идентификатор серииdata — массив точекx — значение по оси Xy — значение по оси YТакой формат считается каноническим и используется по умолчанию без дополнительных настроек.
Наиболее простой случай — числовая ось X. Она применяется в сценариях, где данные равномерны или уже дискретизированы.
const data = [
{
id: "users",
data: [
{ x: 1, y: 10 },
{ x: 2, y: 25 },
{ x: 3, y: 18 }
]
}
];
Особенности:
linear scale)Этот формат наиболее производительный при рендеринге большого количества точек.
Nivo поддерживает категориальные данные, где x — строка.
Это переключает поведение оси на категориальное отображение.
const data = [
{
id: "sales",
data: [
{ x: "янв", y: 30 },
{ x: "фев", y: 45 },
{ x: "мар", y: 28 }
]
}
];
При таком формате:
Важно учитывать, что сортировка данных становится критичной: библиотека не всегда выполняет автоматическую сортировку строковых значений.
Для временных рядов используется формат Date или строка,
приводимая к дате через парсер.
const data = [
{
id: "traffic",
data: [
{ x: new Date(2024, 0, 1), y: 120 },
{ x: new Date(2024, 0, 2), y: 135 },
{ x: new Date(2024, 0, 3), y: 90 }
]
}
];
const data = [
{
id: "traffic",
data: [
{ x: "2024-01-01", y: 120 },
{ x: "2024-01-02", y: 135 },
{ x: "2024-01-03", y: 90 }
]
}
];
При использовании строк важно задать xScale:
xScale={{
type: "time",
format: "%Y-%m-%d",
precision: "day"
}}
Особенности временных данных:
Одно из ключевых преимуществ Line chart в Nivo — поддержка нескольких линий в одном графике.
const data = [
{
id: "desktop",
data: [
{ x: "янв", y: 120 },
{ x: "фев", y: 132 },
{ x: "мар", y: 101 }
]
},
{
id: "mobile",
data: [
{ x: "янв", y: 90 },
{ x: "фев", y: 110 },
{ x: "мар", y: 95 }
]
}
];
Особенности обработки:
В реальных данных часто встречаются пропуски. Nivo не требует полного покрытия оси X.
const data = [
{
id: "sensor",
data: [
{ x: 1, y: 10 },
{ x: 2, y: null },
{ x: 3, y: 14 }
]
}
];
Поведение при null:
Альтернативный вариант — полное отсутствие точки в массиве:
data: [
{ x: 1, y: 10 },
{ x: 3, y: 14 }
]
В этом случае библиотека также интерпретирует разрыв линии.
Часто данные приходят в «плоском» формате API и требуют преобразования.
Исходный формат:
const raw = [
{ type: "A", month: "янв", value: 10 },
{ type: "A", month: "фев", value: 20 },
{ type: "B", month: "янв", value: 15 },
{ type: "B", month: "фев", value: 25 }
];
Преобразование:
const grouped = raw.reduce((acc, item) => {
let series = acc.find(s => s.id === item.type);
if (!series) {
series = { id: item.type, data: [] };
acc.push(series);
}
series.data.push({
x: item.month,
y: item.value
});
return acc;
}, []);
Результат соответствует структуре Nivo Line.
Nivo позволяет использовать произвольные структуры данных через
xScale и yScale, но чаще используется
трансформация перед передачей. Однако возможен вариант с кастомными
полями:
const data = [
{
id: "custom",
data: [
{ time: 1, value: 10 },
{ time: 2, value: 20 }
]
}
];
И настройка:
<ResponsiveLine
data={data}
xScale={{ type: "linear" }}
yScale={{ type: "linear" }}
axisBottom={{
legend: "time",
legendOffset: 36
}}
// маппинг через preprocess:
data={data.map(series => ({
...series,
data: series.data.map(d => ({ x: d.time, y: d.value }))
}))}
/>
Фактически библиотека ожидает строго x/y, поэтому
кастомные ключи всегда приводятся к стандарту на уровне подготовки
данных.
Корректный порядок точек критичен для построения линии.
data.data.sort((a, b) => a.x - b.x);
data.data.sort((a, b) => new Date(a.x) - new Date(b.x));
Сортировка выполняется вручную:
const order = ["янв", "фев", "мар"];
data.data.sort((a, b) => order.indexOf(a.x) - order.indexOf(b.x));
Отсутствие сортировки приводит к «ломаным» линиям и некорректной интерполяции.
Повторяющиеся значения x внутри одной серии создают
неоднозначное поведение.
data: [
{ x: 1, y: 10 },
{ x: 1, y: 15 }
]
Возможные последствия:
Рекомендуется агрегировать данные заранее:
const map = new Map();
raw.forEach(d => {
map.set(d.x, (map.get(d.x) || 0) + d.y);
});
Хотя Line chart не является stacked по умолчанию, данные могут подготавливаться для имитации накопления:
const data = [
{
id: "A",
data: [
{ x: "янв", y: 10 },
{ x: "фев", y: 20 }
]
},
{
id: "B",
data: [
{ x: "янв", y: 5 },
{ x: "фев", y: 15 }
]
}
];
Далее производится предварительное суммирование:
const stacked = data[1].data.map((d, i) => ({
x: d.x,
y: d.y + data[0].data[i].y
}));
При увеличении количества точек важно учитывать формат:
Оптимальный формат:
{ x: number, y: number }
Любые дополнительные поля следует выносить за пределы
data или использовать на уровне preprocessing.
Дополнительные данные могут храниться внутри точки:
{
x: "янв",
y: 10,
meta: {
region: "EU",
status: "ok"
}
}
Nivo игнорирует meta, но передаёт его в tooltip через
кастомные компоненты:
tooltip={({ point }) => (
<div>
{point.data.meta?.region}
</div>
)}
Это позволяет расширять модель данных без нарушения основного формата.
Корректный формат Line chart в Nivo всегда сводится к следующей структуре:
iddatax и yx должен соответствовать выбранной шкалеЛюбые отклонения от этой модели требуют явной нормализации до передачи в компонент.