Загрузка данных

Kepler.gl строит работу с данными вокруг концепции слоёв (layers) и наборов данных (datasets), где каждый dataset представляет собой структурированную таблицу с географическими полями и метаданными. Вся система загрузки данных опирается на единый поток: подготовка данных → парсинг через loaders.gl → преобразование в внутренний формат → регистрация в состоянии приложения через Redux → связывание с визуальными слоями.

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

  • datasets — коллекция загруженных наборов данных
  • dataId — уникальный идентификатор каждого набора
  • rows / fields — строки и описание столбцов
  • columns metadata — типизация и географические признаки

Каждый dataset после загрузки получает структурированное представление, пригодное для быстрого рендеринга WebGL-слоёв.

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


Форматы данных и поддерживаемые источники

Kepler.gl поддерживает несколько типов входных данных, каждый из которых обрабатывается через соответствующие парсеры из loaders.gl.

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

  • CSV (табличные данные)
  • GeoJSON (географические объекты)
  • JSON (структурированные данные)
  • Arrow (колоночный формат для высокопроизводительной загрузки)
  • Custom object arrays (JavaScript-массивы объектов)

CSV остаётся наиболее распространённым вариантом, поскольку он легко интегрируется с внешними системами аналитики.

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


Базовый механизм загрузки через addDataToMap

Центральный механизм добавления данных в Kepler.gl — action addDataToMap. Он передаёт данные в reducer, где происходит их нормализация и включение в состояние приложения.

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

const dataset = {
  data: [
    {lat: 59.93, lng: 30.33, name: 'Point A'},
    {lat: 59.94, lng: 30.35, name: 'Point B'}
  ],
  info: {
    id: 'sample_dataset',
    label: 'Sample Data'
  }
};

dispatch(addDataToMap({
  datasets: dataset
}));

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

  1. Определение типа входных данных
  2. Запуск соответствующего loader-а
  3. Преобразование строк/объектов в табличную структуру
  4. Генерация metadata (тип колонок, география)
  5. Сохранение результата в store

Работа с CSV данными

CSV обрабатывается через встроенный CSVLoader из @loaders.gl/csv. Данные могут поступать как строка или файл.

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

const csvData = `
lat,lng,value
59.93,30.33,10
59.94,30.35,20
`;

dispatch(addDataToMap({
  datasets: {
    info: {
      id: 'csv_dataset',
      label: 'CSV Dataset'
    },
    data: csvData
  }
}));

Во время парсинга:

  • первая строка определяется как header
  • происходит автоматическое определение типов (number, string, timestamp)
  • колонки lat/lng распознаются как географические координаты

Особенность Kepler.gl заключается в автоматическом inference гео-полей, что позволяет минимизировать ручную настройку.


Загрузка GeoJSON

GeoJSON обрабатывается как структурированная геометрия. В отличие от CSV, здесь уже присутствует пространственная модель.

const geojsonData = {
  type: 'FeatureCollection',
  features: [
    {
      type: 'Feature',
      geometry: {
        type: 'Point',
        coordinates: [30.33, 59.93]
      },
      properties: {
        name: 'Point A'
      }
    }
  ]
};

dispatch(addDataToMap({
  datasets: {
    info: {
      id: 'geo_dataset',
      label: 'GeoJSON Dataset'
    },
    data: geojsonData
  }
}));

Внутренне происходит трансформация:

  • geometry извлекается в отдельные поля
  • создаются derived columns (lat/lng для Point)
  • сохраняется оригинальная структура для polygon/line rendering

GeoJSON является основой для таких слоёв, как polygon layer, line layer и arc layer.


Механизм loaders.gl и автоматическое определение типа

Kepler.gl использует loaders.gl как слой абстракции над форматами данных. Это позволяет унифицировать загрузку независимо от источника.

Пример логики:

  • если data — строка → CSVLoader
  • если data — объект с type: FeatureCollection → GeoJSONLoader
  • если data — массив объектов → JSON normalizer

Внутренний pipeline можно представить так:

raw input → loader selection → parse → normalize → enrich metadata → store

Metadata включает:

  • detectedType (quantitative / categorical / timestamp)
  • geoColumns (lat/lng, geometry)
  • field statistics (min, max, unique values)

Загрузка нескольких наборов данных

Kepler.gl поддерживает одновременную работу с несколькими datasets. Каждый из них изолирован по dataId, но может использоваться в одном или нескольких слоях.

dispatch(addDataToMap({
  datasets: [
    {
      info: {
        id: 'dataset_1',
        label: 'Cities'
      },
      data: citiesData
    },
    {
      info: {
        id: 'dataset_2',
        label: 'Routes'
      },
      data: routesData
    }
  ]
}));

При этом:

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

Нормализация и schema inference

После загрузки Kepler.gl строит schema — описание структуры данных.

Каждое поле получает:

  • name
  • type (real, integer, string, timestamp)
  • format hints
  • domain (min/max)

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

{
  fields: [
    {name: "lat", type: "real"},
    {name: "lng", type: "real"},
    {name: "value", type: "integer"}
  ]
}

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

  • построения UI фильтров
  • настройки визуальных каналов (color, size)
  • оптимизации рендеринга

Асинхронная загрузка данных

В реальных приложениях данные часто приходят с сервера. Kepler.gl допускает загрузку через async pipeline.

async function loadData() {
  const response = await fetch('/api/data');
  const json = await response.json();

  dispatch(addDataToMap({
    datasets: {
      info: {
        id: 'remote_data',
        label: 'Remote Dataset'
      },
      data: json
    }
  }));
}

При этом важно учитывать:

  • загрузка происходит вне Kepler.gl core
  • библиотека не управляет сетью
  • ответственность за кеширование лежит на приложении

Интеграция с Redux store

Kepler.gl полностью интегрирован в Redux через keplerGlReducer. Данные попадают в state следующим образом:

state.keplerGl.map.datasets

Каждый dispatch addDataToMap вызывает reducer, который:

  1. валидирует payload
  2. вызывает data processing pipeline
  3. обновляет datasets
  4. триггерит пересчёт слоёв

Пример подключения reducer:

import keplerGlReducer from 'kepler.gl/reducers';

const reducers = combineReducers({
  keplerGl: keplerGlReducer
});

Оптимизация загрузки больших данных

При работе с большими наборами данных (сотни тысяч строк) критичны следующие аспекты:

1. Columnar processing

  • предпочтение Arrow формату
  • минимизация row-based parsing

2. Lazy evaluation

  • данные не полностью копируются в UI state
  • часть вычислений откладывается до рендеринга слоя

3. Typed arrays

  • числовые поля переводятся в Float32Array / Int32Array

4. Memoization schema

  • повторный парсинг избегается при неизменных данных

Частые ошибки при загрузке данных

Несоответствие координат

  • перепутаны lat/lng
  • используются строки вместо чисел

Неверная структура GeoJSON

  • отсутствует FeatureCollection
  • geometry не соответствует стандарту

Дублирование dataId

  • приводит к перезаписи dataset

Смешение типов в колонках

  • снижает точность inference
  • ломает фильтры и агрегации

Преобразования данных на этапе загрузки

Kepler.gl может выполнять предварительные трансформации:

  • агрегация по гео-ячейкам
  • нормализация числовых значений
  • вычисление производных полей
  • timestamp parsing

Пример: строка даты автоматически преобразуется в UNIX timestamp для ускорения фильтрации.


Внутренний поток данных

Полный путь данных в Kepler.gl можно описать следующим образом:

Input Data
   ↓
Loader Selection (CSV / GeoJSON / JSON / Arrow)
   ↓
Parsing (loaders.gl)
   ↓
Normalization (table schema creation)
   ↓
Metadata enrichment (types, domains, geo detection)
   ↓
Redux store (datasets state)
   ↓
Layer binding (visualization)
   ↓
WebGL rendering (deck.gl layers)

Каждый этап строго разделён, что обеспечивает масштабируемость и предсказуемость поведения при работе с различными источниками данных.