Компонент Stream: стековые потоки

Компонент Stream из набора визуализаций Nivo предназначен для отображения многослойных временных или категориальных потоков данных, где каждая серия представляет вклад в общую изменяющуюся величину. В отличие от классической stacked area диаграммы, Stream делает акцент не на абсолютных значениях, а на форме распределения и динамике долей между категориями.

Основная идея заключается в визуализации «течения» данных, где каждая категория представлена слоем, а суммарная форма может быть нормализована различными алгоритмами смещения (offsets), создающими характерные волнообразные структуры.


Формат данных и структура входных значений

Данные для Stream строятся в виде массива объектов, где каждый объект представляет точку по оси X, а свойства объекта — значения категорий.

Пример структуры:

const data = [
  {
    day: '2024-01-01',
    cats: 120,
    dogs: 80,
    birds: 50
  },
  {
    day: '2024-01-02',
    cats: 150,
    dogs: 60,
    birds: 40
  }
];

Ключевые параметры:

  • indexBy — поле, задающее ось X (в примере: day)
  • keys — массив ключей категорий (cats, dogs, birds)

Базовая конфигурация компонента

Stream реализуется через @nivo/stream и используется как React-компонент:

import { ResponsiveStream } from '@nivo/stream';

const MyStream = ({ data }) => (
  <ResponsiveStream
    data={data}
    keys={['cats', 'dogs', 'birds']}
    indexBy="day"
    margin={{ top: 50, right: 110, bottom: 50, left: 60 }}
  />
);

Компонент автоматически рассчитывает слои и применяет выбранный алгоритм нормализации.


Алгоритмы смещения (offsets)

Одна из ключевых особенностей Stream — различные режимы распределения слоёв.

wiggle

Минимизирует «дрожание» слоёв, создавая плавную органическую форму.

Используется для:

  • визуализации трендов
  • художественных графиков
  • анализа долей

expand

Нормализует данные так, что сумма всех слоёв всегда равна 100%.

offset: 'expand'

Применение:

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

none

Обычное накопительное сложение без нормализации.

Используется редко, так как теряется визуальная «потоковость».

silhouette

Центрирует слои вокруг нулевой линии, создавая симметричную форму.


Настройка внешнего вида слоёв

Stream позволяет управлять стилем каждого слоя через свойства:

<ResponsiveStream
  data={data}
  keys={['cats', 'dogs', 'birds']}
  offset="wiggle"
  curve="catmullRom"
  areaOpacity={0.85}
  borderWidth={1}
  borderColor={{ from: 'color', modifiers: [['darker', 0.3]] }}
/>

Ключевые параметры:

  • areaOpacity — прозрачность слоёв
  • borderWidth — толщина границ
  • borderColor — цвет обводки
  • enableStackTooltip — включение общей подсказки по стеку

Кривые интерполяции

Форма потоков определяется параметром curve.

Наиболее используемые варианты:

  • catmullRom — плавные естественные линии
  • basis — сглаженные кривые без острых углов
  • linear — прямолинейные переходы
  • monotoneX — стабильная форма без колебаний

Пример:

curve="monotoneX"

Выбор кривой напрямую влияет на восприятие динамики данных.


Цветовые схемы и идентификация слоёв

Stream активно использует цветовое разделение категорий.

colors={{ scheme: 'nivo' }}

Также возможно задание кастомной функции:

colors={(serie) => {
  if (serie.id === 'cats') return '#ff6b6b';
  if (serie.id === 'dogs') return '#4dabf7';
  return '#51cf66';
}}

Особенность Stream заключается в том, что цвет слоя сохраняется вдоль всей его длины, обеспечивая визуальную непрерывность.


Оси координат и масштабирование

Stream поддерживает стандартные оси Nivo:

axisBottom={{
  tickSize: 5,
  tickPadding: 5,
  tickRotation: -45
}}
axisLeft={{
  tickSize: 5,
  tickPadding: 5
}}

При использовании expand значения оси Y преобразуются в диапазон от 0 до 1, что требует корректного форматирования меток:

axisLeft={{
  format: v => `${Math.round(v * 100)}%`
}}

Интерактивность и tooltips

Stream предоставляет детализированные всплывающие подсказки, содержащие информацию о каждом слое.

tooltip={({ stack }) => (
  <div>
    <strong>{stack.id}</strong>: {stack.value}
  </div>
)}

Доступные данные в tooltip:

  • идентификатор серии
  • значение в точке
  • индекс по оси X
  • нормализованное значение (в режиме expand)

Легенды и идентификация серий

Добавление легенды повышает читаемость графика:

legends={[
  {
    anchor: 'right',
    direction: 'column',
    translateX: 100,
    itemWidth: 80,
    itemHeight: 20,
    symbolSize: 12
  }
]}

Легенды особенно важны при большом количестве ключей, так как Stream может содержать десятки слоёв.


Анимации и переходы состояния

Stream включает встроенную систему плавных переходов:

animate={true}
motionConfig="stiff"

Основные параметры:

  • motionConfig — скорость и характер анимации
  • animate — включение/отключение переходов

При изменении данных слои перерассчитываются с плавным перераспределением формы.


Поведение при изменении данных

Stream чувствителен к:

  • добавлению новых ключей
  • изменению порядка keys
  • пропущенным значениям (undefined/null)
  • изменению диапазона значений

При отсутствии значения в точке рекомендуется явно указывать 0, чтобы избежать разрывов в слоях.


Паттерны и визуальные текстуры

Для повышения различимости слоёв можно использовать паттерны:

patterns={[
  {
    id: 'dots',
    type: 'dots',
    background: 'inherit',
    color: 'rgba(255,255,255,0.3)',
    size: 4
  }
]}

Применение:

fill={[
  { match: { id: 'cats' }, id: 'dots' }
]}

Паттерны полезны при печати и при дальтонической адаптации интерфейсов.


Производительность и оптимизация

Stream относится к визуализациям средней сложности. Основные факторы нагрузки:

  • количество точек по оси X
  • количество ключей (слоёв)
  • включённые анимации
  • сложные кастомные tooltip

Рекомендации:

  • ограничивать количество ключей до разумных значений (до 10–15)
  • избегать частого полного пересоздания массива data
  • использовать мемоизацию данных
  • отключать анимации при больших наборах

Типичные сценарии использования

Stream применяется в задачах, где важна структура распределения:

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

Особенность формата заключается в том, что он подчёркивает не абсолютные значения, а динамику относительных вкладов.


Отличие от stacked area

Несмотря на внешнее сходство, Stream отличается фундаментально:

  • stacked area фиксирует базовую ось (0)
  • Stream смещает базу для визуального баланса формы
  • stacked area ориентирован на точные значения
  • Stream ориентирован на визуальное восприятие структуры

Это делает Stream менее точным, но более выразительным в задачах анализа трендов распределения.