Поле react: условное реагирование

Поле react в декларативных спецификациях Vega и Vega-Lite используется как механизм описания условной реактивности: изменения одних данных, параметров или сигналов автоматически пересчитывают связанные визуальные элементы без ручного управления состоянием. В отличие от императивных подходов, где разработчик явно вызывает обновление графика, здесь система строит граф зависимостей и выполняет пересчёт только затронутых узлов.

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

Поле react описывает:

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

Реактивность в Vega-Lite работает на двух уровнях:

  1. Данные и трансформации — пересчёт фильтров, агрегаций, сортировок
  2. Визуальное кодирование — изменение свойств mark, encoding и scale

Базовая структура поля react

Типовая форма описания реактивного поведения:

{
  data: { ... },
  mark: "bar",
  encoding: {
    x: { field: "category", type: "nominal" },
    y: { field: "value", type: "quantitative" }
  },
  react: {
    trigger: ["selection", "parameter", "dataChange"],
    conditions: [
      {
        when: "selection.active == true",
        apply: {
          encoding: {
            color: { value: "orange" },
            opacity: { value: 1 }
          }
        }
      }
    ],
    otherwise: {
      encoding: {
        color: { value: "steelblue" },
        opacity: { value: 0.7 }
      }
    }
  }
}

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

  • trigger — источники реактивных изменений
  • conditions — список правил
  • apply — изменения при выполнении условия
  • otherwise — поведение по умолчанию

Условия и предикаты

Условная логика в react строится на выражениях, аналогичных Vega expression language. Чаще всего используются:

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

Пример с числовым условием:

react: {
  trigger: ["parameter"],
  conditions: [
    {
      when: "datum.value > threshold",
      apply: {
        encoding: {
          color: { value: "red" }
        }
      }
    }
  ]
}

Здесь threshold — реактивный параметр, изменение которого автоматически приводит к пересчёту цветового кодирования.

Связь react и selection

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

selection: {
  brush: {
    type: "interval"
  }
},

react: {
  trigger: ["selection"],
  conditions: [
    {
      when: "brush",
      apply: {
        encoding: {
          opacity: { value: 1 }
        }
      }
    }
  ],
  otherwise: {
    encoding: {
      opacity: { value: 0.2 }
    }
  }
}

Механизм работает следующим образом:

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

Реакция на изменение данных

Поле react также применяется к динамическим потокам данных. Это особенно важно в сценариях потоковой визуализации.

react: {
  trigger: ["dataChange"],
  conditions: [
    {
      when: "length(data) > 100",
      apply: {
        transform: [
          { type: "window", sort: "time" }
        ]
      }
    }
  ]
}

Здесь реактивность используется для адаптивного управления объёмом данных: при превышении порога включается оконная трансформация.

Приоритеты и порядок вычислений

При наличии нескольких условий система применяет их в порядке объявления. Конфликтующие изменения разрешаются через правило приоритета:

  1. explicit user interaction (selection, parameter)
  2. data-driven triggers
  3. derived transformations

Если несколько условий одновременно истинны, применяется последнее совпавшее правило, либо происходит объединение свойств при совместимых изменениях.

Вложенная реактивность

react может быть вложенным внутри слоёв (layered charts), что позволяет создавать сложные зависимости между визуальными компонентами.

layer: [
  {
    mark: "line",
    encoding: {
      x: { field: "time" },
      y: { field: "value" }
    }
  },
  {
    mark: "point",
    react: {
      trigger: ["selection"],
      conditions: [
        {
          when: "brush",
          apply: {
            encoding: {
              size: { value: 80 }
            }
          }
        }
      ]
    }
  }
]

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

Реактивные выражения и вычисляемые поля

Часто react комбинируется с вычисляемыми выражениями:

react: {
  trigger: ["parameter"],
  conditions: [
    {
      when: "datum.value * scaleFactor > 50",
      apply: {
        encoding: {
          color: { value: "green" }
        }
      }
    }
  ]
}

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

Интеграция с параметрами (params)

Параметры выступают основным источником реактивности:

params: [
  {
    name: "threshold",
    value: 10
  }
],

react: {
  trigger: ["parameter"],
  conditions: [
    {
      when: "datum.value > threshold",
      apply: {
        encoding: {
          opacity: { value: 1 }
        }
      }
    }
  ]
}

Изменение threshold приводит к немедленной перестройке визуального слоя без пересоздания графика.

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

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

  • кэширование промежуточных трансформаций
  • локализацию пересчёта (dirty propagation)
  • батчинг обновлений при множественных триггерах

Это позволяет поддерживать интерактивность даже при больших наборах данных.

Ограничения реактивных условий

При проектировании спецификаций важно учитывать:

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

Поэтому реактивные правила обычно проектируются с минимальным количеством зависимостей и максимально явной логикой условий.

Композиция реактивных правил

Несколько блоков react могут работать совместно, формируя слоистую логику поведения:

react: {
  trigger: ["selection"],
  conditions: [ ... ]
},

react: {
  trigger: ["parameter"],
  conditions: [ ... ]
}

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