setFilter

Назначение и место в архитектуре состояния

setFilter — одно из ключевых действий (actions) в подсистеме visState библиотеки Kepler.gl. Оно отвечает за создание, обновление и синхронизацию фильтров, применяемых к слоям данных.

Фильтры в Kepler.gl являются частью состояния Redux-подобной архитектуры и влияют на отображение данных без изменения исходных датасетов. setFilter работает как декларативный механизм: вместо ручной манипуляции массивами данных задаётся конфигурация фильтра, которую движок визуализации интерпретирует при рендеринге.


Общая сигнатура действия

В типичной реализации действия из vis-state-actions функция setFilter имеет следующую форму:

setFilter(filter)

или в более расширенном виде (внутри внутренних механизмов):

setFilter({
  dataId,
  id,
  name,
  type,
  value,
  domain,
  step,
  view,
  speed,
  enabled,
  animationWindow
})

Фактически действие принимает объект фильтра и либо добавляет его в список фильтров, либо обновляет существующий по id.


Структура объекта фильтра

Фильтр в Kepler.gl представляет собой объект со строго определёнными полями, влияющими на поведение UI и вычисление подмножества данных.

Основные поля

dataId

  • Тип: string | string[]
  • Определяет, к каким датасетам применяется фильтр
  • Поддерживает множественное связывание

id

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

name

  • Человекочитаемое имя
  • Используется в интерфейсе панели фильтров

type

  • Тип фильтра:

    • range — числовой диапазон
    • timeRange — временной диапазон
    • select — выбор одного значения
    • multiSelect — множественный выбор

Диапазон значений и domain/value

Фильтрация всегда опирается на две ключевые структуры:

domain

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

value

  • Текущий активный диапазон или выбранные значения
  • Именно он влияет на отфильтрованный результат

Пример:

domain: [0, 100],
value: [20, 80]

Базовое использование setFilter

Числовой диапазон

dispatch(
  setFilter({
    id: 'speed-filter',
    dataId: 'trips',
    name: 'Speed',
    type: 'range',
    value: [10, 50],
    domain: [0, 120]
  })
)

Такой фильтр ограничивает отображаемые объекты по числовому параметру, например скорости или высоте.


Временной фильтр (timeRange)

dispatch(
  setFilter({
    id: 'time-filter',
    dataId: 'events',
    name: 'Timestamp',
    type: 'timeRange',
    value: [1622505600000, 1625097600000],
    domain: [1622505600000, 1630454400000]
  })
)

Здесь значения задаются в формате Unix timestamp в миллисекундах. Такой фильтр активно используется при работе с потоками событий и маршрутами.


Множественный выбор (multiSelect)

dispatch(
  setFilter({
    id: 'category-filter',
    dataId: 'sales',
    name: 'Category',
    type: 'multiSelect',
    value: ['electronics', 'furniture'],
    domain: ['electronics', 'furniture', 'clothing', 'food']
  })
)

Фильтр пропускает только выбранные категории, исключая остальные.


Поведение при обновлении фильтра

setFilter не только создаёт фильтр, но и обновляет уже существующий при совпадении id.

Механизм работы:

  1. Поиск фильтра в visState.filters
  2. Если найден — происходит merge обновлённых полей
  3. Если не найден — добавление нового элемента в массив
  4. Пересчёт отфильтрованных данных для слоёв

Связь с layers и dataId

Каждый фильтр может быть связан с одним или несколькими датасетами через dataId.

dataId: ['dataset_1', 'dataset_2']

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

При рендеринге Kepler.gl:

  • фильтр проходит по каждому dataset
  • применяется к соответствующему полю слоя
  • результат агрегируется на уровне визуализации

Множественные фильтры и порядок применения

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

  1. Первый фильтр уменьшает пространство данных
  2. Второй фильтр применяется к уже отфильтрованному набору
  3. Результат передаётся в слой визуализации

Пример конфигурации:

[
  {
    id: 'filter-1',
    type: 'range',
    value: [0, 100]
  },
  {
    id: 'filter-2',
    type: 'multiSelect',
    value: ['A', 'B']
  }
]

Анимация фильтров

Фильтры временного типа могут поддерживать анимацию через поле animationWindow.

animationWindow: 'incremental'

или

animationWindow: 'continuous'

Поведение:

  • incremental — шаговое движение по временной шкале
  • continuous — плавное скольжение окна фильтра

Это используется для визуализации потоков данных и динамики событий.


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

При работе с setFilter в больших датасетах ключевым фактором является стоимость пересчёта фильтров.

Особенности:

  • фильтрация выполняется на уровне WebGL/worker pipeline
  • повторные вызовы setFilter могут приводить к перерасчёту всех слоёв
  • оптимизация достигается минимизацией частоты dispatch

Рекомендуемые подходы:

  • избегать частого обновления value в реальном времени
  • использовать дискретные шаги (step)
  • группировать изменения фильтров в один вызов

Поле step и дискретизация

step определяет шаг изменения значения фильтра:

step: 1

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

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

Сложные сценарии использования

Комбинирование временного и числового фильтра

dispatch(setFilter({
  id: 'complex-filter',
  dataId: 'shipments',
  type: 'timeRange',
  value: [start, end],
  domain: [minTime, maxTime],
  step: 3600000
}))

dispatch(setFilter({
  id: 'speed-filter',
  dataId: 'shipments',
  type: 'range',
  value: [5, 40],
  domain: [0, 100]
}))

Такая комбинация позволяет одновременно ограничивать данные по времени и метрикам.


Динамическое обновление фильтра

Часто используется в UI-логике:

function updateRange(min, max) {
  dispatch(setFilter({
    id: 'dynamic-filter',
    dataId: 'points',
    type: 'range',
    value: [min, max]
  }))
}

При каждом вызове фильтр пересчитывает отображаемые точки.


Типичные ошибки при использовании setFilter

Несовпадение dataId

Если dataId не соответствует существующему датасету, фильтр будет создан, но не окажет влияния на визуализацию.


Неверный тип value

  • range требует массив из двух чисел
  • multiSelect требует массив значений
  • select требует одиночное значение

Несоответствие приводит к игнорированию фильтра или ошибкам вычисления.


Потеря синхронизации id

Повторное создание фильтра с другим id вместо обновления существующего приводит к накоплению дубликатов и увеличению нагрузки на рендер.


Внутренний механизм применения фильтра

На уровне исполнения:

  1. setFilter диспатчит action в store
  2. Reducer обновляет visState.filters
  3. Trigger пересчёта filteredIndex
  4. Layers получают обновлённые данные
  5. WebGL обновляет визуализацию

Значение setFilter в общей системе Kepler.gl

setFilter является центральным элементом интерактивной фильтрации данных. Через него реализуются:

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