Категориальные фильтры

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

Категориальная фильтрация в Kepler.gl встроена в систему фильтров слоя и описывается через конфигурационный объект фильтра, который применяется к конкретному набору данных (dataId) и полю таблицы.

Основная задача категориального фильтра — включать или исключать элементы набора данных на основе выбранных значений списка категорий, формируя подмножество данных, передаваемое дальше в визуализационный pipeline deck.gl.


Каждый фильтр в Kepler.gl хранится как объект внутри массива filters в конфигурации состояния приложения. Для категориальной фильтрации используется тип categorical.

Типовая структура:

{
  dataId: ['dataset_1'],
  id: 'filter_1',
  name: 'country',
  type: 'categorical',
  column: {
    name: 'country',
    fieldIdx: 3
  },
  value: ['Kazakhstan', 'Russia'],
  enlarged: true
}

Ключевые элементы:

  • dataId — идентификатор набора данных, к которому применяется фильтр
  • name / column.name — имя поля, по которому выполняется фильтрация
  • type: ‘categorical’ — указание типа фильтра
  • value — массив выбранных категорий
  • fieldIdx — индекс столбца в таблице данных
  • enlarged — флаг отображения расширенного режима UI (в некоторых версиях используется для панели фильтра)

Принцип работы категориального фильтра

Категориальный фильтр выполняет операцию проверки принадлежности значения поля к списку разрешённых значений. На уровне логики это эквивалентно операции:

value ∈ selectedCategories

Если значение строки из датасета содержится в массиве value, объект проходит фильтрацию и попадает в результирующий слой визуализации.

В противном случае запись исключается до этапа рендеринга.


Связь с deck.gl и FilterExtension

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

В отличие от числовых фильтров (range filters), которые используют GPU-ускорение через shader-based filtering, категориальные фильтры чаще применяются как CPU-based предобработка.

Поток обработки выглядит следующим образом:

  1. Исходный dataset загружается в Kepler.gl
  2. Применяются активные фильтры состояния
  3. Категориальные фильтры выполняют фильтрацию массива объектов
  4. Результат передаётся в deck.gl layer
  5. Отрисовка происходит только для прошедших объектов

Режимы выбора категорий

Категориальные фильтры поддерживают несколько режимов поведения интерфейса, которые отражаются в конфигурации:

Множественный выбор (multi-select)

Наиболее распространённый режим, при котором пользователь может выбрать несколько категорий одновременно.

value: ['A', 'B', 'C']

Логика:

value IN ['A', 'B', 'C']

Этот режим используется для анализа распределения объектов по группам.


Единичный выбор (single-select)

В некоторых конфигурациях фильтр ограничивается одной категорией:

value: ['A']

Используется для жёсткой сегментации данных.


Формирование домена категорий

Перед отображением фильтра Kepler.gl формирует список всех возможных категорий, присутствующих в столбце данных. Этот список называется domain.

Пример:

domain: ['Kazakhstan', 'Russia', 'China', 'USA']

Домен используется для:

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

При изменении датасета domain пересчитывается автоматически.


UI-поведение категориального фильтра

В интерфейсе Kepler.gl категориальный фильтр представлен как список чекбоксов. Каждое значение domain отображается как отдельный элемент управления.

Поведенческие особенности:

  • выбор чекбокса добавляет значение в value
  • снятие чекбокса удаляет значение
  • пустой value может означать отсутствие фильтрации или исключение всех объектов (в зависимости от конфигурации)
  • массовые операции “Select all / Clear all” управляют массивом целиком

UI синхронизирован с глобальным состоянием Redux, где хранится конфигурация всех фильтров.


Взаимодействие с состоянием Kepler.gl

В архитектуре Kepler.gl фильтры являются частью глобального состояния visState.

Упрощённая структура:

visState: {
  filters: [
    {
      id: 'filter_1',
      type: 'categorical',
      value: ['A', 'B']
    }
  ]
}

Изменения фильтра происходят через actions:

  • addFilter
  • updateFilter
  • removeFilter

Пример обновления:

dispatch(updateFilter({
  id: 'filter_1',
  value: ['Kazakhstan', 'USA']
}));

После обновления состояния автоматически пересчитываются слои и данные.


Обработка строковых значений

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

Проблемные случаи:

  • различие регистра (USA vs usa)
  • лишние пробелы ("Kazakhstan " vs "Kazakhstan")
  • null/undefined значения
  • смешанные типы данных

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

value = String(value).trim().toLowerCase()

И аналогичная нормализация domain и filter values.


Производительность категориальной фильтрации

Хотя категориальные фильтры не используют GPU-ускорение напрямую, их производительность зависит от:

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

Основные узкие места:

  • пересчёт фильтра при каждом изменении UI
  • копирование больших массивов объектов
  • повторная агрегация данных для слоёв

Оптимизации:

  • кэширование domain
  • мемоизация отфильтрованных наборов
  • использование индексированных структур (Map вместо Array includes)
  • предвычисление категорийных индексов

Индексная фильтрация

Для ускорения операций Kepler.gl может использовать индекс категорий:

{
  'Kazakhstan': [0, 5, 9],
  'USA': [1, 2, 7]
}

Тогда фильтрация сводится к объединению индексов выбранных категорий вместо полного перебора данных.

Это особенно эффективно при больших наборах данных с повторяющимися значениями.


Влияние на слои визуализации

Категориальные фильтры применяются ко всем слоям, которые используют соответствующий dataId.

Это означает:

  • один фильтр может влиять на несколько слоёв
  • слой не имеет собственного состояния фильтрации категорий
  • фильтрация происходит до построения геометрии

Примеры слоёв:

  • Point Layer
  • Arc Layer
  • Hexagon Layer
  • GeoJSON Layer

Все они получают уже отфильтрованный набор данных.


Комбинация с другими типами фильтров

Категориальные фильтры часто используются совместно с:

  • числовыми range-фильтрами (например, год или значение)
  • временными фильтрами (time range)
  • логическими условиями включения/исключения

Комбинированная логика строится как пересечение множеств:

Result = Categorical ∩ Range ∩ Time

Порядок применения фильтров может влиять на производительность, но не на итоговую семантику результата.


Динамическое обновление категорий

При изменении данных Kepler.gl пересчитывает доступные категории. Это важно при:

  • подгрузке новых файлов
  • изменении API-ответов
  • фильтрации уже отфильтрованных данных

Если новые данные содержат дополнительные категории, они автоматически добавляются в domain и становятся доступными в UI без ручной настройки.


Поведение при пустых значениях

Особое внимание требуется обработке null, undefined и пустых строк.

Типичные стратегии:

  • игнорирование значений (исключение из domain)
  • добавление категории Unknown
  • явная обработка как отдельной категории

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


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

Категориальные фильтры позволяют решать задачи сегментации данных:

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

Их ценность проявляется в интерактивной работе с картографическими и пространственными наборами данных, где важна не числовая агрегация, а логическое разделение объектов по признакам.