Matplotlib

Que és?

  • Estándar de facto para visualización en Python
  • Pretende ser similar a las funciones de visualización de MATLAB
  • Diferentes formas de usarla: interfaz pyplot y orientada a objetos

Ejemplos: http://matplotlib.org/gallery.html#pylab_examples

Lo primero que vamos a hacer es activar el modo inline para que muestre figuras en el cuaderno IPython, en lugar de en una ventana nueva.


In [131]:
%matplotlib inline

Importamos los módulos que necesitamos


In [132]:
import numpy as np
import matplotlib.pyplot as plt

API Matlab

Esta API está diseñada para ser compatible con la funciones de "plotting" de MATLAB, de manera tal que la transición desde dicha plataforma sea lo más amena posible.

Para dibujar un conjunto de puntos ejecutamos:


In [133]:
plt.plot([0, 0.1, 0.2, 0.5,0.6], [1, -1, 0, 3, -1], 'ro-')


Out[133]:
[<matplotlib.lines.Line2D at 0x135375d0>]

La tarea más habitual a la hora de trabajar con matplotlib es representar una función. Lo que tendremos que hacer es definir un dominio y evaluarla en dicho dominio.

Definimos el dominio con la función np.linspace, que crea un vector de puntos equiespaciados:


In [134]:
x = np.linspace(-10, 10, 20)
x


Out[134]:
array([-10.        ,  -8.94736842,  -7.89473684,  -6.84210526,
        -5.78947368,  -4.73684211,  -3.68421053,  -2.63157895,
        -1.57894737,  -0.52631579,   0.52631579,   1.57894737,
         2.63157895,   3.68421053,   4.73684211,   5.78947368,
         6.84210526,   7.89473684,   8.94736842,  10.        ])

In [135]:
y = x ** 3

In [136]:
plt.figure()
plt.plot(x, y, 'ro-')
plt.xlabel('x')
plt.ylabel('y')
plt.title('titulo')
plt.legend(["$y = x ^ 3$"])
plt.show()


Notamos varias cosas:

  • Con diversas llamadas a funciones dentro de plt. se actualiza el gráfico actual. Esa es la forma de trabajar con la interfaz pyplot.
  • Podemos añadir etiquetas, y escribir $\LaTeX$ en ellas. Tan solo hay que encerrarlo entre signos de dólar $$.

In [137]:
x = np.linspace(-10, 10, 100)
plt.plot(x, x ** 3, 'ro')
plt.plot(x, -(x**3), 'g--')


Out[137]:
[<matplotlib.lines.Line2D at 0x1700b310>]

Otros tipos de gráficas

Diagramas de dispersión

La función scatter muestra una nube de puntos, con posibilidad de variar también el tamaño y el color.


In [138]:
n = 500
x = np.random.randn(n)
y = np.random.randn(n)

plt.scatter(x, y)


Out[138]:
<matplotlib.collections.PathCollection at 0x1670e950>

Curvas de nivel

La función contour se utiliza para visualizar las curvas de nivel de funciones de dos variables y está muy ligada a la función np.meshgrid. Veamos un ejemplo:

$$f(x) = \cos{x} + \sin^2{y}$$

In [139]:
def f(x, y):
    return np.cos(x) + np.sin(y) ** 2

x = np.linspace(-2, 2)
y = np.linspace(-2, 2)
xx, yy = np.meshgrid(x, y)

plt.contour(xx, yy, f(xx, yy))
plt.colorbar()


Out[139]:
<matplotlib.colorbar.Colorbar instance at 0x13c4a3b0>

La función contourf es casi idéntica pero rellena el espacio entre niveles. Podemos especificar manualmente estos niveles usando el cuarto argumento:


In [140]:
zz = f(xx, yy)
plt.contourf(xx, yy, zz, np.linspace(-0.5, 2.0))
plt.colorbar()


Out[140]:
<matplotlib.colorbar.Colorbar instance at 0x13c7c1b8>

API orientada a objetos

Esta API está diseñada para tener un complto control en cada uno de los objetos que forman parte de la figura.

En la programación orientada a objetos contamos con un conjunto de objetos que tienen estado propio y podemos modificar este estado invocando métodos de estos objetos. Ningún estado de un objeto o programa debe ser global (tal como en la API tipo MATLAB). La ventaja de esta forma de trabajo se manifiesta cuando se requiere crear más de una figura, o cuando una figura contiene sub-figuras.

Para usar la API orientada al objeto distingue dos clases de objetos en un gráfico:

  • La figura almacena los datos de la imagen que queremos generar (tamaño, tipo, resolución, etc)
  • Los ejes representa la grafica que queremos realizar

Comenzamos similarmente al ejemplo anterior, pero en lugar de crear una instancia de figura global almacenamos una referencia a la figura recién creada en la variable fig, y a partir de ella creamos nuevos ejes usando el método add_axes en la instancia fig de la clase Figure.


In [141]:
x = np.linspace(-5, 5, 100)
y = x ** 2

fig = plt.figure(figsize=(10,5), dpi=100)

# Creo los ejes e indico donde se van a ubicar en la figura: izquierda, abajo, ancho, altura (rango 0 a 1)
ejes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) 

ejes.plot(x, y, 'r')

ejes.set_xlabel('x')
ejes.set_ylabel('y')
ejes.set_title(u'Título')
ejes.grid(True)



In [142]:
fig.savefig("figura2d")

Subplots

Utilizando la función subplots podemos dibujar más de una gráfica en una figura


In [143]:
fig, (axes1, axes2) = plt.subplots(1, 2, sharey=True)

fig.set_size_inches(10,5)

axes1.plot(x, x**2, color="blue")
axes1.set_xlabel("Eje x")
axes1.grid(True)

axes2.plot(x, -x**2, 'r')
axes2.set_xlabel(u"Eje x de la gráfica derecha")
axes2.grid(True)


Ejemplo con datos reales


In [144]:
!head temperaturas.csv


STATION,DATE,TMAX,TMIN
GHCND:USW00094728,20130101,44,-33
GHCND:USW00094728,20130102,6,-56
GHCND:USW00094728,20130103,0,-44
GHCND:USW00094728,20130104,28,-11
GHCND:USW00094728,20130105,56,0
GHCND:USW00094728,20130106,78,11
GHCND:USW00094728,20130107,72,28
GHCND:USW00094728,20130108,89,17
GHCND:USW00094728,20130109,94,39

In [145]:
datos = np.loadtxt("temperaturas.csv", usecols=(1, 2, 3), skiprows=1, delimiter=',')

In [146]:
datos


Out[146]:
array([[  2.01301010e+07,   4.40000000e+01,  -3.30000000e+01],
       [  2.01301020e+07,   6.00000000e+00,  -5.60000000e+01],
       [  2.01301030e+07,   0.00000000e+00,  -4.40000000e+01],
       ..., 
       [  2.01312300e+07,   7.20000000e+01,  -4.90000000e+01],
       [  2.01312310e+07,   0.00000000e+00,  -6.00000000e+01],
       [  2.01401010e+07,   6.00000000e+00,  -4.30000000e+01]])

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

fig.set_size_inches(20,10)

x = np.arange(len(datos[:, 1]))

temp_media = (datos[:, 1] + datos[:, 2]) / 2

axes.plot(x, datos[:, 1], 'r')
axes.plot(x, datos[:, 2], 'b')
axes.plot(x, temp_media, 'k')


Out[147]:
[<matplotlib.lines.Line2D at 0x16ae65d0>]

In [148]:
cotizaciones = np.loadtxt("cotizacion.csv", usecols=(1, 2), skiprows=1, delimiter=',')

In [149]:
import csv

fechas = []
with open('cotizacion.csv', 'rb') as csvfile:
    filas = csv.reader(csvfile, delimiter=',')
    for f in filas:
        fechas.append(str(f[0]))
fechas = fechas[1:]

In [150]:
cotizaciones


Out[150]:
array([[  4.   ,   4.11 ],
       [  4.   ,   4.12 ],
       [  4.   ,   4.138],
       ..., 
       [  8.03 ,  10.5  ],
       [  8.01 ,  10.55 ],
       [  8.01 ,  10.5  ]])

In [151]:
fechas[0], fechas[-1]


Out[151]:
('03/01/11', '06/05/14')

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

fig.set_size_inches(20,10)

x = range(len(cotizaciones))

axes.grid(True)

axes.plot(x, cotizaciones[:, 0], 'g')
axes.plot(x, cotizaciones[:, 1], 'b')
paso = len(x)/10
axes.set_xticks(x[::paso])
axes.set_xticklabels(fechas[::paso], rotation=45)


Out[152]:
[<matplotlib.text.Text at 0x16ae9790>,
 <matplotlib.text.Text at 0x16acd310>,
 <matplotlib.text.Text at 0x18270d10>,
 <matplotlib.text.Text at 0x16aca4d0>,
 <matplotlib.text.Text at 0x16acac50>,
 <matplotlib.text.Text at 0x16ad8410>,
 <matplotlib.text.Text at 0x16ad8b90>,
 <matplotlib.text.Text at 0x16ad6350>,
 <matplotlib.text.Text at 0x16ad6ad0>,
 <matplotlib.text.Text at 0x16ad2290>,
 <matplotlib.text.Text at 0x16ad2a10>]

Graficos en tres dimensiones


In [153]:
from mpl_toolkits.mplot3d.axes3d import Axes3D

In [154]:
alpha = 0.7
phi_ext = 2 * np.pi * 0.5
phi_m = np.linspace(0, 2*np.pi, 100)
phi_p = np.linspace(0, 2*np.pi, 100)

def flux_qubit_potential(phi_m, phi_p):
    return 2 + alpha - 2 * np.cos(phi_p)*np.cos(phi_m) - alpha * np.cos(phi_ext - 2*phi_p)

X,Y = np.meshgrid(phi_p, phi_m)
Z = flux_qubit_potential(X, Y).T

In [155]:
fig = plt.figure(figsize=(16,10))

ax = fig.add_subplot(1, 1, 1, projection='3d')

p = ax.plot_surface(X, Y, Z, rstride=4, cstride=4, linewidth=0)



In [156]:
fig.savefig("figura3d")

In [157]:
fig = plt.figure(figsize=(16,10))

ax = fig.add_subplot(1, 1, 1, projection='3d')

p = ax.plot_wireframe(X, Y, Z, rstride=4, cstride=4)



In [158]:
fig = plt.figure(figsize=(16,10))

ax = fig.add_subplot(1,1,1, projection='3d')

ax.plot_surface(X, Y, Z, rstride=4, cstride=4, alpha=0.25)
cset = ax.contour(X, Y, Z, zdir='z', offset=-np.pi)
cset = ax.contour(X, Y, Z, zdir='x', offset=-np.pi)
cset = ax.contour(X, Y, Z, zdir='y', offset=3*np.pi)

ax.set_xlim3d(-np.pi, 2*np.pi);
ax.set_ylim3d(0, 3*np.pi);
ax.set_zlim3d(-np.pi, 2*np.pi);