Matplotlib 를 사용한 SkewT-logP 다이어그램

Beginner

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

소개

이 랩에서는 Python 의 Matplotlib 라이브러리를 사용하여 SkewT-logP 다이어그램을 만드는 방법을 배웁니다. SkewT-logP 다이어그램은 기상학에서 온도 수직 프로파일을 표시하는 데 일반적으로 사용됩니다. 이는 비직교 X 및 Y 축을 포함하므로 복잡한 플롯입니다. Matplotlib 의 변환 (transforms) 및 사용자 정의 투영 (custom projection) API 를 사용하여 이 플롯을 생성합니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단을 클릭하여 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 클래스는 skew-xaxes 를 투영 (projection) 으로 등록하고 적절한 변환을 설정하는 것을 처리합니다. 필요에 따라 표준 스파인 (spines) 및 축 (axes) 인스턴스를 재정의합니다.

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]

투영 (Projection) 등록

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 다이어그램 생성

이제 앞서 등록한 SkewXAxes 투영을 사용하여 SkewT-logP 다이어그램을 생성합니다. 먼저 figure 객체를 생성하고 SkewXAxes 투영을 사용하여 서브플롯 (subplot) 을 추가합니다. 그런 다음 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()

요약

이 랩에서는 Matplotlib 의 변환 (transforms) 과 사용자 정의 투영 API 를 사용하여 SkewT-logP 다이어그램을 만드는 방법을 배웠습니다. 눈금을 그리기 위해 SkewXTick 클래스를 생성하고, 눈금에 대한 별도의 간격을 제공하기 위해 SkewXAxis 클래스를, 그리고 스파인 (spine) 을 그리기 위해 SkewSpine 클래스를 생성했습니다. 또한 SkewXAxes 투영의 변환 및 등록을 처리하기 위해 SkewXAxes 클래스를 생성했습니다. 마지막으로 데이터를 준비하고 SkewXAxes 서브플롯에 플롯하여 SkewT-logP 다이어그램을 생성했습니다.