Трансформация label

Визуализация данных в Vega и Vega-Lite строится вокруг декларативного описания графиков, где текстовые элементы — подписи осей, значения меток, аннотации, легенды — формируются как часть системы кодирования (encoding) и трансформаций (transform). Под термином label transformation в контексте Vega/Vega-Lite обычно понимается совокупность механизмов, отвечающих за преобразование исходных данных в человекочитаемые подписи: форматирование чисел и дат, вычисление текстовых значений, динамическое формирование строк, управление положением и отображением текста.

Архитектура текстовых меток в Vega

В Vega текстовые элементы задаются через mark типа text. Они напрямую связываются с данными и сигналами, а преобразование label происходит на нескольких уровнях:

  • уровень данных (transform)
  • уровень кодирования (encode)
  • уровень форматирования (format / signal / expr)

Базовый текстовый 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 уже считается готовым значением, но в реальных сценариях оно часто создаётся через трансформации.

Генерация label через transform

В Vega ключевым механизмом преобразования данных является блок transform. Именно здесь формируются новые поля, которые затем используются как подписи.

Вычисление строковых значений

{
  "type": "formula",
  "as": "label",
  "expr": "datum.category + ': ' + datum.value"
}

Здесь происходит классическая трансформация label:

  • объединение нескольких полей
  • формирование человекочитаемой строки
  • подготовка данных для text-mark

Форматирование чисел

{
  "type": "formula",
  "as": "label",
  "expr": "format(datum.value, '.2f')"
}

Функция format() используется для управления отображением чисел:

  • количество знаков после запятой
  • научная нотация
  • процентное представление

Форматирование labels через сигналы

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

{
  "name": "precision",
  "value": 2
}

И применение:

{
  "type": "formula",
  "as": "label",
  "expr": "format(datum.value, format('.' + precision + 'f'))"
}

Такой подход делает label адаптивным к внешним параметрам визуализации.

Vega-Lite: декларативная трансформация label

Vega-Lite упрощает работу с текстовыми метками, скрывая большую часть низкоуровневых конструкций Vega. Основной инструмент трансформации label здесь — encoding, а также format, timeUnit, calculate, labelExpr.

Базовое текстовое поле

{
  "mark": "text",
  "encoding": {
    "text": {"field": "value"}
  }
}

Это минимальный вариант без трансформаций.

Форматирование через encoding

Числовые labels

{
  "mark": "text",
  "encoding": {
    "text": {
      "field": "value",
      "type": "quantitative",
      "format": ".1f"
    }
  }
}

Здесь format выполняет трансформацию отображения:

  • не меняет данные
  • меняет только представление label

Форматирование дат

{
  "mark": "text",
  "encoding": {
    "text": {
      "field": "date",
      "type": "temporal",
      "format": "%Y-%m-%d"
    }
  }
}

Поддерживается синтаксис timeFormat, аналогичный d3-time-format.

Ключевые элементы форматирования дат:

  • %Y — год
  • %m — месяц
  • %d — день
  • %H — часы

labelExpr: динамическая трансформация текста

Одним из наиболее мощных механизмов трансформации 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"
    }
  }
}

Возможности:

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

Трансформация labels в осевых подписях

Оси являются одним из основных источников label transformation.

{
  "axis": {
    "format": ".2f",
    "labelAngle": 0,
    "labelExpr": "datum.value + ' units'"
  }
}

Основные механизмы:

  • format — числовое форматирование
  • labelExpr — вычисляемый label
  • labelAngle — управление поворотом текста
  • labelLimit — обрезка длинных подписей

Трансформация label в легендах

Легенды также поддерживают формирование текста:

{
  "legend": {
    "labelExpr": "datum.value.toUpperCase()"
  }
}

Или форматирование числовых диапазонов:

{
  "legend": {
    "format": ".0%"
  }
}

Сложные выражения для label

Expression language Vega позволяет строить сложные текстовые конструкции:

{
  "transform": [
    {
      "type": "formula",
      "as": "label",
      "expr": "'Category: ' + datum.category + '\\nValue: ' + format(datum.value, '.2f')"
    }
  ]
}

Здесь используются:

  • переносы строк (\n)
  • конкатенация строк
  • форматирование чисел
  • комбинирование нескольких полей

Label transformation через агрегации

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

{
  "transform": [
    {
      "type": "aggregate",
      "groupby": ["category"],
      "fields": ["value"],
      "ops": ["sum"],
      "as": ["total"]
    },
    {
      "type": "formula",
      "as": "label",
      "expr": "datum.category + ': ' + datum.total"
    }
  ]
}

Такой подход часто используется для:

  • подписей бар-чартов
  • итоговых значений
  • summary labels

Условные трансформации label

Условная логика часто используется для адаптации подписей:

{
  "type": "formula",
  "as": "label",
  "expr": "datum.value > 0 ? '+' + datum.value : datum.value"
}

Или более сложный случай:

{
  "expr": "datum.value > 1000 ? format(datum.value/1000, '.1f') + 'k' : datum.value"
}

Управление длиной label

При работе с длинными строками применяется ограничение длины:

{
  "axis": {
    "labelLimit": 80
  }
}

Альтернативно через expression:

{
  "expr": "substring(datum.label, 0, 10) + '...'"
}

Label transformation в текстовых диаграммах

В 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

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

  1. исходные данные
  2. агрегация
  3. вычисление выражений
  4. форматирование
  5. отображение

Пример полного пайплайна:

{
  "transform": [
    {"type": "aggregate", "groupby": ["category"], "fields": ["value"], "ops": ["mean"], "as": ["avg"]},
    {"type": "formula", "as": "label", "expr": "datum.category + ' → ' + format(datum.avg, '.2f')"}
  ]
}

Особенности трансформации label в Vega vs Vega-Lite

Возможность Vega Vega-Lite
formula transforms да да
signal-based labels да ограниченно
labelExpr да да
сложные text marks полный контроль абстракция
format осей ручной контроль встроенный

Практика построения устойчивых label

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

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

Композиция label в multi-series данных

{
  "transform": [
    {
      "type": "formula",
      "as": "label",
      "expr": "datum.series + ' (' + format(datum.value, '.1f') + ')'"
    }
  ]
}

Такая композиция позволяет:

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

Динамическое обновление label через выражения

Vega поддерживает реактивные выражения:

{
  "signal": "threshold = 50"
}
{
  "type": "formula",
  "as": "label",
  "expr": "datum.value > threshold ? 'Above' : 'Below'"
}

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