No se si lo he mencionado, pero el plan es enviar un boletín gratuito a todos los suscriptores y un segundo boletín con el código R a los suscriptores premium. Este es el segundo boletín donde muestro lo que puedes obtener al pagar la suscripción premium
Voy a repasar cómo hice el gráfico de la diferencia de puntos en partidos de temporada regular vs playoff desde 1983 a 2024 hay que tener en cuenta que voy a asumir que el lector tiene al menos una comprensión básica de R. Si no estás familiarizado con R o acabas de empezar, te recomendaría echar un vistazo antes a algunos blogs introductorios. Este es solo un ejemplo R Para Ciencia de Datos, pero hay muchísimos recursos similares que te pueden ayudar a dar los primeros pasos.
Temporada Regular vs Playoff
No sé si este gráfico es sencillo o no, pero creo que resume bastante bien cómo suelo trabajar este tipo de visualizaciones.
Si lo único que quieres es el código completo, puedes ir directamente al final de la página.
Primero, cargamos las librerías:
📚# Cargar librerías
library(tidyverse) #para la manipulación de datos
library(rvest) # Para hacer scraping de páginas web
library(ggtext) # Permite usar texto enriquecido (como HTML o Markdown)
library(glue) # Para crear cadenas de texto combinando
library(janitor) # Para limpiar nombres de columna
library(hablar) # Para cambiar el tipo de dato
library(prismatic) # Para el borde de los puntos
library(paletteer) # Color palettes Si no tienes alguno de estos paquetes solamente tienes que hacer
install.packages("tidyverse") Después suelo añadir estas líneas para firmar las gráficas.
# caption ---------------------------------------------------------------------
twitter <- "<span style='color:#000000;font-family: \"Font Awesome 6 Brands\"'></span>"
tweetelcheff <- "<span style='font-weight:bold;'>*@elcheff*</span>"
insta <- "<span style='color:#E1306C;font-family: \"Font Awesome 6 Brands\"'></span>"
instaelcheff <- "<span style='font-weight:bold;'>*@sport_iv0*</span>"
github <- "<span style='color:#000000;font-family: \"Font Awesome 6 Brands\"'></span>"
githubelcheff <- "<span style='font-weight:bold;'>*IvoVillanueva*</span>"
caption <- glue::glue("<br><br>**Datos**: *@ACBCOM* | **Gráfico**: *Ivo Villanueva* • {twitter} {tweetelcheff} • {insta} {instaelcheff} • {github} {githubelcheff}")Ahora vamos a la pomada: toca extraer los datos.
Necesitamos dos tablas, porque los de la temporada regular y los de los Playoffs están en enlaces distintos (cambia el año en la URL).
Empezamos con la tabla de la temporada regular.
Para la temporada regular "https://www.proballers.com/es/baloncesto/liga/30/spain-liga-endesa/calendario/1983"
Para los playoff
"https://www.proballers.com/basketball/league/65/spain-liga-endesa-playoffs/schedule/1983"Voy a explicar primero como sería extraer los datos de un año
df <- "https://www.proballers.com/es/baloncesto/liga/30/spain-liga-endesa/calendario/1983") %>%
read_html() %>%
html_element("table") %>%
html_table() Nos tiene que salir algo asi
Lo primero que hago es limpiar un poco los nombres de las columnas. Para eso uso la función clean_names() de la librería janitor, que convierte los nombres en minúsculas y los hace más manejables.
Después, uso transmute() —que viene a ser una mezcla entre select() y mutate()— para quedarme solo con la columna que me interesa y crear una nueva.
En algunos casos, en lugar del marcador aparece el texto "Game preview". Eso lo tenemos que eliminar, porque si no, no vamos a poder separar bien el resultado en dos columnas.
df <- df %>%
"https://www.proballers.com/es/baloncesto/liga/30/spain-liga-endesa/calendario/1983" %>% # URL origen
read_html() %>% # Leer HTML
html_element("table") %>% # Extraer tabla
html_table() %>% # Convertir tabla
clean_names() %>% # Limpiar nombres
transmute(year = 1983, resultado) %>% # Seleccionar columnas
filter(resultado != "Game preview") %>% # Filtrar filas
separate(resultado, into = c("a", "b"), sep = "-") %>% # Separar el resultado
retype() %>% # Convertir en numero
mutate(dif = abs(a - b)) #extraer la diferencia absolutaConseguiríamos una tabla como esta
y ahora dejamos solo la media de todo el año
df <-
df %>%
group_by(year) %>%
summarise(dif = mean(dif),
.groups = "drop") #esto sirve para desagruparVamos a juntar todo el código mediante una función fijate que cambio el año por la variable years
# diferencial historico fase regular-------------------------------------------
years <- 1982:2023 #definimos el rango de años
diferencial_regular <- function(years){
df <- paste0("https://www.proballers.com/es/baloncesto/liga/30/spain-liga-endesa/calendario/", years) %>%
read_html() %>%
html_element("table") %>%
html_table() %>%
janitor::clean_names() %>%
transmute( year = years, resultado) %>%
filter(resultado != "Game preview") %>%
separate(resultado, into = c("a", "b"),sep = "-" ) %>%
hablar::retype() %>%
mutate(dif = abs(a-b)) %>%
group_by(year) %>%
summarise(dif = mean(dif),
.groups = "drop")
}
regular_df <- map_df( years, diferencial_regular)Y lo que nos sale es:
Ahora vamos con los resultados de los playoff es la misma función pero cambiando el link
years <- 1982:2023 #definimos el rango de años
diferencial_po <- function(years){
df <- paste0("https://www.proballers.com/basketball/league/65/spain-liga-endesa-playoffs/schedule/", years)%>%
read_html() %>%
html_element("table") %>%
html_table() %>%
clean_names() %>%
transmute( year = years, result) %>%
filter(result != "Game preview") %>%
separate(result, into = c("a", "b"),sep = "-" ) %>%
hablar::retype() %>%
mutate(dif_po = abs(a-b)) %>%
group_by(year) %>%
summarise(dif_po = mean(dif_po),
.groups = "drop")
}
po_df <- map_df( years, diferencial_po)
Ahora que tengo las dos tablas, necesito unirlas y poner tanto la diferencia en temporada regular como de playoff en una sola columna para el gráfico de líneas
dat <- regular_df %>%
left_join(po_df, join_by(year)) %>%
pivot_longer(cols = c(dif, dif_po),
names_to = "tipo",
values_to = "valor")Ya tenemos los datos limpios y listos. Ahora sí, vamos a construir el gráfico de líneas.
p <- dat %>%
ggplot(aes(x = year, y = valor, group = tipo)) +
geom_line(aes(color = tipo), size = 1.25) +
geom_point(aes(fill = tipo, color = after_scale(clr_darken(fill, 0.3))), shape = 21, show.legend = FALSE) +
scale_x_continuous(
breaks = 1982:2023,
labels = sprintf("%02d", (1982:2023 + 1) %% 100) #convertir en dos cifras
) +
scale_color_paletteer_d("ggsci::nrc_npg", direction = 1, labels = c("Temporada Regular", "Playoff")) +
scale_fill_paletteer_d("ggsci::nrc_npg", direction = 1) +
coord_cartesian(clip = "off") +
theme_minimal(base_family = "Oswald") +
theme(
plot.background = element_rect(fill = "white", color = "white"),
legend.position = "top",
plot.title.position = "plot",
plot.caption = element_markdown(size = 7, hjust = 0),
plot.title = element_text(face = "bold", size = 20),
plot.subtitle = element_text(face = "italic", size = 10.5),
plot.margin = margin(b = 25, t = 25, r = 50, l = 50),
axis.text = element_text(size = 7)
) +
labs(
color = "",
x = "Años",
y = "Diferencia de Puntos",
title = "Diferencial de puntos Temporada Regular vs Playoff",
subtitle = "1983 - 2024",
caption = caption
)
ggsave("line_chart.png", p, w = 6 * 1.618, h = 6, dpi = 600)Aquí el código completo,
# 📚Cargar librerías-------------------
library(tidyverse) # para la manipulación de datos
library(rvest) # Para hacer scraping de páginas web
library(ggtext) # Permite usar texto enriquecido (como HTML o Markdown)
library(glue) # Para crear cadenas de texto combinando
library(janitor) # Para limpiar nombres de columna
library(hablar) # Para cambiar el tipo de dato
# 🔡 caption -----------------------------------------------------------------
twitter <- "<span style='color:#000000;font-family: \"Font Awesome 6 Brands\"'></span>"
tweetelcheff <- "<span style='font-weight:bold;'>*@elcheff*</span>"
insta <- "<span style='color:#E1306C;font-family: \"Font Awesome 6 Brands\"'></span>"
instaelcheff <- "<span style='font-weight:bold;'>*@sport_iv0*</span>"
github <- "<span style='color:#000000;font-family: \"Font Awesome 6 Brands\"'></span>"
githubelcheff <- "<span style='font-weight:bold;'>*IvoVillanueva*</span>"
caption <- glue::glue("**Datos**: *@Proballers_com* | **Gráfico**: *Ivo Villanueva* • {twitter} {tweetelcheff} • {insta} {instaelcheff} • {github} {githubelcheff}")
# 💾 🤼 scrapear los datos y data Wranglingng ---------------------------------
years <- 1982:2023
diferencial_regular <- function(years) {
df <- paste0("https://www.proballers.com/es/baloncesto/liga/30/spain-liga-endesa/calendario/", years) %>%
read_html() %>%
html_element("table") %>%
html_table() %>%
clean_names() %>%
transmute(year = years, resultado) %>%
filter(resultado != "Game preview") %>%
separate(resultado, into = c("a", "b"), sep = "-") %>%
hablar::retype() %>%
mutate(dif = abs(a - b)) %>%
group_by(year) %>%
summarise(
dif = mean(dif),
.groups = "drop"
)
}
regular_df <- map_df(years, diferencial_regular)
diferencial_po <- function(years) {
df <- paste0("https://www.proballers.com/basketball/league/65/spain-liga-endesa-playoffs/schedule/", years) %>%
read_html() %>%
html_element("table") %>%
html_table() %>%
clean_names() %>%
transmute(year = years, result) %>%
filter(result != "Game preview") %>%
separate(result, into = c("a", "b"), sep = "-") %>%
hablar::retype() %>%
mutate(dif_po = abs(a - b)) %>%
group_by(year) %>%
summarise(
dif_po = mean(dif_po),
.groups = "drop"
)
}
po_df <- map_df(years, diferencial_po)
# Unir las tablas 🛹y convertirlas de ancho a largo --------------------------
dat <- regular_df %>%
left_join(po_df, join_by(year)) %>%
pivot_longer(
cols = c(dif, dif_po),
names_to = "tipo",
values_to = "valor"
)
# 📈 Line chart --------------------------------------------------------------
p <- dat %>%
ggplot(aes(x = year, y = valor, group = tipo)) +
geom_line(aes(color = tipo), size = 1.25) +
geom_point(aes(fill = tipo, color = after_scale(clr_darken(fill, 0.3))), shape = 21, show.legend = FALSE) +
scale_x_continuous(
breaks = 1982:2023,
labels = sprintf("%02d", (1982:2023 + 1) %% 100)
) +
scale_color_paletteer_d("ggsci::nrc_npg", direction = 1, labels = c("Temporada Regular", "Playoff")) +
theme_minimal(base_family = "Oswald") +
theme(
plot.background = element_rect(fill = "white", color = "white"),
legend.position = "top",
plot.title.position = "plot",
plot.caption = element_markdown(size = 7, hjust = 0),
plot.title = element_text(face = "bold", size = 20),
plot.subtitle = element_text(face = "italic", size = 10.5),
plot.margin = margin(b = 25, t = 25, r = 50, l = 50),
axis.text = element_text(size = 7)
) +
labs(
color = "",
x = "Años",
y = "Diferencia de Puntos",
title = "Diferencial de puntos Temporada Regular vs Playoff",
subtitle = "1983 - 2024",
caption = caption
)
ggsave("line_chart.png", p, w = 6 * 1.618, h = 6, dpi = 600)










