Tiza Paso a paso
Practicar →

Pensamiento Computacional · Unidad 6 — Bibliotecas de Python

Gráficos con Matplotlib

Un gráfico es la forma más rápida de entender un conjunto de datos. Con tres líneas ya tenés uno, pero sin títulos no sirve de nada.

Practicar este tema →7 ejercicios que te corrigen paso a paso · gratis, sin cuenta

La explicación

El gráfico mínimo

import matplotlib.pyplot as plt

x = [1, 2, 3, 4]
y = [1, 4, 9, 16]
plt.plot(x, y)
plt.show()

El as plt es la convención, igual que np y pd. plot dibuja y show muestra. Sin show(), en muchos entornos no aparece nada.

Las dos listas tienen que tener la misma cantidad de elementos: cada punto es un x con su y. Si una tiene 4 y la otra 5, Python corta recién al dibujar, con ValueError: x and y must have same first dimension, así que conviene chequearlo antes con len().

Tipos de gráfico

plt.plot(x, y)     líneas       algo que evoluciona (el tiempo)
plt.bar(x, y)      barras       comparar categorías
plt.scatter(x, y)  puntos       ver si dos variables se relacionan
plt.hist(datos)    histograma   cómo se reparten los valores
plt.pie(valores)   torta        partes de un mismo total

Elegir bien importa: un gráfico de líneas entre categorías que no tienen orden sugiere una continuidad que no existe.

La torta: partes de un total

import matplotlib.pyplot as plt

horas = [8, 6, 3, 4, 3]
usos = ["Dormir", "Cursar", "Viajar", "Estudiar", "Otras"]

plt.pie(horas, labels=usos, autopct="%1.1f%%")
plt.title("Un día de cursada (24 horas)")
plt.show()

plt.pie recibe los valores de cada porción y, con labels, el nombre de cada una, en el mismo orden. No hace falta que sumen 100: matplotlib calcula solo qué parte del total es cada valor. autopct="%1.1f%%" escribe ese porcentaje adentro de cada porción, con un decimal: 8 de 24 horas es 33.3%, 6 de 24 es 25.0%.

Cuándo sirve y cuándo no. Una torta muestra partes de un mismo total: las horas de un día, el presupuesto de un viaje, el gasto de un mes. Si los valores no forman un todo (las notas de cinco alumnos, la temperatura de cada día), la torta no significa nada y va un gráfico de barras. Y con muchas categorías, o con porciones parecidas, el ojo no distingue los ángulos: también ahí se leen mejor las barras.

Sin títulos no se entiende

plt.plot(x, y)
plt.title("Notas por parcial")
plt.xlabel("Parcial")
plt.ylabel("Nota")
plt.show()
Un gráfico sin etiquetas de ejes no dice nada. El que lo mira no sabe qué mide cada eje ni en qué unidad. Es el punto que más se descuenta cuando piden un gráfico, y son tres líneas.

Varias series

plt.plot(x, y1, label="Curso A")
plt.plot(x, y2, label="Curso B")
plt.legend()   # sin esto los label no se ven
plt.show()

Cada plot antes del show se dibuja sobre el mismo gráfico. El legend() es el que hace aparecer la referencia.

Juntando todo

df = pd.read_csv("notas.csv")
plt.bar(df["nombre"], df["nota"])
plt.title("Notas del curso")
plt.ylabel("Nota")
plt.show()

Leer con Pandas y graficar con Matplotlib es la combinación estándar, y es a donde apunta toda la unidad: de un archivo de datos a una conclusión que se ve.

Un ejercicio resuelto, paso a paso

Con un CSV de notas (columnas nombre y nota), hacer un gráfico de barras presentable.

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("notas.csv")

plt.bar(df["nombre"], df["nota"])
plt.title("Notas del curso")
plt.xlabel("Estudiante")
plt.ylabel("Nota")
plt.ylim(0, 10)
plt.show()

Por qué barras y no líneas. Los nombres son categorías, no una secuencia. Una línea entre ana, luis y sol sugeriría que hay una evolución entre ellos, y no la hay.

Por qué ylim(0, 10). Sin eso, Matplotlib ajusta el eje al rango de los datos. Si todas las notas están entre 7 y 9, el eje arranca en 7 y las diferencias se ven enormes. Fijar la escala real de las notas evita exagerar sin querer.

Ese último punto es el que más se discute cuando se presentan datos: el eje elegido cambia la historia que cuenta el gráfico. Y la regla no es la misma para todos los gráficos: en uno de barras lo que se compara es la longitud de cada barra, así que el eje tiene que arrancar en 0 — si no, una barra puede verse cinco veces más alta que otra casi igual. En uno de líneas, donde lo que se lee es la forma de la curva, recortar el eje es legítimo: hacelo a propósito y sabiendo qué efecto produce.

Control antes de entregar: ¿tiene título? ¿los dos ejes están etiquetados? ¿se entiende sin que nadie te lo explique? Si la respuesta a las tres es sí, está listo.

Y uno del nivel del parcial

Con el mismo CSV de ventas, hacer un gráfico de líneas de la facturación mensual. Explicar por qué el orden que sale por defecto arruina el gráfico y cómo se arregla.

El problema aparece antes de dibujar nada. groupby ordena los grupos alfabéticamente, y los meses en castellano no están en orden alfabético:

orden alfabético:  abril, agosto, diciembre, enero, febrero, …
orden real:         enero, febrero, marzo, abril, mayo, …

Con dos meses no se nota —enero y febrero están alfabéticamente en orden— pero apenas aparece abril el gráfico queda al revés:

sorted(["enero", "febrero", "abril"])
→ ['abril', 'enero', 'febrero']   abril primero

En un gráfico de líneas eso es grave, porque la línea une los puntos en el orden en que están. Con los meses desordenados, la línea sube y baja mostrando una evolución que no existe. Un gráfico de barras al menos se lee mal; uno de líneas directamente miente.

La solución: decir cuál es el orden bueno y reindexar.

ORDEN = ["enero", "febrero", "marzo", "abril", "mayo", "junio",
        "julio", "agosto", "septiembre", "octubre", "noviembre", "diciembre"]

serie = df.groupby("mes")["monto"].sum()
serie = serie.reindex([m for m in ORDEN if m in serie.index])

El if m in serie.index es para que no aparezcan meses sin datos. Sin eso, reindex los agrega con valor NaN y quedan diez huecos en el gráfico.

Ahora sí, el gráfico:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(serie.index, serie.values, marker="o", linewidth=2)
ax.set_title("Facturacion por mes")
ax.set_ylabel("Pesos")
ax.set_ylim(bottom=0)
ax.grid(alpha=0.3)
fig.tight_layout()

Cada línea de ese bloque hace algo que se nota:

figsize=(7, 4)     → proporción horizontal, que es como se lee una serie de tiempo
marker="o"         → se ve dónde hay dato de verdad y dónde es interpolación
linewidth=2       → la línea por defecto es muy finita en pantalla
set_ylim(bottom=0) → el eje arranca en cero
grid(alpha=0.3)   → se puede leer un valor sin ir hasta el eje
tight_layout()    → que no se corten las etiquetas

El set_ylim(bottom=0) merece un párrafo aparte. Por defecto matplotlib ajusta el eje al rango de los datos, así que una variación de 3900 a 4900 ocupa todo el alto y parece un derrumbe. Con el eje desde cero, la caída se ve como lo que es: un 20 %.

Lo que NO hay que hacer: elegir colores a mano uno por uno, poner leyenda cuando hay una sola serie, o usar 3D. Los colores por defecto de matplotlib están elegidos para distinguirse bien en pantalla.

Guardarlo, que es lo que pide un TP:

fig.savefig("facturacion.png", dpi=110)
plt.close(fig)

dpi=110 o más, porque el valor por defecto (100) se ve borroso en pantallas modernas. Y plt.close(fig) libera la figura: sin eso, un ciclo que genera veinte gráficos se come la memoria.

El título dice qué se está mirando, no qué tipo de gráfico es. "Facturación por mes" sirve; "Gráfico de líneas" no aporta nada que no se vea.

El control final, que siempre conviene hacer: los valores del gráfico tienen que coincidir con los del groupby. Enero 4900 y febrero 3900, y el reindexado no los cambió: solo los puso en orden ✓.

Dónde se pierde el punto: entregar el gráfico con los meses en orden alfabético. El código corre, la imagen sale, y el gráfico dice algo falso — que es peor que no entregarlo.

Dónde se cae la mayoría

Hasta acá la explicación. La práctica es la otra mitad: 7 ejercicios de este tema, en cuatro niveles, que no te dicen sólo si está bien al final sino que te corrigen en cada paso y te explican por qué. Además trae una animación que muestra la idea en movimiento.

Practicar Gráficos con Matplotlib →

Dónde entra este tema en el parcial

Los otros temas de la unidad 6

Bibliotecas de Python

Ver todos los temas de Pensamiento Computacional