100 Días de Código en Python — Día 73: Visualización con Matplotlib — la popularidad de los lenguajes de programación
Nivel: Grado décimo
Área: Tecnología e Informática
Modalidad: Tutorial práctico
Fuente: Curso "100 Days of Code: The Complete Python Pro Bootcamp" (Angela Yu, App Brewery). Contenido del Día 73 (nivel avanzado).
20 min de lectura
17 secciones
Este tutorial adapta pedagógicamente el Día 73. Las secciones 📝 Contenido original del curso provienen de las lecciones 529 a 538; el cuaderno de inicio y el completo (Programming_Languages_(start/complete).ipynb) y el archivo QueryResults.csv están en los recursos del curso. En algunas lecciones el código aparece solo en imágenes; aquí se reconstruye y se verifica. Los retos 🟢🟡🟠🔴, las secciones sobre qué mide realmente este gráfico y gráficos accesibles, el proyecto extra y la etapa 2 del proyecto integrador son creaciones de esta adaptación. Las correcciones al material original aparecen como 🛠️ Nota técnica.
Nota sobre las verificaciones: el 27 de septiembre de 2026, con Python 3.14, pandas 3.0.6, Matplotlib 3.11.2 y una copia pública del archivo QueryResults.csv del curso (publicada en GitHub por otro estudiante del mismo curso), se ejecutó todo el código y se generaron los gráficos. Los resultados coinciden con los del curso: 1991 filas, un DataFrame pivotado de 145 × 14, y el máximo de 35 000 del eje y es adecuado (el mayor valor mensual es 34 478, de Python en mayo de 2020). Se encontraron dos matices: el total acumulado lo lidera JavaScript, no Python, y groupby('TAG').sum()une como texto las fechas de cada lenguaje.
El lenguaje más antiguo todavía en uso es FORTRAN (1957). Desde entonces han aparecido muchos más, pero ¿cuál es el más popular, "del que todo el mundo habla"? Stack Overflow ayudará: cada pregunta lleva etiquetas (tags), y una puede ser el nombre de un lenguaje. Basta con contar cuántas publicaciones tiene cada etiqueta: gana el que tenga más.
Aprenderás a visualizar datos con Matplotlib; a pivotar, agrupar y transformar datos con pandas; a trabajar con fechas y series de tiempo; y a dar estilo a un gráfico de líneas.
Prerequisitos: exploración y groupby con pandas (Día 72), módulo datetime (Día 32), bucles for.
03
1. El cuaderno de inicio y la exploración inicial#
(Fuentes: 530-download-and-open-the-starter-notebook.md y 531-solution-preliminary-data-exploration.md)
Descarga el cuaderno de inicio (ya trae las secciones y retos), súbelo a Google Drive y ábrelo con Colab; agrega QueryResults.csv.
Reto (repaso del Día 72):
Leer el CSV en un DataFramedf con los nombres de columna ['DATE', 'TAG', 'POSTS'] (revisa la documentación de read_csv()).
Ver las primeras y últimas 5 filas.
¿Cuántas filas y columnas?
Contar las entradas de cada columna.
Solución:
Python
12345
df = pd.read_csv('QueryResults.csv', names=['DATE','TAG','POSTS'], header=0)
df.head()
df.tail()
df.shape # (1991, 3)
df.count()# cuenta los valores que NO son NaN en cada columna
header=0 indica que la primera fila del archivo es un encabezado, que se reemplaza por nuestros nombres.
DATE TAG POSTS
0 2008-07-01 00:00:00 c# 3
1 2008-08-01 00:00:00 assembly 8
...
1990 2020-07-01 00:00:00 swift 3607
df.shape → (1991, 3) df.count() → 1991 en las tres columnas
El formato es "largo": cada fila es un par (mes, lenguaje). Julio de 2008 solo tiene C#: Stack Overflow abrió ese mes.
Reto: ¿cuántas publicaciones tiene cada lenguaje? ¿Cuál tuvo más desde la creación de Stack Overflow? Y como algunos lenguajes son más nuevos (Swift) que otros (C), ¿cuántos meses de publicaciones hay por lenguaje?
Solución: agrupar por TAG; .sum() da el total de publicaciones; .count(), los meses con datos.
🛠️ Nota técnica (verificado): con pandas 3, df.groupby('TAG').sum()no falla, pero "suma" también la columna DATE, que en este momento es texto: el resultado es una cadena gigantesca con todas las fechas pegadas. Es mejor seleccionar la columna que interesa:
df['DATE'][1]# notación de corchetes
df.DATE[1]# notación de punto (solo si el nombre no tiene espacios; permite autocompletar)
El contenido es un texto ('2008-08-01 00:00:00'), no una fecha: muestra el innecesario 00:00:00 y no tiene las ventajas de los objetos de fecha. pd.to_datetime() lo convierte:
Python
12
pd.to_datetime(df.DATE[1])# una celda
df.DATE = pd.to_datetime(df.DATE)# toda la columna
Si falta un valor (por ejemplo, si no existiera el dato de Sylvester viejo), pivot() pone NaN.
Mini reto: pivotar df para que cada fila sea una fecha y cada columna un lenguaje (reshaped_df); ver dimensiones, primeras y últimas filas, nombres de columnas y conteo por columna.
Resultado: 145 filas y 14 columnas. El conteo por columna no es igual en todas porque .count() excluye los NaN, que aparecen donde un lenguaje no tuvo publicaciones ese mes (por ejemplo, Swift en julio de 2008). Aquí no conviene borrar esas filas, sino reemplazar NaN por 0:
Python
12
reshaped_df.fillna(0, inplace=True)# o: reshaped_df = reshaped_df.fillna(0)
reshaped_df.isna().values.any()# False: no queda ningún NaN
.values.any() evita revisar a ojo toda la tabla: devuelve un solo True o False.
test_df pivotado:
Actor Arnold Jack Keanu Sylvester
Age
Old 75 99 5 30
Young 80 100 25 50
reshaped_df.shape → (145, 14)
Columnas: assembly, c, c#, c++, delphi, go, java, javascript, perl, php, python, r, ruby, swift
Conteos antes de fillna: go 129, swift 135, r 142, c# 145, el resto 144
Después de fillna(0): reshaped_df.isna().values.any() → False
💡 En el ejemplo de los actores no falta ningún valor (verificado: la tabla está completa). Para ver el NaN del que habla el curso, borra la fila de Sylvester viejo antes de pivotar (Reto 1).
🛠️ Nota técnica: con pandas 3 (modelo Copy-on-Write), inplace=True sigue funcionando sobre el propio DataFrame, pero la documentación recomienda la forma con asignación (reshaped_df = reshaped_df.fillna(0)), que es más clara y funciona igual en todos los casos. Nunca uses inplace=True sobre una columna seleccionada (df['col'].fillna(0, inplace=True)): en pandas 3 no modifica el DataFrame original.
¿Rellenar con 0 es correcto? Aquí sí: si no hay filas para Swift en 2008 es porque hubo cero publicaciones. Pero en otros datos, un NaN puede significar "no se midió", y rellenarlo con 0 sería inventar un dato.
🟢 Reto 1 — Aplicación: borra la fila de Sylvester viejo de test_df, pivota y observa el NaN.
🟡 Reto 2 — Ampliación: pivota al revés: filas = lenguajes, columnas = años (pista: crea antes una columna YEAR con df.DATE.dt.year y usa pivot_table con aggfunc='sum').
🟠 Reto 3 — Desafío: usa reshaped_df.melt() para volver del formato ancho al largo y comprueba que recuperas las filas originales (¿cuántas filas más aparecen y por qué?).
🔴 Reto 4 — Pensamiento computacional: ¿en qué mes cada lenguaje tuvo su máximo de publicaciones? Constrúyelo con idxmax() sobre reshaped_df y ordénalo por fecha. ¿Qué te dice sobre la "vida" de cada lenguaje?
plt.figure(figsize=(16,10))
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.xlabel('Fecha', fontsize=14)
plt.ylabel('Número de publicaciones', fontsize=14)
plt.ylim(0,35000)
plt.plot(reshaped_df.index, reshaped_df['java'])
plt.title('Publicaciones mensuales sobre Java en Stack Overflow', fontsize=16)
plt.show()
plt.figure(...) debe ir antes de plt.plot(...): crea el lienzo.
plt.title no aparece en la lección, pero todo gráfico debe decir qué muestra.
plt.show() es necesario fuera de los cuadernos (en un .py). Para guardarlo como imagen: plt.savefig('java.png', dpi=150, bbox_inches='tight').
reshaped_df.java funciona, pero reshaped_df.c# o reshaped_df.c++no (el # y el + no son válidos en esa notación): para esas columnas, siempre corchetes.
Dos líneas: basta con llamar plt.plot() dos veces. Todas: un bucle for sobre las columnas. Para saber cuál es cuál, una etiqueta por línea y una leyenda; y líneas más gruesas:
Python
123456789101112
plt.figure(figsize=(16,10))
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.xlabel('Date', fontsize=14)
plt.ylabel('Number of Posts', fontsize=14)
plt.ylim(0,35000)for column in reshaped_df.columns:
plt.plot(reshaped_df.index, reshaped_df[column],
linewidth=3, label=reshaped_df[column].name)
plt.legend(fontsize=16)
"Parece que Python es el lenguaje más popular, a juzgar por las publicaciones en Stack Overflow. ¡Python gana!".
Suavizar la serie: las series de tiempo tienen mucho "ruido" (subidas y bajadas). La media móvil promedia una "ventana" de observaciones (por ejemplo, 6 o 12) y la desplaza de una en una:
Python
12
roll_df = reshaped_df.rolling(window=6).mean()# ... el mismo gráfico, dibujando roll_df en lugar de reshaped_df
Prueba con window=3 o window=12.
Resumen del día:groupby, to_datetime, pivot, count() y isna().values.any(), fillna, plot con un bucle, estilo del gráfico, leyenda y rolling().mean().
La media móvil, paso a paso: con window=6, el valor de junio es el promedio de enero a junio; el de julio, el de febrero a julio, y así. Por eso las primeras 5 filas quedan en NaN (verificado): no hay 6 meses anteriores para promediar. Una ventana más grande da una línea más suave, pero reacciona más tarde a los cambios reales.
Ventana
Efecto
3
Poco suavizado; sigue los cambios de cerca
6
Equilibrio (la del curso)
12
Muy suave; elimina los efectos de temporada (por ejemplo, vacaciones)
Un gráfico de 14 líneas es difícil de leer (el propio curso lo nota al agregar la leyenda). Matplotlib repite colores después de 10 líneas, y las personas con daltonismo no distinguen varias de ellas (Día 65). Mejores opciones: mostrar solo los 4 o 5 lenguajes que interesan, usar estilos de línea distintos (linestyle='--') o hacer un gráfico por lenguaje (small multiples, Reto 4).
🟢 Reto 1: grafica solo Python, Java, JavaScript y C# con la media móvil de 12 meses y un título en español.
🟡 Reto 2: agrega una línea vertical en junio de 2014, cuando Apple presentó Swift (plt.axvline(pd.Timestamp('2014-06-01'), linestyle='--')), y una anotación con plt.annotate.
🟠 Reto 3: grafica la participación porcentual de cada lenguaje por mes (publicaciones de un lenguaje ÷ total del mes × 100). ¿Cambia la conclusión respecto a los números absolutos?
🔴 Reto 4 — Pensamiento computacional: con plt.subplots(nrows=4, ncols=4) dibuja un gráfico pequeño por lenguaje, con el mismo eje y. ¿Es más fácil o más difícil de leer que el gráfico con 14 líneas? ¿Por qué?
(Sección creada para esta adaptación a partir de la conclusión de la lección 536.)
"Python gana" es una conclusión atractiva, pero depende de qué midamos:
Medida (verificada con los datos del curso)
Ganador
Total acumulado de publicaciones 2008–2020
JavaScript (2 056 510)
Publicaciones en el último mes (julio de 2020)
Python (31 261), luego JavaScript (23 802)
Mayor valor mensual de todo el periodo
Python (34 478, mayo de 2020)
Y hay preguntas más profundas:
¿Preguntas = popularidad? Un lenguaje puede tener muchas preguntas porque es muy usado… o porque es difícil o confuso. Uno bien documentado puede generar menos preguntas.
¿Quién pregunta en Stack Overflow? Sobre todo, programadores que escriben en inglés. No representa a todas las personas que programan.
¿Hasta cuándo? Los datos terminan en julio de 2020. Desde la aparición de los asistentes de IA, varios análisis han reportado una fuerte caída en las preguntas nuevas en Stack Overflow: un gráfico hecho hoy mostraría otra historia, y la caída no significaría que la gente dejó de programar.
Otras fuentes miden la popularidad distinto: repositorios en GitHub, ofertas de empleo, encuestas a desarrolladores. Una conclusión sólida compara varias.
Los datos se obtuvieron con el Stack Exchange Data Explorer, que permite consultas en SQL (Día 63) sobre los datos públicos del sitio.
10
8. 🚀 Proyecto del día: el informe de popularidad de lenguajes#
Encuentra cuatro problemas: sin header=0, la fila de encabezados del archivo se lee como un dato; fillna(0) sin guardar el resultado; reshaped_df.c# es un error de sintaxis (el # inicia un comentario); y plt.figure va después de plt.plot, así que crea un lienzo nuevo y vacío.
Coordinación de convivencia quiere saber si la inasistencia de los estudiantes tiene patrones: ¿aumenta en ciertos meses?, ¿es igual en todos los grados?
Un CSV en formato largo con FECHA, GRADO (6.° a 11.°) e INASISTENCIAS (número de estudiantes ausentes ese día). Si no hay datos reales anonimizados y autorizados, genera datos simulados con random (y dilo claramente en el informe).
Convierte las fechas, agrega por semana o por mes (lo verás a fondo el Día 75; por ahora, df.FECHA.dt.to_period('M')), y pivota: filas = mes, columnas = grado.
Gráfico de líneas por grado con leyenda, y la versión suavizada.
Conclusiones: ¿qué mes tiene más inasistencia?, ¿qué grado?, ¿qué podría explicarlo? (Vacaciones, temporada de lluvias, época de exámenes.)
Ciclo de trabajo: formula el problema → inténtalo tú → consulta a la IA → lee y entiende → prueba → compara con la documentación oficial → modifica → explica con tus palabras.
Actividad 1 — Un gráfico legible. Pide a una IA el código para graficar las 14 columnas. Luego pídele que lo haga "accesible para personas con daltonismo". Evalúa: ¿usó estilos de línea, marcadores o menos series? Compara con la documentación de Matplotlib sobre linestyle y mapas de colores.
Actividad 2 — inplace. Pregunta a una IA si inplace=True es buena práctica en pandas 3. Contrasta con la sección de Copy-on-Write de la guía de usuario de pandas.
Actividad 3 — Interpretar con cuidado. Muestra a una IA la tabla de la sección 7 y pregúntale cuál es "el lenguaje más popular". ¿Reconoce que depende de la medida y del periodo? Escribe tu propia conclusión en tres líneas.
15
13. 🛠️ Correcciones técnicas al material original#
Archivo
Afirmación o comportamiento del curso
Observación
Tratamiento
532
df.groupby('TAG').sum()
Une como texto las fechas de la columna DATE (verificado); conviene seleccionar ['POSTS']
Nota técnica de la sección 2
536
"Python es el lenguaje más popular"
En el total acumulado gana JavaScript; Python lidera los meses recientes (verificado)
Sección 7
534
En el ejemplo, "no hay valor para Sylvester viejo"
En el código mostrado sí existe (30); el NaN aparece solo si se borra esa fila (verificado)
Nota de la sección 4 y Reto 1
534
fillna(0, inplace=True)
Funciona; con pandas 3 se recomienda asignar el resultado
Nota técnica de la sección 4
535
reshaped_df.java
La notación de punto no sirve para c# ni c++
Sección 5
535, 536
Gráficos sin título
Todo gráfico debe tener título; 14 líneas son difíciles de leer
Secciones 5 y 6
529
Popularidad = publicaciones en Stack Overflow
Los datos terminan en julio de 2020 y la medida tiene sesgos
Sección 7
Todo el día
Resultados numéricos
Coinciden con los del curso (1991 filas, 145 × 14, etc.; verificado)
El cuaderno del informe de popularidad con sus gráficos guardados en PNG.
La tabla de "qué lenguaje gana según la medida" y tu conclusión.
El gráfico de small multiples (Reto 4 de la sección 6).
El análisis de asistencia (proyecto extra).
La etapa 2 del Observatorio de Datos del Colegio.
Cuaderno de errores:header=0 olvidado, groupby().sum() sobre columnas de texto, fechas como texto, pivot con duplicados, fillna sin guardar, notación de punto con c#, plt.figure después de plt.plot, gráfico sin leyenda ni título, demasiadas líneas.