Aula 03 - Matplotlib

Objetivos

  • Criar gráficos 1-2D
  • Customizar gráficos
  • Criar funções para plots complexos
  • Apresentar Cartopy e criar mapas simples

http://www.labri.fr/perso/nrougier/teaching/matplotlib/matplotlib.html

Matplotlib é um pacote (ou módulo) Python usado pela comunidade científica para produzir gráficos 2D. Esse pacote suporta diversos formatos como PNG, JEPG, PostScript/EPS, PDF e SVG.

Matplotlib traz um sub-pacote de conveniência chamado pyplot que, para manter a consistência com usuários do matplotlib, deve sempre ser importado como plt:


In [ ]:
%matplotlib inline

import matplotlib.pyplot as plt

O coração de todos os gráficos é o objeto figure. O objeto Figure está no pode ser desenhado em qualquer formato de saída ou apenas a tela.


In [ ]:
fig = plt.figure()

Sozinho o objeto Figure não é interessante. Temos que "desenhar" algo nele.

Os objetos de desenho do matplotlib são chamados de Artists. De longe o Artists mais útil é o Axes artist. O Axes artist representa o espaço dos dados (x, y) ou em caso de coordenadas polares (r, $\theta$).

Não há limite no número de Artists que podemos adicionar em uma figura. Vamos ver um exemplo.


In [ ]:
ax = plt.axes()

A maior parte do tempo você vai trabalhar com o objeto Axes. A documentação é bem detalhada e recomendo a leitura, principalmente do método plot:


In [ ]:
ax = plt.axes()

line1 = ax.plot([0, 1, 2, 1.5], [3, 1, 2, 4])

Outros tipos de gráficos


In [ ]:
import numpy as np

x = np.linspace(-180, 180, 60)
y = np.linspace(-90, 90, 30)
x2d, y2d = np.meshgrid(x, y)

data = np.cos(3 * np.deg2rad(x2d)) + np.sin(2 * np.deg2rad(y2d))

In [ ]:
plt.contourf(x, y, data);

In [ ]:
plt.imshow(data, extent=[-180, 180, -90, 90],
           interpolation='nearest', origin='lower');

In [ ]:
plt.pcolormesh(x, y, data);

In [ ]:
plt.scatter(x2d, y2d, c=data, s=15);

In [ ]:
plt.bar(x, data.sum(axis=0), width=np.diff(x)[0]);

In [ ]:
plt.plot(x, data.sum(axis=0),
         linestyle='--',
         marker='d',
         markersize=10,
         color='red');

Títulos, Legendas, colorbars e anotações


In [ ]:
fig = plt.figure()
ax = plt.axes()
fig.subplots_adjust(top=0.8)

fig.suptitle(u'Título do "Figure"', fontsize=18, fontweight='bold')
ax.set_title(u'Título do "Axes', fontsize=16)
ax.set_xlabel('O Eixo X')
ax.set_ylabel('O Eixo Y $y=f(x)$', fontsize=16)
ax.text(0.5, 0.5, 'Texto centrado em (0.5, 0.5)\nin data coordinates.',
        horizontalalignment='center', fontsize=14);

In [ ]:
x = np.linspace(-3, 7, 200)

plt.plot(x, 0.5*x**3 - 3*x**2, linewidth=2,
         label='$f(x)=0.5x^2-3x^2$')

plt.plot(x, 1.5*x**2 - 6*x, linewidth=2, linestyle='--',
         label='Gradiente de $f(x)$', )

plt.legend(loc='lower right')
plt.grid(True)

In [ ]:
x = np.linspace(-180, 180, 60)
y = np.linspace(-90, 90, 30)
x2d, y2d = np.meshgrid(x, y)
data = np.cos(3 * np.deg2rad(x2d)) + np.sin(2 * np.deg2rad(y2d))

plt.contourf(x, y, data)
plt.colorbar(orientation='horizontal');

In [ ]:
x = np.linspace(-3, 7, 200)
plt.plot(x, 0.5*x**3 - 3*x**2, linewidth=2)
plt.annotate('Local minimum',
             xy=(4, -18),
             xytext=(-2, -40), fontsize=15,
             arrowprops={'facecolor': 'black', 'frac': 0.3})
plt.grid(True)

In [ ]:
plt.plot(range(10))

plt.savefig('simple.svg')

In [ ]:
from IPython.display import SVG

SVG('./simple.svg')

Exemplo com dados reais


In [ ]:
import numpy as np
import numpy.ma as ma

data = np.loadtxt("./data/dados_pirata.csv", skiprows=1,
                  usecols=range(2, 16), delimiter=',')

data = ma.masked_less_equal(data, -9999)

In [ ]:
plt.pcolormesh(np.flipud(data.T))
plt.colorbar();

In [ ]:
fig, ax = plt.subplots(figsize=(12.5, 5))

cs = ax.pcolormesh(np.flipud(data.T))

fig.colorbar(cs);

In [ ]:
z = [1, 10, 100, 120, 13, 140, 180, 20, 300, 40, 5, 500, 60, 80]

fig, ax = plt.subplots()
ax.plot(data[42, :], z, 'ko')
ax.invert_yaxis()

In [ ]:
fig, ax = plt.subplots(figsize=(9, 3))

ax.plot(data[:, 0])

ax.set_xlabel("Tempo")
ax.set_ylabel("Temperatura")
ax.set_title(u"Série-temporal PIRATA");

In [ ]:
def plot_ts(data):
    fig, ax = plt.subplots(figsize=(9, 3))

    ax.plot(data)
    ax.set_xlabel("Tempo")
    ax.set_ylabel("Temperatura")
    ax.set_title(u"Série-temporal PIRATA")

In [ ]:
plot_ts(data)

In [ ]:
from matplotlib import style

style.available

In [ ]:
with style.context('dark_background'):
    plot_ts(data[:, 0])

In [ ]:
with style.context('ggplot'):
    plot_ts(data[:, 0])

In [ ]:
style.use('ggplot')

n, bins, pathes = plt.hist(data[0, :])

In [ ]:
style.use('ggplot')

idx = 0
mask = data.mask[:, 0]

n, bins, pathes = plt.hist(data[:, 0].data[~mask], bins=10)

In [ ]:
idx = 12

mask = data.mask[:, idx]

n = plt.hist(data[:, idx].data[~mask], bins=30)

In [ ]:
def make_wave():
    twopi = 2 * np.pi
    n = 2
    A = 2
    w = twopi / 10
    k = twopi / 200
    phi = np.deg2rad(180)
    t = np.arange(0, 10 * n, 0.01)
    y = A * np.cos(w * t - k * 0 + phi)

    fig, ax = plt.subplots(figsize=(8, 4))
    ax.plot(t, y, linewidth='2', color='#006633')
    ax.set_frame_on(False)
    ax.axis([-0.1, 20.1, -3, 3])
    ax.get_xaxis().set_ticks([])
    ax.get_yaxis().set_ticks([])

    # Box.
    kw = dict(linestyle='--', color='grey', zorder=90)
    ax.axhline(y=2, xmin=0.15, xmax=0.85, **kw)
    ax.axhline(y=-2, xmin=0.15, xmax=0.85, **kw)
    ax.axvline(x=5, ymin=-0.15, ymax=1.85, **kw)
    ax.axvline(x=15, ymin=-0.15, ymax=1.85, **kw)

    # Zero line.
    _ = ax.annotate('', xy=(20, 0), xycoords='data',
                xytext=(0, 0), textcoords='data',
                arrowprops=dict(arrowstyle='->', color='black'))

    _ = ax.annotate(u'Espaço', xy=(20, 0), xycoords='data',
                xytext=(20, 0.05), textcoords='data', 
                va='bottom', ha='right', color='blue')

    _ = ax.annotate('Tempo', xy=(20, 0), xycoords='data',
                xytext=(20, -0.05), textcoords='data', 
                va='top', ha='right', color='red')

    # Arrow commom properties.
    arrowprops = dict(arrowstyle='<->', color='black')

    # Wave period (or length).
    _ = ax.annotate('', xy=(15, 2.5), xycoords='data',
                xytext=(5, 2.5), textcoords='data',
                arrowprops=arrowprops)

    _ = ax.annotate(u'Comprimento', xy=(10, 2.5), xycoords='data',
                xytext=(10, 2.55), textcoords='data', 
                va='bottom', ha='center', color='blue')

    _ = ax.annotate(u'Período', xy=(10, 2.5), xycoords='data',
                xytext=(10, 2.45), textcoords='data', 
                va='top', ha='center', color='red')

    # Amplitude.
    _ = ax.annotate('', xy=(5, 2), xycoords='data',
                xytext=(5, 0), textcoords='data',
                arrowprops=arrowprops)

    _ = ax.annotate('Amplitude', xy=(5, 1), xycoords='data',
                xytext=(4.9, 1), textcoords='data', 
                va='center', ha='right', rotation=90)

    # Height.
    ax.annotate('', xy=(15, 2), xycoords='data',
                xytext=(15, -2), textcoords='data',
                arrowprops=arrowprops)

    _ = ax.annotate('Altura', xy=(15, 1), xycoords='data',
                xytext=(14.9, 0.1), textcoords='data', 
                va='bottom', ha='right', rotation=90)

    # Angle.
    _ = ax.annotate('', xy=(15, 2), xycoords='data',
                xytext=(5, -2), textcoords='data',
                arrowprops=arrowprops)

    _ = ax.annotate(u'Inclinação', xy=(10, 0), xycoords='data',
                xytext=(10.5, 0.5), textcoords='data', 
                va='center', ha='center', rotation=35)

In [ ]:
make_wave()

In [ ]:
from matplotlib.dates import date2num


def stick_plot(time, u, v, **kw):
    width = kw.pop('width', 0.002)
    headwidth = kw.pop('headwidth', 0)
    headlength = kw.pop('headlength', 0)
    headaxislength = kw.pop('headaxislength', 0)
    angles = kw.pop('angles', 'uv')
    ax = kw.pop('ax', None)
    
    if angles != 'uv':
        raise AssertionError("Stickplot angles must be 'uv' so that"
                             "if *U*==*V* the angle of the arrow on"
                             "the plot is 45 degrees CCW from the *x*-axis.")

    time, u, v = map(np.asanyarray, (time, u, v))
    if not ax:
        fig, ax = plt.subplots()
    
    q = ax.quiver(date2num(time), [[0]*len(time)], u, v,
                  angles='uv', width=width, headwidth=headwidth,
                  headlength=headlength, headaxislength=headaxislength,
                  **kw)

    ax.axes.get_yaxis().set_visible(False)
    ax.xaxis_date()
    return q

def make_quiver():
    from datetime import datetime, timedelta

    x = np.arange(100, 110, 0.1)
    start = datetime.now()
    time = [start + timedelta(days=n) for n in range(len(x))]
    u, v = np.sin(x), np.cos(x)


    fig, ax = plt.subplots(figsize=(11, 2.75))

    q = stick_plot(time, u, v, ax=ax, width=0.002, color='green')

    ref = 1
    qk = ax.quiverkey(q, 0.1, 0.85, ref,
                      "%s N m$^{-2}$" % ref,
                      labelpos='N', coordinates='axes')

In [ ]:
make_quiver()

In [ ]:
from IPython.display import IFrame

url = "http://matplotlib.org/gallery.html"

IFrame(url, width=900, height=500)

Exercícios usando os dados da boia Piratas

  • 1) Plotar dois perfis verticais lado a lado e compartilhando o eixo y. Dica: use o método plt.subplots()

  • 2) Plotar as séries temporais, superfície e fundo, alinhadas verticalmente e compartilhando o eixo x

  • 3) Perfil vertical médio para todo o período


In [ ]:
!head -1 ./data/dados_pirata.csv

In [ ]:
fig, (ax0, ax1) = plt.subplots(ncols=2, sharey=True)

Z = [1, 10, 100, 120, 13, 140, 180, 20, 300, 40, 5, 500, 60, 80]

ax0.plot(data[42, :], Z, 'o')
ax1.plot(data[342, :], Z, 'o')

ax0.invert_yaxis()

In [ ]:
!head -1 ./data/dados_pirata.csv

In [ ]:
fig, (ax0, ax1) = plt.subplots(nrows=2, sharex=True)

ax0.plot(data[:, 0])
ax1.plot(data[:, -3]);

In [ ]:
fig, ax = plt.subplots()

Z = [1, 10, 100, 120, 13, 140, 180, 20, 300, 40, 5, 500, 60, 80]

ax.plot(data.mean(axis=0), Z, 'o')

ax.invert_yaxis()

Perguntas

  • 1) Como fazer para realizar operações (médias, max, min, etc) apenas nos ano (ou meses) desses dados?
  • 2) Como ordenar o eixo z para podermos ligar as linhas?

In [ ]:
url = "https://ocefpaf.github.io/python4oceanographers/blog/2013/12/09/zoom/"

IFrame(url, width=900, height=500)