Введение
Matplotlib - это мощная библиотека визуализации данных для Python. Она предоставляет ряд встроенных шкал для построения графиков данных, но иногда вам может потребоваться кастомная шкала для вашего конкретного сценария использования. В этом лабе мы покажем, как создать кастомную шкалу, которая использует проекцию Меркатора для данных о широте.
Советы по работе с ВМ
После завершения запуска ВМ нажмите в левом верхнем углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.
Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook загрузится полностью. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.
Если вы сталкиваетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.
Импортируем необходимые библиотеки
Начнем с импорта необходимых библиотек.
import numpy as np
from numpy import ma
from matplotlib import scale as mscale
from matplotlib import transforms as mtransforms
from matplotlib.ticker import FixedLocator, FuncFormatter
Определяем класс MercatorLatitudeScale
Далее мы определим класс MercatorLatitudeScale, который реализует кастомную шкалу. Этот класс будет наследоваться от mscale.ScaleBase.
class MercatorLatitudeScale(mscale.ScaleBase):
"""
Масштабирует данные в диапазоне от -pi/2 до pi/2 (-90 до 90 градусов) с использованием
системы, используемой для масштабирования широт в проекции Меркатора__.
Функция масштабирования:
ln(tan(y) + sec(y))
Обратная функция масштабирования:
atan(sinh(y))
Поскольку масштаб Меркатора стремится к бесконечности при +/- 90 градусах,
существует пользовательский порог, выше и ниже которого ничего не будет нарисовано.
Это по умолчанию равно +/- 85 градусов.
__ https://en.wikipedia.org/wiki/Mercator_projection
"""
Реализуем класс MercatorLatitudeTransform
Внутри класса MercatorLatitudeScale мы определим класс MercatorLatitudeTransform, который на самом деле будет преобразовывать данные. Этот класс будет наследоваться от mtransforms.Transform.
class MercatorLatitudeTransform(mtransforms.Transform):
## Должен быть определен два члена значения.
## ``input_dims`` и ``output_dims`` определяют количество входных
## размерностей и выходных размерностей преобразования.
## Они используются фреймворком преобразования для выполнения
## некоторых проверок на ошибки и предотвращения соединения
## несовместимых преобразований. При определении преобразований
## для шкалы, которые, по определению, являются разделяемыми и
## имеют только одну размерность, эти члены должны всегда быть
## установлены в 1.
input_dims = output_dims = 1
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform_non_affine(self, a):
"""
Это преобразование принимает numpy-массив и возвращает преобразованную копию.
Поскольку диапазон шкалы Меркатора ограничен пользовательским
порогом, входной массив должен быть замаскирован, чтобы
содержать только допустимые значения. Matplotlib будет обрабатывать
замаскированные массивы и удалять из графика данные за пределами
допустимого диапазона. Однако возвращаемый массив *должен* иметь
ту же форму, что и входной массив, так как эти значения должны
оставаться синхронизированы с значениями в другой размерности.
"""
masked = ma.masked_where((a < -self.thresh) | (a > self.thresh), a)
if masked.mask.any():
return ma.log(np.abs(ma.tan(masked) + 1 / ma.cos(masked)))
else:
return np.log(np.abs(np.tan(a) + 1 / np.cos(a)))
def inverted(self):
"""
Переопределите этот метод, чтобы Matplotlib знал, как получить
обратное преобразование для этого преобразования.
"""
return MercatorLatitudeScale.InvertedMercatorLatitudeTransform(
self.thresh)
Реализуем класс InvertedMercatorLatitudeTransform
Мы также определим класс InvertedMercatorLatitudeTransform, который будет использоваться для получения обратного преобразования для этой шкалы.
class InvertedMercatorLatitudeTransform(mtransforms.Transform):
input_dims = output_dims = 1
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform_non_affine(self, a):
return np.arctan(np.sinh(a))
def inverted(self):
return MercatorLatitudeScale.MercatorLatitudeTransform(self.thresh)
Регистрируем кастомную шкалу
Мы зарегистрируем кастомную шкалу с Matplotlib с использованием mscale.register_scale.
mscale.register_scale(MercatorLatitudeScale)
Используем кастомную шкалу
Теперь мы можем использовать кастомную шкалу в наших графиках. Вот пример использования кастомной шкалы для данных о широте в проекции Меркатора.
if __name__ == '__main__':
import matplotlib.pyplot as plt
t = np.arange(-180.0, 180.0, 0.1)
s = np.radians(t)/2.
plt.plot(t, s, '-', lw=2)
plt.yscale('mercator')
plt.xlabel('Longitude')
plt.ylabel('Latitude')
plt.title('Mercator projection')
plt.grid(True)
plt.show()
Резюме
В этом практическом занятии мы узнали, как создавать кастомную шкалу в Matplotlib с использованием проекции Меркатора для данных о широте. Мы определили классы MercatorLatitudeScale и MercatorLatitudeTransform и зарегистрировали кастомную шкалу с Matplotlib с использованием mscale.register_scale. Мы также показали пример использования кастомной шкалы для данных о широте в проекции Меркатора.