Общая структура поля transform

Поле transform в Vega-Lite представляет собой декларативный конвейер преобразований данных, который применяется к исходному набору данных до этапа визуального отображения. Каждый элемент массива transform описывает отдельную операцию, а порядок их следования определяет последовательность обработки.

В базовой структуре спецификации Vega-Lite поле transform является массивом объектов:

{
  "data": { "url": "data.csv" },
  "transform": [
    { "...": "..." },
    { "...": "..." }
  ],
  "mark": "line",
  "encoding": { }
}

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

Ключевой принцип — конвейерность: результат каждого преобразования становится входом для следующего.


Порядок выполнения и влияние на результат

Порядок элементов в transform строго определяет вычислительную последовательность:

  1. исходный датасет
  2. первое преобразование
  3. второе преобразование
  4. итоговый набор данных для визуализации

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


Базовая структура отдельного transform-объекта

Каждый элемент массива описывается объектом с одним ключевым типом операции:

{
  "transform": [
    { "filter": "datum.value > 10" },
    { "calculate": "datum.a + datum.b", "as": "sum" }
  ]
}

Особенность Vega-Lite заключается в том, что тип трансформации определяется ключом объекта (filter, calculate, aggregate и т.д.), а не отдельным полем type, как в Vega.


Категории преобразований

Фильтрация данных

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

{ "filter": "datum.sales > 100" }

Условие записывается в выражении Vega Expression Language, где datum представляет текущую запись.


Вычисляемые поля (calculate)

Позволяют создавать новые поля на основе существующих:

{
  "calculate": "datum.price * datum.quantity",
  "as": "revenue"
}

Поле as задаёт имя нового атрибута, добавляемого в поток данных.


Агрегация данных

Агрегация группирует данные и вычисляет статистики:

{
  "aggregate": [
    { "op": "sum", "field": "sales", "as": "total_sales" }
  ],
  "groupby": ["category"]
}

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

  • op — операция (sum, mean, count, min, max)
  • field — исходное поле
  • as — имя результата
  • groupby — поля группировки

Бинирование (bin)

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

{
  "bin": true,
  "field": "age",
  "as": "age_bin"
}

Также возможно явное задание параметров биннинга:

{
  "bin": { "maxbins": 10 },
  "field": "age",
  "as": "age_bin"
}

Работа с временными данными (timeUnit)

Позволяет извлекать компоненты даты:

{
  "timeUnit": "yearmonth",
  "field": "date",
  "as": "year_month"
}

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


Расширение структур данных (flatten)

Применяется для работы с вложенными массивами:

{
  "flatten": ["tags"]
}

Каждый элемент массива превращается в отдельную строку.


Преобразование колонок в строки (fold)

Используется для денормализации таблиц:

{
  "fold": ["Q1", "Q2", "Q3", "Q4"],
  "as": ["quarter", "value"]
}

Обратная операция (pivot)

Преобразует строки в колонки:

{
  "pivot": "quarter",
  "value": "sales",
  "groupby": ["product"]
}

Оконные вычисления (window)

Позволяет выполнять вычисления по скользящим окнам:

{
  "window": [
    { "op": "rank", "as": "rank" }
  ],
  "sort": [{ "field": "sales", "order": "descending" }]
}

Поддерживаются:

  • ранжирование
  • скользящие суммы
  • накопительные значения

Lookup-операции

Позволяют присоединять внешние данные:

{
  "lookup": "id",
  "from": {
    "data": { "url": "table2.csv" },
    "key": "id",
    "fields": ["name"]
  }
}

Комбинирование трансформаций

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

"transform": [
  { "filter": "datum.value != null" },
  { "calculate": "datum.value * 2", "as": "double" },
  { "bin": { "maxbins": 20 }, "field": "double", "as": "binned" },
  {
    "aggregate": [
      { "op": "count", "as": "count" }
    ],
    "groupby": ["binned"]
  }
]

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


Контекст выполнения выражений

Во всех выражениях transform доступен объект datum, представляющий текущую запись, а также стандартные функции Vega Expression Language:

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

Пример:

{ "filter": "datum.score > mean(datum.score)" }

Особенности взаимодействия с encoding

Хотя transform выполняет предобработку, результат напрямую влияет на encoding. Например, вычисляемое поле может стать источником для осей:

"transform": [
  { "calculate": "datum.x * datum.y", "as": "metric" }
],
"encoding": {
  "x": { "field": "metric", "type": "quantitative" }
}

Ограничения и особенности модели

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

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


Отличие подхода Vega-Lite от Vega

В Vega-Lite трансформации декларативно упрощены:

  • нет явного поля type
  • сокращён синтаксис
  • часть логики скрыта за высокоуровневыми операциями

В Vega же трансформации описываются более низкоуровнево:

{
  "type": "filter",
  "expr": "datum.value > 10"
}

Роль transform в архитектуре спецификации

transform занимает промежуточный слой между источником данных и визуальной кодировкой. Его функция заключается в приведении данных к форме, оптимальной для визуального представления:

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

Именно этот слой определяет, какие данные фактически попадут в систему визуальных каналов (x, y, color, size и т.д.).