====== 03 - Plotnine ======
[[https://plotnine.readthedocs.io/en/v0.12.3/|Plotnine]] es una biblioteca de Python para crear gráficos estadísticos. Se basa en la idea de la "gramática de gráficos", que es un enfoque para crear gráficos que se basa en la combinación de elementos básicos.
Plotnine está inspirado en **ggplot** de **R** y comparte muchos de sus conceptos y sintaxis. Por ejemplo, Plotnine utiliza la misma estructura básica que //ggplot//, con un objeto //ggplot()// que representa la base del gráfico y funciones //geom()// que agregan elementos al gráfico.
Además, Plotnine utiliza la misma notación para asignar estéticas a los datos, como //aes("x", "y")//.
Plotnine es una biblioteca potente y versátil que permite crear gráficos estadísticos de alta calidad. Es una herramienta ideal para científicos de datos, analistas y cualquier persona que necesite visualizar datos.
Los tres elementos de un gráfico de Plotnine son:
* **Geometrías**: Definen el tipo de gráfico que se va a crear.\\ \\
* **Aesthetics**: Asignan datos a los elementos del gráfico.\\ \\
* **Temas**: Definen el aspecto general del gráfico.
Estos elementos se combinan para crear gráficos estadísticos de alta calidad.
Vamos a utilizar el //dataset// {{ :clase:ia:saa:1eval:olimpic_games.zip | olimpiadas}} para nuestros ejemplos. Este //dataset// contiene información sobre los atletas que han participado en los juegos olímpicos modernos.
Como siempre, importamos las librerías necesarias:
#Librerías generales
import pandas as pd
from pathlib import Path
#Librerías gráficas
import plotnine as pn
#Configuración
pd.set_option('display.max_columns', 100)
Creamos nuestro //DataFrame// de //Pandas//:
#Cargar ficheros
data_loc = Path('data')
athletes_file = data_loc / 'athlete_events.csv'
#Creamos el DataFrame
athletes_data = pd.read_csv(athletes_file)
Mostramos información para ver las columnas que tenemos:
athletes_data.info()
RangeIndex: 271116 entries, 0 to 271115
Data columns (total 15 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 ID 271116 non-null int64
1 Name 271116 non-null object
2 Sex 271116 non-null object
3 Age 261642 non-null float64
4 Height 210945 non-null float64
5 Weight 208241 non-null float64
6 Team 271116 non-null object
7 NOC 271116 non-null object
8 Games 271116 non-null object
9 Year 271116 non-null int64
10 Season 271116 non-null object
11 City 271116 non-null object
12 Sport 271116 non-null object
13 Event 271116 non-null object
14 Medal 39783 non-null object
dtypes: float64(3), int64(2), object(10)
memory usage: 31.0+ MB
===== Geometrías =====
Las geometrías son los elementos básicos que componen un gráfico. Definen el tipo de gráfico que se va a crear, como un gráfico de línea, de barras, de dispersión, etc.
Vamos a mostrar una serie de gráficos con las medallas ganadas por los atletas españoles. Primero creamos un //DataFrame// con los diferentes tipos de medallas agrupadas por año:
#Seleccionamos sólo los datos de los atletas españoles
athletes_data_spain = athletes_data[athletes_data["Team"] == "Spain"]
#Eliminamos los nulos en la columna Medal para quedarnos sólo con los atletas que ganaron alguna medalla
athletes_data_spain = athletes_data_spain[athletes_data_spain['Medal'].notna()]
#Agrupamos por años con el número total de medallas por tipo
athletes_data_spain_medals = athletes_data_spain.groupby('Year')['Medal'].value_counts().reset_index()
#renombramos la columna count a total
athletes_data_spain_medals.rename(columns={'count': 'Total'}, inplace=True)
athletes_data_spain_medals.head(10)
Year Medal Total
0 1900 Gold 2
1 1920 Silver 23
2 1928 Gold 3
3 1932 Bronze 1
4 1948 Silver 3
5 1952 Silver 1
6 1960 Bronze 14
7 1972 Bronze 1
8 1972 Gold 1
9 1976 Silver 6
10 1980 Silver 19
11 1980 Bronze 3
12 1980 Gold 2
13 1984 Silver 14
14 1984 Bronze 3
15 1984 Gold 2
16 1988 Silver 2
17 1988 Bronze 2
18 1988 Gold 1
19 1992 Gold 48
20 1992 Silver 19
21 1992 Bronze 3
22 1996 Gold 23
23 1996 Bronze 22
24 1996 Silver 21
25 2000 Bronze 20
26 2000 Silver 19
27 2000 Gold 3
28 2004 Silver 15
29 2004 Bronze 9
30 2004 Gold 4
31 2008 Silver 45
32 2008 Bronze 16
33 2008 Gold 7
34 2012 Silver 33
35 2012 Bronze 25
36 2012 Gold 5
37 2016 Silver 19
38 2016 Bronze 17
39 2016 Gold 7
Vamos a ver algunas de las geometrías más comunes.
==== Gráficos de líneas ====
Los gráficos de línea son utilizados para mostrar la evolución de una variable a lo largo del tiempo o de otra variable.
Por ejemplo, queremos ver la evolución del total de medallas ganadas a lo largo de las diferentes olimpiadas. Primero creamos un //DataFrame// para agrupar el total de medallas:
#Creamos un dataframe con el número total de medallas por año
athletes_data_spain_total_medals = athletes_data_spain_medals.groupby('Year')['Total'].sum().reset_index()
athletes_data_spain_total_medals.head(10)
Year Total
0 1900 2
1 1920 23
2 1928 3
3 1932 1
4 1948 3
5 1952 1
6 1960 14
7 1972 2
8 1976 6
9 1980 24
Ahora creamos el gráfico. Para eso, indicamos la fuente de los datos, los ejes X e Y (mediante //pn.aes()//) y el tipo de gráfico (en este caso //pn.geom_line//):
# Creamos el gráfico de líneas
graph = pn.ggplot(
athletes_data_spain_total_medals,
pn.aes(x='Year', y='Total'),
) + pn.geom_line()
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph01.png?400 |}}
==== Gráfico de barras ====
Los gráficos de barras se utilizan para mostrar datos categóricos. Pueden utilizarse para representar el número de elementos en cada categoría, la proporción de elementos en cada categoría o el valor medio de cada categoría.
Por ejemplo, vamos a mostrar el número de cada tipo de medallas ganadas a lo largo de las olimpiadas:
# Creamos el gráfico de barras
graph = pn.ggplot(
athletes_data_spain_medals,
pn.aes(x='Medal', y='Total'),
) + pn.geom_bar(stat='sum')
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph02.png?400 |}}
En este caso, le indicamos que queremos la suma total de cada tipo de medalla con la opción //stat='sum'// cuando creamos el gráfico de barras.
También podríamos crear un gráfico similar al del anterior punto (medallas totales ganadas por año) con la opción //stat='identity'//, para que el gráfico muestre los datos tal y como están en el //DataFrame//.
# Creamos el gráfico de barras
graph = pn.ggplot(
athletes_data_spain_total_medals,
pn.aes(x='Year', y='Total'),
) + pn.geom_bar(stat='identity')
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph03.png?400 |}}
Para hacer este último gráfico, podríamos haber utilizado //geom_col()//, sin necesidad de especificar //stat='identity'//:
# Creamos el gráfico de barras
graph = pn.ggplot(
athletes_data_spain_total_medals,
pn.aes(x='Year', y='Total'),
) + pn.geom_col()
# Mostramos el gráfico
graph.draw()
==== Histograma ====
Un gráfico de histograma es una representación gráfica de la distribución de una variable. Se utiliza para mostrar la frecuencia de los valores que toma una variable.
Un histograma se compone de una serie de barras, cada una de las cuales representa un rango de valores. La altura de cada barra representa la frecuencia de los valores que se encuentran dentro de ese rango.
Por ejemplo, vamos a crear un gráfico para mostrar la distribución de la edad de los españoles que han ganado alguna medalla:
# Creamos el gráfico de histograma
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x='Age'),
)
+ pn.geom_histogram(bins=20)
)
# Mostramos el gráfico
graph.draw()
la opción //bins// se utiliza para indicar la separación del eje x de un gráfico de histograma. El número de bins determina el número de barras que se mostrarán en el gráfico.
{{ :clase:ia:saa:1eval:graph04.png?400 |}}
==== Gráfico de dispersión ====
Un gráfico de dispersión es un tipo de gráfico que muestra la relación entre dos variables numéricas. Cada punto en el gráfico representa un valor de una variable en relación con un valor de la otra variable.
Por ejemplo, vamos a mostrar la relación entre el peso y la altura de los atletas españoles:
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point()
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph05.png?400 |}}
Como vemos, con un simple gráfico podemos apreciar que existe una alta correlación entre ambas variables.
===== Modificando el aspecto de los gráficos =====
Los **temas** en plotnine son una forma de controlar la apariencia de los gráficos. Se pueden utilizar para cambiar el color, el tamaño, la forma y otros aspectos de los gráficos.
Los temas se pueden aplicar a todos los gráficos o a gráficos individuales. Para aplicar un tema a todos los gráficos, se puede utilizar la función **theme_set()**. Para aplicar un tema a un gráfico individual, se puede utilizar la función **theme()**.
Los temas de plotnine están predefinidos, pero también se pueden crear temas personalizados.
Vamos a ver como podemos modificar nuestros gráficos usando alguno de esos temas.
==== Cambiar el color de los puntos ====
En el ejemplo del gráfico de dispersión, los puntos del gráfico son de color negro. Para cambiar el color de los puntos, podemos utilizar la opción color del tema. Por ejemplo, el siguiente código cambiará el color de los puntos a azul:
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point(color = "blue")
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph06.png?400 |}}
==== Cambiar el tamaño de los puntos ====
Para cambiar el tamaño de los puntos, podemos utilizar la opción size del tema. Por ejemplo, el siguiente código cambiará el tamaño de los puntos a 1:
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point(color = "blue", size = 1)
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph07.png?400 |}}
==== Agregar un título al gráfico ====
Podemos agregar un título al gráfico con la opción //ggtitle()//:
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point(color = "blue", size = 1)
+ pn.ggtitle("Relación entre la altura y el peso de los atletas españoles")
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph08.png?400 |}}
==== Modificar las etiquetas ====
También podemos modificar las etiquetas de ambos ejes con //xlab()// y //ylab()//:
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point(color = "blue", size = 1)
+ pn.ggtitle("Relación entre la altura y el peso de los atletas españoles")
+ pn.xlab("Peso")
+ pn.ylab("Altura")
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph09.png?400 |}}
==== Cambiar el estilo de los puntos ====
Para cambiar el estilo de los puntos, podemos usar la opción //shape//:
graph.draw()
# Creamos el gráfico de dispersión
graph = (
pn.ggplot(
athletes_data_spain,
pn.aes(x="Weight", y="Height"),
)
+ pn.geom_point(color="blue", size=1, shape='x')
+ pn.ggtitle("Relación entre la altura y el peso de los atletas españoles")
+ pn.xlab("Peso")
+ pn.ylab("Altura")
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph10.png?400 |}}
==== Mostrar información de diferente color ====
Podemos mostrar la información con diferentes colores según una característica usando la opción //fill//. Por ejemplo, para mostrar las medallas ganadas por los atletas españoles según el tipo:
# Creamos el gráfico de barras
graph = (
pn.ggplot(
athletes_data_spain_medals,
pn.aes(x="Year", y="Total", fill="Medal"),
)
+ pn.geom_col()
+ pn.ggtitle("Medallas ganadas por los atletas españoles")
+ pn.xlab("Año")
+ pn.ylab("Total")
)
# Mostramos el gráfico
graph.draw()
{{ :clase:ia:saa:1eval:graph11.png?400 |}}
===== Ejercicios =====
**Ejercicio 1.a**
Crear un gráfico de barras que muestre el número de medallas ganadas por los atletas de un China en cada deporte.
**Ejercicio 1.b**
Modifica el gráfico anterior para que se diferencien las medallas cambiando el color según el tipo.
**Ejercicio 1.c**
Haz las modificaciones necesarias para que el gráfico del ejercicio anterior quede parecido a éste:
{{:clase:ia:saa:1eval:graph13.png?400|}}
**Ejercicio 2.a**
Crear un gráfico de barras apiladas que muestre la distribución de las medallas ganadas por los atletas de Rusia por año y género. Crea los gráficos separados en dos columnas.
**Ejercicio 2.b **
Modificar el gráfico anterior para mostrar los gráficos en 2 filas separadas.
**Ejercicio 2.c **
Modificar el gráfico anterior para mostrar las columnas de medallistas hombres y mujeres juntas.
**Ejercicio 2.d**
Vuelve a crear el gráfico del ejercicio 2.c eliminando los datos anteriores a 1994.
**Ejercicio 2.e**
Averigua como modificar el gráfico del ejercicio anterior para que se muestre parecido al siguiente:
{{:clase:ia:saa:1eval:graph12.png?400|}}
**Ejercicio 3.a**
Crea un gráfico de líneas que muestre cómo ha evolucionado la cantidad de participantes en los Juegos Olímpicos a lo largo de los años similar al siguiente:
{{:clase:ia:saa:1eval:graph14.png?800|}}
**Ejercicio 3.b**
¿Por qué crees que salen esos dientes de sierra en el gráfico anterior? Arregla los datos para que muestren datos con más relevancia estadística:
{{:clase:ia:saa:1eval:graph15.png?800|}}
**Ejercicio 4**
Elige 5 deportes y mira a ver la evolución de la participación femenina a lo largo de los años con un gráfico:
{{:clase:ia:saa:1eval:graph16.png|}}