Использование библиотеки Matplotlib. Как работать с календарными данными
Дата публикации: 30.03.2013
Дата последней правки: 07.10.2023
Содержание
- Отображение календарных данных в Matplotlib
- Форматтеры для работы с датами
- Локаторы для работы с датами
- Похожие статьи
- Комментарии
Отображение календарных данных в Matplotlib
Иногда нужно построить график, на котором по оси X отложены не числа, а календарные значения (даты или время). Библиотека Matplotlib позволяет рисовать и такие графики. В качестве данных календарного типа могут использоваться списки, содержащие экземпляры классов date или datetime.
В старых версиях библиотеки Matplotlib для отображения календарных данных использовалась отдельная функция matplotlib.pyplot.plot_date, для которой нужно было преобразовать календарные данные в числовые с помощью функции date2num. В данный момент эта функция считается устаревшей, а календарные данные можно отображать с помощью универсальной функции plot().
В данной статье будут рассмотрены форматтеры и локаторы, предназначенные для работы с календарными данными. Напомню, что форматтеры - это классы, предназначенные для задания формата выводимых подписей около рисок на осях. Про использование форматтеров вы можете прочитать в статье Как изменять формат меток на осях. Локаторы - это классы, расставляющие метки по осям в нужных позициях. Про использование локаторов вы можете прочитать в статье Как управлять положением рисок на осях. Форматтеры и локаторы, предназначенные для работы с календарными данными, расположены в модуле matplotlib.dates.
Для начала нарисуем простой график с помощью функции plot(), на котором по оси X будут отложены даты. Все настройки, связанные с датами, оставим установленными по умолчанию.
import matplotlib.pyplot as plt
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
xdata = [
date(2021, 5, 25),
date(2021, 7, 5),
date(2021, 12, 1),
date(2022, 3, 17),
date(2022, 8, 2),
date(2022, 11, 13),
date(2023, 3, 15),
date(2023, 4, 8),
date(2023, 12, 21),
]
# Данные, которые будут отложены по оси Y
ydata = [0.4, 0.3, 0.5, 0.4, 0.6, 0.3, 0.2, 0.1, 0.0]
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis='x', labelrotation=55)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
Результат работы скрипта будет выглядеть следующим образом:
Часто текст надписей у календарных данных получается длинным, и чтобы надписи не перекрывались, в данном примере они были повернуты. Для поворота надписей под осями существует несколько способов, в данной статье мы будем использовать самый простой из них - с помощью функции tick_params.
В следующих разделах мы разберемся, как можно влиять на положение рисок и форматирование надписей на календарных осях.
Форматтеры для работы с датами
Про форматтеры общего назначения на сайте есть отдельная статья, здесь будут рассмотрены только форматтеры, предназначенные для работы с календарными данными, которые, как уже было сказано, расположены в модуле matplotlib.dates. Всего существует три таких форматтера: DateFormatter, AutoDateFormatter и ConciseDateFormatter. Все форматтеры рассматривать не будем, но более подробно остановимся на DateFormatter.
Конструктор DateFormatter может принимать три параметра, обязательным из которых является только первый:
- fmt - строка, описывающая формат представления данных. Формат этой строки соответствует формату, используемому методом strftime.
- tz - параметр задающий часовой пояс. Это может быть экземпляр класса, производного от tzinfo, или строка. Если этот параметр явно не указан или равен None, то берется значение из глобальных настроек rcParams["timezone"], которое по умолчанию равно 'UTC'.
- usetex - булево значение, которое обозначает, следует ли использовать рендер TeX для отображения надписей. Если этот параметр явно не указан или равен None, то берется значение из глобальных настроек rcParams["text.usetex"], которое по умолчанию равно False.
Применим данный форматтер к предыдущему графику таким образом, чтобы отображался только год. Для установки форматтера для оси используется метод set_major_formatter класса Axes.
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
xdata = [
date(2021, 5, 25),
date(2021, 7, 5),
date(2021, 12, 1),
date(2022, 3, 17),
date(2022, 8, 2),
date(2022, 11, 13),
date(2023, 3, 15),
date(2023, 4, 8),
date(2023, 12, 21),
]
# Данные, которые будут отложены по оси Y
ydata = [0.4, 0.3, 0.5, 0.4, 0.6, 0.3, 0.2, 0.1, 0.0]
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis='x', labelrotation=55)
# !!! Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%d.%m.%Y"))
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
Результат работы этого скрипта выглядит следующим образом:
Локаторы для работы с датами
Локаторы, предназначенные для работы с календарными данными, так же как и форматтеры, расположены в модуле matplotlib.dates. Ниже перечислены такие локаторы:
- AutoDateLocator
- YearLocator
- MonthLocator
- WeekdayLocator
- DayLocator
- HourLocator
- MinuteLocator
- SecondLocator
- MicroSecondLocator
Рассмотрим некоторые из них.
AutoDateLocator
Локатор AutoDateLocator используется по умолчанию и предназначен для динамического подбора интервалов между метками в зависимости от количества точек данных. Конструктор AutoDateLocator имеет несколько параметров, однако все они являются необязательными. Если вам не нравится, как AutoDateLocator расставляет риски, можно попытаться повлиять на него несколькими параметрами, в том числе и параметрами конструктора minticks и maxticks, которые задают соответственно минимальное и максимальное желаемое количество рисок.
Изменим предыдущий пример таким образом, чтобы у нас было больше данных по оси X. Дальнейшие примеры мы будем строить на основе таких случайных данных. Так как в следующем примере не установлен явным образом локатор, то по умолчанию используется AutoDateLocator. С помощью форматтера DateFormatter установлено, что по оси X следует отображать только годы.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# !!! Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# !!! Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis='x', labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%Y"))
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
Результат работы будет выглядеть следующим образом (риски расставлены с интервалом 1 год):
Теперь скажем AutoDateLocator, что мы хотели бы видеть от 20 до 30 рисок вдоль оси X. Поскольку на этом графике будет больше рисок, то в подписи к ним помимо года добавим еще номер месяца.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis="x", labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%m.%Y"))
# !!! Изменим локатор, используемый по умолчанию
locator = matplotlib.dates.AutoDateLocator(minticks=20, maxticks=30)
axes.xaxis.set_major_locator(locator)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
После этого график будет выглядеть следующим образом (внутренний алгоритм расстановки рисок класса AutoDateLocator решил, что должно быть 24 риски):
Для более тонкой настройки положения рисок, у класса AutoDateLocator имеется свойство intervald, которое возвращает словарь, с помощью которого можно задать периоды, с которым могут располагаться риски. Это проще объяснить на примере. По умолчанию словарь intervald выглядит следующим образом:
YEARLY : [1, 2, 4, 5, 10, 20, 40, 50, 100, 200, 400, 500,
1000, 2000, 4000, 5000, 10000],
MONTHLY : [1, 2, 3, 4, 6],
DAILY : [1, 2, 3, 7, 14, 21],
HOURLY : [1, 2, 3, 4, 6, 12],
MINUTELY: [1, 5, 10, 15, 30],
SECONDLY: [1, 5, 10, 15, 30],
MICROSECONDLY: [1, 2, 5, 10, 20, 50, 100, 200, 500,
1000, 2000, 5000, 10000, 20000, 50000,
100000, 200000, 500000, 1000000],
}
Это значит, что если риски будут привязаны к годам (ключ YEARLY), то они будут идти через один, или через два, или через четыре, пять, десять, двадцать лет и т.д. согласно значению по ключу YEARLY. Аналогично с месяцами. Например, в предыдущем примере видно, что риски расположены с интервалом 6 месяцев.
Выбор того, к чему привязывать риски (к году, месяцу, дню и т.д.), а также какой интервал выбрать - это как раз работа AutoDateLocator. Но мы можем повлиять на расположение рисок, изменив соответствующие значения в словаре intervald.
Следующий пример показывает использование свойства intervald. Мы изменим значение по ключу matplotlib.dates.MONTHLY таким образом, чтобы в случае, если AutoDateLocator выберет привязку по месяцам (а при наших данных данных эта привязка и будет выбрана), риски шли с интервалом 7 месяцев, начиная с января каждого года.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis="x", labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%m.%Y"))
# Изменим локатор, используемый по умолчанию
locator = matplotlib.dates.AutoDateLocator(minticks=20, maxticks=30)
# !!! Если локатор привяжет риски к месяцам, то
# !!! риски должны идти с интервалом через 8 месяцев, начиная с января каждого года
locator.intervald[matplotlib.dates.MONTHLY] = [7]
axes.xaxis.set_major_locator(locator)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
Результат будет выглядеть следующим образом:
Как видно, риска располагаются неравномерно. Для каждого года первая риска соответствует январю (1 месяц), а затем августу (1 + 7 = 8 месяц).
YearLocator
Более предсказуемо ведут себя локаторы YearLocator, MonthLocator, WeekdayLocator, DayLocator, HourLocator, MinuteLocator, SecondLocator и MicrosecondLocator, предназначенные для явной привязки рисок к годам, месяцам, неделям, дням, часам, минутам, секундам и микросекундам соответственно.
Показывать работу каждого из этих локаторов нет смысла, они работают по одинаковому принципу, но каждый в своем масштабе. Для примера более подробно разберем, как работает YearLocator.
Конструктор YearLocator выглядит следующим образом:
Параметр base задает расстояние (в годах для YearLocator) между соседними рисками, а параметры month и day задают соответственно месяц и день, на который должна приходиться риска каждого года. Параметр tz может задавать часовую зону.
Следующий пример показывает использование локатора YearLocator с параметрами конструктора по умолчанию, когда риски ставятся на каждое первое января каждого года.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis="x", labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%d.%m.%Y"))
# !!! Изменим локатор, используемый по умолчанию
locator = matplotlib.dates.YearLocator()
axes.xaxis.set_major_locator(locator)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
В результате выполнения этого скрипта будет показан следующий график:
Следующий пример также располагает риски каждый год, однако сами риски располагаются на дате каждый год 3 сентября, потому что в конструктор класса YearLocator переданы параметры (month=9, day=3).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis="x", labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%d.%m.%Y"))
# !!! Изменим локатор, используемый по умолчанию
locator = matplotlib.dates.YearLocator(month=9, day=3)
axes.xaxis.set_major_locator(locator)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
Если нужно сделать, чтобы риски располагались в два раза реже (через два года), то в конструктор класса YearLocator нужно добавить параметр base=2. Это показано в следующем примере.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates
if __name__ == "__main__":
# Даты, которые будут отложены по оси X
start = datetime.datetime(2023, 1, 1)
xdata = [start + datetime.timedelta(days=(2 * i)) for i in range(2000)]
# Сгенерим случайный данные по оси Y
np.random.seed(10)
ydata = np.cumsum(np.random.randn(len(xdata)))
# Вызовем subplot явно, чтобы получить экземпляр класса AxesSubplot,
# из которого будем иметь доступ к осям
axes = plt.subplot(1, 1, 1)
# Повернем метки рисок на 55 градусов
axes.tick_params(axis="x", labelrotation=55)
# Изменим формат календарных данных
axes.xaxis.set_major_formatter(matplotlib.dates.DateFormatter("%d.%m.%Y"))
# !!! Изменим локатор, используемый по умолчанию
locator = matplotlib.dates.YearLocator(base=2, month=9, day=3)
axes.xaxis.set_major_locator(locator)
# Отобразим данные
plt.plot(xdata, ydata)
# Отмасштабируем график, чтобы в окно уместились повернутые надписи
plt.tight_layout()
plt.grid()
plt.show()
В результате будет выведен график следующего вида:
По аналогичному принципу работают MonthLocator, WeekdayLocator, DayLocator, HourLocator, MinuteLocator, SecondLocator и MicrosecondLocator. В частности, с помощью MonthLocator можно указать, в какие месяцы и в какие числа должны быть установлены риски. С помощью DayLocator риски расставляются ежемесячно в указанные числа.
На этом закончим рассмотрение локаторов и форматтеров для работы с календарными данными.
Похожие статьи
- Другие статьи про Matplotlib
- Как изменять формат меток на осях
- Как управлять положением рисок на осях
Вы можете подписаться на новости сайта через RSS, Группу Вконтакте или Канал в Telegram.