updateVisData

updateVisData — это действие уровня visState в экосистеме Kepler.gl, предназначенное для обновления уже загруженного набора данных без полной перезагрузки визуализации и без пересоздания всех слоёв с нуля. Его ключевая задача — модифицировать данные карты (datasets) так, чтобы существующие слои, фильтры и конфигурации продолжили работать, но при этом получили обновлённый источник значений.

Kepler.gl построен на архитектуре Redux, где состояние визуализации разделено на несколько ключевых срезов:

  • visState — данные, слои, фильтры, interaction состояния
  • mapState — положение камеры, zoom, bearing, pitch
  • uiState — интерфейсные настройки

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

Главная особенность этого действия — оно не просто заменяет данные, а пытается аккуратно обновить существующие датасеты по dataId.


Когда используется updateVisData

Использование updateVisData оправдано в сценариях, где:

  • поток данных обновляется в реальном времени (WebSocket, polling)
  • необходимо обновить значения точек без пересоздания слоёв
  • структура данных остаётся стабильной (те же поля, тот же dataId)
  • важно сохранить фильтры и визуальные настройки

Типичный кейс — трекинг объектов (транспорт, пользователи, IoT-устройства), где координаты обновляются каждую секунду.


Сигнатура и структура данных

В Kepler.gl обновление данных происходит через action creator:

import {updateVisData} from 'kepler.gl/actions';

Основная форма данных, передаваемых в updateVisData, выглядит так:

const dataset = {
  data: [
    {lat: 40.7, lng: -73.9, speed: 12},
    {lat: 40.8, lng: -73.95, speed: 20}
  ],
  info: {
    id: 'my_dataset'
  }
};

И затем:

dispatch(updateVisData(dataset));

Важный принцип: идентичность dataId

Критически важный момент — совпадение dataId:

  • если info.id совпадает с уже загруженным dataset
  • Kepler.gl обновляет существующий набор данных
  • слои автоматически продолжают использовать новые значения

Если dataId отличается — создаётся новый dataset, а не обновляется существующий.


Внутренняя логика обновления

При вызове updateVisData происходит несколько этапов:

  1. Поиск существующего dataset в visState.datasets

  2. Сопоставление по info.id

  3. Замена массива data

  4. Пересчёт производных структур:

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

Важно, что Kepler.gl старается минимизировать пересоздание объектов, чтобы сохранить производительность при больших данных.


Отличие от addDataToMap

Часто updateVisData путают с addDataToMap, но их поведение принципиально различается.

addDataToMap

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

updateVisData

  • обновляет уже существующий dataset
  • не пересоздаёт слои
  • сохраняет UI и фильтры

Отличие от loadDataToMap

loadDataToMap — более высокий уровень абстракции:

  • загружает данные
  • может применять конфигурацию
  • может создавать mapState, layers, filters

updateVisData — низкоуровневое обновление данных без вмешательства в конфигурацию карты.


React-интеграция KeplerGl

В типичном React-приложении Kepler.gl используется через компонент KeplerGl:

import KeplerGl from 'kepler.gl';
import {useDispatch} from 'react-redux';
import {updateVisData} from 'kepler.gl/actions';

Пример контейнера:

function MapContainer() {
  const dispatch = useDispatch();

  const updateData = (newData) => {
    dispatch(updateVisData({
      data: newData,
      info: {
        id: 'my_dataset'
      }
    }));
  };

  return (
    <KeplerGl
      id="map"
      width={window.innerWidth}
      height={window.innerHeight}
    />
  );
}

Обновление данных в реальном времени

Один из самых частых сценариев — потоковые данные.

setInterval(() => {
  const updatedData = generateNewPoints();

  dispatch(updateVisData({
    data: updatedData,
    info: {
      id: 'realtime_points'
    }
  }));
}, 1000);

В этом случае Kepler.gl:

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

Поведение слоёв при обновлении данных

Слои в Kepler.gl привязаны к dataId. При вызове updateVisData:

  • слой не пересоздаётся

  • обновляется только его data reference

  • сохраняются:

    • стили
    • фильтры слоя
    • настройки интеракции

Однако есть важное ограничение: если структура данных изменилась (например, удалены или переименованы поля), слои могут потерять привязку к колонкам.


Требования к структуре данных

Чтобы обновление прошло корректно:

  • количество колонок должно быть стабильным
  • названия полей должны совпадать
  • типы данных должны сохраняться
  • dataId должен быть постоянным

Нарушение этих условий приводит к:

  • некорректному отображению слоёв
  • сбросу фильтров
  • ошибкам типизации внутри Kepler.gl selectors

Производительность и большие данные

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

Причины:

  • пересчёт типов колонок
  • обновление индексных структур
  • перерасчёт фильтров

Практика оптимизации:

  • предварительная агрегация данных до dispatch
  • обновление только изменившихся сегментов
  • использование батчинга обновлений
  • уменьшение частоты вызова (debounce/throttle)

Частичная иммутабельность

Kepler.gl ожидает иммутабельное обновление состояния. Это означает:

  • нельзя мутировать исходный dataset
  • всегда создаётся новый объект data
  • Redux сравнивает ссылки, а не глубокие структуры

Пример неправильного подхода:

dataset.data.push(newPoint); // недопустимо
dispatch(updateVisData(dataset));

Правильный подход:

const newDataset = {
  ...dataset,
  data: [...dataset.data, newPoint]
};

dispatch(updateVisData(newDataset));

Сценарии с несколькими datasets

Если в карте используется несколько источников данных:

{
  info: {id: 'vehicles'},
  data: [...]
}

{
  info: {id: 'stations'},
  data: [...]
}

updateVisData может применяться выборочно:

dispatch(updateVisData({
  data: updatedVehicles,
  info: {id: 'vehicles'}
}));

При этом остальные datasets остаются неизменными.


Синхронизация с фильтрами

Фильтры в Kepler.gl привязаны к колонкам dataset. При обновлении данных:

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

Особенно чувствительны:

  • timestamp поля
  • string enums
  • географические координаты

Ошибки и диагностика

Типичные проблемы при использовании updateVisData:

1. Dataset не обновляется

  • причина: несовпадение dataId

2. Слои пустые после обновления

  • причина: изменена структура колонок

3. Фильтры сброшены

  • причина: изменение типов данных

4. Производительность резко падает

  • причина: слишком частые обновления или слишком большой payload

Рекомендации по стабильной архитектуре обновлений

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

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

Модель поведения в сложных приложениях

В продвинутых системах Kepler.gl часто используется как визуальный слой поверх потоковой аналитики:

  • Kafka / WebSocket → нормализация данных → updateVisData
  • backend агрегация → фронтенд визуализация
  • временные окна (sliding window) обновляют dataset целиком

В таких архитектурах updateVisData становится центральным механизмом синхронизации состояния карты с внешним миром данных.