Диаграмма SkewT-logP с использованием Matplotlib

PythonPythonBeginner
Практиковаться сейчас

This tutorial is from open-source community. Access the source code

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

В этом лабораторном занятии мы научимся создавать диаграмму SkewT-logP с использованием библиотеки Matplotlib в Python. Диаграмма SkewT-logP широко используется в метеорологии для отображения вертикальных профилей температуры. Это сложный график, так как он включает неортогональные оси X и Y. Мы будем использовать преобразования и API пользовательских проекций Matplotlib для создания этого графика.

Советы по работе с ВМ

После запуска ВМ нажмите в левом верхнем углу, чтобы переключиться на вкладку Notebook и получить доступ к Jupyter Notebook для практики.

Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook не загрузится полностью. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.

Если вы сталкиваетесь с проблемами при обучении, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.

Импортируем необходимые библиотеки

Начнем с импорта необходимых библиотек. Для примера мы будем использовать Matplotlib, NumPy и StringIO.

from contextlib import ExitStack
from matplotlib.axes import Axes
import matplotlib.axis as maxis
from matplotlib.projections import register_projection
import matplotlib.spines as mspines
import matplotlib.transforms as transforms
import matplotlib.pyplot as plt
import numpy as np
from io import StringIO
from matplotlib.ticker import (MultipleLocator, NullFormatter, ScalarFormatter)

Определяем класс SkewXTick

Класс SkewXTick используется для рисования делений на диаграмме SkewT-logP. Он проверяет, нужно ли нарисовать деление на верхней или нижней оси X и в соответствии с этим настраивает видимость деления и сетки.

class SkewXTick(maxis.XTick):
    def draw(self, renderer):
        with ExitStack() as stack:
            for artist in [self.gridline, self.tick1line, self.tick2line, self.label1, self.label2]:
                stack.callback(artist.set_visible, artist.get_visible())
            needs_lower = transforms.interval_contains(self.axes.lower_xlim, self.get_loc())
            needs_upper = transforms.interval_contains(self.axes.upper_xlim, self.get_loc())
            self.tick1line.set_visible(self.tick1line.get_visible() and needs_lower)
            self.label1.set_visible(self.label1.get_visible() and needs_lower)
            self.tick2line.set_visible(self.tick2line.get_visible() and needs_upper)
            self.label2.set_visible(self.label2.get_visible() and needs_upper)
            super().draw(renderer)

    def get_view_interval(self):
        return self.axes.xaxis.get_view_interval()

Определяем класс SkewXAxis

Класс SkewXAxis используется для предоставления двух отдельных наборов интервалов делениям и создания экземпляров пользовательских делений.

class SkewXAxis(maxis.XAxis):
    def _get_tick(self, major):
        return SkewXTick(self.axes, None, major=major)

    def get_view_interval(self):
        return self.axes.upper_xlim[0], self.axes.lower_xlim[1]

Определяем класс SkewSpine

Класс SkewSpine вычисляет отдельный диапазон данных для верхней оси X и рисует спинну (ребро) там. Он также предоставляет этот диапазон художнику оси X для делений и сеток.

class SkewSpine(mspines.Spine):
    def _adjust_location(self):
        pts = self._path.vertices
        if self.spine_type == 'top':
            pts[:, 0] = self.axes.upper_xlim
        else:
            pts[:, 0] = self.axes.lower_xlim

Определяем класс SkewXAxes

Класс SkewXAxes обрабатывает регистрацию наклонной оси X в качестве проекции, а также настройку соответствующих преобразований. Он переопределяет стандартные экземпляры ребер и осей по необходимости.

class SkewXAxes(Axes):
    name ='skewx'

    def _init_axis(self):
        super()._init_axis()
        self.xaxis = SkewXAxis(self)
        self.spines.top.register_axis(self.xaxis)
        self.spines.bottom.register_axis(self.xaxis)

    def _gen_axes_spines(self):
        spines = {'top': SkewSpine.linear_spine(self, 'top'),
                  'bottom': mspines.Spine.linear_spine(self, 'bottom'),
                  'left': mspines.Spine.linear_spine(self, 'left'),
                  'right': mspines.Spine.linear_spine(self, 'right')}
        return spines

    def _set_lim_and_transforms(self):
        super()._set_lim_and_transforms()
        rot = 30
        self.transDataToAxes = (self.transScale + self.transLimits + transforms.Affine2D().skew_deg(rot, 0))
        self.transData = self.transDataToAxes + self.transAxes
        self._xaxis_transform = (transforms.blended_transform_factory(
            self.transScale + self.transLimits, transforms.IdentityTransform()) + transforms.Affine2D().skew_deg(rot, 0) + self.transAxes)

    @property
    def lower_xlim(self):
        return self.axes.viewLim.intervalx

    @property
    def upper_xlim(self):
        pts = [[0., 1.], [1., 1.]]
        return self.transDataToAxes.inverted().transform(pts)[:, 0]

Регистрируем проекцию

Мы зарегистрируем проекцию с Matplotlib, чтобы мы могли использовать ее в нашем графике.

register_projection(SkewXAxes)

Подготавливаем данные

Мы подготовим данные для нашей диаграммы SkewT-logP. Мы будем использовать модуль StringIO для чтения данных из строки и NumPy для загрузки их в массивы.

data_txt = '''
        978.0    345    7.8    0.8
        971.0    404    7.2    0.2
        946.7    610    5.2   -1.8
     ...
    '''
sound_data = StringIO(data_txt)
p, h, T, Td = np.loadtxt(sound_data, unpack=True)

Создаем диаграмму SkewT-logP

Теперь мы создадим диаграмму SkewT-logP с использованием проекции SkewXAxes, которую мы зарегистрировали ранее. Сначала мы создадим объект Figure и добавим подграфик с проекцией SkewXAxes. Затем мы построим на диаграмме данные о температуре и точке росы с использованием функции semilogy. Наконец, мы установим пределы и деления для осей X и Y и отобразим график.

fig = plt.figure(figsize=(6.5875, 6.2125))
ax = fig.add_subplot(projection='skewx')

ax.semilogy(T, p, color='C3')
ax.semilogy(Td, p, color='C2')

ax.axvline(0, color='C0')

ax.yaxis.set_major_formatter(ScalarFormatter())
ax.yaxis.set_minor_formatter(NullFormatter())
ax.set_yticks(np.linspace(100, 1000, 10))
ax.set_ylim(1050, 100)

ax.xaxis.set_major_locator(MultipleLocator(10))
ax.set_xlim(-50, 50)

plt.grid(True)
plt.show()

Резюме

В этом практическом занятии мы узнали, как создавать диаграмму SkewT-logP с использованием преобразований Matplotlib и API пользовательских проекций. Мы создали класс SkewXTick для рисования делений, класс SkewXAxis для предоставления отдельных интервалов для делений и класс SkewSpine для рисования ребра. Мы также создали класс SkewXAxes для обработки преобразований и регистрации проекции SkewXAxes. Наконец, мы создали диаграмму SkewT-logP, подготовив данные и построив их на подграфике SkewXAxes.