Форматы данных для HeatMap

Форматы данных в @nivo/heatmap определяют, каким образом визуализация интерпретирует структуру матрицы значений и как сопоставляет категории по осям X и Y. HeatMap в Nivo построен вокруг идеи двумерного распределения числовых значений, где каждая ячейка представляет комбинацию двух категориальных признаков и одного числового показателя.

Основной формат данных в @nivo/heatmap представляет собой массив объектов, где каждый объект соответствует строке (или группе по оси Y), а внутри содержится массив значений по оси X.

const data = [
  {
    id: 'JavaScript',
    data: [
      { x: 'React', y: 120 },
      { x: 'Vue', y: 80 },
      { x: 'Angular', y: 60 }
    ]
  },
  {
    id: 'Python',
    data: [
      { x: 'Django', y: 90 },
      { x: 'Flask', y: 70 },
      { x: 'FastAPI', y: 110 }
    ]
  }
];

Смысл структуры:

  • id — категория по вертикальной оси (Y-axis)
  • data[] — набор точек внутри строки
  • x — категория по горизонтальной оси (X-axis)
  • y — числовое значение, отображаемое через цветовую шкалу

Такая модель называется nested row-based format и является основным способом передачи данных в HeatMap Nivo.


Принцип интерпретации координат

HeatMap не использует классические координаты графиков. Вместо этого применяется категориальная матрица:

  • ось X: дискретные категории (строки, темы, продукты)
  • ось Y: числовая интенсивность
  • ось Y в структуре данных фактически является значением y, а не координатой

Важно понимать: в Nivo HeatMap y — это не позиция, а величина.


Формирование данных из таблиц (pivot-логика)

Часто исходные данные приходят в «плоском» формате:

const raw = [
  { language: 'JavaScript', framework: 'React', value: 120 },
  { language: 'JavaScript', framework: 'Vue', value: 80 },
  { language: 'Python', framework: 'Django', value: 90 }
];

Для HeatMap такой формат необходимо преобразовать в структуру id + data[]:

function transform(raw) {
  const grouped = {};

  raw.forEach(item => {
    if (!grouped[item.language]) {
      grouped[item.language] = { id: item.language, data: [] };
    }

    grouped[item.language].data.push({
      x: item.framework,
      y: item.value
    });
  });

  return Object.values(grouped);
}

Результат соответствует ожидаемому формату HeatMap.


Альтернативный формат: матричное представление

Хотя Nivo напрямую не требует матрицу, данные часто концептуально представляются как двумерная таблица:

React Vue Angular
JS 120 80 60
Python 90 70 110

Такое представление удобно для генерации структуры:

const matrix = [
  ['JavaScript', 120, 80, 60],
  ['Python', 90, 70, 110]
];

Преобразование в формат Nivo:

const headers = ['React', 'Vue', 'Angular'];

const data = matrix.map(row => ({
  id: row[0],
  data: row.slice(1).map((value, index) => ({
    x: headers[index],
    y: value
  }))
}));

Плоский формат (flat heatmap)

В некоторых архитектурах данных HeatMap строится через набор троек:

const flatData = [
  { x: 'React', y: 'JavaScript', value: 120 },
  { x: 'Vue', y: 'JavaScript', value: 80 },
  { x: 'React', y: 'Python', value: 90 }
];

Такой формат требует агрегации перед передачей в компонент Nivo:

const grouped = flatData.reduce((acc, curr) => {
  if (!acc[curr.y]) {
    acc[curr.y] = { id: curr.y, data: [] };
  }

  acc[curr.y].data.push({
    x: curr.x,
    y: curr.value
  });

  return acc;
}, {});

const nivoData = Object.values(grouped);

Особенности работы с ключами X

Категории x должны быть:

  • уникальными внутри одной строки id
  • консистентными между всеми рядами
  • строковыми или числовыми значениями

При несогласованности ключей HeatMap может:

  • пропускать ячейки
  • визуально «разрывать» матрицу
  • некорректно распределять цвета

Нормализация данных

Для корректной визуализации часто требуется приведение данных к полной сетке:

const xKeys = ['React', 'Vue', 'Angular'];
const yKeys = ['JavaScript', 'Python'];

const normalized = yKeys.map(y => ({
  id: y,
  data: xKeys.map(x => ({
    x,
    y: findValue(y, x) || 0
  }))
}));

Это гарантирует отсутствие «пустых» значений в визуализации.


Использование строковых и числовых осей

HeatMap поддерживает:

  • x как string (категории)
  • y как number (значения)
  • id как string (группы)

Пример смешанного набора:

{
  id: '2024',
  data: [
    { x: 'Q1', y: 100 },
    { x: 'Q2', y: 140 },
    { x: 'Q3', y: 90 }
  ]
}

Поведение при отсутствии значений

Если часть комбинаций отсутствует:

{ x: 'React', y: undefined }

HeatMap интерпретирует это как отсутствие данных. Для контроля визуализации предпочтительно:

  • подставлять 0
  • или null при использовании специальных режимов отображения пустот

Влияние структуры данных на визуализацию

Формат данных напрямую влияет на:

  • плотность матрицы
  • распределение цветовой шкалы
  • возможность использования tooltips
  • агрегацию значений

Чем более регулярна структура id → x → y, тем стабильнее визуальный результат.


Многоуровневые HeatMap-структуры

При расширении модели данных иногда используется дополнительная группировка:

[
  {
    id: 'Frontend',
    data: [
      { x: 'React', y: 120 },
      { x: 'Vue', y: 80 }
    ]
  },
  {
    id: 'Backend',
    data: [
      { x: 'Django', y: 90 },
      { x: 'Express', y: 110 }
    ]
  }
]

Здесь id становится уровнем группировки домена, а x — подкатегорией.


Подготовка данных для динамических HeatMap

При работе с API данные часто приходят постепенно:

const apiData = await fetch('/stats');

const nivoData = transform(apiData);

setData(nivoData);

Критично сохранять:

  • стабильность ключей x
  • одинаковую структуру id
  • числовую типизацию y

Ошибки при формировании структуры

Наиболее распространённые проблемы:

  • смешивание типов x (числа + строки)
  • дублирование x внутри одного id
  • отсутствие полного покрытия категорий
  • передача y как строки вместо чисел

Корректный формат всегда строго типизирован по смыслу:

{ x: 'Category', y: 42 }

Сравнение форматов представления

Nested format (основной):

  • оптимален для Nivo
  • прост в рендере
  • легко масштабируется

Flat format:

  • удобен для хранения и API
  • требует трансформации

Matrix format:

  • удобен для аналитики
  • требует pivot-преобразования

Итоговая модель данных HeatMap

Концептуально HeatMap в Nivo опирается на трёхуровневую структуру:

  • группа (id)
  • категория (x)
  • значение (y)

Именно эта модель обеспечивает универсальность визуализации для любых доменных данных — от аналитики продаж до тепловых карт активности пользователей.