Esta Librería es una de las varias que existen para realizar gráficos en Python. No es la única, pero es sin duda la más usada.
Ventajas:
Muchas información en https://matplotlib.org/
Y una cantidad impresionante de ejemplos (con el código para usarlo en un dibujo similar) en: https://matplotlib.org/stable/plot_types/index.html
Y diagramas para referencias rápidas en: https://matplotlib.org/cheatsheets/
Para usarlo hay que cargar NumPy de manera Obligatoria
Matplotlib se construyó para su uso sobre NumPy
Algunos de los ejemplos presentados en este capítulo fueron tomados de https://matplotlib.org/stable/gallery/
pyplot es lainterfase a la biblioteca de matplotlib. Pyplot está diseñada siguiendo el estilo de un lenguaje llamado Matlab que fue muy exitoso en ingeniería y ciencia. Por lo cual a Matplotlib se accede a traves de pyplot con el siguiente comando:
import matplotlib.pyplot as plt
Es decir de matplotlib cargamos pyplot para usarla esta librería y sus funciones, vemos un ejemplo:
import numpy as np
import matplotlib.pyplot as plt # Esta es la librería para graficar
plt.rcParams["figure.figsize"] = (4,2.5) # <- Este comando es para que la
# versión impresa de este notebook
# tenga las dimensiones
# correctas, el lector debe
# ignorarlo.
Hay mucha información de como usar esta librería en la página oficial: http://matplotlib.org/
Veamos que Matplotlib es muy fácil de usar
x = np.arange(10) # defino un arreglo para tener un referencia
y dibujo $f(x)=x^3$ de una manera compacta.
plt.plot(x, x**3); # El ";" al final es para que no me salga una
# descripción del objeto estilo
# [<matplotlib.lines.Line2D at 0x7fbd28b9b590>]
Cómo pueden ver en el ejemplo, este gráfico nos llevó sólo una línea de código.
El método plot de matplotlib, necesitó la abscisa que es el arreglo NumPy x y la ordenada que es el resultado del cálculo de $f(x)=x^3$, que se realizó al vuelo mientras se corrió el código. Note que no se hizo indicación alguna del tipo de línea, color o punto en el dibujo. Es decir se cargaron valores "default" pre-programados.
Hay modos compactos de órdenes para modificar el gráfico, veamos algunas.
Y también podemos superponer gráficos
plt.plot(x,x**2,':g') #<--- determina la línea
plt.plot(x,x**2,'ob'); #<--- determina los puntos
En este ejemplo, se generaron dos gráficos, uno por línea de código. En la primera línea, se agrego ':g' que significa en un modo muy compacto ":" línea de puntos y "g" color verde (la g es de green). En la segundo línea ahora el "o" indica un punto lleno y "b" color azul (la b es de blue)
Note que la segunda orden no une puntos, y es entonces un gráfico de puntos discretos (no conectados o "scatter" en inglés)
También podría haber utilizado una orden no tan compacta y ser más descriptivo de lo que estoy programando.
plt.plot(x, x**2, c='green', marker='^');
En este ejemplo pueden ver que el color y el símbolo se pueden poner también modos no tan comprimidos y más claros para el lector del código. "c" o "color" indicará el color y "marker" el símbolo para marcar los puntos en el dibujo.
# Para ver como usar la ventana interactiva:
%matplotlib tk
plt.plot(x, x**2, '*b');
Corriendo este ejemplo ahora la ventana del gráfico se va del Notebook hacia el escritorio de la computadora. Este se debe al uso del comando "%matplotlib tk"
que lo puedo revertir con la orden que sigue:
# volviendo al inline graphics mode
%matplotlib inline
plt.rcParams["figure.figsize"] = (4,2.5)
# Genero dos arreglos NumPy
x = np.linspace(0, 20, 100) # 100 valores separados de 0 to 20
y = np.sin(x)
# y los dibujo, pero en el segundo realizo otro cálculo en los valores de la ordenada.
plt.plot(x, y)
plt.plot(x, y**2);
Veamos este dibujo:
plt.plot(x, y);
Pero resulta que quiero que sea entre 0, y 4$\pi$, o que la ordenada este en el rango (-1.5,1)
Tengo que fijar entonces estos límites en ambos ejes. para ello uso los siguientes comandos: xlim, e ylim.
Si no los uso, el gráfico se realizará con valores "default" determinados por el propio Python
plt.plot(x, y)
plt.xlim((0., 4*np.pi))
plt.ylim((-1.5,1.5))
plt.plot(x, y)
plt.xlim((0., np.pi*2))
plt.plot(x, y)
plt.xlim((0., np.pi*3))
No funcionó, sólo veo el último dibujo. El primero se me perdió.
Si tengo más de una figura en una celda, tengo que "cerrar" el primero para que se grafique en la pantalla. Si no lo hago sólo veré el último de estos. Para cerrar el dibujo tengo que usar el comando "plt.show( )"
plt.plot(x, y)
plt.xlim((0., np.pi*2))
plt.show()
plt.plot(x, y)
plt.xlim((0., np.pi*3))
plt.show()
Para ello se utiliza el comando plt.title('texto') donde como string de texto se escribe el título. Los nombres de cada eje se indican con los comandos plt.xlabel('texto') y plt.ylabel('texto') para cada eje respectivamente.
plt.plot(x, y)
plt.xlim((0., np.pi*2))
plt.title('Sen(x) entre 0 y $2\pi$')
plt.xlabel('x')
plt.ylabel('f(x)');
help(plt.plot)
A cada curva o puntos específicos dentro de una figura se los puede diferenciar con una leyenda que se escribe con el comando que los dibuja. Y luego al final, indicando el lugar de la figura donde se pondrá esta leyenda.
x = np.linspace(0, 20, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, '-b', label='seno')
plt.plot(x, y2, '-r', label='coseno')
plt.legend(loc='upper right')
plt.ylim((-1.5, 2.0));
En este caso indicamos con rojo el $\sin(x)$ en azul y el $\cos(x)$ en rojo. Luego la leyenda la dibujamos arriba ("upper") y a la derecha ("right") con el comando plt.legend( ).
Afortunamente la gente de Matplotlib a generado este dibujo que da nombre a las partes de un gráfico del tipo de los que se usan ciencia. Con estos nombres es muy fácil buscar (o adivinar) el comando que se necesita para su modificación para que el dibujo quede a gusto del usuario o bien de los requerimientos de las revistas o congresos.
(Todo es un objeto en Python)
Puedo crear el objeto y luego modificar sus parámetros y agregar lo que quiero graficar. Suele ser más laborioso (no mucho) y las órdenes no son las mismas que las que vimos hasta ahora, pero muy parecidas. La forma de trabajo es que por un lado tengo la figura en sí, y por otro los ejes (ya que puede haber varios) y modifico cada uno con lo que necesito
fig = plt.figure() # una nueva ventana con una figura
ax = fig.add_subplot(1, 1, 1) # especifico (número de filas, columnas, número de figura (axn))
fig, ax = plt.subplots() # Creo la figura como dos objetos: figura en si y ejes
ax.plot(x, y1)
ax.plot(x, y2)
ax.set_xlim(0., 2*np.pi)
ax.legend(['seno', 'coseno'], loc='best')
ax.set_xlabel("$x$")
ax.set_ylabel("$\sin(x)$")
ax.set_title("Yo amo el número $\pi$");
# Lo que sigue desplega una cantidad my grande de información, por ahora lo tengo comentado
#help(ax)
Los gráficos logarítmicos se pueden hacer con un eje logaritmico y otro lineal o con ambos ejes logarítmicos
Si el eje X es el logarítmico puede hacer el gráfico así, donde queda muy claro su escala
xl = np.logspace(1, 4, 100)
fig, ax = plt.subplots()
ax.semilogx(xl, xl**2);
O dejarlo que ponga del valor del logaritmo en el eje directamente, auqnue en esta forma queda menos claro que clase de magnitud es.
xl = np.logspace(1, 4, 100)
fig, ax = plt.subplots()
ax.plot(np.log10(xl), xl**2);
Puedo hacer lo mismo para el eje de las ordenadas (note que cambio entonces "plt.semilogX" por "plt.semilogY")
fig, ax = plt.subplots()
ax.semilogy(xl, xl**3);
fig, ax = plt.subplots(figsize=(6,6))
ax.loglog(xl, xl**3);
ax.grid(True,which="both",ls=":", c='blue')
Hay mucha libertad para elegir el símbolo para el punto, su tamaño y su color veamos un dibujo donde elijo las coordenadas, tamaño y color al azar.
xr = np.random.rand(100)
yr = np.random.rand(100)
cr = np.random.rand(100)
sr = np.random.rand(100)
fig, ax = plt.subplots()
sc = ax.scatter(xr, yr, c=cr, s=30+sr*100, edgecolor='none', alpha=0.5) # colores y tamaños dependen
# del valor de las variables
# que en este caso son números
# al azar
fig.colorbar(sc);
Calculando $\pi$
Con el método de las piedras. Tira 5000 de estas y me fijo
npts = 50000
xs = 2*np.random.rand(npts)-1
ys = 2*np.random.rand(npts)-1
r = xs**2+ys**2
ninside = (r<1).sum()
plt.figure(figsize=(6,6)) # Para que la figura sea cuadrada
plt.title("Aproximación a $\pi$ = %f" % (4*ninside/float(npts)))
plt.plot(xs[r<1],ys[r<1],'b.')
plt.plot(xs[r>1],ys[r>1],'r.')
print("Pi da:", ninside/npts*4)
Para dejar fijos algunos valores "domésticos" del dibujo tenemos dos formas de establecerlos:
Con la orden plc.rc('Lo que queremos cambiar', nuevo valor), donde nuevo valor puede ser una variable en la que está el valor del nuevo parámetro. O la orden:
import matplotlib # cargo TODA la matplotlib
matplotlib.rc('Lo que queremos cambiar', nuevo valor) # modifico un parámetro
Veamos algunos ejemplos:
SMALL_SIZE = 8
MEDIUM_SIZE = 10
BIGGER_SIZE = 12
plt.rc('font', size=SMALL_SIZE) # controls default text sizes
plt.rc('axes', titlesize=SMALL_SIZE) # fontsize of the axes title
plt.rc('axes', labelsize=MEDIUM_SIZE) # fontsize of the x and y labels
plt.rc('xtick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('ytick', labelsize=SMALL_SIZE) # fontsize of the tick labels
plt.rc('legend', fontsize=SMALL_SIZE) # legend fontsize
plt.rc('figure', titlesize=BIGGER_SIZE) # fontsize of the figure title
# y lo mismo se puede hacar para los demás parámetros del
# gráfico
## Ejemplo:
plt.plot(x,np.sin(x))
plt.title('Original')
plt.show()
print("")
print("Hago un cambio en los números de los ticks del eje X")
plt.rc('xtick', labelsize=BIGGER_SIZE)
plt.title('Modifico el eje X')
plt.plot(x,np.sin(x))
plt.show()
print("")
print("y si ahora cambio el eje Y")
plt.rc('ytick', labelsize=BIGGER_SIZE)
plt.title('Modifico el eje Y')
plt.plot(x,np.sin(x))
plt.show()
# O también lo podría hacer de la forma
import matplotlib
SMALL_SIZE = 8
matplotlib.rc('font', size=SMALL_SIZE)
matplotlib.rc('axes', titlesize=SMALL_SIZE)
Matplotlib tiene también capacidad de hacer cálculos para dibujos específicos. Por ejemplo en el caso de calcular un histograma. Los histogramas son graficos de barras, donde cada barra es la cuenta de cuentos eventos se producen en un cierto intervalo.
Veamos como es esto:
N_points = 100000
n_bins = 20
# Generemos dos distribuciones de números la azar
# gaussianas (Son los que tiene forma de campana)
dist1 = np.random.normal(0,0.1,N_points)
dist2 = 0.4 * np.random.normal(0,0.6,N_points) + 2
# Con esos datos hago el dibujo de un histograma
fig, axs = plt.subplots(1, 1, sharey=True, tight_layout=True)
axs.hist(dist1, bins=n_bins);
bins = np.histogram(np.hstack((dist1, dist2)), bins=10)[1]
plt.hist(dist1, bins, edgecolor='black')
plt.hist(dist2, bins, edgecolor='black');
Este es otro de los gráficos que podemos hacer Para este dibujo enero dos coordenadas r y tita con 150 números al azar cada una
N=150
r = 2* np.random.rand(N)
tita = 2 * np.pi * np.random.rand(N)
# Genero un área para cada punto en función de la coordenada r
area = 200* r**2
# Genero colores que los hago depender del la coordenada anfgular
color = tita
# Creo la figura
fig= plt.figure()
# Y en la figura creo un plot polar
ax = fig.add_subplot(projection='polar') #<-- Notar que uso la proyección polar
# para activar esta propiedad
# la dibujo
ax.scatter(tita, r, c=color, s=area, cmap='hsv', alpha=0.75);
Incluso podría tomar una región determinado por el ángulo
fig= plt.figure()
ax = fig.add_subplot(projection='polar')
ax.set_thetamin(45)
ax.set_thetamax(135)
ax.scatter(tita, r, c=color, s=area, cmap='hsv', alpha=0.75);
import numpy as np
import matplotlib.pyplot as plt
# example data
x = np.arange(0.1, 4, 0.1)
y1 = np.exp(-1.0 * x)
y2 = np.exp(-0.5 * x)
# example variable error bar values
y1err = 0.1 + 0.1 * np.sqrt(x)
y2err = 0.1 + 0.1 * np.sqrt(x/2)
fig, (ax0, ax1, ax2) = plt.subplots(nrows=1, ncols=3, sharex=True,
figsize=(12, 6))
ax0.set_title('all errorbars')
ax0.errorbar(x, y1, yerr=y1err)
ax0.errorbar(x, y2, yerr=y2err)
ax1.set_title('only every 6th errorbar')
ax1.errorbar(x, y1, yerr=y1err, errorevery=6)
ax1.errorbar(x, y2, yerr=y2err, errorevery=6)
ax2.set_title('second series shifted by 3')
ax2.errorbar(x, y1, yerr=y1err, errorevery=(0, 6))
ax2.errorbar(x, y2, yerr=y2err, errorevery=(3, 6))
fig.suptitle('Errorbar subsampling')
plt.show()