Поле zero: обнуление домена

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

В Vega-Lite шкала (scale) отвечает за преобразование значений данных в пиксельные координаты. Для количественных данных домен (domain) обычно вычисляется автоматически:

  • минимальное значение данных → нижняя граница шкалы
  • максимальное значение данных → верхняя граница шкалы

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

Проблема отсутствия нуля в домене

Рассмотрим столбчатую диаграмму:

{
  "$schema": "https://vega.github.io/schema/vega-lite/v5.json",
  "data": {
    "values": [
      { "category": "A", "value": 5 },
      { "category": "B", "value": 120 },
      { "category": "C", "value": 45 }
    ]
  },
  "mark": "bar",
  "encoding": {
    "x": { "field": "category", "type": "nominal" },
    "y": { "field": "value", "type": "quantitative" }
  }
}

В таком графике шкала Y начнётся примерно с 5. Визуально разница между значениями усиливается или искажается: 5 и 120 выглядят как несопоставимые величины, хотя реальная пропорция сохраняется.

Поле zero: принудительное включение нуля

В Vega-Lite существует механизм, который управляет включением нуля в домен количественной шкалы — параметр scale.zero.

{
  "encoding": {
    "y": {
      "field": "value",
      "type": "quantitative",
      "scale": {
        "zero": true
      }
    }
  }
}

При zero: true система гарантирует, что домен шкалы будет расширен до нуля, даже если данные его не содержат.

Логика расширения домена

Если исходный набор данных имеет минимальное значение minValue, то при включении нуля домен пересчитывается следующим образом:

  • если minValue > 0 → нижняя граница становится 0
  • если minValue < 0 → верхняя или нижняя граница остаётся без изменений, но 0 гарантированно входит в диапазон

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

Случаи, где zero критичен

Столбчатые диаграммы

Столбцы интерпретируются как величины, растущие от базовой линии. Отсутствие нуля ломает геометрию восприятия:

"mark": "bar",
"encoding": {
  "y": {
    "field": "value",
    "type": "quantitative",
    "scale": { "zero": true }
  }
}

Без этого параметра столбцы могут начинаться с произвольного минимума, что визуально увеличивает различия.

Сравнение величин

При сравнении нескольких категорий:

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

ноль является естественным началом координат.

Когда zero ухудшает визуализацию

Не все графики выигрывают от принудительного включения нуля. В Vega-Lite это особенно заметно в следующих случаях:

  • линии трендов с малым диапазоном изменений
  • временные ряды с флуктуациями
  • плотные scatter plots

Если диапазон значений узкий (например, 98–102), включение нуля «сжимает» график и делает вариации неразличимыми.

Отключение zero

По умолчанию Vega-Lite часто использует zero: true для баров, но в аналитических графиках может быть полезно отключить это поведение:

{
  "encoding": {
    "y": {
      "field": "value",
      "type": "quantitative",
      "scale": {
        "zero": false
      }
    }
  }
}

Это позволяет шкале автоматически подстраиваться под диапазон данных.

Взаимодействие zero с другими параметрами scale

domain

Явно заданный домен всегда имеет приоритет над zero:

"scale": {
  "domain": [10, 200],
  "zero": true
}

В этом случае ноль может быть проигнорирован, если он выходит за пределы явно заданного диапазона.

nice

Параметр nice округляет границы шкалы до «красивых» значений:

"scale": {
  "zero": true,
  "nice": true
}

При совместном использовании ноль включается в домен, а остальные границы подстраиваются под округления (например, 0–120 вместо 5–118).

Поведение в stacked-диаграммах

В стековых диаграммах ноль становится точкой отсчёта для накопления значений:

{
  "mark": "bar",
  "encoding": {
    "y": {
      "field": "value",
      "type": "quantitative",
      "stack": "zero",
      "scale": {
        "zero": true
      }
    }
  }
}

Здесь zero и stack: "zero" усиливают друг друга: один фиксирует базовую линию, другой определяет метод накопления.

Геометрический смысл обнуления домена

Масштаб с включённым нулём задаёт линейное преобразование вида:

[ f(x) = a x + b]

где ограничение f(0) фиксируется как базовая точка отсчёта координатной системы. Это делает визуализацию интерпретируемой как абсолютную, а не относительную.

Влияние на восприятие данных

Обнуление домена изменяет не данные, а способ их интерпретации:

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

Визуально это создаёт «жёсткую» шкалу, где отсутствие значения и ноль совпадают по смыслу.

Особенности поведения в Vega (низкоуровневый слой)

В Vega (не Vega-Lite) аналогичное поведение реализуется через ручное управление доменом:

"scales": [
  {
    "name": "y",
    "type": "linear",
    "domain": {"data": "table", "field": "value"},
    "zero": true
  }
]

Здесь zero работает как директива расширения вычисленного домена, а не как часть декларативного encoding.

Ошибки при использовании zero

Типичные проблемы возникают при неправильном применении:

  • включение zero в логарифмических шкалах (несовместимо)
  • использование в плотных временных рядах
  • конфликт с фиксированным domain

Логарифмическая шкала физически не может включать ноль, поэтому параметр игнорируется или приводит к ошибке конфигурации.

Семантика выбора между true и false

Выбор значения scale.zero фактически определяет философию визуализации:

  • true — абсолютное сравнение относительно нуля
  • false — относительное сравнение внутри диапазона данных

Это не техническая настройка, а изменение интерпретационного слоя визуализации.