Introducción a la programación en Python
clase 11

Gráficas

En Python la biblioteca más extendida para gráficas 2D y 3D es matplotlib. Permite obtener gráficas de muy buena calidad, con una gran capacidad de control y una curva de aprendizaje moderada. Todos los aspectos de la figura pueden controlarse mediante código. Por más información consultar el sitio de la biblioteca: http://matplotlib.org/.

La siguiente instrucción permite incorporar las gráficas en este documento (sin que se abra una nueva ventana para cada gráfica)

In [2]:
%matplotlib inline

Para poder utilizar Matplotlib desde un programa existe en principio dos opciones. La más directa y tal vez más sencilla es importar el módulo pylab.

In [1]:
from pylab import *

La otra alternativa, más purista, es importar el módulo matplotlib.pyplot (como plt como convención).

In [2]:
import matplotlib.pyplot as plt

La primera forma de usar Matplotlib a través de pylab está diseñada para ser compatible con Matlab, un lenguaje de computación científica muy utilizado.

A continuación un ejemplo de uso sencillo.

In [4]:
from pylab import *
In [5]:
x = linspace(0, 5, 10)
y = x ** 2
In [6]:
figure()
plot(x, y, 'r')
xlabel('x')
ylabel('y')
title('titulo')
show()

Es la forma más directa de iniciarse si uno está familiarizado con Matlab ya que la mayoría de sus funciones están implementadas. Además el código resulta más compacto y sencillo, especialmente para gráficas simples.

In [7]:
subplot(1,2,1)
plot(x, y, 'r--')
subplot(1,2,2)
plot(y, x, 'g*-');

Sin embargo, las opción más recomendada es usar la interfaz provista por pyplot para hacer cosas avanzadas, por ejemplo cuando intervienen varias gráficas y se desea un control más preciso de los elementos. El código puede resultar más complejo y está fuertemente orientado a objetos. A continuación un ejemplo equivalente al anterior.

In [8]:
fig = plt.figure()

axes = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # left, bottom, width, height (range 0 to 1)

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

axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('titulo');

Si bien el código es más elaborado, permite mayor control, como se muestra en el siguiente ejemplo.

In [9]:
fig = plt.figure()

axes1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # main axes
axes2 = fig.add_axes([0.2, 0.5, 0.4, 0.3]) # inset axes

# main figure
axes1.plot(x, y, 'r')
axes1.set_xlabel('x')
axes1.set_ylabel('y')
axes1.set_title('title')

# insert
axes2.plot(y, x, 'g')
axes2.set_xlabel('y')
axes2.set_ylabel('x')
axes2.set_title('insert title');

Existen manejadores de ejes que pueden facilitar la ubicación y distribución de gráficas en una misma figura. Uno de ellos es subplot, el cual se ilustra en los siguientes ejemplos.

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

axes.plot(x, y, 'r')
axes.set_xlabel('x')
axes.set_ylabel('y')
axes.set_title('title');
In [15]:
fig, axes = plt.subplots(nrows=1, ncols=2)

for ax in axes:
    ax.plot(x, y, 'r')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_title('title')

Ejemplo

A modo de ejemplo podemos retomar el ejercicio de la talea y color para visualizar las secuencias de altura y duración resultantes.

In [18]:
import matplotlib.pyplot as plt

def isorritmico(talea, color):
    '''crea una melodía isorrítmica a partir de una talea y un color'''
    # extiende las secuencias para que tengan la misma cantidad de elementos
    clen, tlen = len(color), len(talea)
    talea *= clen
    color *= tlen
    # crea la lista de notas como tuples (altura, duración)
    notas = [(x, y) for x, y in zip(color, talea)]
    return notas

talea = [1.25, 0.75, 0.5, 0.25, 0.5]
color = [72, 62, 59, 56, 67, 70, 66, 57, 63, 76, 73, 65]

notas = isorritmico(talea, color)

altura_duracion = [list(t) for t in zip(*notas)]
alturas = altura_duracion[0]
duraciones = altura_duracion[1]
In [20]:
fig, (ax1, ax2) = plt.subplots(nrows=2, ncols=1)

x = range(len(notas))

ax1.plot(x, alturas, 'r-x')
ax1.set_ylabel('Midi')
ax1.set_title('alturas');

ax2.plot(x, duraciones, 'g--o')
ax2.set_xlabel('nota')
ax2.set_ylabel('negra')
ax2.set_title('duraciones');

Guardar una imagen

Es posible guardar una figura como imagen usando la función savefig de la clase Figura.

In [21]:
fig.savefig("taleacolor.png")

Se pueden controlar varias cosas al guardar una imagen, como por ejemplo los dpi.

In [22]:
fig.savefig("taleacolor.png", dpi=200)

Leyendas

Se pueden agregar leyendas a las gráficas. Esto resulta especialmente útil cuando se superponen gráficas.

In [23]:
x = linspace(0, 5, 10)

fig, ax = plt.subplots()

ax.plot(x, x**2, label="curva 1")
ax.plot(x, x**3, label="curva 2")
ax.legend();

Color, estilo y grosor de líneas

Los colores y estilo de línea se pueden establecer como antes usando el estilo de Matlab.

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

ax.plot(x, x**2, 'b.-') # blue line with dots
ax.plot(x, x**3, 'g--') # green dashed line
ax.set_title('ejemplo lineas');

También se pueden indicar los colores por sus nombres en inglés o su código RGB en valores hexadecimales.

Además es posible indicar un valor de transparencia mediante el parámetro alpha.

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

ax.plot(x, x+1, color="red", alpha=0.5) # half-transparant red
ax.plot(x, x+2, color="#1155dd")        # RGB hex code for a bluish color
ax.plot(x, x+3, color="#15cc55")        # RGB hex code for a greenish color
ax.set_title('ejemplo lineas y transparencia');

El grosor de la línea se puede controlar mediante el parámetro linewidth y el estilo mediante el parámetro linestle.

Mediante marker y markersize se puede establecer un marcador y su tamaño.

In [26]:
fig, ax = plt.subplots(figsize=(12,6))

ax.plot(x, x+1, color="blue", linewidth=0.25)
ax.plot(x, x+2, color="blue", linewidth=0.50)
ax.plot(x, x+3, color="blue", linewidth=1.00)
ax.plot(x, x+4, color="blue", linewidth=2.00)

# possible linestype options ‘-‘, ‘–’, ‘-.’, ‘:’, ‘steps’
ax.plot(x, x+5, color="red", lw=2, linestyle='-')
ax.plot(x, x+6, color="red", lw=2, ls='-.')
ax.plot(x, x+7, color="red", lw=2, ls=':')

# custom dash
line, = ax.plot(x, x+8, color="black", lw=1.50)
line.set_dashes([5, 10, 15, 10]) # format: line length, space length, ...

# possible marker symbols: marker = '+', 'o', '*', 's', ',', '.', '1', '2', '3', '4', ...
ax.plot(x, x+ 9, color="green", lw=2, ls='*', marker='+')
ax.plot(x, x+10, color="green", lw=2, ls='*', marker='o')
ax.plot(x, x+11, color="green", lw=2, ls='*', marker='s')
ax.plot(x, x+12, color="green", lw=2, ls='*', marker='1')

# marker size and color
ax.plot(x, x+13, color="purple", lw=1, ls='-', marker='o', markersize=2)
ax.plot(x, x+14, color="purple", lw=1, ls='-', marker='o', markersize=4)
ax.plot(x, x+15, color="purple", lw=1, ls='-', marker='o', markersize=8, markerfacecolor="red")
ax.plot(x, x+16, color="purple", lw=1, ls='-', marker='s', markersize=8, 
        markerfacecolor="yellow", markeredgewidth=2, markeredgecolor="blue");
ax.set_title('ejemplo de estilos de línea');

Es posible definir una grilla y controlar su apariencia, como en el siguiente ejemplo.

In [30]:
fig, axes = plt.subplots(1, 2, figsize=(10,3))

# default grid appearance
axes[0].plot(x, x**2, x, x**3, lw=2)
axes[0].grid(True)
#axes[0].set_xlim((3,5))
axes[0].set_title('Grilla por defecto');

# custom grid appearance
axes[1].plot(x, x**2, x, x**3, lw=2)
axes[1].grid(color='b', alpha=0.5, linestyle='dashed', linewidth=0.5)
axes[1].set_title('Grilla modificada');

Histogramas

La función hist permite calcular histogramas, como en el siguiente ejemplo.

In [28]:
n = np.random.randn(100000)
fig, axes = plt.subplots()

axes.hist(n)
axes.set_xlim((min(n), max(n)))
axes.set_title("Default histogram");

Otro tipo de gráficas

Existe una serie de funciones especiales para producir otro tipo de gráficos. En el siguiente ejemplo se presentan algunas posibilidades.

In [31]:
xx = np.linspace(-0.75, 1., 100)
n = array([0,1,2,3,4,5])
In [32]:
fig, axes = plt.subplots(1, 4, figsize=(12,3))

axes[0].scatter(xx, xx + 0.25*randn(len(xx)))
axes[0].set_title("scatter")

axes[1].step(n, n**2, lw=2)
axes[1].set_title("step")

axes[2].bar(n, n**2, align="center", width=0.5, alpha=0.5)
axes[2].set_title("bar")

axes[3].fill_between(x, x**2, x**3, color="green", alpha=0.5);
axes[3].set_title("fill_between");
In []: