Ridgeline plots (joy plots) en matplotlib con joypy

Librería

joypy

Autor principal

Leonardo Taccari

Conjunto de datos de muestra

La librería joypy toma como entrada un data frame de pandas con varias variables numéricas y también una variable categórica opcional que representa grupos, como en el data frame de muestra del siguiente bloque de código.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

Ridgeline plots con la función joyplot

Por defecto, si pasas un data frame de pandas como entrada, la función joyplot creará un ridgeline plot de las variables numéricas. Esto es, mostrará gráficos de densidad apilados para cada una de las variables numéricas del data frame.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df)

# plt.show()

Joy plot en Python con joypy

Ridgeline plot por grupo

Sin embargo, puede que quieras crear un joy plot de una única variable pero dividido por grupo. En este escenario habrá tantas densidades como grupos que representarán la distribución de la variable para cada uno de ellos. Para ello tendrás que especificar el nombre de la variable categórica con by y el nombre de la variable numérica (o variables) con column.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1")

# plt.show()

Ridgeline plot en matplotlib con joypy

Ridgeline plot para cada variable y grupo

La última alternativa es crear un ridgeline plot que muestra la densidad para cada variable y grupo, de forma que cada grupo tendrá tantas densidades como variables numéricas. Puedes hacerlo especificando todas las variables numéricas que quieras con column (e.g. column = ["var1", "var2"]) o simplemento utilizando by para que se tengan en cuenta todas las variables numéricas, como en el ejemplo siguiente.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo")

# plt.show()

Ridgeline plot con varias variables en Python

Título del gráfico

La función joyplot también proporciona otros argumentos para personalizar la apariencia visual de los gráficos. Por ejemplo, con title puedes agregar un título a la figura.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, title = "Título del joy plot")

# plt.show()

La librería joypy de Python

Joy plot con leyenda

Si quieres agregar una leyenda al gráfico para identificar las diferentes variables puedes especificar legend = True de modo que se agregará una leyenda automática.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", legend = True)

# plt.show()

Agregar una leyenda a un ridgeline plot de Python

Joy plot con histogramas

Los gráficos ridgeline también pueden mostrar histogramas en lugar de estimaciones de densidad. Tendrás que establecer hist = True y especificar el número de intervalos de clase que quieras con bins, que por defecto es 10.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1",
                        hist = True, bins = 50)

# plt.show()

Ridgeline plot con histogramas en matplotlib

Agregar un grid

El argumento grid es por defecto False y se puede utilizar para agregar un grid vertical al gráfico cuando se establece como True. Esta característica es interesante para comparar la distribución de los diferentes grupos.

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", grid = True)

# plt.show()

Agregar un grid a un joyplot de Python

Tipo de densidad

El argumento kind se puede utilizar para elegir el tipo de densidad que se quiere dibujar. Las posibles opciones son "kde" (por defecto), "counts", "normalized_counts" y "values".

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1",
                        kind = "counts")

# plt.show()

Estimación kernel de la densidad de un gráfico ridgeline en matplotlib

Colores de las líneas y de las áreas

joypy también proporciona varias formas de personalizar la apariencia visual de los gráficos. Si quieres cambiar el color azul por defecto de las densidades puedes especificar un nuevo color con color.

Color de las densidades de un ridgeline en Python

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", color = "darkseagreen")

# plt.show()

Color diferente para cada grupo

Ten en cuenta que también puedes pasar un array de colores como entrada al argumento color con tantos colores como grupos (o variables) para que cada densidad tenga un color diferente.

Colores diferentes para cada grupo de un gráfico ridgeline en matplotlib

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})
colores = ["#FDAE61", "#FEE08B", "#FFFFBF", "#E6F598", "#ABDDA4"]

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", color = colores)

# plt.show()

Usando una paleta de colores

Una alternativa a lo anterior es utilizar alguna paleta de colores predefinida de matplotlib con colormap. Recuerda que tendrás que importar cm de matplotlib con from matplotlib import cm.

Usando una paleta de colores de matplotlib para cambiar el color de los ridges de un joyploy

import matplotlib.pyplot as plt
from matplotlib import cm
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", colormap = cm.Pastel1)

# plt.show()

Transparencia del color

En ocasiones las densidades solapan unas sobre otras. Si esto sucede puedes establecer fade = True de modo que cada densidad será más opaca que la anterior (desde la superior a la inferior), permitiendo una mejor visualización de las densidades.

Cambiar la opacidad del color de fondo de las densidades con joypy

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", fade = True)

# plt.show()

Color de las líneas

Las líneas de las densidades son negras por defecto, pero con linecolor puedes elegir el color que prefieras. En el siguiente ejemplo las coloreamos de blanco.

Color de las curvas de densidad de un ridgeline plot hecho con joypy

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", linecolor = "white")

# plt.show()

Eliminar el color de fondo

Ten en cuenta que también puedes eliminar el área de las densidades y tan solo dejar la línea con fill = False.

Eliminar el color de las densidades de un joy plot de Python

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, by = "grupo", column = "var1", fill = False)

# plt.show()

Color de fondo

Por último, también puedes personalizar el color de fondo del gráfico con el argumento background, que por defecto es None.

Cambiar el color de fondo de un gráfico de joypy

import matplotlib.pyplot as plt
from matplotlib import cm
import pandas as pd
import numpy as np; np.random.seed(2)
import random; random.seed(2)
import joypy

# Data frame de muestra
df = pd.DataFrame({'var1': np.random.normal(70, 100, 500),
                   'var2': np.random.normal(250, 100, 500),
                   'grupo': random.choices(["G1", "G2", "G3", "G4", "G5"], k = 500)})

fig, ax = joypy.joyplot(df, background = "lavender")

# plt.show()
Data Sketches

A journey of imagination, exploration, and beautiful data visualizations

Comprar en Amazon
Storytelling con Datos

Visualización de datos para profesionales

Comprar en Amazon

También te puede interesar