Форматирование подписей: .tickFormat()

В библиотеке D3.js форматирование подписей делений осей является ключевым механизмом управления читаемостью графиков. Метод .tickFormat() применяется к оси и позволяет полностью контролировать отображение значений тиков (tick labels), заменяя стандартное форматирование масштабов (scales).

Каждая ось в D3 строится на основе масштаба (scale), который преобразует числовые или временные значения в координаты. По умолчанию подписи тиков формируются автоматически на основе типа шкалы:

  • числовые шкалы используют встроенное форматирование JavaScript
  • временные шкалы используют ISO-подобные представления или локальные форматы
  • линейные шкалы отображают «сырые» значения

Метод .tickFormat() переопределяет этот механизм и задаёт функцию форматирования, которая применяется ко всем значениям тиков.

Сигнатура:

axis.tickFormat(formatFunction)

или с использованием форматтера D3:

axis.tickFormat(d3.format(".2f"))

Базовый принцип работы

.tickFormat() принимает функцию, которая получает значение тика и возвращает строку:

function format(value) {
  return String(value);
}

Простейшая настройка:

const axis = d3.axisBottom(scale)
  .tickFormat(d => d);

В этом случае форматирование фактически остаётся стандартным, но теперь оно контролируется вручную.

Форматирование чисел через d3.format

Одним из наиболее мощных инструментов является d3.format, основанный на спецификации formatting syntax, аналогичной Python format mini-language.

Примеры базовых форматов:

d3.format(".0f")   // целые числа
d3.format(".2f")   // 2 знака после запятой
d3.format(",.0f")  // разделение тысяч
d3.format(".2%")   // проценты

Пример: округление значений оси

const xAxis = d3.axisBottom(xScale)
  .tickFormat(d3.format(".1f"));

Результат:

  • 10.345 → 10.3
  • 5.987 → 6.0

Локализация чисел

D3 поддерживает локализованные форматы через d3.formatLocale.

const locale = d3.formatLocale({
  decimal: ",",
  thousands: " ",
  grouping: [3],
  currency: ["₸", ""]
});

const format = locale.format(",.2f");

Применение:

axis.tickFormat(format);

Такой подход критичен для интерфейсов, ориентированных на разные языковые стандарты, где:

  • десятичный разделитель может быть запятая
  • разделение тысяч может быть пробел
  • символ валюты может отличаться

Форматирование процентов

Процентное отображение является частым сценарием при визуализации долей:

const percentFormat = d3.format(".0%");

Использование:

d3.axisLeft(yScale)
  .tickFormat(percentFormat);

Преобразование:

  • 0.25 → 25%
  • 0.8 → 80%

Важно учитывать, что входные данные должны быть в диапазоне 0–1.

Форматирование валют

const currency = d3.format("$.2f");

Пример:

axis.tickFormat(currency);

Результат:

  • 1200 → $1,200.00
  • 99.5 → $99.50

Для нестандартных валют символ заменяется через локаль:

const kz = d3.formatLocale({
  decimal: ".",
  thousands: " ",
  grouping: [3],
  currency: ["₸", ""]
});

const formatKZT = kz.format(",.0f");

Форматирование временных шкал

Для временных осей используется d3.timeFormat.

const formatTime = d3.timeFormat("%Y-%m-%d");

Пример оси:

d3.axisBottom(timeScale)
  .tickFormat(d3.timeFormat("%d.%m"));

Основные токены форматирования времени

  • %Y — год (2026)
  • %m — месяц (01–12)
  • %d — день месяца
  • %H — часы (24h)
  • %M — минуты
  • %S — секунды

Пример более детального формата:

d3.timeFormat("%d %B %Y");

Полное подавление отображения некоторых тиков

Функция .tickFormat() позволяет не отображать отдельные значения, возвращая пустую строку:

axis.tickFormat(d => (d % 10 === 0 ? d : ""));

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

  • уменьшения визуального шума
  • выделения ключевых значений
  • кастомной логики подписей

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

Форматирование может зависеть от значения:

axis.tickFormat(d => {
  if (d > 1000) return d3.format(".2s")(d);
  return d;
});

Результат:

  • 1200 → 1.2k
  • 500 → 500

Использование научной нотации

const sci = d3.format(".2e");

Применение:

axis.tickFormat(sci);

Пример:

  • 1000000 → 1.00e+6

Это полезно для графиков с большими диапазонами значений.

Сокращённые числовые форматы

D3 поддерживает SI-prefix форматирование:

const si = d3.format(".2s");

Пример:

  • 1500 → 1.5k
  • 2000000 → 2.0M

Использование на осях:

d3.axisLeft(yScale)
  .tickFormat(d3.format(".2s"));

Влияние на читаемость графиков

Форматирование подписей напрямую влияет на интерпретацию данных:

  • чрезмерная точность увеличивает когнитивную нагрузку
  • округление улучшает восприятие трендов
  • сокращения (k, M, B) помогают при больших диапазонах

Комбинация .tickValues() и .tickFormat() часто используется совместно для полного контроля оси.

Связь с количеством тиков

Хотя .tickFormat() не управляет количеством тиков, он влияет на их восприятие. Часто используется вместе:

d3.axisBottom(scale)
  .ticks(10)
  .tickFormat(d3.format(".1f"));

Потоковая обработка значений

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

axis.tickFormat(d => Math.round(d * 100) / 100);

или более сложная логика:

axis.tickFormat((d, i) => {
  return i % 2 === 0 ? d : "";
});

Потенциальные ошибки и ограничения

  • возврат null или undefined приводит к отображению пустых значений
  • слишком тяжёлые функции форматирования ухудшают производительность при большом числе тиков
  • несоответствие масштаба и формата (например, проценты для значений > 1) искажает интерпретацию данных

Комбинирование с логарифмическими шкалами

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

d3.axisBottom(logScale)
  .tickFormat(d3.format(".0e"));

или более читаемый вариант:

d3.axisBottom(logScale)
  .tickFormat(d3.format(".2s"));

Кастомные форматеры без d3.format

Возможна полная замена системы форматирования:

axis.tickFormat(d => `value: ${d}`);

или с внешними библиотеками:

axis.tickFormat(d => Intl.NumberFormat("ru-RU").format(d));

Поведение при разных типах шкал

  • Linear scale: числовые значения
  • Time scale: объекты Date
  • Log scale: экспоненциально распределённые значения
  • Ordinal scale: строковые категории

Каждый тип требует собственного подхода к форматированию, особенно при использовании .tickFormat().

Композиция форматирования

В сложных визуализациях форматирование часто комбинируется:

const format = d => {
  if (d < 0) return "(" + d3.format(".2f")(-d) + ")";
  return d3.format(".2f")(d);
};

axis.tickFormat(format);

Такой подход применяется для:

  • финансовых данных
  • статистических отклонений
  • симметричных шкал

Влияние на responsive-графики

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

const format = width < 500
  ? d3.format(".1s")
  : d3.format(",.2f");

axis.tickFormat(format);

Это позволяет адаптировать плотность информации под размер контейнера.