Функция datum и parent

datum представляет собой базовый контекст данных в выражениях Vega и Vega-Lite. В момент вычисления каждого визуального элемента доступ к текущей записи данных осуществляется через объект datum. Это универсальная точка входа к полям строки данных, независимо от того, используется ли mark, transform или событие взаимодействия.

В типичной визуализации каждый графический примитив (точка, прямоугольник, линия) связан с одной записью входного набора данных. Именно эта запись и попадает в datum. Доступ к значениям осуществляется через точечную нотацию:

datum.value
datum.category
datum.x
datum.y

datum не является копией исходного объекта в классическом смысле — это контекст, который формируется на этапе вычисления сцены Vega. Он может включать дополнительные поля, добавленные трансформациями (filter, calculate, aggregate, window и другие).

В выражениях Vega datum доступен в следующих контекстах:

  • encode блоки marks (enter, update, exit)
  • signal expressions при взаимодействии
  • transform calculate expressions
  • scale и axis callbacks (в ограниченном виде через события)
  • tooltip и hover логика

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

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

{
  "category": "A",
  "count": 42
}

parent как контекст вложенных структур

parent используется в сценариях, где данные имеют иерархическую или вложенную структуру. В отличие от datum, который всегда указывает на текущий элемент, parent предоставляет доступ к родительской записи в иерархии.

Наиболее характерные случаи появления parent:

  • facet-композиции в Vega-Lite
  • вложенные transform (nesting)
  • иерархические структуры (tree, treemap, partition)
  • сводные представления (groupby внутри групп)

Если datum относится к элементу нижнего уровня, parent ссылается на объект уровня выше.

Пример иерархии:

parent (категория)
 └── datum (элемент внутри категории)

В выражениях это выглядит следующим образом:

datum.value
parent.category
parent.total

Различие datum и parent

Ключевое различие заключается в уровне иерархии данных:

  • datum — текущий элемент визуализации
  • parent — родительский элемент в группировке или дереве

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

Вложенные визуализации формируют несколько уровней контекста:

  1. datum — точечный элемент (например, бар в группе)
  2. parent — группа (например, категория)
  3. parent.parent — более высокий уровень иерархии (в глубоких структурах)

Применение datum в вычисляемых выражениях

datum активно используется в выражениях calculate для создания новых полей:

{
  "type": "formula",
  "as": "scaledValue",
  "expr": "datum.value * 10"
}

Также datum используется в логике условного форматирования:

datum.value > 100 ? 'high' : 'low'

или в визуальных свойствах:

"fill": {
  "signal": "datum.value > 50 ? 'red' : 'blue'"
}

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


Использование parent в facet-композициях Vega-Lite

В Vega-Lite facet создаёт подграфики на основе группировки данных. После компиляции Vega формирует структуру, где каждая панель имеет parent-контекст.

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

{
  "facet": {
    "row": {"field": "category", "type": "nominal"}
  },
  "spec": {
    "mark": "bar",
    "encoding": {
      "x": {"field": "subCategory", "type": "nominal"},
      "y": {"field": "value", "type": "quantitative"}
    }
  }
}

После компиляции:

  • parent.category доступен на уровне панели
  • datum.value доступен на уровне столбца внутри панели

Это позволяет строить выражения, которые зависят от группы:

datum.value / parent.total

Иерархические визуализации и parent

В структурах типа tree, treemap или sunburst parent играет ключевую роль.

В Vega transform tree структура данных формируется как узлы с ссылками на родителей:

datum.name
datum.value
parent.name
parent.depth

Пример использования:

datum.value / parent.value

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


Поведение при отсутствии parent

Если визуализация не использует иерархию, parent:

  • отсутствует
  • равен undefined
  • не участвует в scope выражения

Попытка обращения к parent.value в плоской структуре приводит к неопределённому результату выражения. В Vega это обычно обрабатывается через условные конструкции:

parent ? parent.value : 0

или:

isValid(parent) ? parent.value : datum.value

Взаимодействие datum и signals

datum часто используется внутри signal expressions, особенно в событиях:

{
  "signals": [
    {
      "name": "hoverValue",
      "on": [
        {
          "events": "@bar:mouseover",
          "update": "datum.value"
        }
      ]
    }
  ]
}

Здесь datum относится к элементу, над которым произошло событие.

parent в событиях используется реже, но становится важным в facet-графиках, где событие может происходить внутри панели.


datum в трансформациях calculate и filter

В transform pipeline datum представляет промежуточное состояние данных:

{
  "transform": [
    {
      "filter": "datum.value > 10"
    },
    {
      "calculate": "datum.value + 5",
      "as": "adjusted"
    }
  ]
}

Каждый этап трансформации переопределяет datum, добавляя или изменяя поля.

parent в трансформациях обычно появляется только после группировки:

{
  "transform": [
    {
      "aggregate": [
        {"op": "sum", "field": "value", "as": "total"}
      ],
      "groupby": ["category"]
    }
  ]
}

После этого category становится parent-контекстом для агрегированных datum.


datum и parent в выражениях масштаба и геометрии

В mark encoding datum часто используется для позиционирования:

"x": {"signal": "datum.x"}
"y": {"signal": "height - datum.y"}

В иерархических графиках parent может задавать базовый уровень:

datum.y0 + datum.y1 / 2

или относительное позиционирование:

datum.x + parent.offset

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

Нормализация внутри группы

datum.value / parent.sum

Сравнение с родительским значением

datum.value > parent.value

Фильтрация внутри иерархии

datum.depth === parent.depth + 1

Построение относительных шкал

(datum.value - parent.min) / (parent.max - parent.min)

Особенности компиляции Vega-Lite

Vega-Lite при компиляции в Vega автоматически:

  • создаёт datum для всех mark элементов
  • формирует parent при facet, repeat и hierarchy
  • добавляет вспомогательные поля (group index, stack values)
  • обеспечивает согласованность scope выражений

В результате datum и parent становятся частью runtime сцены, а не исходного JSON.


Ограничения и тонкости

  • datum не существует вне контекста визуального элемента
  • parent не гарантирован в плоских данных
  • глубина parent зависит от структуры композиции
  • в сложных facet-сценах возможно несколько уровней вложенности
  • выражения должны учитывать возможность undefined значений

datum и parent формируют базовую модель контекстного доступа к данным в Vega. datum обеспечивает локальный доступ к записи, parent добавляет структурный уровень иерархии, позволяя строить вычисления над группами, панелями и древовидными структурами без явного управления состоянием данных.