Misión 5. Dibuja el sonido

▶ Abrir en Colab ▶ Ejecutar en Binder

Colab abre en segundos. Binder, la primera vez, construye el entorno en la nube (10-20 min) y luego queda en caché.

Misión 5. Encargo: «pinta la popularidad y la energía».
Victoria: una figura y un mapa del sonido que puedas enseñar.
Insignia en juego: cartógrafo del sonido.

El encargo

Tienes en el cuaderno un catálogo entero de música: tres mil trescientas canciones con sus rasgos de sonido —lo bailable que es cada una, cuánta energía tiene, si es alegre o triste, su tempo, su duración—, ya descargadas (Misión 2), interrogadas (Misión 3) y limpias de averías (Misión 4). Es un tesoro… y es ilegible. Nadie, por muy listo que sea, lee tres mil trescientas filas de números y «oye» algo. Los datos, en bruto, son mudos. Para que hablen hace falta darles una forma que el ojo entienda de un vistazo, y esa forma es un gráfico.

Aquí cambia el oficio. Hasta ahora le pedías a la máquina un número —una media, un conteo, el género más popular— y ella te contestaba con una cifra. En esta misión le vas a pedir algo distinto: que dibuje. Que convierta una columna de miles de valores en una línea que sube y baja, en unas barras que se comparan solas, en un mapa de colores donde cada género aparece pintado según cómo suena. Un buen gráfico no es un adorno que se pone al final para que el informe quede bonito: es una herramienta de pensamiento, la lente con la que un analista descubre lo que las cifras escondían.

Tu encargo es pintar la popularidad y la energía de la música, y al terminar te llevarás dos trofeos. El primero, una figura que retrata cada género por sus dos caras —cuánto gusta y cuánta energía tiene—. El segundo, un mapa: una rejilla de colores que enseña, de un solo golpe, la huella de sonido de cada género. Con los dos en la mano habrás ganado la insignia cartógrafo del sonido. Pero cuidado: dibujar datos tiene una trampa peligrosa. Es facilísimo hacer un gráfico que miente —que exagera una diferencia minúscula, o que esconde una enorme—, y muchas veces quien lo hace ni siquiera se da cuenta. Así que esta misión no va solo de dibujar bonito. Va de dibujar honesto. Un cartógrafo del sonido que engaña no sirve para nada.

Piénsalo así. Tu cerebro tiene, desde hace cientos de miles de años, un superpoder que ninguna calculadora iguala: mirar una escena y entenderla de golpe —dónde está el camino, cuál es el árbol más alto, por dónde viene el peligro—. Ese mismo poder, el de ver, es el que un gráfico despierta. Una tabla obliga al cerebro a hacer un trabajo que odia: leer símbolos en fila, memorizarlos y compararlos de cabeza, uno a uno. Un gráfico, en cambio, le habla en su idioma nativo —formas, alturas, colores, distancias— y por eso una tendencia que en una tabla te costaría diez minutos descubrir salta de una figura en un segundo. Dibujar datos no es adornarlos: es traducirlos al único idioma que el ojo lee sin esfuerzo. Ese es todo el oficio, y esta misión te lo enseña entero.

El mapa de la misión.

Como siempre, no saltamos a la victoria: la construimos pieza a pieza, y cada pieza es una micro-victoria que puedes enseñar. Este es el recorrido:

  1. Ver por qué un gráfico dice más que una tabla —con tus propios datos—.

  2. Coger el lápiz de la máquina: matplotlib, y su modelo de figura y ejes.

  3. Aprender a elegir el gráfico según la pregunta que quieras responder.

  4. Dibujar barras para comparar géneros —y empezar el eje en cero, sin trampa—.

  5. Descubrir el factor de mentira y por qué un eje mal puesto engaña.

  6. Elegir colores que todo el mundo pueda ver (la paleta Okabe-Ito).

  7. Dibujar líneas para un rango continuo y nubes de puntos para relacionar dos cosas.

  8. Juntarlo en la figura de la victoria y vencer al jefe de parte: el mapa del sonido de los géneros.

Y una regla de oro para toda la misión, hermana de la de la Misión 1: antes de dibujar, pregúntate qué quieres que se vea. Un gráfico sin una pregunta detrás es un garabato. Vamos allá.

La herramienta

Recordatorio: qué tienes en las manos

Antes de dibujar nada, recuerda con qué trabajas. En la Misión 4 dejaste la música limpia y la guardaste en un fichero. Vuelve a cargarla en una celda —en Colab, con pandas, tu herramienta de la Misión 3—:

import pandas as pd

musica = pd.read_csv("musica.csv")   # el que limpiaste en la Mision 4
print(musica.shape)
print(list(musica.columns))
(3351, 10)
['track_name', 'artists', 'track_genre', 'popularity',
 'danceability', 'energy', 'valence', 'tempo', 'duration_ms',
 'explicit']

Tres mil trescientas filas y diez columnas. Cada fila es una canción, y las columnas te dicen todo sobre ella: su track_name (título) y sus artists (intérpretes), el track_genre (el género: pop, rock, jazz…) y —las estrellas de esta misión— sus rasgos de sonido: la popularity (popularidad, de 0 a 100), la danceability (lo bailable que es, de 0 a 1), la energy (energía, de 0 a 1), el valence (lo alegre o positiva que suena, de 0 a 1), el tempo (pulsaciones por minuto), la duration_ms (duración en milisegundos) y explicit (si lleva lenguaje explícito, verdadero o falso). El catálogo trae ciento catorce géneros distintos; para comparar cómodo, elegimos un puñado de seis muy diferentes entre sí:

generos = ["pop", "rock", "classical", "hip-hop",
           "jazz", "reggaeton"]

Seis mundos de sonido: el pop de la radio, el rock de guitarras, la música clásica, el hip-hop, el jazz y el reggaeton. Guarda esa lista: la usarás en casi todas las figuras. Y una herramienta que ya conoces y que va a ser tu mejor amiga aquí: el groupby de la Misión 3, que agrupa las filas y resume cada grupo con un número. Con él sacamos, por ejemplo, la popularidad media de cada género:

hueco = musica[musica["track_genre"].isin(generos)]
print(hueco.groupby("track_genre")["popularity"].mean().round(1))
track_genre
classical    67.3
hip-hop      87.1
jazz         72.3
pop          91.1
reggaeton    89.2
rock         87.2
Name: popularity, dtype: float64

Seis números, uno por género. Ya se intuye algo —el pop y el reggaeton pegan más fuerte que el jazz o la clásica—, pero seis cifras aún se leen a ojo. La gracia de un gráfico se nota cuando las cifras son muchas. Vamos a verlo.

Por qué un gráfico dice más que una tabla

Hagamos una prueba honesta, contigo de juez. Vamos a mirar cómo se relaciona la popularidad con la energía: la popularidad media de las canciones en cada nivel de energía, de las más apagadas (energía 0) a las más desatadas (energía 1), redondeando la energía a un decimal. Son solo once números —pocos—, y aun así vas a comprobar que en forma de tabla no dicen casi nada y en forma de dibujo lo cuentan todo. Y ojo, no te lo voy a contar yo: lo vas a sentir tú, que es muy distinto. Prepárate para notar el momento exacto en que un montón de cifras se convierte, de golpe, en una historia que entiendes. Ese chispazo —«ah, ya lo veo»— es la razón de ser de esta misión entera.

nivel = (musica["energy"] * 10).round() / 10   # energia a un decimal
perfil = musica.groupby(nivel)["popularity"].mean().round(1)
print(perfil.to_dict())
{0.0: 65.0, 0.1: 56.0, 0.2: 59.4, 0.3: 62.3, 0.4: 65.8, 0.5: 69.5,
 0.6: 70.0, 0.7: 70.5, 0.8: 71.7, 0.9: 68.6, 1.0: 59.7}

Léela con calma. ¿Ves el patrón? Cuesta, ¿verdad? Hay que ir número a número, recordar el anterior, comparar… y aun así la forma no aparece. Tu cerebro no está hecho para leer tablas: está hecho para ver. La figura 5.1 pone los mismos once números de dos maneras, la tabla a la izquierda y un gráfico de línea a la derecha, y la diferencia es brutal.

Figura 5.1. Los mismos números, dos formas. Los mismos once números —la popularidad media en cada nivel de energía— como tabla (izquierda) y como línea (derecha). La tabla obliga a leer cifra a cifra; el gráfico enseña de un vistazo la loma: la popularidad sube con la energía hasta un punto dulce hacia 0,8 y luego cae. Datos: musica.csv. Figura mis05_tabla_vs_grafico.

En cuanto los números se vuelven una línea, la historia salta a la cara: la popularidad dibuja una loma. Sube desde las canciones más apagadas, llega a su cima en las de energía media-alta —hacia 0,8, con 71,7 de popularidad media— y vuelve a caer en las más desatadas (energía 1,0, que baja a 59,7). Hay un punto dulce: ni demasiado sosa ni pasadísima de vueltas. No has hecho ninguna cuenta nueva —son los mismos once números de antes—, pero ahora los entiendes. Eso es un gráfico: la misma información, colocada de forma que el ojo la lea sin esfuerzo.

Detrás de esto hay una ciencia, y merece un minuto. Hace ya cuarenta años, dos investigadores, William Cleveland y Robert McGill, midieron con qué precisión juzgan las personas las cantidades según cómo se dibujen. Su descubrimiento ordena todo lo que harás en esta misión: el ojo compara con muchísima precisión posiciones (dos puntos sobre una misma regla) y longitudes (dos barras); comparamos regular los ángulos; y comparamos fatal las áreas y los colores. De ahí sale la primera regla del oficio: siempre que puedas, codifica lo que importa como una posición o una longitud, no como un ángulo o un tamaño. Por eso, más adelante, unas barras ganarán casi siempre a una tarta.

NotaPara saber más: por eso la tarta casi nunca gana

El famoso gráfico de tarta (pie chart) pide justo lo que peor hacemos: comparar ángulos de porciones. ¿La porción azul es mayor o menor que la naranja, si las dos rondan un cuarto del círculo? Hay que entornar los ojos. Las mismas cantidades en barras —posiciones sobre un eje— se comparan solas y, de regalo, se pueden ordenar. La tarta solo se defiende con dos o tres porciones muy dispares; en casi todo lo demás, gana la barra. No es una manía: es que el ojo mide mejor una longitud que un ángulo.

Que quede clara una cosa, para no coger manía a las tablas: la tabla no es el enemigo. Si lo que necesitas es un valor exacto —«¿cuánto marca exactamente la popularidad media a energía 0,5?»—, una tabla gana a cualquier gráfico, que te obligaría a estimar a ojo. Lo que pasa es que tabla y gráfico responden a preguntas distintas: la tabla es para consultar un número concreto; el gráfico, para ver una forma, una tendencia, una comparación. La torpeza está en confundirlas —soltar una tabla de cien filas cuando lo que querías era enseñar que la energía tiene un punto dulce—. La regla es fácil: si tu mensaje es «este valor exacto», tabla; si es «mira cómo cambia» o «mira cuál es mayor», gráfico. En esta misión casi siempre querrás lo segundo.

El lápiz de la máquina: matplotlib

La herramienta con la que Python dibuja se llama matplotlib. Nació en 2003, de la mano de un científico llamado John Hunter que quería hacer figuras de calidad sin salir de Python, y desde entonces es la base sobre la que se apoya casi todo lo demás. En Colab ya viene instalada; solo hay que llamarla. Su apodo de siempre es plt:

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(6, 3.5))
ax.plot([1, 2, 3, 4], [10, 40, 25, 30])
ax.set_title("mi primer grafico")

Fíjate en la primera línea de dibujo, porque es la más importante de toda la biblioteca: fig, ax = plt.subplots(). Te devuelve dos cosas con nombre. La fig (de figure, «figura») es el lienzo entero, la hoja de papel. El ax (de axes, «ejes») es la región donde de verdad se dibuja, con sus ejes y su cuadrícula. A partir de ahí, todo lo que quieras pintar se lo pides al ax con un punto: ax.plot(...) traza una línea, ax.bar(...) unas barras, ax.scatter(...) una nube de puntos. Y las etiquetas, igual: ax.set_title, ax.set_xlabel (el rótulo del eje horizontal), ax.set_ylabel (el del vertical). Es siempre el mismo patrón, y cuando lo interiorizas dibujas cualquier cosa: crea la pareja fig, ax; pide dibujos al ax; ponle etiquetas honradas.

Una figura se construye por capas.

No intentes escribir la figura perfecta de un tirón. Un buen dibujante empieza por lo esencial —los datos— y va añadiendo detalles uno a uno, ejecutando después de cada paso para ver cómo mejora. Mira cómo crece la misma figura, capa a capa. Primero, solo los datos, pelados:

fig, ax = plt.subplots(figsize=(6, 3.5))
ax.plot(perfil.index, perfil.values)      # paso 1: los datos, sin mas

Ya se ve la curva, pero nadie sabría qué mide. Añade los rótulos de los ejes —sin ellos, un gráfico es un acertijo—:

ax.set_xlabel("energia (0 a 1)")          # paso 2: que mide cada eje
ax.set_ylabel("popularidad media")

Y, por último, un título que diga de qué va:

ax.set_title("Popularidad segun la energia")   # paso 3: el titulo

Tres pasos, tres micro-victorias. Esa costumbre —dibujar, mirar, añadir una cosa, volver a mirar— es como se trabaja de verdad, y es mil veces menos frustrante que pelearte con veinte órdenes a la vez sin saber cuál falló. Y un aviso: el rótulo de eje que falta es el error más común y más tonto de todos. No dejes nunca una figura sin decir qué mide cada eje y en qué unidades; una figura sin rótulos es un acertijo, no una respuesta.

Las partes de una figura.

Conviene ponerle nombre a lo que ves, porque cada nombre es también la orden que lo dibuja. Una figura de matplotlib tiene: el título (lo pone set_title), los dos ejes con sus rótulos (set_xlabel y set_ylabel), las marcas numeradas de cada eje —los ticks, que puedes elegir con set_xticks—, la cuadrícula tenue de fondo que ayuda a leer los valores, y el área de dibujo donde caen los datos. No hace falta tocarlas todas cada vez —matplotlib pone marcas y cuadrícula por su cuenta—, pero saber cómo se llaman te da el mando: cuando quieras que el eje de energía marque solo 0, 0,25, 0,5, 0,75 y 1 en vez de todos los números, ya sabes que eso es un set_xticks. Poco a poco irás mandando tú sobre cada pieza, en vez de conformarte con lo que sale por defecto.

NotaPara saber más: las dos caras de matplotlib

Por internet verás mucho código que dibuja con plt.plot(...), plt.title(...), sin crear ningún ax. Funciona: es la «cara rápida» de matplotlib, que dibuja sobre una figura invisible «la de ahora mismo». Es cómoda para un tanteo, pero se lía en cuanto tienes dos gráficos, porque nunca sabes sobre cuál está actuando cada orden. La forma con fig, ax que usamos aquí es la «cara ordenada»: cada gráfico tiene su nombre y no hay magia oculta. Aprende esta desde el principio y te ahorrarás muchos líos.

Guardar la figura de verdad.

Un gráfico que solo se ve en la pantalla se pierde. Para quedártelo, guárdalo en un fichero con fig.savefig. Y aquí un consejo de profesional: guárdalo en PDF, no en foto.

fig.savefig("mi_grafico.pdf")   # vectorial: no pixela nunca

Un PDF es un dibujo vectorial: guarda las instrucciones («una línea de aquí a allá»), no una cuadrícula de puntitos como una foto. ¿La ventaja? Que puedes ampliarlo todo lo que quieras —imprimirlo en un póster— y nunca se ve pixelado. Una imagen .png está bien para pegar en un chat; un .pdf es lo que llevas a un informe serio. Y otra ventaja escondida, que enlaza con la regla sagrada de la Misión 1 —la reproducibilidad—: tu figura ya no es un fichero suelto que podrías perder, sino unas líneas de código que la vuelven a fabricar idéntica siempre que las ejecutes. La figura es código.

Elige el gráfico según la pregunta

Aquí está el secreto que separa a quien dibuja bien de quien dibuja al tuntún: el gráfico lo elige la pregunta, no tu gusto. Antes de tocar matplotlib, di en voz alta qué quieres saber, y la forma casi se elige sola. Estas son las cinco preguntas que cubren casi todo, con su gráfico:

  • «¿Cuál es mayor?» —comparar cantidades entre categorías (los géneros)—. El gráfico es de barras. El ojo compara longitudes de maravilla.

  • «¿Cómo cambia a lo largo de un rango?» —la evolución de algo según sube un rasgo continuo, como la energía o el tempo—. El gráfico es de líneas. La línea une un valor con el siguiente y dibuja la tendencia.

  • «¿Van juntas dos cosas?» —si cuando una sube la otra sube o baja (la bailabilidad y la alegría, la energía y la positividad)—. El gráfico es de dispersión, una nube de puntos.

  • «¿Qué pasa cruzando dos ejes a la vez?» —el género y el rasgo—. El gráfico es un mapa de calor: una rejilla de colores. Ese será tu mapa final.

  • «¿Cómo se reparte una sola cosa?» —¿son casi todas las canciones parecidas de populares o hay de todo?—. El gráfico es un histograma, que cuenta cuántas caen en cada tramo.

Guárdate esta lista como una brújula. Cada vez que vayas a dibujar, vuelve a ella: primero la pregunta, después la forma. Fíjate en que ninguna de las cinco filas empieza por «quiero un gráfico de barras»: empieza por una pregunta, y la forma viene detrás, casi sola. Ese es el orden de un analista, y el revés —elegir la forma bonita y luego buscarle un dato que meterle dentro— es el de quien acaba engañándose. Recorramos ahora las formas, una a una, con tu catálogo de música.

No engañar: el factor de mentira

Coge esas dos barras casi iguales —rock 87,2 y hip-hop 87,1— y voy a enseñarte a hacer que parezcan completamente distintas sin cambiar ni un dato. El truco más viejo y más sucio de los gráficos: mover el punto donde empieza el eje. La figura 5.3 lo hace con las dos mismas barras.

dos = med.loc[["hip-hop", "rock"]]   # 87.1 y 87.2

fig, (mal, bien) = plt.subplots(1, 2, figsize=(6.4, 3.0))
mal.bar(dos.index, dos.values, color=["#8a8a8a", "#D55E00"])
mal.set_ylim(87.0, 87.3)             # eje TRAMPOSO: no empieza en cero
mal.set_title("Eje tramposo")

bien.bar(dos.index, dos.values, color=["#8a8a8a", "#D55E00"])
bien.set_ylim(0, 100)                # eje HONRADO: empieza en cero
bien.set_title("Eje honrado")
fig.savefig("mis05_liefactor.pdf")

Figura 5.3. El mismo dato, dos mensajes opuestos. Hip-hop (87,1) y rock (87,2), una diferencia real de una décima. A la izquierda, con el eje arrancado en 87,0, una barra parece el doble que la otra: pura mentira. A la derecha, con el eje en cero, la verdad: son casi idénticas. Solo cambia dónde empieza el eje. Figura mis05_liefactor.

En el panel de la izquierda el eje no empieza en cero, sino en 87,0, muy cerquita de los dos valores. ¿El efecto? Que la diferencia de una décima —la parte de la barra que asoma por encima de 87,0— se estira hasta que una barra parece el doble que la otra. Un titular tramposo diría: «¡el rock duplica en popularidad al hip-hop!». Y sería una mentira redonda, aunque cada número del gráfico sea cierto. En el panel de la derecha el eje arranca en cero, como Dios manda, y aparece la verdad desnuda: las dos barras son gemelas.

Un señor llamado Edward Tufte, que dedicó su vida a estudiar cómo los gráficos engañan, le puso número a esto: el factor de mentira. Es una división muy sencilla: cuánto exagera el dibujo dividido entre cuánto cambia de verdad el dato. Si el dibujo es honrado, vale 1. En nuestro panel tramposo el dato cambia un 0,1 % (de 87,1 a 87,2) pero el dibujo lo enseña como un 100 %: el factor de mentira se dispara por encima de ochocientos. Cuanto más lejos de 1, más gordo el embuste. La regla que te llevas es de las que valen para toda la vida: en un gráfico de barras, el eje empieza en cero. Siempre. Porque la barra dice su valor con su longitud, y una longitud medida desde un cero falso miente.

NotaPara saber más: la excepción de las líneas

¿Y en un gráfico de líneas, también hay que empezar en cero? Aquí hay un matiz bonito. En una línea, el valor lo lleva la posición del punto, no una longitud desde la base. Si una serie oscila entre 56 y 72, dibujarla sobre un eje de 0 a 100 la aplasta en una raya casi plana y no ves la loma. Ahí es legítimo acercar la lupa y empezar el eje cerca de los datos —con una condición: decirlo con honradez, con el eje bien etiquetado—. La regla del cero es de las barras (que miden con longitudes), no de las líneas (que miden con posiciones). Saber cuándo aplicar una regla y cuándo no es lo que distingue a un experto de quien solo repite normas.

La letra pequeña: el pie de figura

Debajo de cada figura de este libro hay un párrafo en letra pequeña —el pie de figura— que casi nadie lee del todo y que, sin embargo, es lo que separa un gráfico serio de un dibujo cualquiera de internet. El pie honrado contesta a tres preguntas mudas que cualquier lector espabilado se hace: ¿qué estoy viendo?, ¿de dónde salen estos números? y ¿en qué unidades?. Un gráfico sin pie —o con un pie que solo repite el título— te pide que te lo creas por las buenas, y un analista no pide fe: ofrece pruebas.

Mira los pies de tus propias figuras. Todos dicen de dónde vienen los datos («musica.csv»), qué mide cada eje y con qué escala (la popularidad de 0 a 100, los rasgos de 0 a 1) y qué significa cada color o cada línea. Esa costumbre tiene un nombre grande —la procedencia del dato— y una razón sencilla: quien lea tu figura dentro de un año, o quien quiera comprobar si dijiste la verdad, tiene que poder rastrear cada número hasta su origen. Es la misma honradez de la Misión 4, ahora aplicada al dibujo: no distorsionar, declarar de dónde sale todo, dejar la figura reproducible. Cuando dibujes para enseñárselo a alguien, escribe siempre el pie —la fuente, las unidades y la fecha—. Es la firma de un cartógrafo que no tiene nada que esconder.

Colores que todo el mundo pueda ver

Un gráfico honrado también tiene que poder leerse, y aquí hay algo que casi nadie te cuenta: no todos vemos los colores igual. Alrededor de una de cada doce personas —sobre todo chicos— tiene algún tipo de daltonismo, y la confusión más común es entre el rojo y el verde. Piénsalo: si haces un gráfico donde «lo malo» es rojo y «lo bueno» es verde, hay un compañero de clase de cada dos aulas que no distingue tu mensaje. No es un detalle: es dejar gente fuera.

La solución la encontraron dos investigadores japoneses, Masataka Okabe y Kei Ito, que diseñaron una paleta de ocho colores pensada para que se distingan aunque tengas daltonismo. Se llama, por ellos, la paleta Okabe-Ito, y es la que usa todo este libro —sí, también las figuras que estás viendo—. Sus colores tienen nombres de código que puedes copiar tal cual:

AZUL      = "#0072B2"   # el azul del libro
BERMELLON = "#D55E00"   # el naranja-rojizo para resaltar
VERDE     = "#009E73"
NARANJA   = "#E69F00"
GRIS      = "#8a8a8a"   # para lo que quieres atenuar

Esos códigos raros que empiezan por almohadilla son colores en formato hexadecimal: una receta de cuánto rojo, verde y azul lleva cada uno. No hace falta que los entiendas; basta con copiarlos. Fíjate en que en la figura de las barras usamos justo el bermellón de esta paleta para resaltar y el gris para atenuar. Además de elegir bien el color, hay una segunda regla de oro: que el color nunca sea la única pista. Si distingues dos líneas solo por el color, quien no vea ese color se pierde; pero si además una es continua y la otra de puntos, o una lleva círculos y la otra cuadrados, el gráfico se lee igual. Se llama doble codificación, y es de puro sentido común: da la misma información por dos caminos, y así no dejas a nadie atrás.

NotaPara saber más: el mito de los colores por defecto

Es tentador pensar «matplotlib ya elige colores bonitos, ¿para qué complicarme?». Cuidado: los colores que matplotlib pone por defecto a cada serie no son seguros para el daltonismo. Hay una buena noticia, eso sí: para los mapas de calor, el degradado por defecto de matplotlib —se llama viridis, del morado al amarillo— sí está diseñado para verse bien con daltonismo y hasta en blanco y negro. Por eso lo usarás en tu mapa final. Pero para las barras y las líneas, elige tú los colores a mano, con Okabe-Ito. Un buen dibujante no confía en lo que viene por defecto: decide.

NotaPara saber más: el texto alternativo

Hay un canal de accesibilidad que no se ve en el papel pero es decisivo en la web: el texto alternativo (alt text), la descripción que un lector de pantalla lee en voz alta a una persona ciega. Para quien no ve la imagen, un gráfico sin texto alternativo sencillamente no existe. Y el descuido es la norma: un estudio de cien mil cuadernos halló que el 99,8 % de las figuras hechas con código no lo tenían. Cuando publiques una figura en la web, escríbele una frase que cuente lo que se ve —«la popularidad dibuja una loma: sube con la energía hasta un punto dulce y luego cae»—. No cuesta nada y no deja fuera a nadie. La honradez de un gráfico también es esto: que pueda llegarle a todo el mundo.

Líneas: la loma de la energía

Segunda pregunta: ¿cómo cambia la popularidad a lo largo del rango de energía?. Es un «¿cómo cambia a lo largo de un rango?», así que toca una línea. Ya la viste asomar en la figura 5.1; ahora la dibujas tú, con nombre y etiquetas. La línea es la forma natural de un rango continuo porque une cada nivel con el siguiente y te deja recorrerlo de izquierda a derecha, de menos energía a más.

nivel = (musica["energy"] * 10).round() / 10
perfil = musica.groupby(nivel)["popularity"].mean()

fig, ax = plt.subplots(figsize=(6, 3.5))
ax.plot(perfil.index, perfil.values, color="#0072B2", marker="o")
ax.set_xlabel("energia (0 a 1)")
ax.set_ylabel("popularidad media")
ax.set_title("La loma de la energia")

print("Cima:", perfil.idxmax(), "con", round(perfil.max(), 1))
print("Valle:", perfil.idxmin(), "con", round(perfil.min(), 1))
Cima: 0.8 con 71.7
Valle: 0.1 con 56.0

Ahí está la loma: la cima está en energía 0,8, con 71,7 de popularidad media, y el valle en energía 0,1, con 56,0. Ni las canciones apagadas ni las pasadísimas de vueltas triunfan tanto como las de energía media-alta. Una regla importante de las líneas: aquí el eje horizontal tiene un orden natural —de menos energía a más— y jamás lo reordenes por valor. A las barras las ordenábamos por tamaño para leer el ranking; un rango continuo, en cambio, tiene un orden sagrado —el de menos a más— y reordenarlo por valor destruiría lo único que el eje horizontal tiene que contar. El 0,7 va antes que el 0,8 porque tiene menos energía; punto.

Hay una razón más honda para usar una línea aquí, y no unas barras. La línea une un nivel de energía con el siguiente, y al unirlos afirma algo: que entre 0,7 y 0,8 la popularidad pasó de un valor a otro de forma continua, sin saltos. Eso es cierto con un rasgo que crece poco a poco —la energía es un continuo— y por eso la línea encaja. Pero cuidado: unir con una línea cosas que no son continuas es otro engaño sutil. Si en el eje horizontal tienes los seis géneros, ¡no los unas con una línea!, porque entre «pop» y «jazz» no hay nada intermedio que la línea pueda estar contando. Para categorías sueltas, como los géneros, barras; para un continuo como la energía, líneas. La forma no solo enseña el dato: también afirma qué clase de dato es.

Dispersión: cuanto más bailable, más alegre

Tercera pregunta: ¿van juntas dos cosas?. Tienes en los datos, para cada canción, lo bailable que es (danceability) y lo alegre que suena (valence). ¿Se relacionan? Para eso está el gráfico de dispersión: cada canción es un punto, con la bailabilidad en el eje horizontal y la alegría en el vertical. No hay forma más directa de mirar una relación —posición contra posición— y el ojo lee de un vistazo si la nube sube, baja o no va a ninguna parte.

muestra = musica.sample(1500, random_state=42)   # 1500 al azar

fig, ax = plt.subplots(figsize=(5.4, 3.5))
ax.scatter(muestra["danceability"], muestra["valence"],
           color="#0072B2", alpha=0.25)   # alpha: puntos translucidos
ax.set_xlabel("bailabilidad (0 a 1)")
ax.set_ylabel("alegria (0 a 1)")
fig.savefig("mis05_dispersion.pdf")

r = musica["valence"].corr(musica["danceability"])
print("Relacion (r):", round(r, 2))
Relacion (r): 0.48

La figura 5.4 muestra la nube, y sube de izquierda a derecha: cuanto más bailable, más alegre. Tiene todo el sentido —una canción hecha para bailar suele sonar positiva y luminosa; una lenta y sombría, ni se baila ni levanta el ánimo—. Ese r = 0,48 que imprimimos es el coeficiente de correlación, un número entre \(-1\) y \(+1\) que resume la nube: cerca de \(0\), no hay relación; cerca de \(+1\), cuando una sube la otra sube con fuerza (nuestro caso); cerca de \(-1\), cuando una sube la otra baja. Pero —y esto es oro— el número nunca sustituye al dibujo: solo mirando la nube ves si es una banda apretada o una niebla dispersa, algo que el \(0,48\) por sí solo no te cuenta.

NotaPara saber más: el número miente, el dibujo no

Hay un ejemplo famosísimo entre los que enseñan estadística, el «cuarteto de Anscombe»: cuatro nubes de puntos completamente distintas —una casi recta, una curva, una con un solo punto disparado— que tienen exactamente la misma media, la misma dispersión y la misma correlación. Si solo miras los números, parecen gemelas; en cuanto las dibujas, no se parecen en nada. La moraleja es la médula de esta misión: un resumen numérico puede esconder formas radicalmente distintas, y por eso hay que mirar los datos, no solo calcular con ellos. El \(r = 0{,}48\) te avisa de que hay relación; solo la nube te dice de qué clase.

Figura 5.4. Cuanto más bailable, más alegre. Cada punto es una canción: su bailabilidad y su alegría. La nube sube hacia la derecha —más bailable, más positiva—, con una correlación de \(r = 0{,}48\). Los puntos son translúcidos (alpha) para que se vea la densidad donde se amontonan. Datos: musica.csv, muestra de 1500 con semilla 42. Figura mis05_dispersion.

Un detalle técnico que salva muchos gráficos: el alpha=0.25. Con miles de puntos, si los pintas opacos se tapan unos a otros y todo se vuelve una mancha negra —se llama sobredibujado—. Al hacerlos translúcidos, donde se amontonan muchos el color se satura y donde hay pocos queda pálido: la propia densidad se convierte en información. Y una última honradez: hemos cogido una muestra de 1500 canciones al azar, con random_state=42, para que la nube no sea una plasta ilegible. Ese 42 es la semilla —la de la Misión 1—: garantiza que tú y yo saquemos exactamente las mismas 1500 canciones y, por tanto, la misma figura. Reproducibilidad hasta en el azar.

Y aquí una advertencia que un analista lleva tatuada, porque es la más importante de toda la estadística: que dos cosas vayan juntas no significa que una cause la otra. Nuestra nube dice que las canciones bailables suelen ser más alegres, y en este caso sí hay una conexión razonable —el ánimo y el ritmo van de la mano—. Pero la correlación, por sí sola, jamás lo demuestra: podría ser que un tercer factor moviera las dos a la vez, o pura coincidencia. Hay correlaciones famosas y absurdas —cuanto más helado se vende, más gente se ahoga en la playa— que no significan que el helado ahogue a nadie: es que en verano pasan las dos cosas. La nube te enseña que dos variables bailan juntas; por qué bailan es una pregunta distinta, que hay que responder con cabeza y no solo con el gráfico. Lo verás con lupa en la Misión 6. De momento, graba la frase: correlación no es causa.

La forma de los datos: el histograma

Queda una quinta pregunta, más callada pero de las que un analista se hace antes que ninguna: ¿cómo se reparte una sola columna?. No «¿cuál es la media?» —eso es un número solo— sino algo más rico: ¿son casi todas las canciones parecidas de populares, o hay de todo?, ¿la mayoría pega fuerte con algún caso flojo de vez en cuando, o está todo repartido por igual? Un promedio esconde eso; para verlo hace falta un histograma. La idea es cortar el rango de valores en tramos —en inglés los llaman bins, «cajones»— y contar cuántas canciones caen en cada tramo. La altura de cada barra es ese recuento: cuántas canciones marcaron una popularidad de ese pelo.

fig, ax = plt.subplots(figsize=(5.6, 3.4))
ax.hist(musica["popularity"], bins=30, color="#0072B2",
        edgecolor="white")
ax.axvline(80, color="#1a1a1a", ls=":")     # umbral de "muy popular"
ax.set_xlabel("popularidad (0-100)")
ax.set_ylabel("n de canciones")
fig.savefig("mis05_histograma.pdf")

grandes = (musica["popularity"] >= 80).sum()
print("Canciones muy populares (>=80):", grandes)
print("Porcentaje del catalogo:",
      round(100 * (musica["popularity"] >= 80).mean(), 1))
Canciones muy populares (>=80): 732
Porcentaje del catalogo: 21.8

La figura 5.5 enseña la forma, y cuenta una historia que ninguna media contaría. El montón de canciones se apila a la derecha, en valores altos —lo normal es que ronden los 70-80 de popularidad—, y desde ahí baja una cola larga hacia la izquierda, cada vez más flaca, hasta algún caso raro que apenas llega a 12. Es lo que se llama una distribución sesgada: no es simétrica como una campana, sino que tiene un lado corto y otro largo. Recuerda que este catálogo son las treinta canciones más populares de cada género, así que casi todas pegan fuerte: el 21,8 % pasa de 80 —el club de los grandes éxitos—, pero esa cola de la izquierda esconde un puñado de temas que, aun siendo lo más sonado de su género, no arrancaron. Un histograma te enseña a la vez lo normal y lo excepcional, y por eso es la primera figura que un analista dibuja de cualquier columna nueva: para saber con qué clase de dato está tratando antes de calcular nada.

Y hay una trampa que el histograma te ayuda a esquivar. Es tentador resumir esta columna diciendo «la popularidad media es 68», y quedarse tan ancho. Pero en una distribución sesgada como esta, la media engaña un poco: esas pocas canciones flojas de la cola —las de 30, 20, 12— tiran de la media hacia abajo, de modo que la media (67,8) es menor que la lectura más típica (la mediana, 70,0). No es un abismo aquí, pero en distribuciones muy sesgadas —los sueldos de un país, las visitas de una web— la media puede mentir a base de bien, y solo el histograma te avisa de que hay una cola tirando de ella. Moraleja: nunca resumas una columna con un solo número sin haber mirado antes su forma. El promedio es un buen criado y un mal amo.

Figura 5.5. ¿Cómo se reparten las canciones? Cada barra cuenta cuántas canciones tienen una popularidad de ese tramo. El grueso se apila en valores altos y baja en una cola larga hacia la izquierda (distribución sesgada); la línea de puntos marca el umbral de 80, que solo el 22 % alcanza. Datos: musica.csv. Figura mis05_histograma.
NotaPara saber más: cuántos cajones

El bins=30 decide en cuántos tramos se parte el rango, y no es un detalle inocente. Con pocos cajones (bins=5) la figura sale a brochazos y esconde la forma; con demasiados (bins=200) cada barra tiene cuatro canciones y todo es ruido dentado. La buena elección enseña la forma sin inventar picos: para miles de datos, entre 20 y 50 cajones suele ir bien. Prueba a cambiar el número y mira cómo respira el histograma —es la mejor manera de cogerle el punto—.

Los cuatro reflejos del dibujante honrado

Antes de la victoria, para y repasa. Has aprendido cinco formas —barras, líneas, dispersión, mapa de calor e histograma— y, mezcladas entre ellas, cuatro reglas de honradez que valen para todas y que quiero que se te queden como reflejos, cosas que hagas sin pensar. Son estas:

  1. Elige la forma que el ojo lee mejor. Posición y longitud antes que ángulo o área. Ante la duda entre tarta y barras, barras. La forma la manda la pregunta, no tu gusto.

  2. No mientas con la escala. En barras, el eje empieza en cero, siempre. En líneas puedes acercar la lupa, pero dilo con el eje bien etiquetado. El factor de mentira acecha en cada eje mal puesto.

  3. No dejes a nadie fuera con los colores. Paleta Okabe-Ito, y el color nunca como única pista (doble codificación: forma, trazo, leyenda).

  4. Declara de dónde sale todo. Rótulos con unidades, un pie honrado con la fuente, la barra de color en los mapas. Un gráfico que no se puede rastrear no se puede creer.

No son adornos de teoría: son la lista de comprobación que separa un gráfico que informa de uno que solo llena hueco —o que engaña—. Cuélgala en la bitácora y pásale revista a cada figura que dibujes, hasta que te salga sola. Con esos cuatro reflejos en la mano ya puedes cobrar la victoria sin miedo a engañarte ni a engañar.

La victoria

Tienes ya las cuatro formas —barras, líneas, dispersión y, en un momento, el mapa— y las cuatro reglas de honradez. Toca cobrar el primer trofeo: una figura del sonido que retrate a los géneros por sus dos caras, la que pide tu encargo: la popularidad y la energía. La haremos con dos paneles en un mismo lienzo, porque un género tiene dos caras y merecen verse juntas.

La primera cara ya la conoces: cuánto gusta cada género —su popularidad—. La segunda es cuánta energía tiene —si es un tema que te levanta del asiento o uno para escuchar con los ojos cerrados—. Y aquí viene lo bonito: no tienen por qué coincidir. Veamos:

porpop = hueco.groupby("track_genre")["popularity"].mean().sort_values()
porene = hueco.groupby("track_genre")["energy"].mean().sort_values()

fig, (izq, der) = plt.subplots(1, 2, figsize=(7, 3.1))

izq.barh(range(len(porpop)), porpop.values, color="#0072B2")
izq.set_yticks(range(len(porpop)))
izq.set_yticklabels(porpop.index)
izq.set_title("Por popularidad")
izq.set_xlabel("popularidad media (0-100)")

der.barh(range(len(porene)), porene.values, color="#D55E00")
der.set_yticks(range(len(porene)))
der.set_yticklabels(porene.index)
der.set_title("Por energia")
der.set_xlabel("energia media (0 a 1)")

fig.tight_layout()
fig.savefig("mis05_victoria.pdf")

print("Genero mas popular:", porpop.idxmax(), round(porpop.max(), 1))
print("Genero mas energico:", porene.idxmax(), round(porene.max(), 2))
Genero mas popular: pop 91.1
Genero mas energico: rock 0.7

Ahí la tienes, la figura 5.6: cada género por sus dos caras. A la izquierda, la popularidad: manda el pop (91,1), seguido del reggaeton y, empatados, rock y hip-hop; abajo, jazz y clásica. A la derecha, la energía, y ¡mira cómo cambia el orden!: ahora el rey es el rock (0,70), la clásica se queda en el sótano (0,14, un tema de piano no te desata) y el pop, tan popular, es solo intermedio en energía. Lo interesante es justo eso: el género más popular no es el más enérgico. Popularidad y energía cuentan historias distintas, y por eso pintamos las dos. La única constante es la clásica: la menos popular y la menos enérgica de las seis.

Figura 5.6. Las dos caras del sonido. A la izquierda, la popularidad media de cada género (manda el pop); a la derecha, la energía media (manda el rock). El orden cambia de un panel a otro: el más popular no es el más enérgico. Datos: musica.csv. Figura mis05_victoria.

Fíjate en el fig.tight_layout() justo antes de guardar: es la orden «coloca bien los paneles para que no se pisen las etiquetas». Cuando tengas varios paneles, acuérdate de él o te saldrán los rótulos amontonados. Pequeño truco, gran diferencia.

NotaPara saber más: subplots, una rejilla de ejes

La orden plt.subplots(1, 2) pide una fila y dos columnas de ejes, y por eso pudimos desempaquetar la pareja izq, der. Cambiando esos dos números pides la rejilla que quieras: plt.subplots(2, 2) da cuatro paneles (dos filas, dos columnas), y entonces te devuelve una tabla de ejes que se recorre con dos índices, ax[0][1]. Es como tener varias hojas de dibujo en el mismo folio. Ojo a un detalle que pilla a todo el mundo: plt.subplots() a secas, sin números, devuelve un único ax pelado, no una lista de uno; en cuanto pides varios, devuelve la colección. Con esa orden montarás, en los retos, el cuadro de mando de cuatro paneles del sonido.

¿Lo lograste?

Como en cada misión, no te fías de que «parece que salió»: lo compruebas. La orden assert de la Misión 1 vuelve a hacer de guardián. Esta celda recalcula las dos caras, comprueba que el más popular es el pop y el más enérgico el rock y, si todo cuadra, confirma que la figura quedó bien guardada:

import os

porpop = hueco.groupby("track_genre")["popularity"].mean()
porene = hueco.groupby("track_genre")["energy"].mean()
assert porpop.idxmax() == "pop", "Casi: revisa el groupby de popularidad."
assert porene.idxmax() == "rock", "Casi: el mas energico deberia ser rock."
assert os.path.exists("mis05_victoria.pdf"), "Falta el PDF; ejecutala arriba."
print("Lo lograste. Figura del sonido guardada.")
Lo lograste. Figura del sonido guardada.

Si ves ese mensaje y tienes el PDF en tu carpeta, has fabricado tu primera figura de datos reales, de principio a fin: cargar, agrupar, dibujar, comprobar y guardar. La mitad de la insignia cartógrafo del sonido ya es tuya. Falta el mapa, que es el jefe.

La bitácora del analista

Abre la bitácora que empezaste en la Misión 1 —esa celda de texto al final del cuaderno— y anota lo de hoy. Un cartógrafo guarda sus mapas, pero también el camino que los dibujó. Para la Misión 5, apunta al menos:

  • La pregunta de cada figura: «¿qué género es el más popular?», «¿cómo cambia la popularidad con la energía?».

  • El hecho que descubriste: «el más popular es el pop (91,1); el más enérgico, el rock (0,70)»; «más bailable \(\rightarrow\) más alegre, \(r = 0{,}48\)».

  • Una trampa que aprendiste a esquivar: el eje que no empieza en cero, o el color que deja fuera a los daltónicos.

  • Una duda: ¿por qué las canciones explícitas puntúan más alto? (Pista: compara explicit verdadero y falso con un groupby…).

Sube de nivel: dos rasgos, dos líneas

Una línea cuenta una historia; dos líneas comparadas cuentan un argumento. Ya viste que la popularidad hace una loma con la energía. Pregunta nueva: cuando sube la energía, ¿qué le pasa a la bailabilidad y a la alegría? ¿Suben las dos igual? ¿Va una siempre por delante de la otra? Para responderlo, dibujamos las dos líneas en el mismo lienzo, una encima de otra, y las comparamos punto a punto —las dos contra el mismo eje de energía—:

nivel = (musica["energy"] * 10).round() / 10
baile   = musica.groupby(nivel)["danceability"].mean()
alegria = musica.groupby(nivel)["valence"].mean()

fig, ax = plt.subplots(figsize=(6.2, 3.5))
ax.plot(baile.index, baile.values, color="#0072B2",
        marker="o", ls="-",  label="bailabilidad")
ax.plot(alegria.index, alegria.values, color="#D55E00",
        marker="s", ls="--", label="alegria")
ax.set_xlabel("energia (0 a 1)")
ax.set_ylabel("valor medio (0 a 1)")
ax.legend()
fig.savefig("mis05_comparacion.pdf")

print("Bailabilidad max:", round(baile.max(), 2), "en energia", baile.idxmax())
print("Alegria max:", round(alegria.max(), 2), "en energia", alegria.idxmax())
Bailabilidad max: 0.64 en energia 0.7
Alegria max: 0.59 en energia 0.8

La figura 5.7 pone las dos historias juntas, y ahora sí se lee el argumento entero. Las dos líneas tienen la misma forma —suben con la energía hasta una loma y luego caen un poco—, pero la de la bailabilidad va siempre por encima de la de la alegría: en todo el rango, la música es más bailable que alegre. La bailabilidad llega a su cima antes (energía 0,7, con 0,64) y la alegría un pelín después (energía 0,8, con 0,59). Traducido: la energía empuja el cuerpo y el ánimo a la vez, pero antes las ganas de bailar que la sonrisa. Eso ni un número solo ni una línea sola podían enseñarlo; hacían falta las dos líneas, comparadas.

Figura 5.7. Dos rasgos, contra la energía. La bailabilidad (azul, continuo, círculos) y la alegría (bermellón, discontinuo, cuadrados) según el nivel de energía. Misma forma —una loma—, pero la bailabilidad va siempre por encima. Datos: musica.csv. Figura mis05_comparacion.

Y fíjate en cómo están dibujadas las dos líneas, porque es la doble codificación del §5.2.8 en acción. No se distinguen solo por el color (azul y bermellón): una es continua con círculos y la otra discontinua con cuadrados. ¿Por qué molestarse, si ya tienen colores distintos? Porque así el gráfico se sigue leyendo aunque lo fotocopien en blanco y negro, aunque lo proyecte un cañón descolorido, aunque lo mire alguien que no distingue el azul del naranja. Y la ax.legend() traduce cada trazo a su rasgo: con dos series o más, la leyenda deja de ser opcional —sin ella, los colores no significan nada—. Una línea sola no necesita leyenda; dos, sí siempre.

Sube de nivel: ¿gustan más las explícitas?

Ya sabes comparar rasgos; comparemos ahora dos grupos de canciones. Tienes en los datos una columna explicit que vale verdadero si la canción lleva lenguaje explícito y falso si no. La pregunta —¿gustan más las explícitas?— se responde con el groupby de siempre, porque comparar, como dijimos, es restar y mirar:

media_grupo = musica.groupby("explicit")["popularity"].mean()
print(media_grupo.round(1))
diferencia = media_grupo[True] - media_grupo[False]
print("Diferencia explicitas - limpias:", round(diferencia, 1))
explicit
False    66.8
True     74.8
Name: popularity, dtype: float64
Diferencia explicitas - limpias: 8.0

Ahí está: las canciones limpias marcan 66,8 de popularidad media y las explícitas suben a 74,8, ocho puntos más. Y si afinas por género —y de paso recuperas el truco de dibujar con caracteres de la Misión 1, que aquí, como adelanto del mapa, todavía sirve—, ves el ranking de un vistazo:

orden = hueco.groupby("track_genre")["popularity"].mean().round(1)
orden = orden.sort_values(ascending=False)
for g, v in orden.items():
    print(g, "#" * int(v / 3), v)   # cada # vale unos 3 puntos
pop ############################## 91.1
reggaeton ############################# 89.2
rock ############################# 87.2
hip-hop ############################# 87.1
jazz ######################## 72.3
classical ###################### 67.3

Las barras de texto dejan clarísimo el escalón: pop, reggaeton, rock y hip-hop, casi clavados arriba; jazz y clásica, un buen trecho por debajo. Ahora bien, aquí un cartógrafo honrado se muerde la lengua antes de titular. Esa diferencia de 8 puntos entre explícitas y limpias parece grande… ¿pero lo es de verdad, o es que las explícitas se concentran en géneros ya muy populares como el reggaeton y el hip-hop? Un solo número no basta para saberlo. Separar el efecto de una cosa del de otra que va pegada a ella es, justamente, el oficio de la Misión 6. Por ahora quédate con la destreza: comparar dos grupos es agruparlos, restar sus medias y dibujar la diferencia para verla.

El mapa: cruza dos ejes a la vez

Queda la cuarta pregunta, la más ambiciosa: ¿qué pasa cuando cruzas dos cosas a la vez?. Hasta ahora mirabas la popularidad por género o un rasgo por su cuenta, por separado. Pero, ¿y si cada género tuviera su rasgo fuerte distinto? ¿Y si uno fuera muy bailable pero poco enérgico, y otro al revés? Una barra no puede enseñar eso: necesitas ver género y rasgo a la vez, las dos dimensiones cruzadas. Para eso está el mapa de calor (heatmap): una rejilla donde cada casilla —un género, un rasgo— se pinta de un color según su valor. Es, literalmente, un mapa del sonido.

La idea es sencilla: una tabla de doble entrada —géneros en las filas, rasgos en las columnas— donde en vez de escribir el número en cada casilla, lo pintamos. Colores oscuros para poco, colores claros para mucho. El ojo, que medía fatal los colores para comparar cifras exactas, es en cambio buenísimo para ver un patrón de golpe: dónde están las manchas claras, dónde las oscuras. Y aquí el color sí es el protagonista, así que hay que elegirlo con un cuidado extremo. La regla no admite discusión: un degradado secuencial y honrado como viridis —el que matplotlib trae por defecto, del morado al amarillo—, que se ve bien con daltonismo y en blanco y negro. Nunca, jamás, el viejo arcoíris: inventa fronteras donde el dato es liso y se vuelve ilegible para muchos. Este es, además, el trofeo grande, así que te lo enfrenta el jefe.

NotaPara saber más: por qué viridis y no el arcoíris

El degradado arcoíris (rojo-amarillo-verde-azul) parece la elección natural para un mapa de calor, y es una trampa. Tiene dos defectos graves. Uno: su banda amarilla es tan luminosa que el ojo ve un «borde» donde el dato no cambia nada, inventando escalones falsos. Dos: al mezclar rojos y verdes, se desmorona para quien tiene daltonismo y se vuelve papilla en blanco y negro. viridis se diseñó justo para arreglar esto: sube de brillo de forma pareja, así que pasos iguales de dato se ven como pasos iguales de color, y conserva su orden para todo el mundo. Cuando dudes con un mapa de calor, viridis.

El jefe de parte: el mapa del sonido de los géneros

Hora de enfrentarte al jefe de parte, el miniproyecto que corona la misión. El encargo del jefe es el trofeo mayor: dibujar el mapa del sonido, una rejilla que cruce ocho géneros con cuatro rasgos y pinte cada casilla con su valor medio. Un solo golpe de vista tendrá que contar la huella de cada género: cómo de popular, bailable, enérgico y alegre es.

La pieza clave es una tabla de doble entrada —prima del groupby de la Misión 3, pero resumiendo varias columnas a la vez—. Le decimos: agrupa por track_genre y saca la media de cada rasgo. Como los rasgos vienen en escalas distintas (la popularidad de 0 a 100, los demás de 0 a 1), dividimos la popularidad entre 100 para que todos compartan la escala 0-1 y los colores sean comparables:

import matplotlib.pyplot as plt

rasgos = ["popularity", "danceability", "energy", "valence"]
generos8 = ["classical", "ambient", "jazz", "pop",
            "hip-hop", "reggaeton", "rock", "metal"]

# tabla de doble entrada: una fila por genero, una columna por rasgo
huella = musica[musica["track_genre"].isin(generos8)]
huella = huella.groupby("track_genre")[rasgos].mean()
huella = huella.reindex(generos8)          # ordenados de menos a mas energia
huella["popularity"] = huella["popularity"] / 100   # a la escala 0-1
print("Forma de la tabla:", huella.shape)

fig, ax = plt.subplots(figsize=(6.4, 3.4))
im = ax.imshow(huella.values, aspect="auto", cmap="viridis")  # pintar
ax.set_yticks(range(len(generos8)))
ax.set_yticklabels(generos8)
ax.set_xticks(range(len(rasgos)))
ax.set_xticklabels(["popularidad", "baile", "energia", "alegria"])
fig.colorbar(im, ax=ax, label="valor (0 a 1)")   # la barra de color
fig.tight_layout()
fig.savefig("mis05_mapa.pdf")
Forma de la tabla: (8, 4)

Ocho filas, cuatro columnas: treinta y dos casillas, cada una un rasgo medio de un género. La orden ax.imshow las pinta según su valor con el degradado viridis, y —no lo olvides nunca— fig.colorbar añade la barra de color, esa leyenda a la derecha que traduce cada tono a su número. Un mapa de calor sin barra de color es una decoración, no una medición: nadie sabría si el amarillo es 0,1 o es 0,9. El resultado es la figura 5.8, y es tu obra maestra.

Figura 5.8. El mapa del sonido. Cada casilla es un género (fila) y un rasgo (columna), pintada con su valor medio en el degradado viridis (oscuro = poco, claro = mucho); la popularidad va reescalada a 0-1. Se lee de un vistazo la huella de cada género: la energía crece de la clásica al metal, y la casilla más clara es el pop en popularidad. Datos: musica.csv. Figura mis05_mapa.

Míralo bien, porque cuenta varias historias en una imagen. De arriba abajo (entre filas, ordenadas de menos a más energía): la columna de la energía se va aclarando, de la clásica casi morada (0,14, la casilla más oscura del mapa) al metal luminoso (0,83). De izquierda a derecha (dentro de cada fila): cada género enseña su perfil —el reggaeton y el hip-hop, muy claros en bailabilidad; la clásica y el ambient, oscuros en casi todo salvo en popularidad, porque hasta sus temas son de los más sonados de su género—. La casilla más clara de todas —el valor más alto del mapa— es el pop en popularidad (0,91). Lo increíble es que ninguna de las figuras anteriores enseñaba todo esto a la vez: las barras daban un rasgo pero perdían los demás. El mapa los cruza y te lo enseña todo junto. Eso es cartografiar el sonido.

Detente un momento en lo que acabas de hacer, porque es grande. Has cogido tres mil trescientas canciones —una montaña de números que ni tú ni nadie podríais leer a mano— y las has resumido en treinta y dos casillas de color que cualquiera entiende en cinco segundos. Ahí está el poder del mapa de calor: comprime una barbaridad de datos en una imagen legible sin perder el patrón. Y fíjate en que este mapa no tiene calles ni relojes —sus ejes son géneros y rasgos—, pero funciona igual que un mapa de verdad: cada casilla es un «lugar» (un género, un rasgo) pintado según lo que allí ocurre. El día que quieras el otro mapa, el geográfico —dónde se escucha cada estilo en el mundo, coloreado por su popularidad—, existen herramientas para dibujarlo, y las nombramos al final. Pero la idea es la misma que ya dominas: colorear un espacio según un dato. Acabas de aprender a pensar como un cartógrafo; ponerle calles es solo cambiar de lápiz.

¿Lo lograste? (nivel jefe)

El jefe también se comprueba, y con dos guardianes: que la tabla tenga la forma correcta y que el género más popular sea el que debe ser. Si los dos callan, has vencido:

huella = musica[musica["track_genre"].isin(generos8)]
huella = huella.groupby("track_genre")[rasgos].mean()
assert huella.shape == (8, 4), "La tabla deberia ser 8 generos x 4 rasgos."

mas_popular = huella["popularity"].idxmax()
assert mas_popular == "pop", "El genero mas popular deberia ser pop."
print("Mapa validado. Insignia desbloqueada: cartografo del sonido.")
Mapa validado. Insignia desbloqueada: cartografo del sonido.

Si ves ese mensaje, enhorabuena de verdad: tienes tu figura del sonido y tu mapa, los dos trofeos del encargo, y te has ganado la insignia cartógrafo del sonido. Has aprendido a convertir tres mil trescientas cifras mudas en imágenes que hablan, y —más importante— a hacerlo sin engañar a nadie ni dejar a nadie fuera. Eso es un cartógrafo del sonido de verdad.

Retos: elige tu nivel

Ahora te toca a ti, con el lápiz en la mano. Los retos suben de dificultad: \(\star\) es imprescindible, \(\star\star\) te reta y \(\star\star\star\) es de jefe. Haz al menos todas las de una estrella; sube hasta donde te apetezca. Y en todas, la regla de oro: primero la pregunta, después la forma. Un consejo para atacarlos: no empieces tecleando: empieza dibujando en tu cabeza (o en un papel) cómo esperas que salga la figura —¿sube?, ¿baja?, ¿cuál barra será la más alta?—. Es la versión dibujada del «predice antes de ejecutar» de la Misión 1, y funciona igual de bien: si la figura que sale no se parece a la que imaginaste, o te equivocaste tú o te equivocaste al programar, y en ambos casos acabas de aprender algo. Un analista no se sorprende de sus propios gráficos.

  • Cambia el color del mejor. En la figura de barras, cambia el bermellón "#D55E00" del género más popular por el verde "#009E73". Ejecuta y mira: ¿sigue guiando la vista igual de bien? ¿Qué color grita más «mírame»?

  • Tu propio punto dulce. Dibuja la línea de la popularidad según la energía (la del §5.2.9) y, antes de ejecutar, apuesta: ¿a qué nivel de energía estará la cima? Comprueba con perfil.idxmax() y con tus ojos en la figura.

  • El eje tramposo, en tus manos. Coge la figura de barras y añádele ax.set_xlim(86, 92). Ejecuta. ¿A que ahora el jazz y la clásica parecen no gustarle a nadie y el pop arrasar? Acabas de fabricar una mentira. Bórrala.

  • Explícitas. Con un groupby sobre la columna explicit (falso = limpia, verdadero = explícita), saca la popularidad media de cada grupo y dibújala en dos barras. ¿Gustan más las explícitas?

  • ★★ Energía y alegría. Haz un gráfico de dispersión de energy (eje X) contra valence (eje Y), con una muestra de 1500 filas y random_state=42. Calcula la correlación con musica["valence"].corr(musica["energy"]). ¿Sube o baja la nube? ¿Tiene sentido que las canciones con más energía suenen más alegres?

  • ★★ Barras por bailabilidad. Dibuja seis barras con la bailabilidad media de cada género de tu lista. Ordénalas por valor y resalta la más bailable. ¿Cuál es? (Pista: el reggaeton pega fuerte aquí).

  • ★★ Dos líneas, doble codificación. En un mismo ax, dibuja la energía media y la alegría media por tramo de danceability (redondeada a un decimal). Que una línea sea continua y la otra de puntos (ls=":"), además de dos colores Okabe-Ito, y añade una ax.legend(). Así se leería aunque se imprimiera en blanco y negro.

  • ★★ El mapa, con más géneros. Rehaz el mapa de calor con diez géneros en vez de ocho, y añade una quinta columna: la duración media en minutos (duration_ms / 60000) reescalada de 0 a 1. ¿Qué género destaca por ser el más largo?

  • ★★★ El jefe: calcula tú el factor de mentira. Con las dos medias casi iguales (87,1 y 87,2) y un eje que empieza en 87,0, calcula a mano cuánto exagera el dibujo. Pista: la parte visible de cada barra es su valor menos 87,0; divide la diferencia aparente entre la diferencia real (0,1). Compara tu número con el «más de ochocientos» del texto.

  • ★★★ El jefe: el panel de cuatro. Junta en una sola figura de cuatro paneles (plt.subplots(2, 2)) tus cuatro vistas: barras de popularidad por género, línea de popularidad por energía, barras de energía por género y el mapa de calor. Pon un título a cada panel y un fig.tight_layout(). Es el cuadro de mando del sonido, en una imagen.

  • ★★★ El jefe: pon un titular honrado. Coge tu figura de la victoria y cámbiale el título por una frase con conclusión, no una etiqueta: en vez de «popularidad y energía por género», algo como «el pop manda en gusto, pero el rock es el más eléctrico». Un titular que se pueda creer o discutir. Ese es el paso de un gráfico para descubrir a un gráfico para comunicar.

¿Te has atascado? En el apéndice C tienes, para cada reto, primero una pista y solo después la solución. Pero el pacto es este: entra ahí después de haberlo intentado de verdad.

NotaPara saber más: exploración frente a comunicación

Hay dos clases de gráfico que se parecen en el código y en poco más. El exploratorio es para ti: rápido, feo, sin pulir, hecho para descubrir —veinte figuras amontonadas para ver cuál esconde algo raro—. El de comunicación es para otros: cuidado, con un solo mensaje en primer plano, un titular que enuncia la conclusión, lo importante resaltado y lo demás atenuado. Ni publiques un borrador exploratorio ni pierdas horas maquillando algo que solo ibas a mirar tú. Las figuras de esta misión, con sus títulos, sus colores elegidos y su honradez, son ya de comunicación: están hechas para enseñar.

Tu caja de herramientas

Mira todo lo que sabes dibujar ahora y hace unas páginas no. Pégala en la bitácora y vuelve a ella cuando dudes.

  • El lienzo: fig, ax = plt.subplots(figsize=(6, 3.5)). Guardar: fig.savefig("f.pdf") (¡en PDF!).

  • Barras («¿cuál es mayor?»): ax.bar / ax.barh. Ordena por valor, resalta el importante, eje en cero.

  • Líneas («¿cómo cambia a lo largo de un rango?»): ax.plot. No reordenar jamás el eje continuo.

  • Dispersión («¿van juntas dos cosas?»): ax.scatter, con alpha si hay muchos puntos. Mira la nube, no solo la \(r\).

  • Mapa de calor («¿dos ejes a la vez?»): groupby de varias columnas + ax.imshow(..., cmap="viridis") + fig.colorbar.

  • Histograma («¿cómo se reparte una columna?»): ax.hist(..., bins=30). Mira la forma antes de resumir con un número.

  • Etiquetas: ax.set_xlabel, ax.set_ylabel, ax.set_title. Y fig.tight_layout() con varios paneles.

  • Honradez: eje en cero (barras), color Okabe-Ito, nunca solo el color, barra de color en los mapas.

  • Colores: azul #0072B2, bermellón #D55E00, verde #009E73, gris #8a8a8a.

No la memorices: úsala. La memoria viene sola de tanto dibujar.

Cuando quieras ir en serio

Todo esto lo has hecho con matplotlib, que es el lápiz que hay debajo de casi todo. Cuando quieras dar el salto, hay herramientas «de mayores» esperando. seaborn se monta encima de matplotlib y hace en una línea muchos gráficos estadísticos que aquí nos costaron varias —entiende de tablas de pandas y elige buenos colores por su cuenta—. plotly dibuja gráficos interactivos para la web, con los que puedes hacer zoom y pasar el ratón por encima de un punto para ver su valor. Y hay un mundo entero de mapas geográficos —con calles y coordenadas— que se pintan con bibliotecas como folium, para el día que tus datos sí tengan lugar: dónde suena cada género en el mundo. No los necesitas para las próximas misiones; pero cuando tu música te pida un mapa sobre el plano real del planeta, sabrás que existe el camino.

Hay una diferencia más, entre dos maneras de dibujar, que conviene que conozcas aunque todavía no la necesites: el gráfico para descubrir y el gráfico para comunicar. Cuando exploras tus datos —veinte figuras rápidas y feas para ver cuál esconde algo raro— estás dibujando para ti: da igual que no tengan título, tú ya sabes qué miras. Pero cuando enseñas una conclusión a otra persona, el gráfico cambia de oficio: hay que pulirlo, resaltar el mensaje, atenuar lo demás y ponerle un título que diga la conclusión, no la etiqueta —no «popularidad por género», sino «el pop es el rey del gusto»—. Las figuras de esta misión, con sus títulos, sus colores elegidos y sus pies honrados, ya son de comunicar: están hechas para enseñárselas a alguien y que lo entienda a la primera. Ese salto —de dibujar para pensar a dibujar para convencer sin mentir— es de los que más te van a valer, dentro y fuera de la ciencia.

Por cierto, un último apunte de cartógrafo honrado. La herramienta cambia cada pocos años —matplotlib, seaborn, plotly, la que venga—, pero lo que has aprendido hoy no caduca: elegir la forma según la pregunta, no mentir con los ejes, no dejar a nadie fuera con los colores. Eso vale con cualquier lápiz, hoy y dentro de veinte años. Y es una destreza que se te va a colar en toda la vida: en cuanto sepas dibujar datos con honradez, empezarás a ver las trampas de los demás —el eje cortado del anuncio, la tarta imposible del telediario, el color que esconde lo que no interesa que veas—. Un cartógrafo del sonido que sabe mentir con un gráfico es, por eso mismo, el que mejor detecta cuándo se lo hacen a él. El gráfico que de verdad importa no es el que dibuja la biblioteca más nueva, sino el que un lector honesto entiende sin ser engañado.

Misión 5 completada. Insignia cartógrafo del sonido, desbloqueada. Has pintado la popularidad y la energía de la música —una figura de sus dos caras y un mapa de sus huellas— y has aprendido a hacerlo con honradez. En la Misión 6 darás el siguiente paso: dejar de fiarte de lo que «parece» en un gráfico y aprender a medir si una diferencia es de verdad grande o es pura casualidad. Las explícitas parecen gustar más… ¿pero cuánto de seguro estamos, o es que van en géneros ya populares? Eso, la próxima vez.