lección 2
La gramatica de matplotlib: figure, axes y el flujo de trabajo
El modelo mental de matplotlib: figure es el lienzo, axes es el grafico. Aprende el flujo fig-ax que usaras en el 95% de tus visualizaciones.
⏱ 55 min
Ya sabes que grafico elegir para cada pregunta. Ahora necesitas CONSTRUIRLO — y para eso necesitas una herramienta que te deje controlar cada pixel. Matplotlib es esa herramienta: la base sobre la que se construye practicamente toda la visualizacion en Python. Seaborn se monta encima, pandas.plot() la llama por detras, y la mayoria de librerias cientificas generan figuras de matplotlib. Aprenderla no es aprender UNA libreria: es aprender la gramatica comun de todas las demas. Y su modelo mental — figure, axes, elementos — es lo que te va a permitir pasar de "me sale algo" a "controlo exactamente lo que sale".
El problema de matplotlib es que tiene DOS interfaces, y si no entiendes cual es cual, acabas mezclando codigo que funciona a veces y se rompe en cuanto quieres algo complejo. La interfaz "pyplot" (plt.plot, plt.bar, plt.title) imita a MATLAB: rapida para prototipos, desastrosa para graficos con varios paneles o personalizacion seria. La interfaz "orientada a objetos" (fig, ax = plt.subplots()) es la que usan los profesionales. Es la que vas a aprender aqui.
### El modelo mental: lienzo, marco, grafico
Piensa en un cuadro: la Figure es el bastidor completo con su marco. Los Axes son los recuadros donde realmente se pinta. Un bastidor puede tener un solo recuadro (lo mas habitual) o varios (cuando quieres comparar dos graficos lado a lado). El error mas comun de principiante es confundir Figure con Axes: llaman plt.title() pensando que va al grafico y en realidad va al axes actual, que con un solo grafico es el que esperas y con dos deja de serlo. Si creas dos paneles y llamas a plt.title(), el titulo se lo lleva el ultimo panel que creaste y el primero se queda mudo. Para el titulo de la figure entera existe plt.suptitle(). Y para no depender nunca de cual es "el actual", escribes ax.set_title() sobre el axes que quieres.
### El patron que usaras siempre: fig, ax = plt.subplots()
1import matplotlib.pyplot as plt23# El patron profesional: SIEMPRE empieza asi4fig, ax = plt.subplots(figsize=(8, 5))56# Datos7meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun']8ingresos = [120, 135, 128, 142, 155, 148]910# Pintar en el axes (NO en plt directamente)11ax.plot(meses, ingresos, marker='o', color='#a3e635', linewidth=2)1213# Configurar el axes14ax.set_title('Ingresos mensuales S1 2024')15ax.set_xlabel('Mes')16ax.set_ylabel('Miles EUR')17ax.spines['top'].set_visible(False)18ax.spines['right'].set_visible(False)1920# Guardar (actua sobre la figure)21plt.tight_layout()22plt.savefig('ingresos_s1.png', dpi=150)23plt.close()
El flujo completo: crear figure+axes, pintar, configurar, guardar, cerrar
Consejo de senior: nunca uses plt.show() en un script de produccion o en un notebook que se ejecuta automaticamente. plt.show() bloquea la ejecucion esperando que cierres la ventana. Usa plt.savefig() para guardar y plt.close() para liberar. Solo usa plt.show() cuando estas explorando interactivamente en un Jupyter Notebook.
### Los tres graficos basicos: plot, bar, scatter
Con tres metodos cubres el 80% de las necesidades: ax.plot() para lineas temporales, ax.bar() (o ax.barh()) para comparaciones, y ax.scatter() para relaciones. Cada uno acepta los datos como listas o arrays de numpy, y devuelve un objeto que puedes guardar si necesitas modificarlo despues (raro, pero posible).
1import matplotlib.pyplot as plt23# --- Barras verticales ---4fig, ax = plt.subplots(figsize=(7, 4))5productos = ['Web', 'App', 'API', 'Widget']6usuarios = [4500, 3200, 1800, 900]7ax.bar(productos, usuarios, color='#22d3ee')8ax.set_title('Usuarios activos por producto')9ax.set_ylabel('Usuarios')10plt.tight_layout()11plt.savefig('barras.png', dpi=150)12plt.close()1314# --- Scatter ---15fig, ax = plt.subplots(figsize=(7, 5))16precio = [10, 25, 15, 40, 30, 55, 20, 35]17satisfaccion = [8.2, 7.5, 8.0, 6.1, 7.0, 5.5, 7.8, 6.8]18ax.scatter(precio, satisfaccion, color='#f59e0b', s=80, alpha=0.7)19ax.set_xlabel('Precio (EUR)')20ax.set_ylabel('Satisfaccion (1-10)')21ax.set_title('A mayor precio, menor satisfaccion?')22plt.tight_layout()23plt.savefig('scatter.png', dpi=150)24plt.close()
bar() para comparar categorias, scatter() para explorar relaciones
### Personalizar: colores, tamanos y estilos
Matplotlib acepta colores como cadenas hex (#a3e635), como nombres CSS (tomato, steelblue) o como tuplas RGB normalizadas (0.64, 0.90, 0.21). Para un analista, lo practico es usar hex de la paleta de tu empresa o de una paleta perceptualmente uniforme como viridis.
1import matplotlib.pyplot as plt23fig, ax = plt.subplots(figsize=(8, 5))45meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun']6plan_basic = [200, 210, 215, 220, 225, 230]7plan_pro = [150, 160, 175, 180, 195, 210]89# Dos lineas con estilos distintos10ax.plot(meses, plan_basic, marker='o', color='#a3e635',11 linewidth=2, label='Basic')12ax.plot(meses, plan_pro, marker='s', color='#22d3ee',13 linewidth=2, linestyle='--', label='Pro')1415# Leyenda, titulos, limpieza16ax.legend(loc='upper left', frameon=False)17ax.set_title('Pro crece mas rapido que Basic (+40% vs +15%)')18ax.set_ylabel('Clientes activos')19ax.spines['top'].set_visible(False)20ax.spines['right'].set_visible(False)21ax.set_ylim(0, 300) # Forzar que el eje Y empiece en 02223plt.tight_layout()24plt.savefig('crecimiento_planes.png', dpi=150)25plt.close()
Dos series en el mismo axes: color, estilo de linea y leyenda para distinguirlas
Cuidado con el eje Y que no empieza en cero. En un grafico de barras matplotlib empieza en cero el solo, porque la barra se dibuja desde ahi; aun asi, escribir ax.set_ylim(0, ...) no sobra, porque deja la intencion por escrito y te protege si alguien toca el rango mas adelante. Donde si recorta es en lineas y en scatter: si tus datos van de 98 a 102, matplotlib ajusta el eje de 97,8 a 102,2 y esa diferencia de cuatro puntos ocupa el grafico entero. Ahi la decision es tuya y depende del mensaje: si quieres ensenar la variacion pequena, recortar tiene sentido y hay que decirlo en el titulo; si quieres ensenar la magnitud, pon ax.set_ylim(0, ...). Lo que no vale es recortar sin darte cuenta.
### Subplots: varios graficos en un solo lienzo
Cuando quieres comparar dos graficos lado a lado (ventas vs costes, este trimestre vs el anterior), usas subplots con multiples axes. La llamada plt.subplots(1, 2) crea una fila con dos columnas; plt.subplots(2, 1) crea dos filas con una columna. Cada axes es independiente: tiene su propio titulo, sus propios ejes, sus propios datos.
1import matplotlib.pyplot as plt23fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5), sharey=True)45# Panel izquierdo: ingresos6meses = ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun']7ingresos = [120, 135, 128, 142, 155, 148]8ax1.plot(meses, ingresos, marker='o', color='#a3e635', linewidth=2)9ax1.set_title('Ingresos S1 2024')10ax1.set_ylabel('Miles EUR')11ax1.spines['top'].set_visible(False)12ax1.spines['right'].set_visible(False)1314# Panel derecho: costes15costes = [80, 82, 85, 88, 90, 92]16ax2.plot(meses, costes, marker='s', color='#f59e0b', linewidth=2)17ax2.set_title('Costes S1 2024')18ax2.set_ylabel('Miles EUR')19ax2.spines['top'].set_visible(False)20ax2.spines['right'].set_visible(False)2122fig.suptitle('Ingresos crecen mas rapido que costes: margen mejora', fontsize=13)23plt.tight_layout()24plt.savefig('ingresos_vs_costes.png', dpi=150)25plt.close()
Dos paneles lado a lado: la comparacion visual es inmediata
### Guardar como imagen: formatos y resolucion
plt.savefig() acepta cualquier formato que soporte tu sistema: PNG (rasterizado, el mas comun), SVG (vectorial, ideal para web), PDF (vectorial, para documentos). El parametro dpi (dots per inch) controla la resolucion del PNG: 72 dpi es pantalla basica, 150 es presentacion, 300 es impresion. Para un dashboard web, 150 es suficiente. Para un informe que se va a imprimir, usa 300.
1# Guardar en distintos formatos2plt.savefig('grafico.png', dpi=150, bbox_inches='tight')3plt.savefig('grafico.svg') # Vectorial, sin dpi4plt.savefig('grafico.pdf') # Para LaTeX o informes56# bbox_inches='tight' recorta el espacio en blanco sobrante7# Es mas preciso que tight_layout() para el guardado
Tres formatos habituales y el truco de bbox_inches
Consejo de senior: si tu grafico va a un informe automatizado (un PDF que se genera cada lunes), usa siempre la misma resolucion y tamano. Asi el informe no "salta" visualmente de una semana a otra. Yo tengo un fichero config.py con ANCHO, ALTO, DPI y COLORES que importo en cada script de reporting. Es media hora de setup que te ahorra dolores de cabeza durante meses.
### La interfaz pyplot vs la orientada a objetos
### Receta rapida: del dato al grafico en 6 lineas
Una vez que interiorizas el patron, cualquier grafico sigue la misma receta: (1) crear figure+axes, (2) pintar los datos, (3) configurar titulo y etiquetas, (4) limpiar lo que sobra, (5) guardar, (6) cerrar. Lo que cambia es el metodo de pintado (plot/bar/scatter/hist) y los parametros esteticos. La estructura es siempre la misma.
Regístrate para guardar tu progreso.
## comentarios
Reporta erratas, ayuda a otros o comparte tu opinión. Sé constructivo.
Inicia sesión para comentar y responder.
cargando comentarios...