Что такое логарифмическая шкала и когда её использовать?
Логарифмическая шкала представляет собой нелинейную шкалу, на которой расстояния между точками пропорциональны логарифму соответствующих значений, а не самим значениям. Это означает, что равные отрезки на оси соответствуют равным отношениям (или факторам) между значениями, а не равным разностям. Например, расстояние между 10 и 100 такое же, как между 100 и 1000 (поскольку 100/10 = 1000/100 = 10), а не такое же, как между 10 и 20.
Логарифмические шкалы крайне полезны, когда:
- Данные охватывают очень широкий диапазон значений, отличающихся на несколько порядков (например, от единиц до миллионов). Линейная шкала в этом случае сделает маленькие значения почти неразличимыми.
- Нас интересуют относительные изменения или темпы роста/падения, а не абсолютные разности.
- Распределение данных сильно скошено (например, степенной закон).
В областях данных, таких как анализ трафика веб-сайтов, доходности инвестиций, распространения вирусного контента или распределения богатства, часто встречаются данные с широким диапазоном и экспоненциальным ростом/падением, где логарифмическая шкала позволяет лучше визуализировать структуру.
Основы построения графиков с логарифмической шкалой в Matplotlib (pyplot.yscale(‘log’))
Matplotlib делает построение графиков с логарифмической шкалой тривиальным с помощью модуля pyplot. Для установки логарифмической шкалы по оси Y достаточно вызвать метод plt.yscale('log') перед отображением графика.
import matplotlib.pyplot as plt
import numpy as np
# Пример данных, охватывающих несколько порядков
x: np.ndarray = np.arange(1, 11)
y: np.ndarray = np.array([1, 5, 20, 50, 100, 300, 800, 1500, 5000, 12000]) # Произвольные данные
plt.figure(figsize=(8, 6))
plt.plot(x, y, marker='o')
# Устанавливаем логарифмическую шкалу по оси Y
plt.yscale('log')
plt.title('График с логарифмической шкалой по оси Y (по умолчанию)')
plt.xlabel('X значение')
plt.ylabel('Y значение (логарифмическая шкала)')
plt.grid(True, which='both', linestyle='--', linewidth=0.5)
plt.show()
Этот код построит график, где ось Y будет использовать логарифмическую шкалу (по основанию 10 по умолчанию). Matplotlib автоматически рассчитает основные и вспомогательные деления (major and minor ticks) для логарифмической шкалы.
Проблема стандартных меток оси Y в логарифмическом масштабе
Хотя plt.yscale('log') быстро переключает шкалу, автоматическое форматирование меток (tick labels) не всегда идеально подходит для всех сценариев или требований к презентации. По умолчанию Matplotlib может использовать:
- Экспоненциальное представление (например, $10^0$, $10^1$, $10^2$ вместо 1, 10, 100) для основных делений.
- Стандартное десятичное представление, но только для основных делений (1, 10, 100, 1000…).
- Десятичное представление с плавающей точкой (например,
1.0,10.0,100.0).
Вспомогательные деления (minor ticks) на логарифмической шкале обычно соответствуют значениям между степенями (например, 2, 3, …, 9 между 10^0 и 10^1). По умолчанию Matplotlib не подписывает вспомогательные деления, чтобы избежать перегруженности графика. Однако иногда требуется более детальное форматирование, другое представление чисел (например, без десятичных знаков для целых) или подписи для определенных вспомогательных делений.
Именно для таких случаев требуется ручная настройка форматирования меток оси Y.
Настройка меток оси Y: основные подходы
Для более тонкого контроля над тем, как выглядят метки на осях, Matplotlib предоставляет модуль matplotlib.ticker. Этот модуль содержит различные классы, которые можно использовать для определения расположения делений (Locator) и форматирования их меток (Formatter). Для логарифмической шкалы нас в первую очередь интересуют Formatter.
Доступ к объекту форматера для оси Y можно получить через ax.yaxis.get_major_formatter() и ax.yaxis.get_minor_formatter(), где ax — это объект осей (Axes). Установить новый форматер можно с помощью ax.yaxis.set_major_formatter(new_formatter) и ax.yaxis.set_minor_formatter(new_formatter).
Использование matplotlib.ticker для форматирования меток
Модуль matplotlib.ticker предлагает несколько встроенных форматеров:
ScalarFormatter: Форматирует числа в виде десятичных чисел с плавающей точкой или в экспоненциальном виде, автоматически выбирая наиболее подходящий формат в зависимости от диапазона значений. Это форматер по умолчанию для линейных шкал и часто используется для логарифмических шкал, чтобы получить более читаемые десятичные числа.FormatStrFormatter: Позволяет задать строку формата в стилеsprintf(например,'%.0f'для целых чисел,'%.2f'для двух знаков после запятой). Подходит для простого и единообразного форматирования.FuncFormatter: Самый гибкий форматер, который принимает пользовательскую функцию для генерации строки метки из значения деления и его позиции. Позволяет реализовать любую логику форматирования.LogFormatter,LogFormatterSciNotation: Специализированные форматеры для логарифмических шкал, которые по умолчанию используют экспоненциальное представление ($10^x$).
Для настройки меток в стандартном десятичном или пользовательском строковом формате на логарифмической шкале чаще всего используются ScalarFormatter и FormatStrFormatter для основных делений, а также FuncFormatter для более сложной логики или форматирования вспомогательных делений.
Применение ScalarFormatter для отображения чисел в обычном формате
ScalarFormatter пытается представить метки в простом десятичном формате, избегая экспоненциальной записи, если это возможно и читаемо. На логарифмической шкале он часто используется для того, чтобы метки $10^0, 10^1, 10^2$ отображались как 1, 10, 100. Он может обрабатывать основные и, опционально, вспомогательные деления.
Пример использования:
from matplotlib.ticker import ScalarFormatter
# ... (код для создания графика и данных из предыдущего примера)
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(x, y, marker='o')
ax.set_yscale('log')
# Создаем и применяем ScalarFormatter для основных делений
formatter = ScalarFormatter()
ax.yaxis.set_major_formatter(formatter)
# Можно также применить к вспомогательным делениям, если они есть (не подписываются по умолчанию)
# ax.yaxis.set_minor_formatter(formatter)
ax.set_title('График с ScalarFormatter для меток оси Y')
ax.set_xlabel('X значение')
ax.set_ylabel('Y значение (логарифмическая шкала)')
ax.grid(True, which='both', linestyle='--', linewidth=0.5)
plt.show()
ScalarFormatter обычно хорошо работает