Визуализация данных в Vega и Vega-Lite строится вокруг декларативного описания графиков, где текстовые элементы — подписи осей, значения меток, аннотации, легенды — формируются как часть системы кодирования (encoding) и трансформаций (transform). Под термином label transformation в контексте Vega/Vega-Lite обычно понимается совокупность механизмов, отвечающих за преобразование исходных данных в человекочитаемые подписи: форматирование чисел и дат, вычисление текстовых значений, динамическое формирование строк, управление положением и отображением текста.
В Vega текстовые элементы задаются через mark типа text.
Они напрямую связываются с данными и сигналами, а преобразование label
происходит на нескольких уровнях:
Базовый текстовый mark:
{
"type": "text",
"from": {"data": "table"},
"encode": {
"enter": {
"x": {"scale": "x", "field": "x"},
"y": {"scale": "y", "field": "y"},
"text": {"field": "label"},
"fill": {"value": "black"}
}
}
}
Здесь label уже считается готовым значением, но в
реальных сценариях оно часто создаётся через трансформации.
В Vega ключевым механизмом преобразования данных является блок
transform. Именно здесь формируются новые поля, которые
затем используются как подписи.
{
"type": "formula",
"as": "label",
"expr": "datum.category + ': ' + datum.value"
}
Здесь происходит классическая трансформация label:
{
"type": "formula",
"as": "label",
"expr": "format(datum.value, '.2f')"
}
Функция format() используется для управления
отображением чисел:
Vega позволяет использовать signal для динамического
управления текстом:
{
"name": "precision",
"value": 2
}
И применение:
{
"type": "formula",
"as": "label",
"expr": "format(datum.value, format('.' + precision + 'f'))"
}
Такой подход делает label адаптивным к внешним параметрам визуализации.
Vega-Lite упрощает работу с текстовыми метками, скрывая большую часть
низкоуровневых конструкций Vega. Основной инструмент трансформации label
здесь — encoding, а также format,
timeUnit, calculate,
labelExpr.
{
"mark": "text",
"encoding": {
"text": {"field": "value"}
}
}
Это минимальный вариант без трансформаций.
{
"mark": "text",
"encoding": {
"text": {
"field": "value",
"type": "quantitative",
"format": ".1f"
}
}
}
Здесь format выполняет трансформацию отображения:
{
"mark": "text",
"encoding": {
"text": {
"field": "date",
"type": "temporal",
"format": "%Y-%m-%d"
}
}
}
Поддерживается синтаксис timeFormat, аналогичный d3-time-format.
Ключевые элементы форматирования дат:
%Y — год%m — месяц%d — день%H — часыОдним из наиболее мощных механизмов трансформации label в Vega-Lite
является labelExpr. Он позволяет использовать выражения
Vega Expression Language.
{
"mark": "text",
"encoding": {
"text": {
"field": "value",
"type": "quantitative",
"labelExpr": "datum.value > 100 ? 'High: ' + datum.value : 'Low: ' + datum.value"
}
}
}
Возможности:
Оси являются одним из основных источников label transformation.
{
"axis": {
"format": ".2f",
"labelAngle": 0,
"labelExpr": "datum.value + ' units'"
}
}
format — числовое форматированиеlabelExpr — вычисляемый labellabelAngle — управление поворотом текстаlabelLimit — обрезка длинных подписейЛегенды также поддерживают формирование текста:
{
"legend": {
"labelExpr": "datum.value.toUpperCase()"
}
}
Или форматирование числовых диапазонов:
{
"legend": {
"format": ".0%"
}
}
Expression language Vega позволяет строить сложные текстовые конструкции:
{
"transform": [
{
"type": "formula",
"as": "label",
"expr": "'Category: ' + datum.category + '\\nValue: ' + format(datum.value, '.2f')"
}
]
}
Здесь используются:
\n)При использовании aggregate трансформация label
становится зависимой от группировки данных.
{
"transform": [
{
"type": "aggregate",
"groupby": ["category"],
"fields": ["value"],
"ops": ["sum"],
"as": ["total"]
},
{
"type": "formula",
"as": "label",
"expr": "datum.category + ': ' + datum.total"
}
]
}
Такой подход часто используется для:
Условная логика часто используется для адаптации подписей:
{
"type": "formula",
"as": "label",
"expr": "datum.value > 0 ? '+' + datum.value : datum.value"
}
Или более сложный случай:
{
"expr": "datum.value > 1000 ? format(datum.value/1000, '.1f') + 'k' : datum.value"
}
При работе с длинными строками применяется ограничение длины:
{
"axis": {
"labelLimit": 80
}
}
Альтернативно через expression:
{
"expr": "substring(datum.label, 0, 10) + '...'"
}
В text mark часто комбинируются несколько уровней
трансформации:
{
"mark": "text",
"transform": [
{
"type": "formula",
"as": "label",
"expr": "datum.name + ': ' + format(datum.value, '.0f')"
}
],
"encoding": {
"text": {"field": "label"},
"x": {"field": "x"},
"y": {"field": "y"}
}
}
В сложных визуализациях label проходит несколько стадий:
Пример полного пайплайна:
{
"transform": [
{"type": "aggregate", "groupby": ["category"], "fields": ["value"], "ops": ["mean"], "as": ["avg"]},
{"type": "formula", "as": "label", "expr": "datum.category + ' → ' + format(datum.avg, '.2f')"}
]
}
| Возможность | Vega | Vega-Lite |
|---|---|---|
| formula transforms | да | да |
| signal-based labels | да | ограниченно |
| labelExpr | да | да |
| сложные text marks | полный контроль | абстракция |
| format осей | ручной контроль | встроенный |
При проектировании трансформаций label важно учитывать:
encodetransform для вычисленийformat для визуализации{
"transform": [
{
"type": "formula",
"as": "label",
"expr": "datum.series + ' (' + format(datum.value, '.1f') + ')'"
}
]
}
Такая композиция позволяет:
Vega поддерживает реактивные выражения:
{
"signal": "threshold = 50"
}
{
"type": "formula",
"as": "label",
"expr": "datum.value > threshold ? 'Above' : 'Below'"
}
Это позволяет label реагировать на изменения параметров визуализации без пересборки данных.