Язык выражений Vega Expression Language (VEL) используется для описания вычислений внутри спецификаций визуализаций Vega и Vega-Lite. Он представляет собой компактный интерпретируемый язык, встроенный в декларативную модель описания графиков, позволяющий задавать динамическое поведение визуализации без необходимости перехода к полноценному JavaScript-коду.
VEL применяется в нескольких ключевых контекстах: вычисление сигналов, преобразование данных, настройка параметров отображения, обработка событий, а также динамическое управление свойствами визуальных элементов.
Выражения Vega выполняются в строго определённых контекстах, где доступны различные переменные:
signal — глобальные и локальные сигналы, определяющие состояние визуализации datum — текущая строка данных в трансформациях и кодировании event — данные события взаимодействия (мышь, клавиатура) item — текущий графический элемент (mark item) parent — родительский элемент в иерархических структурах
Каждый контекст ограничивает набор доступных сущностей, что повышает предсказуемость вычислений и безопасность исполнения.
Пример обращения к данным в выражении:
datum.value * 2
VEL использует JavaScript-подобный синтаксис, но с ограниченным набором операций. Поддерживаются:
+, -,
*, /, %&&, ||,
!==, !=, >,
<, >=, <=condition ? a : bПример:
datum.sales > 100 ? "high" : "low"
Выражения всегда возвращают значение и не поддерживают побочные эффекты.
Сигналы являются центральным механизмом реактивности Vega. Они представляют изменяемые значения, которые могут зависеть от пользовательского ввода или других вычислений.
Доступ к сигналам осуществляется напрямую по имени:
width / 2
или в более сложных выражениях:
scaleFactor * (signalValue + offset)
Сигналы часто используются для управления масштабом, позиционированием и фильтрацией данных.
VEL включает набор встроенных функций, разделённых по категориям.
abs(x) — модуль числаround(x) — округлениеfloor(x), ceil(x) — округление вниз и
вверхpow(x, n) — степеньsqrt(x) — квадратный кореньlog(x), exp(x) — логарифм и
экспонентаmin(a, b, ...), max(a, b, ...)Пример:
sqrt(datum.x * datum.x + datum.y * datum.y)
substring(str, start, end)indexof(str, search)replace(str, pattern, replacement)lower(str), upper(str)trim(str)Пример:
upper(datum.category)
length(array)indexof(array, value)inrange(value, array)join(array, separator)Пример:
length(datum.items)
VEL включает поддержку работы с датами через встроенный объект
Date и набор утилит:
now() — текущее времяtime(d) — преобразование в timestampyear(d), month(d),
date(d)hours(d), minutes(d),
seconds(d)Пример:
year(datum.timestamp)
Объект datum предоставляет доступ к текущей записи
данных в контексте трансформаций и визуальных кодировок.
Пример простого доступа:
datum.value
Сложные вычисления часто комбинируют несколько полей:
datum.revenue - datum.cost
или условные конструкции:
datum.value > threshold ? datum.value : 0
В выражениях взаимодействия доступен объект event,
содержащий данные пользовательских действий:
event.x, event.yevent.shiftKey,
event.ctrlKeyevent.typeПример:
event.shiftKey ? datum.selected : false
Логические конструкции используются для фильтрации и управления отображением:
datum.value > 50 && datum.category == "A"
Тернарный оператор применяется для более компактных ветвлений:
datum.value > 0 ? datum.value : 0
Комбинация условий:
datum.a > 10 || (datum.b < 5 && datum.c == 0)
VEL не является строго типизированным языком, однако выполняет автоматические преобразования типов:
0 и 1Пример:
"Value: " + datum.value
{
"name": "opacity",
"value": 0.5,
"on": [
{
"events": "mouseover",
"update": "1"
},
{
"events": "mouseout",
"update": "0.5"
}
]
}
{
"type": "circle",
"encode": {
"enter": {
"x": {"field": "x"},
"y": {"field": "y"},
"size": {"expr": "datum.value * 10"}
}
}
}
{
"type": "filter",
"expr": "datum.value > 100"
}
При вычислении выражений соблюдается стандартный порядок:
!, -)Пример:
datum.a + datum.b * datum.c
эквивалентно:
datum.a + (datum.b * datum.c)
Язык выражений Vega намеренно ограничен:
Это обеспечивает детерминированность и предсказуемость визуализаций даже при сложных интерактивных сценариях.
Фильтрация и нормализация значений:
datum.value > 0 ? sqrt(datum.value) / maxValue : 0
Интерактивное выделение:
event.item && event.item.datum.id == datum.id ? 1 : 0.3
Группировка по времени:
year(datum.date) + "-" + month(datum.date)
Комбинированная логика отображения:
datum.active && datum.score > threshold ? "visible" : "hidden"