Diagrama SkewT-logP Usando Matplotlib

Beginner

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

Introdução

Neste laboratório, aprenderemos como criar um diagrama SkewT-logP usando a biblioteca Matplotlib em Python. Um diagrama SkewT-logP é comumente usado em meteorologia para exibir perfis verticais de temperatura. É um gráfico complexo, pois envolve eixos X e Y não ortogonais. Usaremos as transformações e a API de projeção personalizada do Matplotlib para criar este gráfico.

Dicas para a VM

Após a inicialização da VM, clique no canto superior esquerdo para mudar para a aba Notebook e acessar o Jupyter Notebook para praticar.

Às vezes, pode ser necessário aguardar alguns segundos para que o Jupyter Notebook termine de carregar. A validação das operações não pode ser automatizada devido a limitações no Jupyter Notebook.

Se você enfrentar problemas durante o aprendizado, sinta-se à vontade para perguntar ao Labby. Forneça feedback após a sessão, e resolveremos o problema prontamente para você.

Importar as Bibliotecas Necessárias

Começaremos importando as bibliotecas necessárias. Usaremos Matplotlib, NumPy e StringIO para este exemplo.

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)

Definir a Classe SkewXTick

A classe SkewXTick é usada para desenhar os ticks no diagrama SkewT-logP. Ela verifica se o tick precisa ser desenhado no eixo X superior ou inferior e, consequentemente, define a visibilidade do tick e da linha de grade.

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()

Definir a Classe SkewXAxis

A classe SkewXAxis é usada para fornecer dois conjuntos separados de intervalos ao tick e criar instâncias do tick personalizado.

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]

Definir a Classe SkewSpine

A classe SkewSpine calcula a faixa de dados separada do eixo X superior e desenha a espinha (spine) ali. Ela também fornece essa faixa ao artista do eixo X para ticks e linhas de grade.

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

Definir a Classe SkewXAxes

A classe SkewXAxes lida com o registro dos eixos skew-x como uma projeção, bem como a configuração das transformações apropriadas. Ela substitui as instâncias padrão de spines e eixos conforme apropriado.

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]

Registrar a Projeção

Registraremos a projeção com o Matplotlib para que possamos usá-la em nosso gráfico.

register_projection(SkewXAxes)

Preparar os Dados

Prepararemos os dados para o nosso diagrama SkewT-logP. Usaremos o módulo StringIO para ler os dados de uma string e o NumPy para carregá-los em arrays.

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)

Criar o Diagrama SkewT-logP

Agora criaremos o diagrama SkewT-logP usando a projeção SkewXAxes que registramos anteriormente. Primeiro, criaremos um objeto figura e adicionaremos um subplot com a projeção SkewXAxes. Em seguida, plotaremos os dados de temperatura e ponto de orvalho no diagrama usando a função semilogy. Finalmente, definiremos os limites e as marcações (ticks) para os eixos X e Y e exibiremos o gráfico.

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()

Resumo

Neste laboratório, aprendemos como criar um diagrama SkewT-logP usando as transformações do Matplotlib e a API de projeção personalizada. Criamos uma classe SkewXTick para desenhar as marcações (ticks), uma classe SkewXAxis para fornecer intervalos separados para as marcações e uma classe SkewSpine para desenhar a espinha (spine). Também criamos uma classe SkewXAxes para lidar com as transformações e o registro da projeção SkewXAxes. Finalmente, criamos um diagrama SkewT-logP preparando os dados e plotando-os no subplot SkewXAxes.