├── .gitignore ├── 01_ggplot_basico.qmd ├── 01_ggplot_basico_soluciones.qmd ├── 02_ggplot_intermedio.qmd ├── 02_ggplot_intermedio_soluciones.qmd ├── 03_ggplot_avanzado.qmd ├── 03_ggplot_avanzado_soluciones.qmd ├── 04_leaflet.qmd ├── 04_leaflet_soluciones.qmd ├── 05_plotly_basico.qmd ├── 05_plotly_basico_soluciones.qmd ├── 06_plotly_avanzado.qmd ├── 06_plotly_avanzado_soluciones.qmd ├── 07_rmarkdown.qmd ├── 08_flexdashboard.qmd ├── 08_flexdashboard_soluciones.qmd ├── 09_shiny_basico.qmd ├── 09_shiny_basico_soluciones.qmd ├── 10_shiny_avanzado.qmd ├── 10_shiny_avanzado_soluciones.qmd ├── 11_proyecto.qmd ├── LICENSE.txt ├── README.md ├── _quarto.yml ├── dat ├── defunciones_espana.csv ├── economist.csv ├── elecciones_2019_provincias.csv ├── elecciones_2019_votos.csv ├── lineas_metro.geojson ├── listings.csv ├── neighbourhoods.geojson ├── paradas_metro_madrid.geojson ├── poblacion_espana.csv ├── provincias_ccaas.csv ├── spain_ccaas.geojson ├── spain_provinces.geojson ├── stations.csv ├── stations_status.csv ├── trips.csv └── usa_president.csv ├── index.qmd ├── rdataviz.Rproj ├── resources ├── 01_ggplot_basico │ ├── banana.png │ ├── barplot.jpg │ ├── boxplot.png │ ├── chart_type.png │ ├── dinos.png │ ├── lineplot.png │ ├── log.jpg │ ├── pie_vs_bar.png │ ├── scatterplot.jpg │ ├── stacked.jpg │ ├── stacked100.jpg │ └── zero.png ├── 02_ggplot_intermedio │ ├── 2_apiladas.png │ └── 3_rep_preference.png ├── 03_ggplot_avanzado │ └── export_from_rstudio.png ├── 04_leaflet │ ├── popup.png │ └── projection.gif ├── 07_rmarkdown │ ├── knit.png │ ├── knit_params.png │ └── new_rmarkdown.png ├── 08_flexdashboard │ ├── elementos_html.png │ ├── layout_columnas.png │ ├── layout_filas.png │ ├── layout_pestanas.png │ ├── layout_tamano.png │ ├── value_box.png │ ├── varias_paginas.png │ └── varias_paginas_menu.png ├── 09_shiny_basico │ ├── 01_histograma.png │ ├── 02_plotly.png │ ├── 03_leaflet.png │ ├── 04_widget.png │ ├── control_widgets.png │ ├── layout_01.png │ ├── layout_02.png │ ├── run_app.png │ └── run_shiny.png └── 10_shiny_avanzado │ ├── 1_fibonacci.png │ └── 2_boton.png ├── scripts └── deploy.sh └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | 8 | # User-specific files 9 | .Ruserdata 10 | 11 | # Example code in package build process 12 | *-Ex.R 13 | 14 | # Output files from R CMD build 15 | /*.tar.gz 16 | 17 | # Output files from R CMD check 18 | /*.Rcheck/ 19 | 20 | # RStudio files 21 | .Rproj.user/ 22 | 23 | # produced vignettes 24 | vignettes/*.html 25 | vignettes/*.pdf 26 | 27 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 28 | .httr-oauth 29 | 30 | # knitr and R markdown default cache directories 31 | *_cache/ 32 | /cache/ 33 | 34 | # Temporary files created by R markdown 35 | *.utf8.md 36 | *.knit.md 37 | 38 | # R Environment Variables 39 | .Renviron 40 | 41 | # pkgdown site 42 | docs/ 43 | 44 | # translation temp files 45 | po/*~ 46 | 47 | *.docx 48 | *.zip 49 | gestion/ 50 | *.html 51 | temp/ 52 | webinars/ 53 | contenido/ 54 | 55 | /.quarto/ 56 | _book/ 57 | *_files/ 58 | site_libs/ 59 | -------------------------------------------------------------------------------- /01_ggplot_basico_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Soluciones capítulo 1' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ```{r, message=FALSE} 10 | library(dplyr) 11 | library(ggplot2) 12 | library(palmerpenguins) 13 | ``` 14 | 15 | 16 | ### Actividad 1 17 | 18 | Abre [colorbrewer](http://colorbrewer2.org/) y elige una paleta de colores para representar estos tres gráficos sobre el mapa que muestran de ejemplo. Para elegir una correcta, piensa en la naturaleza de los datos (secuenciales, divergentes o cualitativos): 19 | 20 | 1. El nivel de contaminación por región: **secuencial** 21 | 2. Cambio relativo en el número de habitantes con respecto a la última decada (p.e. -5%, +10%, ...): **divergente** 22 | 3. La etnia predominante por región: **cualitativa** 23 | 24 | ### Actividad 2 25 | 26 | Examina el dataset `diamonds`, incluido dentro de la librería de `ggplot2`. Consulta la ayuda con `?diamonds` y examina su contenido. 27 | 28 | Pinta la relación en un gráfico de puntos del precio frente a los quilates. 29 | 30 | ```{r} 31 | # opcional, toco el alpha (opacidad) para que se vean mejor los puntos superpuestos 32 | ggplot(diamonds, aes(x = carat, y = price)) + 33 | geom_point(alpha = 0.2) 34 | ``` 35 | 36 | ### Actividad 3 37 | 38 | Con el dataset `penguins`: 39 | 40 | 1. Pinta la relación entre longitud y profundidad del pico (bill). 41 | 42 | ```{r} 43 | ggplot(data = penguins) + 44 | geom_point(mapping = aes(x = bill_length_mm, y = bill_depth_mm)) 45 | ``` 46 | 47 | 2. Añade al gráfico del punto 1 la distinción entre especies mediante el color. 48 | 49 | ```{r} 50 | ggplot(data = penguins) + 51 | geom_point(mapping = aes(x = bill_length_mm, y = bill_depth_mm, color = species)) 52 | ``` 53 | 54 | 3. Añade al gráfico del punto 1 la distinción entre el peso corporal mediante el color. 55 | 56 | ```{r} 57 | ggplot(data = penguins) + 58 | geom_point(mapping = aes(x = bill_length_mm, y = bill_depth_mm, color = body_mass_g)) 59 | ``` 60 | 61 | 4. ¿Qué observas en las escalas de color que ha utilizado ggplot en cada uno de los dos casos? ¿De qué naturaleza (secuencial, divergente o cualitativa) es cada una de ellas? ¿Por qué crees que ha hecho esto por defecto? 62 | 63 | Respuesta: para `species` se utiliza una escala cualitativa, para `body_mass_g` se utiliza una secuencial. Es por el tipo de dato: para datos factor / cadenas de caracters / booleanos, ggplot utiliza por defecto escalas cualitativas. Para numéricos, ggplot utiliza escalas secuenciales. 64 | 65 | ### Actividad 4 66 | 67 | 1. Lee los datos del economista (dat/economist.csv), con indicadores de desarrollo y corrupción por países: 68 | 69 | * HDI: Human Development Index (1: más desarrollado) 70 | * CPI: Corruption Perception Index (10: menos corrupto) 71 | 72 | 2. Crea un gráfico que: 73 | 74 | * Cada país sea un punto 75 | * El eje x indique CPI, el y HDI 76 | * El color del punto indique la región 77 | * Su tamaño sea proporcional al ranking HDI 78 | 79 | 3. ¿Qué conclusiones extraes del gráfico? 80 | 81 | ```{r} 82 | economist <- read.csv("dat/economist.csv") 83 | 84 | ggplot(economist) + 85 | geom_point(aes(x = CPI, y = HDI, color = Region, size = HDI.Rank)) 86 | ``` 87 | 88 | ### Actividad 5 89 | 90 | 1. Lee los datos de los resultados de las elecciones presidenciales de los Estados Unidos (dat/usa_president.csv). Puedes consultar más información sobre este dataset [aquí](https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/42MVDX). 91 | 92 | 2. Pinta en un gráfico de líneas la evolución del número de votos a lo largo de los años del partido republicado frente al demócrata. 93 | 94 | > Ten en cuenta que tendrás que hacer una transformación de los datos antes de pintarlos. Razona en qué formato necesitas el dataframe y aplica las operaciones necesarias antes de utilizar ggplot. 95 | 96 | ```{r} 97 | # Lectura del dataset 98 | usa_president <- read.csv("dat/usa_president.csv") 99 | 100 | # Agrupo para los partidos de interés, por año y partido 101 | usa_president_by_year <- usa_president %>% 102 | filter(party %in% c("democrat", "republican")) %>% 103 | group_by(year, party) %>% 104 | summarise(candidatevotes = sum(candidatevotes)) 105 | 106 | # Pinto las líneas por cada partido 107 | ggplot(usa_president_by_year) + 108 | geom_line(aes(x = year, y = candidatevotes, color = party)) 109 | ``` 110 | -------------------------------------------------------------------------------- /02_ggplot_intermedio_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Soluciones capítulo 2' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ```{r, message=FALSE} 10 | library(dplyr) 11 | library(ggplot2) 12 | library(palmerpenguins) 13 | ``` 14 | 15 | ### Actividad 1 16 | 17 | Rescata el gráfico que hiciste en el capítulo anterior, pero añadiendo el tercer punto aquí detallado. 18 | 19 | 1. Lee los datos del economista (dat/economist.csv), con indicadores de desarrollo y corrupción por países: 20 | 21 | * HDI: Human Development Index (1: más desarrollado) 22 | * CPI: Corruption Perception Index (10: menos corrupto) 23 | 24 | 2. Crea un gráfico que: 25 | 26 | * Cada país sea un punto 27 | * El eje `x` indique CPI, el `y` HDI 28 | * El color del punto indique la región 29 | * Su tamaño sea proporcional al ranking HDI 30 | 31 | 3. Pinta una línea de tendencia que muestre la relación entre el CPI y el HDI (entre el eje `x` y el eje `y`) 32 | 33 | ```{r} 34 | economist <- read.csv("dat/economist.csv") 35 | 36 | # Fíjate en el mapeo "común", en ggplot, y el mapeo "específico", en geom_point 37 | # Además, de forma opcional, he personalizado la escala de colores por una que 38 | # distingue mejor las categorías 39 | ggplot(economist, aes(x = CPI, y = HDI)) + 40 | geom_point(aes(color = Region, size = HDI.Rank)) + 41 | scale_color_brewer(palette = "Dark2") + 42 | geom_smooth() 43 | ``` 44 | 45 | ### Actividad 2 46 | 47 | 1. Lee los datos de las elecciones presidenciales de EEUU (dat/usa_president.csv) 48 | 49 | 2. Quédate únicamente con los datos de las elecciones de 2016, con los resultados de los partidos demócrata y republicano, y con las filas con writein = FALSE (fe de erratas: en la versión original del capítulo viene TRUE en lugar de FALSE). 50 | 51 | 3. Quédate con el número de votos demócratas y republicanos para cada estado. 52 | 53 | 4. Pinta un gráfico de barras apiladas. Bonus: ordénalo por total de votos 54 | 55 | ```{r} 56 | usa_president <- read.csv("dat/usa_president.csv") 57 | 58 | # Transformación previa 59 | usa_elections <- usa_president %>% 60 | filter(year == 2016, party %in% c("democrat", "republican"), !writein) %>% 61 | arrange(totalvotes) 62 | 63 | # Mi paleta de colores 64 | # También podría utilizar códigos hexadecimales, como p.e. 65 | # palette <- c("democrat" = "#4575b4", "republican" = "#d73027") 66 | palette <- c("democrat" = "blue", "republican" = "red") 67 | 68 | # Forma 1 para ordenar las barras: reorder 69 | ggplot(usa_elections) + 70 | geom_col(aes(y = reorder(state_po, totalvotes), x = candidatevotes, fill = party)) + 71 | scale_fill_manual(values = palette) 72 | 73 | # Forma 2 para ordenar las barras: cambiar el orden del factor 74 | states <- unique(usa_elections$state_po) 75 | usa_elections$state_po <- factor(usa_elections$state_po, levels = states) 76 | 77 | # Con scale_xxx_manual defino mi propia paleta de colores 78 | ggplot(usa_elections) + 79 | geom_col(aes(y = state_po, x = candidatevotes, fill = party)) + 80 | scale_fill_manual(values = palette) 81 | ``` 82 | 83 | ### Actividad 3 84 | 85 | 1. Lee los datos de las elecciones presidenciales de EEUU (dat/usa_president.csv) 86 | 87 | 2. Como antes, quédate únicamente con los datos de las elecciones de 2016, con los resultados de los partidos demócrata y republicano, y con las filas con writein = TRUE (fe de erratas: en la versión original del capítulo viene TRUE en lugar de FALSE). 88 | 89 | 3. Calcula para cada estado, una columna nueva que se llame `rep_preference` definida como `(votos_republicanos / (votos_republicanos + votos_democratas) - 0.5) * 2` . Esta columna tendrá valores cercanos al 0 para estados donde hubo un resultado cercano al empate, acercándose al 1 si ganaron los republicanos y acercándose al -1 si ganaron los demócratas. Nota: puede que te resulte útil separar los datos en dos datasets (votos republicanos y votos demócratas) y luego unirlos. 90 | 91 | 4. Pinta un gráfico de puntos, en el eje `y` el estado (la abreviatura de dos caracteres) y en el eje `x` el valor de `republican_preference`. El color del punto será una escala divergente, en la que a mayor victoria republicana sea más rojo (valor más positivo), mayor victoria demócrata más azul (valor más negativo), y los cercanos al empate sean blancos o amarillos (valor más cercano al cero). 92 | 93 | 8. Ordena los estados por `rep_preference` y centra el 0 en mitad del gráfico. 94 | 95 | 9. Centra el cero en mitad del eje x 96 | 97 | 10. Centra el cero en el valor neutro de la escala de colores 98 | 99 | ```{r} 100 | # Separo los dataframes en dos: votos rep y votos dem 101 | rep_votes <- usa_elections %>% 102 | filter(party == "republican") %>% 103 | select(state_po, candidatevotes) 104 | dem_votes <- usa_elections %>% 105 | filter(party == "democrat") %>% 106 | select(state_po, candidatevotes) 107 | 108 | # Los cruzo, para tener los votos de ambos en la misma fila 109 | votes <- dem_votes %>% 110 | inner_join(rep_votes, by = "state_po", suffix = c("_dem", "_rep")) %>% 111 | mutate( 112 | rep_preference = (candidatevotes_rep / (candidatevotes_rep + candidatevotes_dem) - 0.5) * 2 113 | ) %>% 114 | arrange(rep_preference) 115 | 116 | # Gracias a limits centro, tanto la escala de color, como la del eje x 117 | # Con scale_xxxx_distiller transformo una escala de colorbrewer, pensada para un 118 | # número pequeño de categorías, en una escala continua, interpolando los valores 119 | # intermedios. Consulta la ayuda para más opciones 120 | ggplot(votes) + 121 | geom_point(aes(y = reorder(state_po, rep_preference), x = rep_preference, color = rep_preference)) + 122 | scale_color_distiller(palette = "RdYlBu", limits = c(-1, 1)) + 123 | scale_x_continuous(limits = c(-1, 1)) 124 | ``` 125 | -------------------------------------------------------------------------------- /03_ggplot_avanzado.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: '3 - Gráficos estáticos con ggplot: nivel avanzado' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ## ¿Qué vamos a hacer? 10 | 11 | En los capítulos 1 y 2 hemos visto cómo crear gráficos estáticos con ggplot, con diferentes geometrías (puntos, líneas, boxplots, barras, ...), escalas (numéricas continuas, categóricas, temporales, ...) y transformaciones estadísticas. 12 | 13 | En este nuevo capítulo vamos a aprender a personalizar los gráficos ajustando el aspecto y a presentar datos geoespaciales sobre mapas. 14 | 15 | ## 1. Títulos, etiquetas y temas 16 | 17 | Vamos a rescatar uno de los gráficos que hicimos en el anterior capítulo para personalizarlo. 18 | 19 | ```{r} 20 | library(ggplot2) 21 | library(dplyr) 22 | 23 | # Lectura de los datos 24 | defunciones <- read.csv("dat/defunciones_espana.csv") 25 | 26 | # Conversión de la fecha de tipo character a Date 27 | defunciones <- defunciones %>% 28 | mutate(fecha_defuncion = as.Date(fecha_defuncion)) 29 | 30 | # Pintamos la mortalidad observada y esperada 31 | ggplot(defunciones, aes(x = fecha_defuncion)) + 32 | geom_ribbon(aes(ymin = defunciones_esperadas_q01, ymax = defunciones_esperadas_q99), 33 | fill = "blue", alpha = 0.3) + 34 | geom_line(aes(y = defunciones_observadas), color = "black") + 35 | geom_line(aes(y = defunciones_esperadas), color = "blue") + 36 | scale_x_date(date_breaks = "1 month", date_labels = "%b-%y") 37 | ``` 38 | 39 | Si vamos a utilizar el gráfico en un informe divulgativo o una presentación, es recomendable poner un título, una leyenda, y mejorar el texto de los ejes. 40 | 41 | > Conviene tener siempre a mano la documentación de ggplot para conocer todos los elementos que podemos personalizar. Está disponible dentro del paquete lanzando `?labs` o en su [web](https://ggplot2.tidyverse.org/reference/labs.html). 42 | 43 | En la documentación, vemos que podemos definir, entr otros elementos: 44 | 45 | * Título, subtítulo y pie mediante `labs(title, subtitle, caption)` 46 | * Nombre de cualquier elemento estético con una lista de valores con nombre. Por ejemplo, `labs(x = "Nombre eje x", fill = "Nombre de la variable para el color")`. 47 | 48 | ```{r} 49 | ggplot(defunciones, aes(x = fecha_defuncion)) + 50 | geom_ribbon(aes(ymin = defunciones_esperadas_q01, ymax = defunciones_esperadas_q99), 51 | fill = "blue", alpha = 0.3) + 52 | geom_line(aes(y = defunciones_observadas), color = "black") + 53 | geom_line(aes(y = defunciones_esperadas), color = "blue") + 54 | scale_x_date(date_breaks = "1 month", date_labels = "%b-%y") + 55 | labs(title = "Mortalidad en España", 56 | subtitle = "Defunciones observadas y esperadas entre agosto de 2019 y agosto de 2020", 57 | caption = "Fuente: MoMo, Centro Nacional de Epidemiología", 58 | x = "Fecha", 59 | y = "Defunciones" 60 | ) 61 | ``` 62 | 63 | Solo nos faltaría una leyenda para el color, y así diferenciar que las líneas negras son las defunciones observadas y la azul las esperadas. ¿Por qué ggplot no la genera automáticamente, como en otros gráficos que hemos hecho? Por ejemplo, en este: 64 | 65 | ```{r} 66 | # Lectura de los datos del CSV 67 | usa_president <- read.csv("dat/usa_president.csv") 68 | 69 | # Filtro por los partidos de mi interés y agrupo por partido y año 70 | usa_president_by_year <- usa_president %>% 71 | filter(party %in% c("democrat", "republican", "libertarian", "green"), 72 | writein == FALSE) %>% 73 | group_by(year, party) %>% 74 | summarise(candidatevotes = sum(candidatevotes)) 75 | 76 | # Definición de mi paleta personalizada de colores por partido 77 | parties_palette <- c("democrat" = "blue", "republican" = "red", "libertarian" = "gold", "green" = "darkgreen") 78 | 79 | # Gráfico de evolución en número de votos por partido y año 80 | ggplot(usa_president_by_year, aes(x = year, y = candidatevotes, color = party)) + 81 | geom_line() + 82 | scale_y_log10(labels = scales::comma) + 83 | scale_color_manual(values = parties_palette) + 84 | labs( 85 | x = "Año", 86 | y = "Votos", 87 | color = "Partido" 88 | ) 89 | ``` 90 | 91 | La diferencia es que, en el gráfico de votos, los colores son parte del mapeo de estéticos a columnas mediante `aes(...)` mientras que en el gráfico de defunciones, son geometrías (`geom_line`) diferentes. En el primer caso, ggplot añade automáticamente la leyenda pero, en el segundo, no lo hará a no ser que lo especifiquemos. Podemos hacerlo creando una paleta manual que usemos en la escala del color e incluyéndola dentro del mapeo de `aes(...)`. De la siguiente forma: 92 | 93 | ```{r} 94 | # Paleta 95 | mortality_palette <- c("Observadas" = "black", "Esperadas" = "blue") 96 | 97 | # Guardo el gráfico en la variable p para no repetir este código continuamente 98 | p <- ggplot(defunciones, aes(x = fecha_defuncion)) + 99 | geom_ribbon(aes(ymin = defunciones_esperadas_q01, ymax = defunciones_esperadas_q99), 100 | fill = "blue", alpha = 0.3) + 101 | geom_line(aes(y = defunciones_observadas, color = "Observadas")) + 102 | geom_line(aes(y = defunciones_esperadas, color = "Esperadas")) + 103 | scale_x_date(date_breaks = "1 month", date_labels = "%b-%y") + 104 | scale_color_manual(values = mortality_palette) + 105 | labs(title = "Mortalidad en España", 106 | subtitle = "Defunciones observadas y esperadas entre agosto de 2019 y agosto de 2020", 107 | caption = "Fuente: MoMo, Centro Nacional de Epidemiología", 108 | x = "Fecha", 109 | y = "Defunciones", 110 | color = "Defunciones" 111 | ) 112 | 113 | p 114 | ``` 115 | 116 | Hay otros aspectos estéticos que podemos personalizar: el tipo de fuente que se usa en las diferentes partes del gráfico, su color y tamaño, el grid que aparece detrás, los márgenes, etc. Todos estos valores toman un valor por defecto, heredado de su tema (_theme_). Si no especificamos uno, el tema por defecto es `theme_gray()`, pero ggplot nos proporciona más opciones: `theme_classic`, `theme_bw`, `theme_minimal`, ... 117 | 118 | ```{r} 119 | p + theme_minimal() 120 | ``` 121 | 122 | > Prueba a escribir en la consola `theme_` y examina con el autocompletado todas las opciones de temas que vienen con ggplot. Prueba varias de ellas sobre el gráfico. 123 | 124 | Un tema son opciones por defecto sobre todos los elementos estéticos del gráfico, pero podemos sobrescribirlos. 125 | 126 | ```{r} 127 | p + 128 | theme_minimal() + 129 | theme(legend.position = "bottom", 130 | axis.text.x = element_text(angle = 90, hjust = 1), 131 | plot.title = element_text(size = 18, hjust = 0.5)) 132 | ``` 133 | 134 | > De nuevo, es necesario tener la documentación a mano. En [theme](https://ggplot2.tidyverse.org/reference/theme.html) encontramos todos los argumentos que podemos especificar para alterar aspectos del gráfico. Es imposible que nos conozcamos los argumentos de memoria, solo tenemos que tener claro que los podemos localizar rápidamente en la documentación. 135 | 136 | ## 2. Facets 137 | 138 | Hemos visto que podemos añadir variables a visualizar mediante el mapeo de estéticos con `aes(...)`: la posición con x e y, el color, el tipo de línea, el tamaño de un punto, etc. 139 | 140 | Otra opción, muy útil cuando tenemos variables categóricas, es dividir el gráfico en varios, cada uno mostrando un subconjunto de los datos. Estos son los _facets_. 141 | 142 | Para crear un _facet_ por una variable, podemos utilizar `facet_wrap()`, especificando la fórmula de generación de los _sub-gráficos_. Esta fórmula se puede crear con `~ mi_variable_categorica`. 143 | 144 | ```{r} 145 | library(palmerpenguins) 146 | 147 | ggplot(penguins, aes(x = flipper_length_mm, y = body_mass_g)) + 148 | geom_point() + 149 | facet_wrap(~ species) 150 | ``` 151 | 152 | > Puedes controlar el número de filas y columnas que se usan mediante los parámetros nrow y ncol de `facet_wrap`. Consulta su ayuda y prueba a cambiarlos sobre el gráfico anterior. 153 | 154 | > En la documentación de `facet_wrap`, consulta para qué sirve el parámetro `scales` y prueba a cambiarlo en el gráfico anterior. 155 | 156 | Para dividir el gráfico por dos variables en lugar de por una, se suele utilizar `facet_grid` en su lugar, y una formula del tipo `mi_variable_1 ~ mi_variable_2`. 157 | 158 | ```{r} 159 | # Quito las filas con el sexo nulo 160 | tmp <- penguins %>% 161 | filter(!is.na(sex)) 162 | 163 | # Creo el facet por sexo y especie 164 | ggplot(tmp, aes(x = flipper_length_mm, y = body_mass_g)) + 165 | geom_point() + 166 | facet_grid(sex ~ species) 167 | ``` 168 | 169 | > Normalmente, ponemos la variable que más valores tiene en columnas, y la que menos en filas. Esto es porque los gráficos suelen tener más ancho que alto, y así aprovechamos mejor el espacio. 170 | 171 | ## 3. Mapas 172 | 173 | Representar gráficos con datos geolocalizados es bastante común. Este proceso suele requerir de dos pasos: 174 | 175 | 1. Pintar el mapa base, es decir, los polígonos que forman las regiones que vamos a representar (p.e. los países del mundo, las comunidades autónomas de España, los barrios de Madrid, ...) 176 | 2. Añadir la información que queremos representar (p.e. la densidad de la población, la incidencia de una determinada enfermedad, ...) 177 | 178 | Para seguir la parte sobre mapas, necesitarás tener instalado el paquete sf. 179 | 180 | ```{r, eval=FALSE} 181 | # Instálalo si aún no lo tienes 182 | install.packages("sf") 183 | ``` 184 | 185 | ### Mapas de polígonos 186 | 187 | La forma más fácil de pintar un mapa es utilizando `geom_polygon`. Tenemos algunos mapas de ejemplo disponibles con `map_data`: 188 | 189 | ```{r} 190 | italy <- map_data("italy") 191 | head(italy) 192 | ``` 193 | 194 | ```{r} 195 | ggplot(italy, aes(x = long, y = lat, group = group)) + 196 | geom_polygon(fill = "white", color = "black") + 197 | coord_quickmap() 198 | ``` 199 | 200 | > Utilizamos coord_quickmap para que longitud y latitud sigan la misma escala y no aparezca deformado. 201 | 202 | Aunque resulta muy cómodo hacerlo de esta forma, no es habitual encontrar los mapas base (los polígonos) en un formato de tabla como este, con información de latitud y longitud. Los formatos más habituales son: geoJSON, shapefiles y bases de datos (especialmente PostgreSQL con PostGIS) 203 | 204 | Para leer estos formatos, tenemos `sf::read_sf()`. 205 | 206 | ```{r} 207 | library(sf) 208 | 209 | # Leo los polígonos de un geojson que contiene las provincias españolas simplificadas 210 | provincias <- read_sf("dat/spain_provinces.geojson") 211 | head(provincias) 212 | ``` 213 | 214 | Tenemos una tabla con una fila por provincia, cada una de ellas con ciertos metadatos (código INE, nombre, ...) y un objeto geometría, con la definición del polígono. 215 | 216 | Para representar el mapa base, utilizamos `geom_sf`. 217 | 218 | ```{r} 219 | ggplot(provincias) + 220 | geom_sf() 221 | ``` 222 | 223 | Podemos añadir etiquetas a nuestros mapas mediante `geom_sf_label()` o `geom_sf_text()`. 224 | 225 | ```{r} 226 | ggplot(provincias) + 227 | geom_sf() + 228 | geom_sf_label(aes(label = nombre)) 229 | ``` 230 | 231 | Sobre la geometría, podemos mapear otros atributos. Es muy habitual colorear las regiones según el dato que queramos representar. Para ello, primero tenemos que incorporar al mapa esta información. 232 | 233 | Para ilustrarlo, vamos a representar la participación en las últimas elecciones españolas por provincia. 234 | 235 | ```{r} 236 | # La información de las elecciones la tenemos en: 237 | # - elecciones_2019_provincias.csv con la información a nivel de provincia (población, censo, votos válidos, ...) 238 | # - elecciones_2019_votos.csv con el número de votos por provincia y partido 239 | # Para calcular la participación, solo necesitamos el primer dataset 240 | elecciones <- read.csv("dat/elecciones_2019_provincias.csv") 241 | head(elecciones) 242 | ``` 243 | 244 | ```{r} 245 | # Calculamos el ratio de participación 246 | participacion <- elecciones %>% 247 | mutate(ratio_participacion = round((votos_validos + votos_nulos) / censo_electoral, 3)) %>% 248 | select(provincia_cod_ine, ratio_participacion) 249 | 250 | head(participacion) 251 | ``` 252 | ```{r} 253 | # Añadimos al mapa esta información 254 | tmp <- provincias %>% 255 | inner_join(participacion, by = c("codigo" = "provincia_cod_ine")) 256 | 257 | # Representamos la participación coloreando cada provincia 258 | # Invertimos la escala con trans = "reverse" para que las intensidades 259 | # mayores correspondan a niveles más altos de participación 260 | ggplot(tmp) + 261 | geom_sf(aes(fill = ratio_participacion)) + 262 | scale_fill_continuous(trans = "reverse") 263 | ``` 264 | 265 | ## 4. Exportación 266 | 267 | Tenemos varias formas de guardar los gráficos que vamos generando. 268 | 269 | `ggsave()` guarda el último gráfico generado. 270 | 271 | ```{r eval=FALSE} 272 | # ggsave guarda el último gráfico generado 273 | ggsave("mi_grafico.png") 274 | ``` 275 | 276 | Si estamos en una sesión interactiva con RStudio, podemos pinchar en _Export_ en la ventana de _Plots_. 277 | 278 | ![](resources/03_ggplot_avanzado/export_from_rstudio.png) 279 | 280 | Y ahí podremos elegir varias opciones de exportación, como la ruta del fichero o el tamaño de la imagen. 281 | 282 | Aunque podemos utilizar estas dos opciones para guardar los gráficos en disco, lo normal es que formen parte de un documento Rmarkdown y que lo exportemos junto a texto formateado a PDF, HTML u otros formatos. Profundizaremos sobre este tema en el capítulo dedicado a Rmarkdown. 283 | 284 | ## Profundiza 285 | 286 | Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias: 287 | 288 | * [Chuleta de ggplot](https://github.com/rstudio/cheatsheets/raw/master/data-visualization-2.1.pdf): sintetiza las funciones más habituales para ggplot. Muy útil para tener a mano a la hora de utilizar la librería. 289 | * [Visualización de datos con ggplot](https://r4ds.had.co.nz/data-visualisation.html) disponible en el libro online de R for Data Science. 290 | * [Exploratory data analysis](https://r4ds.had.co.nz/exploratory-data-analysis.html) también disponible en el libro online de R for Data Science. 291 | * [R Graphics Cookbook de Winston Chang](https://www.amazon.com/dp/1491978600/) con recetas para pintar los gráficos más habituales. 292 | * [ggplot2: Elegant Graphics por Data Analyisis](https://ggplot2-book.org/) profundiza sobre el uso de ggplot para realizar gráficos más avanzados y personalizados. De especial interés en este tema es su [sección dedicada a mapas](https://ggplot2-book.org/maps.html). 293 | 294 | 295 | ## Conclusiones 296 | 297 | Nos podemos quedar con las siguientes ideas como resumen de este tema: 298 | 299 | * Es importante cuidar los textos (título, descripción, pie, nombres de los ejes, ...) cuando nuestros gráficos van dirigidos a un público general, o van a ser incluidos en un informe. 300 | * Los textos se pueden especificar con `labs()`. 301 | * Los temas de `ggplot` son plantillas con valores por defecto como tipo y tamaño de fuente, estilo de grid de fondo, ... pero estos valores los podemos sobrescribir. 302 | * Los _facets_ sirven para separar en gráficos diferentes las observaciones por una o varias variables categóricas. 303 | * Para representar _facets_ sobre una variable, utilizamos `facet_wrap`. Si es sobre dos variables, utilizamos `facet_grid`. 304 | * Para pintar gráficas con mapas, necesitamos dos cosas: el mapa base (los polígonos) y los datos a representar. 305 | * Para leer un mapa base en un formato habitual (geojson, shapefiles, ...) podemos utilizar `sf::read_sf`. 306 | * Para pintar los polígonos de un mapa, podemos utilizar `geom_sf`. Lo más habitual es mapear el color de relleno _fill_ a la propiedad que queramos representar. 307 | 308 | ## Actividades 309 | 310 | ### Actividad 1 311 | 312 | Sobre el dataset `diamonds`, pinta: 313 | 314 | * El histograma del precio según los _facets_ de la calidad del corte (`cut`) 315 | * Un gráfico de barras por claridad (`clarity`) según los _facets_ de calidad del corte (`cut`) y color (`color`). 316 | 317 | ### Actividad 2 318 | 319 | Utilizando los datos de elecciones (elecciones_2019_provincias.csv y elecciones_2019_votos.csv) y el mapa base con las provincias (spain_provinces.geojson), crea los siguientes gráficos: 320 | 321 | 1. Un mapa coloreado según la población de cada provincia (mayor intensidad = mayor población). 322 | 2. Un mapa con el color del partido más votado en cada provincia (PP en azul, PSOE en rojo, ...). 323 | 3. Un _facet_ de mapas, con 4, marcando el porcentaje de votos a los 4 partidos políticos (PP, PSOE, VOX, Podemos). Por ejemplo, en el facet del PSOE, se verán en un color más intenso las provincias con mayor % de votos a PSOE, y menos aquellas con menor %. Y así con cada uno de los partidos. 324 | 325 | ### Actividad 3 326 | 327 | Repasa estos gráficos que acabas de generar y añade títulos, nombres de eje, y personaliza el tema utilizado. 328 | -------------------------------------------------------------------------------- /03_ggplot_avanzado_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Soluciones capítulo 3' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ```{r, message=FALSE} 10 | library(dplyr) 11 | library(ggplot2) 12 | library(sf) 13 | ``` 14 | 15 | 16 | ### Actividad 1 17 | 18 | Sobre el dataset `diamonds`, pinta: 19 | 20 | * El histograma del precio según los _facets_ de la calidad del corte (`cut`) 21 | * Un gráfico de barras por claridad (`clarity`) según los _facets_ de calidad del corte (`cut`) y color (`color`). 22 | 23 | ```{r} 24 | # histograma del precio según la calidad del corte 25 | ggplot(diamonds, aes(x = price)) + 26 | geom_histogram(bins = 30) + 27 | facet_wrap(~ cut, scales = "free_y") + 28 | theme_minimal() + 29 | labs( 30 | title = "Relación entre el precio y la calidad", 31 | y = "# diamantes", 32 | x = "precio" 33 | ) 34 | ``` 35 | 36 | ```{r} 37 | # gráfico de barras por claridad según la calidad del corte y color 38 | ggplot(diamonds, aes(x = clarity)) + 39 | geom_bar() + 40 | facet_grid(cut ~ color, scales = "free_y") + 41 | theme_minimal() + 42 | theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) + 43 | labs( 44 | y = "# diamantes", 45 | x = "Claridad", 46 | title = "Diamantes por color, calidad y claridad" 47 | ) 48 | ``` 49 | 50 | ### Actividad 2 51 | 52 | Utilizando los datos de elecciones (elecciones_2019_provincias.csv y elecciones_2019_votos.csv) y el mapa base con las provincias (spain_provinces.geojson), crea los siguientes gráficos: 53 | 54 | 1. Un mapa coloreado según la población de cada provincia (mayor intensidad = mayor población). 55 | 2. Un mapa con el color del partido más votado en cada provincia (PP en azul, PSOE en rojo, ...). 56 | 3. Un _facet_ de mapas, con 4, marcando el porcentaje de votos a los 4 partidos políticos (PP, PSOE, VOX, Podemos). Por ejemplo, en el facet del PSOE, se verán en un color más intenso las provincias con mayor % de votos a PSOE, y menos aquellas con menor %. Y así con cada uno de los partidos. 57 | 58 | ```{r} 59 | # mapa coloreado según la población de cada provincia 60 | provincias <- read_sf("dat/spain_provinces.geojson") 61 | elecciones_provincias <- read.csv("dat/elecciones_2019_provincias.csv") 62 | 63 | tmp <- provincias %>% 64 | inner_join(elecciones_provincias, by = c("codigo" = "provincia_cod_ine")) 65 | 66 | ggplot(tmp) + 67 | geom_sf(aes(fill = poblacion)) + 68 | scale_fill_continuous(trans = "reverse") + 69 | theme_void() + 70 | labs( 71 | title = "Población por provincias", 72 | fill = "Población" 73 | ) 74 | ``` 75 | 76 | ```{r} 77 | # mapa con el color del partido más votado en cada provincia 78 | elecciones_votos <- read.csv("dat/elecciones_2019_votos.csv") 79 | 80 | mas_votado <- elecciones_votos %>% 81 | group_by(provincia_cod_ine) %>% 82 | arrange(desc(votos)) %>% 83 | summarise(partido = first(partido)) 84 | 85 | tmp <- provincias %>% 86 | inner_join(mas_votado, by = c("codigo" = "provincia_cod_ine")) 87 | 88 | paleta_partidos <- c( 89 | "erc" = "#f7a003", 90 | "navarra_suma" = "#444444", 91 | "pnv" = "#278347", 92 | "pp" = "#3caee1", 93 | "psoe" = "#bb0201", 94 | "teruelexiste" = "#eeeeee", 95 | "vox" = "#83b431" 96 | ) 97 | 98 | ggplot(tmp) + 99 | geom_sf(aes(fill = partido)) + 100 | scale_fill_manual(values = paleta_partidos) + 101 | theme_void() + 102 | labs( 103 | title = "Partido más votado por provincia", 104 | fill = "Partido" 105 | ) 106 | ``` 107 | 108 | ```{r} 109 | # Un _facet_ de mapas, con 4, marcando el porcentaje de votos a los 4 partidos políticos 110 | # (PP, PSOE, VOX, Podemos) 111 | 112 | votos <- elecciones_votos %>% 113 | filter(partido %in% c("pp", "psoe", "podemos", "vox")) %>% 114 | inner_join(elecciones_provincias) %>% 115 | mutate(ratio_votos = votos / votos_validos) 116 | 117 | tmp <- provincias %>% 118 | inner_join(votos, by = c("codigo" = "provincia_cod_ine")) 119 | 120 | ggplot(tmp) + 121 | geom_sf(aes(fill = ratio_votos)) + 122 | scale_fill_distiller(palette = "Blues", trans = "reverse") + 123 | facet_wrap(~ partido) + 124 | theme_void() 125 | ``` 126 | 127 | ### Actividad 3 128 | 129 | Repasa estos gráficos que acabas de generar y añade títulos, nombres de eje, y personaliza el tema utilizado. 130 | 131 | 132 | ```{r} 133 | # Hecho sobre los propios gráficos 134 | ``` 135 | -------------------------------------------------------------------------------- /04_leaflet_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Soluciones capítulo 4" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ```{r, message=FALSE} 10 | library(dplyr) 11 | library(sf) 12 | library(leaflet) 13 | library(tidyr) 14 | ``` 15 | 16 | 17 | ### Actividad 1 18 | 19 | Pinta el metro de Madrid, con: 20 | 21 | * Las paradas 22 | * Las líneas de metro, cada una con un color diferente. 23 | 24 | _Nota_: No vale crear una capa por línea diferente de metro, todas las líneas deben ir en la misma. 25 | 26 | _Bonus_: personaliza los colores con el suyo oficial (línea 2 en rojo, línea 7 en naranja, ...) 27 | 28 | ```{r} 29 | paradas_metro <- read_sf("dat/paradas_metro_madrid.geojson") 30 | lineas_metro <- read_sf("dat/lineas_metro.geojson") 31 | 32 | colores_lineas <- c( 33 | "L1" = "#38a3dc", 34 | "L2" = "#f40104", 35 | "L3" = "#fbe115", 36 | "L4" = "#944247", 37 | "L5" = "#96bf0e", 38 | "L6" = "#9fa4a6", 39 | "L7" = "#f7a64b", 40 | "L8" = "#f500ff", 41 | "L9" = "#a3228d", 42 | "L10" = "#174594", 43 | "L11" = "#185b00", 44 | "L12" = "#a49a00", 45 | "Ramal" = "#090080" 46 | ) 47 | 48 | # Cuidado, no confundas domain y levels. levels respeta el orden, 49 | # domain no 50 | paleta_lineas <- colorFactor( 51 | palette = unname(colores_lineas), 52 | levels = names(colores_lineas) 53 | ) 54 | 55 | leaflet(lineas_metro) %>% 56 | addProviderTiles("CartoDB.Positron") %>% 57 | setView(lng = -3.69, lat = 40.43, zoom = 12) %>% 58 | addPolylines(data = lineas_metro, color = ~paleta_lineas(Linea), opacity = 0.8) %>% 59 | addCircleMarkers(data = paradas_metro, stroke = FALSE, radius = 5, fillOpacity = 0.5) %>% 60 | addLegend( 61 | position = "bottomright", 62 | pal = paleta_lineas, 63 | values = ~Linea, 64 | title = "Línea" 65 | ) 66 | ``` 67 | 68 | ### Actividad 2 69 | 70 | Reproduce un mapa con el % de voto a cada uno de los 4 principales partidos por Comunidad Autónoma, en lugar de por provincia. 71 | 72 | Necesitarás, además de los datos que ya hemos ido usando en este capítulo, los siguientes: 73 | 74 | * `dat/provincias_ccaas.csv`: con el detalle de qué provincia pertenece a cada comunidad autónoma (mediante sus códigos INE). 75 | * `dat/spain_ccaas.geojson`: con el geojson de las comunidades autónomas simplificado 76 | 77 | ```{r} 78 | # Código adaptado del ejemplo por provincias del capítulo 79 | # Lectura de geojson 80 | mapa_ccaas <- read_sf("dat/spain_ccaas.geojson") 81 | 82 | # Lectura de datos 83 | elecciones <- read.csv("dat/elecciones_2019_provincias.csv") 84 | votos <- read.csv("dat/elecciones_2019_votos.csv") 85 | prov_ccaa <- read.csv("dat/provincias_ccaas.csv") 86 | 87 | votos_partidos <- votos %>% 88 | mutate( 89 | partido = ifelse(partido %in% c("encomupodem", "podemos_encomun"), "podemos", partido), 90 | partido = ifelse(partido == "navarra_suma", "pp", partido), 91 | ) %>% 92 | filter(partido %in% c("psoe", "pp", "vox", "podemos")) %>% 93 | inner_join(elecciones, by = "provincia_cod_ine") %>% 94 | inner_join(prov_ccaa, by = c("provincia_cod_ine" = "cod_ine_provincia")) %>% 95 | group_by(cod_ine_ccaa, partido) %>% 96 | summarise( 97 | votos = sum(votos), 98 | votos_validos = sum(votos_validos) 99 | ) %>% 100 | mutate(ratio_votos = round(votos / votos_validos, 3)) %>% 101 | select(cod_ine_ccaa, partido, ratio_votos) 102 | 103 | # Nos viene mejor pasarlo a formato ancho, con una columna por partido 104 | votos_partidos_ancho <- votos_partidos %>% 105 | pivot_wider(names_from = partido, values_from = ratio_votos) 106 | 107 | mapa_votos <- mapa_ccaas %>% 108 | inner_join(votos_partidos_ancho, by = c("codigo" = "cod_ine_ccaa")) 109 | 110 | # Las paletas, también rescatadas del capítulo 111 | pal_votos_psoe <- colorBin( 112 | palette = "Reds", 113 | domain = mapa_votos$psoe, 114 | bins = 5 115 | ) 116 | 117 | pal_votos_pp <- colorBin( 118 | palette = "Blues", 119 | domain = mapa_votos$pp, 120 | bins = 5 121 | ) 122 | 123 | pal_votos_vox <- colorBin( 124 | palette = "Greens", 125 | domain = mapa_votos$vox, 126 | bins = 5 127 | ) 128 | 129 | pal_votos_podemos <- colorBin( 130 | palette = "Purples", 131 | domain = mapa_votos$vox, 132 | bins = 5 133 | ) 134 | 135 | # Pinto el mapa, con una capa por ratio de votos a ese partido 136 | leaflet(data = mapa_votos) %>% 137 | # Capa del PSOE 138 | addPolygons(color = ~pal_votos_psoe(psoe), 139 | label = ~nombre, 140 | stroke = FALSE, 141 | fillOpacity = 1, 142 | group = "PSOE" 143 | ) %>% 144 | # Capa del PP 145 | addPolygons(color = ~pal_votos_pp(pp), 146 | label = ~nombre, 147 | stroke = FALSE, 148 | fillOpacity = 1, 149 | group = "PP" 150 | ) %>% 151 | # Capa de VOX 152 | addPolygons(color = ~pal_votos_vox(vox), 153 | label = ~nombre, 154 | stroke = FALSE, 155 | fillOpacity = 1, 156 | group = "VOX" 157 | ) %>% 158 | # Capa de Podemos 159 | addPolygons(color = ~pal_votos_podemos(podemos), 160 | label = ~nombre, 161 | stroke = FALSE, 162 | fillOpacity = 1, 163 | group = "Podemos" 164 | ) %>% 165 | # Control de capas 166 | addLayersControl( 167 | baseGroups = c("PSOE", "PP", "VOX", "Podemos"), 168 | options = layersControlOptions(collapsed = FALSE) 169 | ) 170 | ``` 171 | 172 | ### Actividad 3 173 | 174 | Lee `dat/listings.csv`. Contiene un listado de alojamientos anunciados en AirBnB en Madrid. 175 | 176 | Coge aleatoriamente una muestra de 500 alojamientos y píntalos sobre un mapa de Madrid. Cada marcador debe tener un color diferente dependiendiendo del tipo (`room_type`). 177 | 178 | ```{r} 179 | listings <- read.csv("dat/listings.csv") %>% 180 | sample_n(500) 181 | 182 | paleta_tipo <- colorFactor("Set1", domain = unique(listings$room_type)) 183 | 184 | leaflet(listings) %>% 185 | addProviderTiles("CartoDB.Positron") %>% 186 | setView(lng = -3.69, lat = 40.43, zoom = 12) %>% 187 | addCircleMarkers(lat = ~latitude, lng = ~longitude, color = ~paleta_tipo(room_type), 188 | stroke = FALSE, radius = 2, fillOpacity = 0.5) %>% 189 | addLegend( 190 | position = "bottomright", 191 | pal = paleta_tipo, 192 | values = ~room_type, 193 | title = "Tipo de habitación" 194 | ) 195 | ``` 196 | -------------------------------------------------------------------------------- /05_plotly_basico.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: '5 - Gráficos interactivos con plotly: nivel básico' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ## ¿Qué vamos a hacer? 10 | 11 | En capítulos previos hemos visto herramientas para generar tanto visualizaciones estáticas (gráficos con ggplot) como dinámicas (mapas con leaflet). 12 | 13 | En este y el siguiente capítulo veremos una alternativa interactiva a los gráficos de ggplot: plotly. Al igual que leaflet, plotly es una librería de gráficos basada en javascript, pero disponible a través de su paquete en R para poder crearlos directamente desde este lenguaje. 14 | 15 | Antes de empezar, nos tendremos que asegurar de tener las librerías de `plotly` y `htmlwidgets` instaladas. 16 | 17 | ```{r, eval=FALSE} 18 | # Ejecuta las siguiente líneas en el caso de que no los tengas instalados 19 | install.packages("plotly") 20 | install.packages("htmlwidgets") 21 | ``` 22 | 23 | ## Gráficos básicos 24 | 25 | Al pintar un gráfico con plotly, seguiremos la siguiente estructura: 26 | 27 | * Con la función `plot_ly` pintamos el gráfico en sí, pasando los datos como argumento y definiendo: 28 | 29 | * El tipo (y, opcionalmente, el subtipo): de puntos, líneas, barras, ... Se establecen usando los parámetros `type` y `mode`. 30 | * Los mapeos de valores a columnas del dataset, usando `x`, `y`, `color`, `size`, ... 31 | * Geometrías adicionales utilizando `add_xxxx`, como `add_markers`, `add_lines`, `add_ribbons`, ... 32 | 33 | * Con la función `layout` personalizaremos elementos como el título, los ejes o la leyenda. 34 | 35 | ### Gráficos de puntos 36 | 37 | Podemos pintar un gráfico de puntos usando `type='scatter'` y `mode='markers'`. El mapeo de propiedades a columnas se hace utilizando `~mi_columna`. 38 | 39 | ```{r} 40 | library(dplyr) 41 | library(plotly) 42 | library(palmerpenguins) 43 | 44 | plot_ly(data = penguins, type = "scatter", mode = "markers", 45 | x = ~flipper_length_mm, y = ~body_mass_g) 46 | ``` 47 | 48 | > Fíjate en la interactividad. Pasa el ratón por encima de los puntos, prueba a seleccionar un subconjunto de los puntos y utiliza los controles de arriba a la izquierda. 49 | 50 | Podemos personalizarlo. La lista completa de opciones está disponible [aquí](https://plotly.com/r/reference). Navega hasta ella y prueba a buscar todas las posibles opciones del parámetro `marker` dentro de un _scatterplot_ (gráfico de puntos). 51 | 52 | Vamos a mapear los colores según la especie del pingüino y a personalizar un poco el estilo de los puntos (_markers_). 53 | 54 | ```{r} 55 | plot_ly(data = penguins, type = "scatter", mode = "markers", 56 | x = ~flipper_length_mm, y = ~body_mass_g, color = ~species, 57 | marker = list( 58 | size = 10, 59 | line = list(width = 2), 60 | opacity = 0.6 61 | ) 62 | ) 63 | ``` 64 | 65 | ### Gráficos de líneas 66 | 67 | El gráfico de líneas lo pintamos utilizando `type='scatter'` y `mode='lines'`. 68 | 69 | Vamos a pintar un ejemplo utilizando los datos históricos de paro de EEUU. 70 | 71 | ```{r} 72 | # Calculo la tasa de desempleo 73 | paro <- economics %>% 74 | mutate(unemploy_ratio = unemploy / pop) 75 | 76 | # Pinto mi gráfico de líneas 77 | plot_ly(paro, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines") 78 | ``` 79 | 80 | Podemos añadir diferentes líneas utilizando `add_lines`. 81 | 82 | ```{r} 83 | plot_ly(paro, type = "scatter", mode = "lines") %>% 84 | add_lines(x = ~date, name = "Población", y = ~pop * 1000) %>% 85 | add_lines(x = ~date, name = "Paro", y = ~unemploy * 1000) 86 | ``` 87 | 88 | > Para pasar el gráfico a las siguientes funciones (de plot_ly a add_lines), utilizamos `%>%`, igual que en `dplyr` y en `leaflet`. En realidad, este operador pertenece a la librería `magrittr` y lo que hace es pasar el argumento de la izquierda del operador como primer argumento de la función de la derecha. 89 | 90 | Si nuestros datos tienen nulos, tenemos dos alternativas para pintar las líneas: 91 | 92 | * Dejar el hueco, rompiendo visualmente la línea. 93 | * Conectar con una línea los puntos con información más cercanos, haciendo una línea más larga. 94 | 95 | Para ver la diferencia, vamos a insertar nulos en la serie del paro, en las fechas desde el 1 de enero de 2002 hasta el 1 de enero del 2005. 96 | 97 | ```{r} 98 | # Insertamos nulos 99 | tmp <- paro %>% 100 | mutate(unemploy_ratio = ifelse(date >= as.Date("2002-01-01") & date <= as.Date("2005-01-01"), 101 | NA, unemploy_ratio)) 102 | 103 | # Pintamos con huecos, es la opción por defecto 104 | # resulta lo mismo que especificar connectgaps = FALSE 105 | plot_ly(tmp, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines") 106 | ``` 107 | 108 | ```{r} 109 | # Pintamos con huecos, es la opción por defecto 110 | # resulta lo mismo que especificar connectgaps = FALSE 111 | plot_ly(tmp, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines", connectgaps = TRUE) 112 | ``` 113 | 114 | También podemos pintar bandas alrededor de líneas, un recurso muy utilizado cuando existen intervalos de confianza. Rescatemos el ejemplo con los datos de defunciones en España. 115 | 116 | Conseguimos pintar una banda pintando primero la línea superior (donde acaba) y luego la línea inferor (donde empieza), marcando esta última como `fill = "tonexty"`. 117 | 118 | ```{r} 119 | # Lectura de los datos 120 | defunciones <- read.csv("dat/defunciones_espana.csv") 121 | 122 | # Conversión de la fecha de tipo character a Date 123 | defunciones <- defunciones %>% 124 | mutate(fecha_defuncion = as.Date(fecha_defuncion)) 125 | 126 | # Pintamos la mortalidad observada y la estimada junto con su intervalo de confianza 127 | plot_ly(defunciones, type = "scatter", mode = "lines") %>% 128 | add_trace(x = ~fecha_defuncion, y = ~defunciones_observadas, name = "Observadas", 129 | line = list(color = "black")) %>% 130 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas, name = "Esperadas", 131 | line = list(color = "rgb(22, 96, 167)")) %>% 132 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q99, name = "Esperadas lim. sup.", 133 | line = list(color = "gray", width = 0.5, dash = "dash")) %>% 134 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q01, name = "Esperadas lim. inf.", 135 | fill = "tonexty", fillcolor="rgba(22, 96, 167, 0.3)", 136 | line = list(color = "gray", width = 0.5, dash = "dash")) 137 | ``` 138 | 139 | > Fíjate en cómo definimos los colores: con rgb(r, g, b, a). Es una forma de definir un color en base a sus tres componentes (r = red, g = green, b = blue, a = alpha). El alpha es el grado de opacidad. También lo podríamos definir mediante un nombre (como blue) o su código hexadecimal (como #0000FF). 140 | 141 | ### Gráficos de barras 142 | 143 | Para representar un gráfico de barras, necesitamos especificar `x` e `y`. 144 | 145 | Es habitual utilizarlos para hacer un conteo sobre una variable categórica. 146 | 147 | ```{r} 148 | penguins_count <- penguins %>% 149 | group_by(species) %>% 150 | summarise(count = n()) 151 | 152 | plot_ly(penguins_count, x = ~species, y = ~count, type = "bar") 153 | ``` 154 | 155 | También disponemos de los tipos de gráficos de barras habituales: agrupados y apilados. 156 | 157 | ```{r} 158 | penguins_count_2 <- penguins %>% 159 | group_by(species, sex) %>% 160 | summarise(count = n()) 161 | 162 | plot_ly(penguins_count_2, x = ~species, y = ~count, color = ~sex, type = "bar") 163 | ``` 164 | 165 | 166 | ```{r} 167 | plot_ly(penguins_count_2, x = ~species, y = ~count, color = ~sex, type = "bar") %>% 168 | layout(barmode = "stack") 169 | ``` 170 | 171 | > Es la primera vez que utilizamos la función `layout`. La usaremos en plotly para ajustar detalles del gráfico como los ejes, títulos, leyendas y otras propiedades. 172 | 173 | ## Gráficos estadísticos 174 | 175 | ### Histogramas 176 | 177 | En plotly también podemos utilizar gráficos que realizan de forma implícita transformaciones estadísticas. Uno de los más habituales es el histograma, que nos muestra la distribución de una determinada variable. 178 | 179 | ```{r} 180 | plot_ly(penguins, x = ~body_mass_g, type = "histogram") 181 | ``` 182 | 183 | También podemos sobrescribir la función de _binning_, es decir, la transformación estádistica. Es habitual utilizarla para realizar un histograma sobre una variable categórica contando sus observaciones, que produce un resultado equivalente a los ejemplos previos que hemos visto con gráficos de barras. 184 | 185 | ```{r} 186 | plot_ly(penguins, x = ~species, histfunc = "sum", type = "histogram") 187 | ``` 188 | 189 | > La diferencia entre el gráfico de barras anterior y este histograma es que, en el de barras, hicimos nosotros la transformación estadística (agrupar y contar) con dplyr y pasamos los resultados ya preparados; en este histograma, le pasamos todos los datos, y es plot_ly el encargado de hacer la transformación. En este caso el resultado es similar, pero en otros, el caso del histograma puede derivar en un peor rendimiento (proceso más lento). 190 | 191 | Otro caso de uso habitual es el de pintar varios histogramas superpuestos, para comparar la distribución en base a una segunda variable. Para hacerlo, utilizamos el `barmode="overlay"` dentro de layout. 192 | 193 | ```{r} 194 | plot_ly(penguins, x =~body_mass_g, color =~sex, type = "histogram", alpha = 0.6) %>% 195 | layout(barmode = "overlay") 196 | ``` 197 | 198 | ### Boxplots 199 | 200 | Ya vimos que los boxplots son habituales al hacer un análisis exploratorio sobre nuestro dataset o para representar ante un público con ciertos conocimientos estadísticos. En plotly los podemos pintar utilizando el `type="box"`. 201 | 202 | ```{r} 203 | plot_ly(penguins, x = ~species, y = ~body_mass_g, type = "box") 204 | ``` 205 | 206 | También tenemos en plotly una alternativa gráfica a los boxplots: los gráficos de violín. También muestran distribuciones, pero suelen ser un poco más amigables para un público con menos conocimientos de estadística. 207 | 208 | ```{r} 209 | plot_ly(penguins, x = ~species, y = ~body_mass_g, type = "violin") 210 | ``` 211 | 212 | ## Personalización 213 | 214 | Podemos personalizar la mayor parte de los aspecto estéticos de nuestro gráfico en la función `layout`. 215 | 216 | ### Título y ejes 217 | 218 | Los siguientes argumentos de `layout` nos sirven para personalizar varios textos: 219 | 220 | * `title`: el título principal del gráfico 221 | * `xaxis`: las propiedades del eje x 222 | * `yaxis`: las propiedades del eje x 223 | 224 | Vamos a personalizar estos textos sobre el gráfico que teníamos mostrando las defunciones en España. 225 | 226 | ```{r} 227 | p <- plot_ly(defunciones, type = "scatter", mode = "lines") %>% 228 | add_trace(x = ~fecha_defuncion, y = ~defunciones_observadas, name = "Observadas", 229 | line = list(color = "black")) %>% 230 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas, name = "Esperadas", 231 | line = list(color = "rgb(22, 96, 167)")) %>% 232 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q99, name = "Esperadas lim. sup.", 233 | line = list(color = "gray", width = 0.5, dash = "dash")) %>% 234 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q01, name = "Esperadas lim. inf.", 235 | fill = "tonexty", fillcolor="rgba(22, 96, 167, 0.3)", 236 | line = list(color = "gray", width = 0.5, dash = "dash")) %>% 237 | layout(title = "Mortalidad observada y esperada en España", 238 | xaxis = list(title = "Fecha"), 239 | yaxis = list(title = "Defunciones")) 240 | 241 | p 242 | ``` 243 | 244 | ### Tooltips 245 | 246 | En los gráficos que hemos estado representando, podemos ver que el estilo del _tooltip_ (el cuadro con información al pasar el ratón por encima en algún punto) por defecto es `(valor en eje x, valor en eje y)`. 247 | 248 | Podemos personalizar este valor de diferentes formas. 249 | 250 | Un caso de uso habitual cuando tenemos varias líneas es unificar el _tooltip_, de forma que la información de todas las líneas aparezca junta en el cuadro de información, con `layout(hovermode = " unified")` 251 | 252 | ```{r} 253 | p %>% 254 | layout(hovermode = "x unified") 255 | ``` 256 | 257 | Para personalizar el texto y formato del _tooltip_ podemos utilizar los [_hovertemplates_](https://plotly.com/r/reference/#pie-hovertemplate). Se trata de plantillas en las que podemos incluir: 258 | 259 | * Variables con `%{variable}` 260 | * Números con [formato d3](https://github.com/d3/d3-3.x-api-reference/blob/master/Formatting.md#d3_format), en la forma `variable|formato` 261 | * Fechas con [formato d3](https://github.com/d3/d3-3.x-api-reference/blob/master/Time-Formatting.md#format), en la forma `variable:formato` 262 | * Etiquetas html como `
` para saltar de línea, `...` para resaltar en negrita, ... 263 | 264 | _Nota_: d3 es una librería de visualización de datos de javascript de bajo nivel, en la que se basan muchas otras. Puedes consultar los links con la documentación necesaria de los formatos citados. 265 | 266 | Aquí tenemos un ejemplo con todos los elementos descritos: etiquetas html, y variables con formateo especial de números y fechas. 267 | 268 | ```{r} 269 | plot_ly(paro, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines", name = "Paro", 270 | hovertemplate = "Fecha: %{x|%B %Y}
Paro: %{y:.2%}") %>% 271 | layout(title = "Paro en EEUU", 272 | xaxis = list(title = "Fecha"), 273 | yaxis = list(title = "Paro")) 274 | ``` 275 | 276 | ## Transformación de gráficos de ggplot a plotly 277 | 278 | Plotly trae una función para transformar gráficos de `ggplot2` a `plotly`. Esta funcionalidad resulta muy útil si ya tenemos una serie de gráficos hechos con `ggplot2` y queremos hacerlos interactivos de una forma rápida. 279 | 280 | Si por el contrario, nos encontramos de cero con un proyecto de visualización de datos interactivo, es mejor empezarlo con las funciones de `plot_ly` puras: la transformación vía ggplot2 tiene sus limitaciones. 281 | 282 | La función que transforma un gráfico de de `ggplot2` a `plotly` es `ggplotly`. Veamos un ejemplo: 283 | 284 | ```{r} 285 | library(ggplot2) 286 | 287 | # Generamos un gráfico con ggplot 288 | p <- ggplot(data = penguins, mapping = aes(x = flipper_length_mm, y = body_mass_g)) + 289 | geom_point() 290 | 291 | # Con la función ggplotly, lo volvemos interactivo: es decir, lo transformamos 292 | # en un gráfico de plotly 293 | ggplotly(p) 294 | ``` 295 | 296 | ## Profundiza 297 | 298 | Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias: 299 | 300 | * [Chuleta de plotly](https://images.plot.ly/plotly-documentation/images/r_cheat_sheet.pdf): sintetiza las funciones más habituales para plotly. Muy útil para tener a mano a la hora de utilizar la librería. 301 | * [Referencia completa de atributos de plotly](https://plotly.com/r/reference): documenta todos los posibles atributos que se pueden establecer por cada tipo de gráfico. 302 | * [Referencia de gráficos básicos en plotly](https://plotly.com/r/basic-charts/): consúltalo para ver más ejemplos de gráficos básicos 303 | * [Referencia de gráficos estadísticos en plotly](https://plotly.com/r/statistical-charts/): documentación completa de los gráficos estadísticos en plotly 304 | 305 | ## Conclusiones 306 | 307 | Nos podemos quedar con las siguientes ideas como resumen de este tema: 308 | 309 | * Cuando nos encontramos ante un proyecto de visualización de datos, podemos decidir si hacerlo con gráficos estáticos o dinámicos. El primer caso es más rápido y sencillo; el segundo, proporciona visualizaciones más completas y enriquecidas. 310 | * En R, podemos utilizar ggplot2 para gráficos estáticos y plotly para gráficos dinámicos. 311 | * Si tenemos una visualización de datos ya hecha con ggplot2 y queremos pasarla rápidamente a interactiva, podemos utilizar `ggplotly()`. Si, por el contrario, nos encontramos ante un proyecto a empezar desde cero, es preferible utilizar las funciones puras de `plot_ly`. 312 | * Los mapeos de propiedades con columnas se hacen utilizando `~mi_columna`. 313 | * Las personalizaciones más estéticas como cambiar textos, fuentes, formatos, etc. se hacen con la función `layout()`. 314 | 315 | ## Actividades 316 | 317 | Vamos a pintar con plotly algunos gráficos que ya habíamos representado con ggplot. Para hacerlo, no utilices `ggplotly`: utiliza las funciones puras de `plotly`. 318 | 319 | ### Actividad 1 320 | 321 | Utilizando el dataset `diamonds`, representa la relación en un gráfico de puntos del precio frente a los quilates. 322 | 323 | ### Actividad 2 324 | 325 | Con el dataset `penguins`: 326 | 327 | 1. Pinta la relación entre longitud y profunidad del pico. 328 | 329 | 2. Añade al gráfico del punto 1 la distinción entre especies mediante el color. 330 | 331 | 3. Añade al gráfico del punto 1 la distinción entre el peso corporal mediante el color. 332 | 333 | ### Actividad 3 334 | 335 | 1. Lee los datos del economista (dat/economist.csv), con indicadores de desarrollo y corrupción por países: 336 | 337 | * HDI: Human Development Index (1: más desarrollado) 338 | * CPI: Corruption Perception Index (10: menos corrupto) 339 | 340 | 2. Crea un gráfico que: 341 | 342 | * Cada país sea un punto 343 | * El eje x indique CPI, el y HDI 344 | * El color del punto indique la región 345 | * Su tamaño sea proporcional al ranking HDI 346 | 347 | ### Actividad 4 348 | 349 | 1. Lee los datos de los resultados de las elecciones presidenciales de los Estados Unidos (dat/usa_president.csv). 350 | 351 | 2. Pinta en un gráfico de líneas la evolución del número de votos a lo largo de los años del partido republicado frente al demócrata. 352 | -------------------------------------------------------------------------------- /05_plotly_basico_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Soluciones capítulo 5' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ```{r, message=FALSE} 10 | library(dplyr) 11 | library(tidyr) 12 | library(palmerpenguins) 13 | library(plotly) 14 | ``` 15 | 16 | 17 | ### Actividad 1 18 | 19 | Utilizando el dataset `diamonds`, representa la relación en un gráfico de puntos del precio frente a los quilates. 20 | 21 | ```{r} 22 | diamonds_5k <- sample_n(diamonds, 5000) 23 | 24 | plot_ly(diamonds_5k, type = "scatter", mode = "markers", 25 | x = ~carat, y = ~price) 26 | ``` 27 | 28 | ### Actividad 2 29 | 30 | Con el dataset `penguins`: 31 | 32 | 1. Pinta la relación entre longitud y profundidad del pico. 33 | 34 | 2. Añade al gráfico del punto 1 la distinción entre especies mediante el color. 35 | 36 | 3. Añade al gráfico del punto 1 la distinción entre el peso corporal mediante el color. 37 | 38 | ```{r} 39 | plot_ly(penguins, type = "scatter", mode = "markers", 40 | x = ~bill_length_mm, y = ~bill_depth_mm) 41 | ``` 42 | 43 | ```{r} 44 | plot_ly(penguins, type = "scatter", mode = "markers", 45 | x = ~bill_length_mm, y = ~bill_depth_mm, color = ~species) 46 | ``` 47 | 48 | ```{r} 49 | plot_ly(penguins, type = "scatter", mode = "markers", 50 | x = ~bill_length_mm, y = ~bill_depth_mm, color = ~body_mass_g) 51 | ``` 52 | 53 | ### Actividad 3 54 | 55 | 1. Lee los datos del economista (dat/economist.csv), con indicadores de desarrollo y corrupción por países: 56 | 57 | * HDI: Human Development Index (1: más desarrollado) 58 | * CPI: Corruption Perception Index (10: menos corrupto) 59 | 60 | 2. Crea un gráfico que: 61 | 62 | * Cada país sea un punto 63 | * El eje x indique CPI, el y HDI 64 | * El color del punto indique la región 65 | * Su tamaño sea proporcional al ranking HDI 66 | 67 | ```{r} 68 | economist <- read.csv("dat/economist.csv") 69 | 70 | plot_ly(economist, type = "scatter", mode = "markers", 71 | x = ~CPI, y = ~HDI, size = ~HDI.Rank, color = ~Region, text = ~Country, 72 | hovertemplate = "%{text}
CPI: %{x}
HDI: %{y}") 73 | ``` 74 | 75 | ### Actividad 4 76 | 77 | 1. Lee los datos de los resultados de las elecciones presidenciales de los Estados Unidos (dat/usa_president.csv). 78 | 79 | 2. Pinta en un gráfico de líneas la evolución del número de votos a lo largo de los años del partido republicado frente al demócrata. 80 | 81 | ```{r} 82 | usa_president <- read.csv("dat/usa_president.csv") 83 | 84 | usa_elections <- usa_president %>% 85 | filter(!writein, party %in% c("democrat", "republican")) %>% 86 | group_by(year, party) %>% 87 | summarise(candidatevotes = sum(candidatevotes)) %>% 88 | ungroup() 89 | 90 | plot_ly(usa_elections, type = "scatter", mode = "lines", 91 | x = ~year, y = ~candidatevotes, color = ~party) 92 | ``` 93 | 94 | -------------------------------------------------------------------------------- /06_plotly_avanzado.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: '6 - Gráficos interactivos con plotly: nivel avanzado' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ## ¿Qué vamos a hacer? 10 | 11 | En el capítulo anterior realizamos nuestras primeras visualizaciones de datos interactivas con plotly. En este, veremos funcionalidades más avanzadas: controles y animaciones. 12 | 13 | ## Barra de herramientas 14 | 15 | La barra de herramientas (_modebar_) de plotly es el conjunto de botones que aparece arriba a la derecha con los gráficos que creamos. 16 | 17 | Por ejemplo: 18 | 19 | ```{r} 20 | library(dplyr) 21 | library(plotly) 22 | library(palmerpenguins) 23 | 24 | p <- plot_ly(data = penguins, type = "scatter", mode = "markers", 25 | x = ~flipper_length_mm, y = ~body_mass_g) 26 | p 27 | ``` 28 | 29 | Por defecto aparece con estos controles: 30 | 31 | * `toImage`: descarga como imagen estática (png) el gráfico. 32 | * `zoom2d`: hace zoom en la zona seleccionada. 33 | * `pan2d`: cambia el control por un _drag_ (pinchar y arrastrar) para desplazar la zona visible del gráfico. 34 | * `select2d`: selecciona una zona con un cuadrado. 35 | * `lasso2d`: selecciona una zona con un lazo libre. 36 | * `zoomIn2d`: aumenta el zoom. 37 | * `zoomOut2d`: disminuye el zoom. 38 | * `autoScale2d`: establece automáticamente el zoom y la posición para que se visualicen todos los datos. 39 | * `resetScale2d`: resetea los parámetros de zoom a su estado original. 40 | * `toggleSpikelines`: muestra u oculta las guías que van desde los ejes hasta su valor en el gráfico. 41 | * `hoverClosestCartesian`: muestra el tooltip al pasar el ratón por encima, en donde se encuentra su valor. 42 | * `hoverCompareCartesian`: muestra el tooltip continuamente, con el valor sobre el punto y el eje. Si hay varias trazas, lo muestra sobre todas ellas. 43 | * Y el logo de plotly 44 | 45 | > Interactúa con estos controles en el gráfico que acabas de representar. 46 | 47 | Puedes ver (está en _javascript_, pero es posible interpretarlo) todas las posibles opciones de la barra de herramientas [aquí](https://github.com/plotly/plotly.js/blob/master/src/components/modebar/buttons.js). 48 | 49 | Esta barra de herramientas se puede personalizar con la functión `config()`. Es muy recomendable hacerlo, según el uso que creamos que debe darle el usuario de esta visualización. Y aplicar la misma configuración a todos los gráficos del cuadro de mando. 50 | 51 | Para eliminarla completamente, ponemos a `FALSE` la opción `displayModeBar`. 52 | 53 | ```{r} 54 | p %>% 55 | config(displayModeBar = FALSE) 56 | ``` 57 | 58 | Para eliminar el logo de plotly: 59 | 60 | ```{r} 61 | p %>% 62 | config(displaylogo = FALSE) 63 | ``` 64 | 65 | Para eliminar una serie de botones: 66 | 67 | ```{r} 68 | p %>% 69 | config(modeBarButtonsToRemove = c("zoom2d", "zoomIn2d", "zoomOut2d", "autoScale2d")) 70 | ``` 71 | 72 | ## Controles interactivos 73 | 74 | Los controles son elementos que ponemos a disposición del usuario y que alteran de alguna manera la visualización. 75 | 76 | Estos controles los definimos mediante la propiedad `updatemenu` de `layout()`. Dependiendo de la acción que realizará la interacción con el control, debemos establecer el parámetro `method`: 77 | 78 | * `restyle`: modifica los datos o sus atributos. 79 | * `relayout`: modifica los atributos del _layout_. 80 | * `update`: modifica los datos y/o el _layout_. 81 | * `animate`: comienza o pausa la animación. 82 | 83 | ### Botones 84 | 85 | Para crear un botón, añadiremos un `updatemenu` con `type="buttons"` y un parámetro `buttons` con el nombre (`label`) y el efecto que provoca (`method` y `args`). 86 | 87 | Veamos un ejemplo con el que cambiar el color de los puntos. Usaremos el método de `restyle`: 88 | 89 | ```{r} 90 | plot_ly(data = penguins, type = "scatter", mode = "markers", 91 | x = ~flipper_length_mm, y = ~body_mass_g, color = I("blue")) %>% 92 | layout(updatemenus = list( 93 | list( 94 | type = "buttons", 95 | buttons = list( 96 | list(label = "Azul", 97 | method = "restyle", 98 | args = list("marker.color", "blue")), 99 | list(label = "Rojo", 100 | method = "restyle", 101 | args = list("marker.color", "red"))) 102 | ))) 103 | ``` 104 | 105 | > Cuidado con los niveles de anidamiento de las listas, es fácil confundirse y poner alguno de menos. 106 | 107 | Si el parámetro que queremos modificar con el botón se encuentra dentro de `layout()`, utilizaremos el método de `relayout`. 108 | 109 | Veamos un caso en el que queremos mostrar u ocultar la leyenda en base al click sobre el botón. 110 | 111 | ```{r} 112 | plot_ly(data = penguins, type = "scatter", mode = "markers", 113 | x = ~flipper_length_mm, y = ~body_mass_g, color = ~species, colors = "Set1") %>% 114 | layout( 115 | updatemenus = list( 116 | list( 117 | type = "buttons", 118 | buttons = list( 119 | list(label = "Mostrar", 120 | method = "relayout", 121 | args = list("showlegend", TRUE)), 122 | list(label = "Ocultar", 123 | method = "relayout", 124 | args = list("showlegend", FALSE))) 125 | ))) 126 | ``` 127 | 128 | Cuando necesitamos actualizar tanto los datos como el _layout_, utilizamos el método de `update`. Su parámetro `args` será una lista de dos elementos: el primero, el que modifica los datos o sus atributos; el segundo, el que modifica el _layout_. 129 | 130 | Un caso de uso habitual es para mostrar diferentes series en un gráfico. 131 | 132 | ```{r} 133 | # Leemos los datos de las elecciones presidenciales de EEUU 134 | usa_president <- read.csv("dat/usa_president.csv") 135 | 136 | # Nos quedamos solo con los resultados de demócratas y republicanos 137 | # y agrupamos para conocer el número de votos de cada partido por año 138 | # Atención: normalmente no es necesario hacer el ungroup explícito de 139 | # un dataframe con dplyr, pero en este caso, si no lo haces, no se pintan 140 | # correctamente las líneas con plotly 141 | usa_president_by_year <- usa_president %>% 142 | filter(party %in% c("democrat", "republican"), 143 | writein == FALSE) %>% 144 | group_by(year, party) %>% 145 | summarise(candidatevotes = sum(candidatevotes)) %>% 146 | arrange(year) %>% 147 | ungroup() 148 | 149 | # Separamos en dos dataframes los votos de unos y de otros 150 | usa_democrat <- usa_president_by_year %>% 151 | filter(party == "democrat") 152 | 153 | usa_republican <- usa_president_by_year %>% 154 | filter(party == "republican") 155 | 156 | # Creamos un gráfico en el que el usuario puede elegir si ver la evolución 157 | # del voto demócrata, republicano o ambas 158 | plot_ly(type = "scatter", mode = "lines", x = ~year, y = ~candidatevotes, 159 | data = usa_democrat, name = "Demócratas", color = I("blue")) %>% 160 | add_lines(data = usa_republican, name = "Republicanos", color = I("red")) %>% 161 | layout( 162 | updatemenus = list( 163 | list( 164 | type = "buttons", 165 | buttons = list( 166 | list(label = "Ambos", 167 | method = "update", 168 | args = list( 169 | list(visible = c(TRUE, TRUE)), 170 | list(title = "Evolución del voto demócrata y republicano") 171 | )), 172 | list(label = "Demócrata", 173 | method = "update", 174 | args = list( 175 | list(visible = c(TRUE, FALSE)), 176 | list(title = "Evolución del voto demócrata") 177 | )), 178 | list(label = "Republicano", 179 | method = "update", 180 | args = list( 181 | list(visible = c(FALSE, TRUE)), 182 | list(title = "Evolución del voto republicano") 183 | )) 184 | )))) 185 | ``` 186 | 187 | ### Selectores 188 | 189 | Los selectores (_dropdowns_) se configuran de forma equivalente a los botones. La diferencia entre unos y otros es visual: mientras que los botones se muestran todos al mismo tiempo, el selector es un menú desplegable en el que solo se ve una opción activa. 190 | 191 | Vamos a reproducir el ejemplo previo con un _dropdown_. Basta con eliminar `type = "buttons"` dentro de la especificación de `updatemenus`. 192 | 193 | ```{r} 194 | # Creamos un gráfico en el que el usuario puede elegir si ver la evolución 195 | # del voto demócrata, republicano o ambas 196 | plot_ly(type = "scatter", mode = "lines", x = ~year, y = ~candidatevotes, 197 | data = usa_democrat, name = "Demócratas", color = I("blue")) %>% 198 | add_lines(data = usa_republican, name = "Republicanos", color = I("red")) %>% 199 | layout( 200 | updatemenus = list( 201 | list( 202 | buttons = list( 203 | list(label = "Ambos", 204 | method = "update", 205 | args = list( 206 | list(visible = c(TRUE, TRUE)), 207 | list(title = "Evolución del voto demócrata y republicano") 208 | )), 209 | list(label = "Demócrata", 210 | method = "update", 211 | args = list( 212 | list(visible = c(TRUE, FALSE)), 213 | list(title = "Evolución del voto demócrata") 214 | )), 215 | list(label = "Republicano", 216 | method = "update", 217 | args = list( 218 | list(visible = c(FALSE, TRUE)), 219 | list(title = "Evolución del voto republicano") 220 | )) 221 | )))) 222 | ``` 223 | 224 | ### Selectores de rango 225 | 226 | Los selectores de rango sirven para hacer zoom sobre un área concreta del gráfico. Se utiliza a menudo en las series temporales, inicializado a los datos más recientes, pero con posibilidad de visualizar mayor histórico. 227 | 228 | ```{r} 229 | # Lectura de los datos 230 | defunciones <- read.csv("dat/defunciones_espana.csv") 231 | 232 | # Conversión de la fecha de tipo character a Date 233 | defunciones <- defunciones %>% 234 | mutate(fecha_defuncion = as.Date(fecha_defuncion)) 235 | 236 | # Pintamos la mortalidad observada y la estimada junto con su intervalo de confianza 237 | plot_ly(defunciones, type = "scatter", mode = "lines") %>% 238 | add_trace(x = ~fecha_defuncion, y = ~defunciones_observadas, name = "Observadas", 239 | line = list(color = "black")) %>% 240 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas, name = "Esperadas", 241 | line = list(color = "rgb(22, 96, 167)")) %>% 242 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q99, name = "Esperadas lim. sup.", 243 | line = list(color = "gray", width = 0.5, dash = "dash")) %>% 244 | add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q01, name = "Esperadas lim. inf.", 245 | fill = "tonexty", fillcolor="rgba(22, 96, 167, 0.3)", 246 | line = list(color = "gray", width = 0.5, dash = "dash")) %>% 247 | layout(title = "Mortalidad en España", 248 | xaxis = list( 249 | title = "Fecha", 250 | rangeselector = list( 251 | buttons = list( 252 | list( 253 | count = 3, 254 | label = "3 meses", 255 | step = "month", 256 | stepmode = "backward"), 257 | list( 258 | count = 6, 259 | label = "6 meses", 260 | step = "month", 261 | stepmode = "backward"), 262 | list( 263 | label = "todo", 264 | step = "all") 265 | )), 266 | 267 | rangeslider = list(type = "date")), 268 | yaxis = list(title = "Defunciones") 269 | ) 270 | ``` 271 | 272 | 273 | ## Animaciones 274 | 275 | En `plot_ly` contamos con una propiedad estética para animar los gráficos: `frame`. También soporta un parámetro `ids` para suavizar las transiciones con el mismo identificador. 276 | 277 | Para visualizar los siguientes ejemplos, necesitarás tener instalado el paquete `gapminder`, que contiene datos de esperanza de vida, PIB per cápita y población por país y año. 278 | 279 | ```{r, eval=FALSE} 280 | # Ejecuta la siguiente línea en el caso de que no lo tengas instalado 281 | install.packages("gapminder") 282 | ``` 283 | 284 | ```{r} 285 | # Cargamos los datos de gapminder 286 | data(gapminder, package = "gapminder") 287 | 288 | # Este es el gráfico base, sin animar 289 | p <- gapminder %>% 290 | plot_ly(x = ~gdpPercap, y = ~lifeExp, size = ~pop, 291 | text = ~country, color = ~continent, hoverinfo = "text") %>% 292 | layout(xaxis = list(type = "log")) 293 | 294 | p 295 | ``` 296 | Para animarlo, añadimos la capa a animar, especificando frame y, opcionalmente, ids (solo es necesario si queremos suavizar las transiciones entre objetos). También debemos aplicar la función `animation_opts`. Alguno de sus argumentos son: 297 | 298 | * `frame`: los milisegundos que dura cada unidad de frame. 299 | * `transition`: los milisegundos que dura la transición (por defecto toma el mismo valor que `frame`). 300 | * `easing`: el tipo de transición ([aquí](https://github.com/plotly/plotly.js/blob/master/src/plots/animation_attributes.js) tienes todas). Algunas son: `linear`, `quad`, `cubic`, `sin`, `elastic`, `bounce`, ... 301 | 302 | ```{r} 303 | p %>% 304 | add_markers(frame = ~year, ids = ~country) %>% 305 | animation_opts(frame = 1000, easing = "linear", redraw = FALSE) 306 | ``` 307 | 308 | > Prueba a cambiar el tipo de transición (`easing`) por otro y observa el efecto. 309 | 310 | Podemos personalizar la posición del botón de animación. 311 | 312 | ```{r} 313 | p %>% 314 | add_markers(frame = ~year, ids = ~country) %>% 315 | animation_opts(frame = 1000, easing = "linear", redraw = FALSE) %>% 316 | animation_button(x = 1, xanchor = "right", y = 0, yanchor = "bottom") 317 | ``` 318 | 319 | Y también podemos personalizar el _slider_ de animación. 320 | 321 | ```{r} 322 | # Para animarlo: 323 | # 1. Añadimos la capa a animar, especificando frame y, opcionalmente, ids 324 | # 2. Configramos la animación mediante animation_opts, _button y _slider 325 | p %>% 326 | add_markers(frame = ~year, ids = ~country) %>% 327 | animation_opts(frame = 1000, easing = "linear", redraw = FALSE) %>% 328 | animation_button(x = 1, xanchor = "right", y = 0, yanchor = "bottom") %>% 329 | animation_slider(currentvalue = list(prefix = "Año ")) 330 | ``` 331 | 332 | > Consulta la documentación de `animation_opts`, `animation_button` y `animation_slider`. 333 | 334 | ## Profundiza 335 | 336 | Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias: 337 | 338 | * [Chuleta de plotly](https://images.plot.ly/plotly-documentation/images/r_cheat_sheet.pdf): sintetiza las funciones más habituales para plotly. Muy útil para tener a mano a la hora de utilizar la librería. 339 | * [Referencia completa de atributos de plotly](https://plotly.com/r/reference): documenta todos los posibles atributos que se pueden establecer por cada tipo de gráfico. 340 | * [Más opciones en la barra de herramientas de plotly](https://plotly-r.com/control-modebar.html): consúltalo para crear botones personalizados o controlar la forma en la que se descarga un gráfico como imagen. 341 | * [Controles de plotly](https://plotly.com/r/#controls): documentación completa sobre los controles de interacciones de plotly. 342 | * [Animaciones acumuladas](https://plotly.com/r/cumulative-animations/): documenta cómo realizar animaciones acumuladas (por ejemplo, el efecto de una línea que va avanzando poco a poco) 343 | * [Más sobre animaciones en plotly](https://plotly-r.com/animating-views.html): hay varios ejemplos completos de animaciones con plotly. 344 | 345 | ## Conclusiones 346 | 347 | Nos podemos quedar con las siguientes ideas como resumen de este tema: 348 | 349 | * Los gráficos en plotly traen una barra de acciones con bastantes opciones por defecto. Conviene personalizarla según las opciones que realmente vaya a necesitar el usuario. 350 | * Podemos añadir botones y selectores a los gráficos de plotly para disparar acciones que alteran la visualización. 351 | * Las animaciones cuentan con un estético a mapear nuevo: `frame`. Opcionalmente usaremos `ids` si necesitamos suavizar las transiciones entre un mismo objeto. 352 | 353 | ## Actividades 354 | 355 | ### Actividad 1 356 | 357 | Utilizando los datos del dataset de `penguins`, pinta un gráfico de puntos que muestre la relación entre longitud y profunidad del pico. Añade un selector (_dropdown_) que permita al usuario elegir si quiere ver los datos de los machos, las hembras o ambos. 358 | 359 | ### Actividad 2 360 | 361 | Lee los datos de evolución de la población en España (dat/poblacion_espana.csv). Crea una animación que muestre un gráfico de líneas, donde el eje `x` muestra la edad de inicio del rango (edad_desde), y el eje `y` muestra la población en ese rango. Anima el gráfico para que vaya mostrando la evolución año a año. 362 | 363 | -------------------------------------------------------------------------------- /06_plotly_avanzado_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Soluciones capítulo 6' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | 10 | ```{r, message=FALSE} 11 | library(dplyr) 12 | library(tidyr) 13 | library(palmerpenguins) 14 | library(plotly) 15 | ``` 16 | 17 | 18 | ### Actividad 1 19 | 20 | Utilizando los datos del dataset de `penguins`, pinta un gráfico de puntos que muestre la relación entre longitud y profunidad del pico. Añade un selector (_dropdown_) que permita al usuario elegir si quiere ver los datos de los machos, las hembras o ambos. 21 | 22 | ```{r} 23 | updatemenus <- list( 24 | list( 25 | buttons = list( 26 | list(label = "Ambos", 27 | method = "update", 28 | args = list( 29 | list(visible = c(TRUE, TRUE)) 30 | )), 31 | list(label = "Hembras", 32 | method = "update", 33 | args = list( 34 | list(visible = c(TRUE, FALSE)) 35 | )), 36 | list(label = "Machos", 37 | method = "update", 38 | args = list( 39 | list(visible = c(FALSE, TRUE)) 40 | )) 41 | ))) 42 | 43 | penguins_f <- filter(penguins, sex == "female") 44 | penguins_m <- filter(penguins, sex == "male") 45 | 46 | plot_ly(penguins_f, type = "scatter", mode = "markers", 47 | x = ~bill_length_mm, y = ~bill_depth_mm, color = I("purple"), 48 | name = "Hembras") %>% 49 | add_trace(data = penguins_m, color = I("orange"), name = "Machos") %>% 50 | layout(updatemenus = updatemenus) 51 | ``` 52 | 53 | ### Actividad 2 54 | 55 | Lee los datos de evolución de la población en España (dat/poblacion_espana.csv). Crea una animación que muestre un gráfico de líneas, donde el eje `x` muestra la edad de inicio del rango (edad_desde), y el eje `y` muestra la población en ese rango. Anima el gráfico para que vaya mostrando la evolución año a año. 56 | 57 | ```{r} 58 | poblacion <- read.csv("dat/poblacion_espana.csv") 59 | 60 | plot_ly(poblacion, type = "scatter", mode = "lines", 61 | x = ~edad_desde, y = ~poblacion, frame = ~anio, name = "Población") %>% 62 | layout(title = "Evolución de la población española", 63 | xaxis = list(title = "Rango edad")) 64 | ``` 65 | -------------------------------------------------------------------------------- /08_flexdashboard_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Soluciones capítulo 8" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | output: 8 | html_document: 9 | highlight: null 10 | --- 11 | 12 | Para probar que se genera correctamente el dashboard con flexdashboard, tendrás que copiar el código a un .Rmd y renderizarlo p.e. desde RStudio. 13 | 14 | 15 | ````markdown 16 | --- 17 | title: "Airbnb en Madrid" 18 | output: 19 | flexdashboard::flex_dashboard: 20 | orientation: rows 21 | vertical_layout: fill 22 | --- 23 | 24 | `r ''````{r setup, include=FALSE} 25 | library(flexdashboard) 26 | library(plotly) 27 | library(dplyr) 28 | library(leaflet) 29 | ``` 30 | 31 | `r ''````{r} 32 | # Lectura y tratamiento de datos 33 | listings <- read.csv("dat/listings.csv") 34 | ``` 35 | 36 | Row 37 | ----------------------------------------------------------------------- 38 | 39 | ### Número de alojamientos 40 | 41 | `r ''````{r} 42 | valueBox(nrow(listings), icon = "fa-home") 43 | ``` 44 | 45 | `r ''````{r} 46 | valueBox(nrow(listings), icon = "fa-home") 47 | ``` 48 | 49 | ### Precio medio por noche 50 | 51 | `r ''````{r} 52 | valueBox(round(mean(listings$price)), icon = "fa-euro") 53 | ``` 54 | 55 | 56 | ### % alojamientos completos 57 | 58 | `r ''````{r} 59 | count_entire <- nrow(listings[listings$room_type == "Entire home/apt", ]) 60 | valueBox(round(100 * count_entire / nrow(listings)), icon = "fa-home") 61 | ``` 62 | 63 | 64 | ### % habitaciones privadas 65 | 66 | `r ''````{r} 67 | count_private <- nrow(listings[listings$room_type == "Private room", ]) 68 | valueBox(round(100 * count_private / nrow(listings)), icon = "fa-home") 69 | ``` 70 | 71 | 72 | Row 73 | ----------------------------------------------------------------------- 74 | 75 | ### Distribución geográfica 76 | 77 | `r ''````{r} 78 | listings_1k <- listings %>% 79 | sample_n(1000) 80 | 81 | paleta_tipo <- colorFactor("Set1", domain = unique(listings_1k$room_type)) 82 | 83 | leaflet(listings_1k) %>% 84 | addProviderTiles("CartoDB.Positron") %>% 85 | setView(lng = -3.69, lat = 40.43, zoom = 12) %>% 86 | addCircleMarkers(lat = ~latitude, lng = ~longitude, color = ~paleta_tipo(room_type), 87 | stroke = FALSE, radius = 2, fillOpacity = 0.5) %>% 88 | addLegend( 89 | position = "bottomright", 90 | pal = paleta_tipo, 91 | values = ~room_type, 92 | title = "Tipo de habitación" 93 | ) 94 | ``` 95 | 96 | ### Alojamientos por tipo de habitación 97 | 98 | `r ''````{r} 99 | count_by_type <- listings %>% 100 | group_by(room_type) %>% 101 | summarise(count = n()) 102 | 103 | plot_ly(count_by_type, type = "bar", x = ~room_type, y = ~count) 104 | ``` 105 | 106 | ```` 107 | -------------------------------------------------------------------------------- /09_shiny_basico.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "9 - Shiny - nivel básico" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | output: 8 | html_document: 9 | highlight: null 10 | --- 11 | 12 | ## ¿Qué vamos a hacer? 13 | 14 | En capítulos anteriores hemos visto bastantes utilidades para visualizar datos de manera interactiva: `plotly` para crear gráficos, `leaflet` para mapas, `R Markdown` para documentos y `flexdashboard` para cuadros de mando. En estos dos capítulos veremos cómo construir aplicaciones web interactivas directamente desde R, utilizando Shiny. 15 | 16 | Deberás tener el paquete `shiny` instalado. 17 | 18 | ```{r, eval=FALSE} 19 | # Ejecuta el comando en el caso de que no lo tengas instalado 20 | install.packages("shiny") 21 | ``` 22 | 23 | Antes de continuar, explora la [galería de ejemplos de Shiny](https://shiny.rstudio.com/gallery/#demos). También te resultará muy útil tener a mano la [chuleta de Shiny](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf). 24 | 25 | Este capítulo viene acompañado de una carpeta de ejemplos, que deberás tener a mano para poder ejecutar las aplicaciones que iremos viendo. 26 | 27 | ## Arquitectura 28 | 29 | ### Interfaz gráfica y servidor 30 | 31 | Una aplicación de shiny suele estar generada por script llamado `app.R`. Está formada por dos elementos principales: 32 | 33 | * La interfaz gráfica: contiene el _layout_ y aspecto de la aplicación. Genera el HTML que verá el usuario. 34 | * Las funciones de servidor: controla la lógica necesaria para lanzar la aplicación y responder a las acciones del usuario (clicks, selecciones, etc.). 35 | 36 | Estos dos elementos pueden estar en el mismo script `app.R` (útil si es una aplicación muy sencilla), o en tres separados (más recomendable para casos complejos): `app.R`, `ui.R` y `server.R`. 37 | 38 | Para ejecutar la aplicación, hay que llamar a `shinyApp(ui, server)`. 39 | 40 | Hay que tener en cuenta que, con Shiny, vamos a desarrollar aplicaciones web que necesitan de un servidor. Hasta ahora, generábamos documentos html _standalone_ que solo necesitaban un explorador web para ser visualizados, pero no un servidor. Esto significa que es necesario un sitio (un ordenador propio, o en la nube) que lo ejecute y responda a las acciones del usuario. Por este motivo, cuando lancemos una aplicación en local, veremos que R Studio se queda esperando, y nos dice en qué puerto ha desplegado la aplicación. 41 | 42 | Por ejemplo, prueba a lanzar: 43 | 44 | ``` 45 | library(shiny) 46 | runExample("01_hello") 47 | ``` 48 | 49 | Verás que sale un mensaje en la consola parecido a este: 50 | 51 | ![](resources/09_shiny_basico/run_shiny.png) 52 | 53 | Cuando cierres la ventana que se abre al ejecutarlo, R Studio matará la aplicación. Si la has abierto en un explorador adicional, verás que se queda en gris: esto significa que el servidor ya no está escuchando y no podrás interactuar con ella. 54 | 55 | ### Nuestra primera aplicación 56 | 57 | Vamos a crear nuestra primera aplicación en shiny: un histograma en el que el usuario puede ajustar el número de _bins_ utilizado. 58 | 59 | Al comienzo del script, es habitual tener todas las librerías que vamos a necesitar: 60 | 61 | ``` 62 | # Librerías necesarias 63 | library(shiny) 64 | library(palmerpenguins) 65 | library(ggplot2) 66 | ``` 67 | 68 | La interfaz gráfica tendrá: 69 | 70 | * Un panel lateral con los _inputs_ del usuario: en este caso, un selector del tipo _slider_ para elegir el número de _bins_. 71 | * Un panel principal con el _output_: el gráfico generado. 72 | 73 | ``` 74 | # La interfaz gráfica 75 | ui <- fluidPage( 76 | 77 | # El título de la aplicación 78 | titlePanel("Distribución del peso en los pingüinos"), 79 | 80 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 81 | # y un panel principal más grande a la derecha 82 | sidebarLayout( 83 | 84 | # Usaremos el panel izquierdo para los inputs 85 | sidebarPanel( 86 | 87 | # Input de tipo slider, para seleccionar el número 88 | # de bins del histograma 89 | sliderInput(inputId = "bins", 90 | label = "Número de bins:", 91 | min = 1, 92 | max = 50, 93 | value = 25) 94 | 95 | ), 96 | 97 | # El panel principal con los outputs 98 | mainPanel( 99 | 100 | # El histograma 101 | plotOutput(outputId = "histogram") 102 | 103 | ) 104 | ) 105 | ) 106 | ``` 107 | 108 | > Tienes una referencia más completa de los elementos de interfaz que puedes utilizar en la [chuleta](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf), en la sección de _layouts_ e _inputs_. 109 | 110 | Y un servidor, con una función `renderPlot`, con estas características: 111 | 112 | * Es reactiva: se vuelve a ejecutar cada vez que cambia alguno de sus inputs. En este caso, cada vez que cambia `input$bins`. 113 | * La salida es un gráfico. 114 | 115 | ``` 116 | # El servidor 117 | server <- function(input, output) { 118 | 119 | # Genera el histograma con el número de bins seleccionado 120 | output$histogram <- renderPlot({ 121 | ggplot(penguins, aes(x = body_mass_g)) + 122 | geom_histogram(bins = input$bins) 123 | }) 124 | 125 | } 126 | ``` 127 | 128 | Para generar la aplicación, utilizamos: 129 | 130 | ``` 131 | shinyApp(ui = ui, server = server) 132 | ``` 133 | 134 | Puedes lanzar este ejemplo desde la consola con: 135 | 136 | ``` 137 | library(shiny) 138 | runApp("examples/01_histograma") 139 | ``` 140 | 141 | ![](resources/09_shiny_basico/01_histograma.png) 142 | 143 | También puedes ejecutarla desde R Studio, abriendo el script `app.R` y haciendo click en `Run App`. 144 | 145 | ![](resources/09_shiny_basico/run_app.png) 146 | 147 | ### Gráficos interactivos de plotly 148 | 149 | Lo habitual es que, para aprovechar la interactividad de Shiny, utilicemos elementos interactivos. Vamos a ver un ejemplo sacando un gráfico de plotly. 150 | 151 | La interfaz gráfica será parecida al caso anterior, pero en este caso: 152 | 153 | * Ponemos un selector de lista, para permitir que el usuario elija la propiedad (longitud del pico, peso, ...) sobre la que mostrar el histograma. 154 | * La salida ya no será un _plot_ estático, sino un gráfico de _plotly_. Utilizaremos `plotlyOutput` en lugar de `plotOutput`. 155 | 156 | ``` 157 | library(shiny) 158 | library(palmerpenguins) 159 | library(plotly) 160 | 161 | # La interfaz gráfica 162 | ui <- fluidPage( 163 | 164 | # El título de la aplicación 165 | titlePanel("Distribución de las propiedades de los pingüinos"), 166 | 167 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 168 | # y un panel principal más grande a la derecha 169 | sidebarLayout( 170 | 171 | # Usaremos el panel izquierdo para los inputs 172 | sidebarPanel( 173 | 174 | # Input de tipo select sobre una lista de opciones 175 | selectInput( 176 | inputId = "property", 177 | label = "Propiedad", 178 | choices = list("Longitud del pico" = "bill_length_mm", 179 | "Profundidad del pico" = "bill_depth_mm", 180 | "Longitud de la aleta" = "flipper_length_mm", 181 | "Peso" = "body_mass_g") 182 | ) 183 | 184 | ), 185 | 186 | # El panel principal con los outputs 187 | mainPanel( 188 | 189 | # El histograma 190 | plotlyOutput(outputId = "histogram") 191 | 192 | ) 193 | ) 194 | ) 195 | ``` 196 | 197 | La función de servidor ahora producirá un gráfico de plotly, por lo que usaremos `renderPlotly` en lugar de `renderPlot`. 198 | 199 | ``` 200 | # El servidor 201 | server <- function(input, output) { 202 | 203 | # Genera el histograma sobre la propiedad seleccionada 204 | output$histogram <- renderPlotly({ 205 | plot_ly(penguins, x = ~get(input$property), type = "histogram", nbinsx = input$bins) %>% 206 | layout(xaxis = list(title = "Propiedad")) 207 | }) 208 | 209 | } 210 | 211 | # Generamos la aplicación 212 | shinyApp(ui = ui, server = server) 213 | ``` 214 | 215 | > Fíjate en el truco de get(). La estamos utilizando para transformar una cadena de texto en un objeto. 216 | 217 | Puedes ejecutar el ejemplo lanzando: 218 | 219 | ``` 220 | library(shiny) 221 | runApp("examples/02_plotly") 222 | ``` 223 | 224 | ![](resources/09_shiny_basico/02_plotly.png) 225 | 226 | ### Mapas de leaflet 227 | 228 | También podemos representar mapas con `leaflet`. Con respecto a los ejemplos anteriores, solo cambia: 229 | 230 | * En la interfaz gráfica, el output se genera con `leafletOutput(map_id)`. 231 | * En el servidor, se utiliza la función `renderLeaflet`. 232 | 233 | Para ilustarlo, vamos a ver un ejemplo muy simple, en el que permitimos al usuario elegir el _tile_ del mapa entre una serie de opciones. 234 | 235 | ``` 236 | library(shiny) 237 | library(leaflet) 238 | 239 | # La interfaz gráfica 240 | ui <- fluidPage( 241 | 242 | # El título de la aplicación 243 | titlePanel("Mapas base de leaflet"), 244 | 245 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 246 | # y un panel principal más grande a la derecha 247 | sidebarLayout( 248 | 249 | # Usaremos el panel izquierdo para los inputs 250 | sidebarPanel( 251 | 252 | # Input de tipo select sobre una lista de opciones, para los mapas base 253 | selectizeInput( 254 | inputId = "provider_name", 255 | label = "Tile", 256 | choices = names(providers) 257 | ) 258 | 259 | ), 260 | 261 | # El panel principal con los outputs 262 | mainPanel( 263 | 264 | # El histograma 265 | leafletOutput(outputId = "map") 266 | 267 | ) 268 | ) 269 | ) 270 | 271 | # El servidor 272 | server <- function(input, output) { 273 | 274 | # Genera el mapa con el proveedor de tiles seleccionado 275 | output$map <- renderLeaflet({ 276 | leaflet() %>% 277 | addProviderTiles(input$provider_name) %>% 278 | setView(lng = -3.69, lat = 40.43, zoom = 6) 279 | }) 280 | 281 | } 282 | 283 | # Generamos la aplicación 284 | shinyApp(ui = ui, server = server) 285 | ``` 286 | 287 | > No todos los mapas base funcionarán, ya que algunos necesitan _api keys_. 288 | 289 | Puedes ejecutar el ejemplo con: 290 | 291 | ``` 292 | library(shiny) 293 | runApp("examples/03_leaflet") 294 | ``` 295 | 296 | ![](resources/09_shiny_basico/03_leaflet.png) 297 | 298 | > Tienes una referencia más completa de los elementos de salida que puedes utilizar en la [chuleta](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf), en la sección de _outputs_. Fíjate en que puedes generar texto, tablas estáticas o interactivas (_DataTables_), etc. 299 | 300 | ## Interfaz de usuario 301 | 302 | ### Layout 303 | 304 | Vamos a profundizar en la creación de interfaces de usuario. El _layout_ es la distribución que siguen los diferentes componentes de nuestra aplicación. Utilizamos la función `fluidPage` para crear una vista que se ajusta automáticamente al tamaño del explorador del usuario. Y creamos la interfaz añadiendo elementos de forma jerárquica dentro de dicha función. 305 | 306 | Una distribución muy habitual es la que hemos visto en los ejemplos anteriores, con un panel lateral para los _inputs_ y otro principal para los _outputs_. 307 | 308 | ``` 309 | ui <- fluidPage( 310 | titlePanel("título"), 311 | 312 | sidebarLayout( 313 | sidebarPanel("panel de inputs"), 314 | mainPanel("panel principal (outputs)") 315 | ) 316 | ) 317 | ``` 318 | 319 | ![](resources/09_shiny_basico/layout_01.png) 320 | 321 | > Consulta todas las opciones de cada uno de los elementos en su ayuda, como p.e. en `?sidebarLayout`. Prueba a modificar el ejemplo anterior, situando el panel de _inputs_ a la derecha en lugar de a la izquierda. 322 | 323 | > Consulta la [guía completa de layouts en Shiny](https://shiny.rstudio.com/articles/layout-guide.html) para explorar más opciones. 324 | 325 | ### Elementos HTML 326 | 327 | Dentro del _panel_, podemos añadir elementos HTML como títulos, párrafos o imágenes. Los más habituales son: 328 | 329 | | función | Descripción | 330 | | ------------- | ---------------------------- | 331 | | p | Párrafo | 332 | | h1 ... h6 | Título de nivel 1 hasta 6 | 333 | | a | Link | 334 | | code | Bloque de código formateado | 335 | | img | Imagen | 336 | | strong | Texto en negrita | 337 | | em | Texto en cursiva | 338 | | br | Salto de línea | 339 | 340 | Como ejemplo, vamos a pintar una serie de elementos de interfaz. 341 | 342 | ``` 343 | ui <- fluidPage( 344 | titlePanel("título"), 345 | 346 | sidebarLayout( 347 | sidebarPanel("panel de inputs"), 348 | mainPanel( 349 | h1("Título de nivel 1"), 350 | h2("Título de nivel 2"), 351 | h3("Título de nivel 3"), 352 | h4("Título de nivel 4"), 353 | h5("Título de nivel 5"), 354 | h5("Título de nivel 6"), 355 | p("Párrafo"), 356 | br(), 357 | strong("Texto en negrita"), 358 | br(), 359 | em("Texto en cursiva"), 360 | br(), 361 | code("bloque de código formateado"), 362 | br(), 363 | a("Link", src="https://shiny.rstudio.com/"), 364 | br(), 365 | img("Imagen", src="https://shiny.rstudio.com/images/logoRStudio.svg") 366 | ) 367 | ) 368 | ) 369 | ``` 370 | 371 | ![](resources/09_shiny_basico/layout_02.png) 372 | 373 | ## Controles 374 | 375 | Los controles son los _widgets_ con los que puede interactuar el usuario para modificar los _inputs_ de la aplicación. Shiny nos proporciona los siguientes: 376 | 377 | ![](resources/09_shiny_basico/control_widgets.png) 378 | 379 | > Puedes comprobar cómo es la interacción con ellos en la [galería de widgets de shiny](https://shiny.rstudio.com/gallery/widget-gallery.html). 380 | 381 | Las funciones correspondientes son: 382 | 383 | | función | Descripción | 384 | | ------------- | ---------------------------- | 385 | | actionButton | Botón | 386 | | checkboxInput | Checkbox | 387 | | checkboxGroupInput | Grupo de checkboxes | 388 | | dateInput | Selector de fecha | 389 | | dateRangeInput | Selector de rango de fecha | 390 | | fileInput | Botón para subir un fichero | 391 | | helpText | Texto de ayuda | 392 | | numericInput | Input para un valor numérico | 393 | | radioButtons | Selector de tipo radio (solo un valor permitido del grupo) | 394 | | selectInput | Selector de lista de valores | 395 | | sliderInput | Input para un valor numérido con un _slider_ | 396 | | textInput | Input para una cadena de texto | 397 | 398 | El primer argumento de todos estos controles es el `inputId`. Este ID es el que nos permite conectarlo a las funciones reactivas de servidor y modificar los _outputs_ en función de los _inputs_. 399 | 400 | Vamos a verlo con un ejemplo muy sencillo, en el que simplemente repetimos el texto que ha introducido el usuario: 401 | 402 | ``` 403 | library(shiny) 404 | 405 | # La interfaz gráfica 406 | ui <- fluidPage( 407 | 408 | # El título de la aplicación 409 | titlePanel("título"), 410 | 411 | # Panel con barra al lateral 412 | sidebarLayout( 413 | 414 | # Usaremos el panel izquierdo para los inputs 415 | sidebarPanel( 416 | 417 | # Input de tipo texto, con ID input_text 418 | textInput( 419 | inputId = "input_text", 420 | label = "Escribe algo" 421 | ) 422 | 423 | ), 424 | 425 | # El panel principal con los outputs 426 | mainPanel( 427 | 428 | # Output de tipo texto, con ID output_text 429 | textOutput(outputId = "output_text") 430 | 431 | ) 432 | ) 433 | ) 434 | 435 | # El servidor 436 | server <- function(input, output) { 437 | 438 | # Genera el output output_text utilizando input_text 439 | output$output_text <- renderText({ 440 | paste("El usuario ha escrito:", input$input_text) 441 | }) 442 | 443 | } 444 | 445 | # Generamos la aplicación 446 | shinyApp(ui = ui, server = server) 447 | ``` 448 | 449 | Puedes ejecutar el ejemplo con: 450 | 451 | ``` 452 | library(shiny) 453 | runApp("examples/04_widget") 454 | ``` 455 | 456 | ![](resources/09_shiny_basico/04_widget.png) 457 | 458 | ## Profundiza 459 | 460 | Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias: 461 | 462 | * [Chuleta de Shiny](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf): muy útil para tener a mano los comandos más habituales de Shiny. 463 | * [Galeria](https://shiny.rstudio.com/gallery/): ejemplos con código y resultado de varios cuadros de mando y aplicaciones desarrolladas con R Shiny. 464 | * [Tutoriales en vídeo](https://shiny.rstudio.com/tutorial/): una serie de tutoriales de todos los niveles sobre el manejo de Shiny. 465 | * [Guía de layouts en Shiny](https://shiny.rstudio.com/articles/layout-guide.html): artículo más completo sobre el uso de _layouts_. 466 | 467 | ## Conclusiones 468 | 469 | Nos podemos quedar con las siguientes ideas como resumen de este tema: 470 | 471 | * Con Shiny creamos aplicaciones web utilizando R. 472 | * Una aplicación tiene dos componentes: la interfaz gráfica y el servidor. 473 | * Los controles de usuario son los _inputs_. 474 | * Como _outputs_ podemos generar gráficas, tablas, texto, mapas, ... 475 | 476 | ## Actividades 477 | 478 | ### Actividad 1 479 | 480 | Crea una aplicación, utilizando el dataset de los pingüinos, que tenga: 481 | 482 | * Como inputs, unos _radio buttons_ para elegir el sexo. 483 | * Como outputs: 484 | 485 | * Un gráfico de puntos de _plotly_ mostrando en el eje x el peso, y en el eje y la longitud de la aleta, y con un color diferente por especie, solo para el sexo escogido. 486 | * Una _datatable_ paginada con el detalle de especie, sexo, peso y longitud de la aleta, para el sexo escogido. 487 | 488 | ### Actividad 2 489 | 490 | Crea una aplicación de shiny para visualizar las líneas y paradas del metro de Madrid sobre un mapa interactivo. 491 | 492 | Tienes disponible los datos en `dat/lineas_metro.geojson` y `dat/paradas_metro_madrid.geojson`. 493 | 494 | La aplicación tendrá: 495 | 496 | * Como inputs, el listado de líneas disponibles. 497 | * Como output, un mapa de `leaflet` mostrando la línea y sus paradas sobre Madrid. 498 | -------------------------------------------------------------------------------- /09_shiny_basico_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Soluciones capítulo 9" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | output: 8 | html_document: 9 | highlight: null 10 | --- 11 | 12 | Para probar correctamente las aplicaciones shiny, tendrás que copiar y pegar el código a un intérprete de R. 13 | 14 | 15 | ```{r, include=FALSE} 16 | library(dplyr) 17 | library(tidyr) 18 | library(shiny) 19 | library(palmerpenguins) 20 | library(plotly) 21 | library(leaflet) 22 | library(DT) 23 | library(sf) 24 | ``` 25 | 26 | ### Actividad 1 27 | 28 | Crea una aplicación, utilizando el dataset de los pingüinos, que tenga: 29 | 30 | * Como inputs, unos _radio buttons_ para elegir el sexo. 31 | * Como outputs: 32 | 33 | * Un gráfico de puntos de _plotly_ mostrando en el eje x el peso, y en el eje y la longitud de la aleta, y con un color diferente por especie, solo para el sexo escogido. 34 | * Una _datatable_ paginada con el detalle de especie, sexo, peso y longitud de la aleta, para el sexo escogido. 35 | 36 | ```{r, eval=FALSE} 37 | # La interfaz gráfica 38 | ui <- fluidPage( 39 | sidebarLayout( 40 | sidebarPanel( 41 | radioButtons( 42 | inputId = "sex", 43 | label = "Sexo", 44 | choices = c("female", "male") 45 | ) 46 | ), 47 | 48 | mainPanel( 49 | plotlyOutput(outputId = "chart"), 50 | dataTableOutput(outputId = "table") 51 | ) 52 | ) 53 | ) 54 | 55 | # El servidor 56 | server <- function(input, output) { 57 | 58 | output$chart <- renderPlotly({ 59 | tmp <- filter(penguins, !is.na(sex), sex == input$sex) 60 | plot_ly(tmp, type = "scatter", mode = "markers", 61 | x = ~body_mass_g, y = ~flipper_length_mm) 62 | }) 63 | 64 | output$table <- renderDataTable({ 65 | penguins %>% 66 | filter(!is.na(sex), sex == input$sex) %>% 67 | select(species, sex, body_mass_g, flipper_length_mm) 68 | }) 69 | } 70 | 71 | # Generamos la aplicación 72 | shinyApp(ui = ui, server = server) 73 | ``` 74 | 75 | ### Actividad 2 76 | 77 | Crea una aplicación de shiny para visualizar las líneas y paradas del metro de Madrid sobre un mapa interactivo. 78 | 79 | Tienes disponible los datos en `dat/lineas_metro.geojson` y `dat/paradas_metro_madrid.geojson`. 80 | 81 | La aplicación tendrá: 82 | 83 | * Como inputs, el listado de líneas disponibles. 84 | * Como output, un mapa de `leaflet` mostrando la línea y sus paradas sobre Madrid. 85 | 86 | ```{r, eval=FALSE} 87 | lineas_metro <- read_sf("dat/lineas_metro.geojson") 88 | lineas_select <- lineas_metro$Linea 89 | names(lineas_select) <- lineas_metro$Texto 90 | 91 | # La interfaz gráfica 92 | ui <- fluidPage( 93 | sidebarLayout( 94 | sidebarPanel( 95 | selectInput( 96 | inputId = "linea", 97 | label = "Línea", 98 | choices = lineas_select 99 | ) 100 | ), 101 | 102 | mainPanel( 103 | leafletOutput(outputId = "map") 104 | ) 105 | ) 106 | ) 107 | 108 | # El servidor 109 | server <- function(input, output) { 110 | 111 | paradas_metro <- read_sf("dat/paradas_metro_madrid.geojson") 112 | lineas_metro <- read_sf("dat/lineas_metro.geojson") 113 | 114 | colores_lineas <- c( 115 | "L1" = "#38a3dc", 116 | "L2" = "#f40104", 117 | "L3" = "#fbe115", 118 | "L4" = "#944247", 119 | "L5" = "#96bf0e", 120 | "L6" = "#9fa4a6", 121 | "L7" = "#f7a64b", 122 | "L8" = "#f500ff", 123 | "L9" = "#a3228d", 124 | "L10" = "#174594", 125 | "L11" = "#185b00", 126 | "L12" = "#a49a00", 127 | "Ramal" = "#090080" 128 | ) 129 | 130 | paleta_lineas <- colorFactor( 131 | palette = unname(colores_lineas), 132 | levels = names(colores_lineas) 133 | ) 134 | 135 | output$map <- renderLeaflet({ 136 | # Filtros 137 | tmp_lineas <- lineas_metro %>% 138 | filter(Linea == input$linea) 139 | tmp_paradas <- paradas_metro %>% 140 | filter(line == input$linea) 141 | 142 | leaflet(tmp_lineas) %>% 143 | addProviderTiles("CartoDB.Positron") %>% 144 | setView(lng = -3.69, lat = 40.43, zoom = 12) %>% 145 | addPolylines(data = tmp_lineas, color = ~paleta_lineas(Linea), opacity = 0.8) %>% 146 | addCircleMarkers(data = tmp_paradas, stroke = FALSE, radius = 5, fillOpacity = 0.5) %>% 147 | addLegend( 148 | position = "bottomright", 149 | pal = paleta_lineas, 150 | values = ~Linea, 151 | title = "Línea" 152 | ) 153 | }) 154 | 155 | } 156 | 157 | # Generamos la aplicación 158 | shinyApp(ui = ui, server = server) 159 | ``` 160 | 161 | -------------------------------------------------------------------------------- /10_shiny_avanzado.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "10 - Shiny - nivel avanzado" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | output: 8 | html_document: 9 | highlight: null 10 | --- 11 | 12 | ## ¿Qué vamos a hacer? 13 | 14 | En el capítulo anterior empezamos a utilizar Shiny para crear aplicaciones web interactivas. Aprendimos a crear una interfaz gráfica y un servidor que reaccione ante las acciones del usuario. 15 | 16 | En este nuevo capítulo profundizaremos sobre la reactividad en Shiny y veremos ejemplos de uso más avanzados. Te resultará muy útil tener a mano la [chuleta de Shiny](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf). 17 | 18 | Este capítulo, al igual que el anterior, viene acompañado de una carpeta de ejemplos, que deberás tener a mano para poder ejecutar las aplicaciones que iremos viendo. 19 | 20 | ## Reactividad 21 | 22 | ### Entradas, salidas y conductores 23 | 24 | La reactividad es el pegamento entre los _inputs_ de usuario y los _outputs_ generados como resultado. Una salida reactiva es aquella que genera su resultado automáticamente cuando un usuario cambia el valor de algún control. 25 | 26 | Existen tres tipos de objetos en la programación reactiva: 27 | 28 | * La entrada, implementada en _Shiny_ con el objeto `input`. 29 | * La salida, implementada con el objeto `output`. 30 | * El conductor (opcional), implementada con la funcion `reactive`. Son componentes que se colocan entre las entradas y las salidas. Se suelen utilizar para encapsular operaciones computacionalmente costosas y evitar que se re-evalúen más veces de las necesarias. Veremos un ejemplo de uso un poco más adelante. 31 | 32 | Cuando el valor de alguna entrada cambia, provoca que se re-calculen todas las salidas (y, opcionalmente, conductores) que dependan de ella. 33 | 34 | Vamos a fijarnos en uno de los ejemplos del anterior capítulo: 35 | 36 | ``` 37 | library(shiny) 38 | library(palmerpenguins) 39 | library(plotly) 40 | 41 | # La interfaz gráfica 42 | ui <- fluidPage( 43 | 44 | # El título de la aplicación 45 | titlePanel("Distribución de las propiedades de los pingüinos"), 46 | 47 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 48 | # y un panel principal más grande a la derecha 49 | sidebarLayout( 50 | 51 | # Usaremos el panel izquierdo para los inputs 52 | sidebarPanel( 53 | 54 | # Input de tipo select sobre una lista de opciones 55 | selectInput( 56 | inputId = "property", 57 | label = "Propiedad", 58 | choices = list("Longitud del pico" = "bill_length_mm", 59 | "Profundidad del pico" = "bill_depth_mm", 60 | "Longitud de la aleta" = "flipper_length_mm", 61 | "Peso" = "body_mass_g") 62 | ) 63 | 64 | ), 65 | 66 | # El panel principal con los outputs 67 | mainPanel( 68 | 69 | # El histograma 70 | plotlyOutput(outputId = "histogram") 71 | 72 | ) 73 | ) 74 | ) 75 | 76 | # El servidor 77 | server <- function(input, output) { 78 | 79 | # Genera el histograma sobre la propiedad seleccionada 80 | output$histogram <- renderPlotly({ 81 | plot_ly(penguins, x = ~get(input$property), type = "histogram", nbinsx = input$bins) %>% 82 | layout(xaxis = list(title = "Propiedad")) 83 | }) 84 | 85 | } 86 | 87 | # Generamos la aplicación 88 | shinyApp(ui = ui, server = server) 89 | ``` 90 | 91 | En este caso: 92 | 93 | * La entrada es la variable con ID `property`. Se recoge a través de un `select` en la interfaz. 94 | * La salida es la variable con ID `histogram`. Es un gráfico generado en el servidor, y definido en la interfaz. La función se ejecuta cada vez que cambia su única variable de entrada, `property`. 95 | 96 | Aquí no hay ningún componente de tipo conductor. Vamos a ver un caso en el que nos resultará útil implementar uno. 97 | 98 | Vamos a hacer una calculadora de la serie de Fibonacci. La serie de Fibonacci es la que resulta de sumar los dos números previos: 1, 1, 2, 3, 5, 8, 13, ... A partir de cierta longitud, empieza a ser pesada computacionalmente. 99 | 100 | A nuestra aplicación le pasaremos hasta qué número de la serie calcular, y nos devolverá las siguientes tres cosas: la serie hasta ese número, lo que suman todos los números de la serie, y su media. 101 | 102 | Una primera aproximación para hacerlo sería esta: 103 | 104 | ``` 105 | library(shiny) 106 | 107 | # Función para calcular el enésimo número de la serie de fibonacci 108 | fibonacci <- function(n) { 109 | if (n < 1) { 110 | return(NA) 111 | } 112 | if (n < 3) { 113 | return(1) 114 | } 115 | fibonacci(n - 1) + fibonacci(n - 2) 116 | } 117 | 118 | 119 | # La interfaz gráfica 120 | ui <- fluidPage( 121 | 122 | # El título de la aplicación 123 | titlePanel("Serie de Fibonacci"), 124 | 125 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 126 | # y un panel principal más grande a la derecha 127 | sidebarLayout( 128 | 129 | # Usaremos el panel izquierdo para los inputs 130 | sidebarPanel( 131 | 132 | # Input de tipo slide 133 | numericInput(inputId = "numero", 134 | label = h3("Número"), 135 | value = 10, 136 | min = 1, 137 | max = 30), 138 | 139 | ), 140 | 141 | # El panel principal con los outputs 142 | mainPanel( 143 | 144 | h4("Serie: ", textOutput(outputId = "serie")), 145 | h4("Suma: ", textOutput(outputId = "suma")), 146 | h4("Media: ", textOutput(outputId = "media")), 147 | 148 | ) 149 | ) 150 | ) 151 | 152 | # El servidor 153 | server <- function(input, output) { 154 | 155 | # El output serie contiene toda la serie 156 | output$serie <- renderText({ 157 | serie <- sapply(1:input$numero, fibonacci) 158 | paste(serie, collapse = ", ") 159 | }) 160 | 161 | # El output suma contiene toda la suma de todos los valores de la serie 162 | output$suma <- renderText({ 163 | serie <- sapply(1:input$numero, fibonacci) 164 | sum(serie) 165 | }) 166 | 167 | # El output media contiene toda la media de todos los valores de la serie 168 | output$media <- renderText({ 169 | serie <- sapply(1:input$numero, fibonacci) 170 | mean(serie) 171 | }) 172 | 173 | } 174 | 175 | # Generamos la aplicación 176 | shinyApp(ui = ui, server = server) 177 | ``` 178 | 179 | Puedes lanzar este ejemplo haciendo: 180 | 181 | ``` 182 | library(shiny) 183 | runApp("examples/01_fibonacci_sin_conductor") 184 | ``` 185 | 186 | 187 | ![](resources/10_shiny_avanzado/1_fibonacci.png) 188 | 189 | ¿Cuál es el problema de esta implementación? La función de cálculo de la serie de Fibonacci se ejecuta 3 veces cada vez que cambia el número en el _input_, una para cada _output_. Vamos a optimizarla utilizando un conductor, para que solo se evalúe una única vez en cada cambio del valor de _input_. 190 | 191 | ``` 192 | # El servidor 193 | server <- function(input, output) { 194 | 195 | # El output serie contiene toda la serie 196 | output$serie <- renderText({ 197 | serie <- sapply(1:input$numero, fibonacci) 198 | paste(serie, collapse = ", ") 199 | }) 200 | 201 | # El output suma contiene toda la suma de todos los valores de la serie 202 | output$suma <- renderText({ 203 | serie <- sapply(1:input$numero, fibonacci) 204 | sum(serie) 205 | }) 206 | 207 | # El output media contiene toda la media de todos los valores de la serie 208 | output$media <- renderText({ 209 | serie <- sapply(1:input$numero, fibonacci) 210 | mean(serie) 211 | }) 212 | ``` 213 | 214 | Presta atención a cómo hemos definido el conductor. El cálculo debe estar como una expresión dentro de la función `reactive`. 215 | 216 | > Si intentas leer algún `input` fuera de funciones reactivas, verás que falla (las funciones reactivas son las de renderPlot, renderText, reactive, ...). 217 | 218 | Puedes lanzar este ejemplo haciendo: 219 | 220 | ``` 221 | library(shiny) 222 | runApp("examples/02_fibonacci_con_conductor") 223 | ``` 224 | 225 | > Ejecuta ambos y prueba algún número grande (p.e. 25) y comprueba que tarda menos la implementación con conductor que la sin conductor. 226 | 227 | ### Control de la reactividad 228 | 229 | En todos los ejemplos anteriores, la salida se re-evaluaba al cambiar alguno de los parámetros de entrada. En general, es útil para dar esa sensación de interacción fluida a la aplicación. Pero en algún caso, es posible que no queramos que sea así. 230 | 231 | Por ejemplo, imagina una aplicación en la que hay que completar bastantes parámetros de entrada, y la función de cálculo de las salidas es lenta. Cada vez que cambiemos uno de estos _inputs_, la aplicación se quedará calculando los _outputs_. Si tenemos cuatro, cinco valores de entrada, lanzará la evaluación al terminar de completar cada uno de ellos. En estos casos, el comportamiento habitual es esperar a tener todos los valores de entrada rellenos y luego, bajo demanda, evaluar las salidas. La acción para indicar que ya se debe evaluar suele ser un botón. 232 | 233 | Vamos a hacer una pequeña aplicación que nos muestra un histograma del peso de los pingüinos en base a los filtros de especie y sexo que escojamos. El histograma se actualizará únicamente al hacer click en un botón, y no automáticamente. 234 | 235 | ``` 236 | library(shiny) 237 | library(palmerpenguins) 238 | library(dplyr) 239 | library(ggplot2) 240 | 241 | # Extraigo todas las especies y sexos (distintos de NA) para los select 242 | all_species <- unique(penguins$species) 243 | all_sexes <- unique(penguins[!is.na(penguins$sex), ]$sex) 244 | 245 | # La interfaz gráfica 246 | ui <- fluidPage( 247 | 248 | # El título de la aplicación 249 | titlePanel("Ejemplo con botón"), 250 | 251 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 252 | # y un panel principal más grande a la derecha 253 | sidebarLayout( 254 | 255 | # Usaremos el panel izquierdo para los inputs 256 | sidebarPanel( 257 | 258 | # Input de tipo select para la especie 259 | selectInput(inputId = "especie", 260 | label = h3("Especie"), 261 | choices = all_species), 262 | 263 | # Input de tipo select para el sexo 264 | selectInput(inputId = "sexo", 265 | label = h3("Sexo"), 266 | choices = all_sexes), 267 | 268 | actionButton(inputId = "actualizar", label = "Actualizar") 269 | 270 | ), 271 | 272 | # El panel principal con los outputs 273 | mainPanel( 274 | 275 | plotOutput("histograma"), 276 | 277 | ) 278 | ) 279 | ) 280 | 281 | # El servidor 282 | server <- function(input, output) { 283 | 284 | # El output serie contiene toda la serie 285 | output$histograma <- renderPlot({ 286 | 287 | # Utilizamos input$calcular (el botón) como dependencia, para que se 288 | # recalcule al hacer click (fuera de isolate!) 289 | input$actualizar 290 | 291 | # El resto de las dependencias (valores de entrada) las metemos dentro de una expresión 292 | # de isolate. Con isolate evitamos que se dispare automáticamente la evaluación. 293 | datos_filtrados <- isolate({ 294 | filter(penguins, species == input$especie, sex == input$sexo) 295 | }) 296 | 297 | # Finalmente, el gráfico resultante 298 | ggplot(datos_filtrados, aes(x = body_mass_g)) + 299 | geom_histogram(bins = 20) 300 | }) 301 | 302 | } 303 | 304 | # Generamos la aplicación 305 | shinyApp(ui = ui, server = server) 306 | ``` 307 | 308 | Fíjate bien en cómo lo hemos hecho: 309 | 310 | * Dentro de la función de servidor para calcular nuestro gráfico de salida, `histograma`, ponemos como dependencia el valor de entrada correspondiente al botón, `actualizar`. 311 | * El resto de valores de entrada dependientes (la especie y el sexo), los metemos dentro de una expresión en la función `isolate`. Al estar dentro de la función, no provocarán la evaluación automática de la salida. 312 | 313 | Puedes lanzar este ejemplo haciendo: 314 | 315 | ``` 316 | library(shiny) 317 | runApp("examples/03_action_button") 318 | ``` 319 | 320 | ![](resources/10_shiny_avanzado/2_boton.png) 321 | 322 | > Ejecuta la aplicación y comprueba que, efectivamente, el histograma no se actualiza cambiando los valores de entrada, sino que espera al click sobre el botón. 323 | 324 | ## Profundiza 325 | 326 | Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias: 327 | 328 | * [Chuleta de Shiny](https://shiny.rstudio.com/images/shiny-cheatsheet.pdf): muy útil para tener a mano los comandos más habituales de Shiny. 329 | * [Galeria](https://shiny.rstudio.com/gallery/): ejemplos con código y resultado de varios cuadros de mando y aplicaciones desarrolladas con R Shiny. 330 | * [Tutoriales en vídeo](https://shiny.rstudio.com/tutorial/): una serie de tutoriales de todos los niveles sobre el manejo de Shiny. 331 | * [Visión general de la reactividad en Shiny](https://shiny.rstudio.com/articles/reactivity-overview.html): descripción de los diferentes tipos de objetos relacionados con la reactividad: entradas, salidas y conductores. 332 | * [Programación de la ejecución reactiva](https://shiny.rstudio.com/articles/execution-scheduling.html): artículo que detalla el funcionamiento interno de Shiny para re-evaluar los componentes de la aplicacion. 333 | * [Entendiendo la reactividad](https://shiny.rstudio.com/articles/understanding-reactivity.html): profundiza en el funcionamiento de la reactividad, con el objetivo de optimizar las aplicaciones realizadas con Shiny y evitar cometer algunos errores comunes. 334 | * [Prevención de reactividad automática](https://shiny.rstudio.com/articles/isolation.html): artículo sobre el uso de `isolate` y los `actionButtons`. 335 | * [Uso de bases de datos en Shiny](https://shiny.rstudio.com/articles/overview.html): son una serie de artículos que documentan cómo integrar Shiny con bases de datos utilizando _pools_ de conexiones. 336 | * [Personalización del aspecto de las aplicaciones en Shiny](https://shiny.rstudio.com/articles/css.html): detalla cómo personalizar el aspecto de las aplicaciones realizadas con Shiny utilizando un _css_ propio. 337 | 338 | ## Conclusiones 339 | 340 | Nos podemos quedar con las siguientes ideas como resumen de este tema: 341 | 342 | * La reactividad hace que se evalúen las salidas según los valores de entrada. 343 | * Por defecto, las salidas se evalúan en cuanto cambia alguna de las entradas de las que dependen. 344 | * Si hay varias salidas que dependen de una función costosa, es recomendable evaluarla una única vez, en lugar de una por salida. Para hacerlo, podemos utilizar los conductores (función `reactive`). 345 | * Podemos evitar que una salida se evalúe cada vez que cambia alguna de sus entradas con la función `isolate`. Y podemos evaluar la salida bajo demanda con un `actionButton`. 346 | 347 | ## Actividades 348 | 349 | ### Actividad 1 350 | 351 | Partiendo del ejemplo `examples/02_fibonacci_con_conductor`, añade un botón al menú lateral y cambia la implementación para que los resultados se actualicen al pulsarlo, y no al cambiar el parámetro de entrada. 352 | 353 | ### Actividad 2 354 | 355 | Crea una aplicación de shiny para visualizar el porcentaje de voto a cada uno de los partidos en las últimas elecciones. 356 | 357 | La aplicación tendrá: 358 | 359 | * Como inputs, el listado de partidos disponibles. 360 | * Como outputs: 361 | 362 | * Un mapa de `leaflet` mostrando las provincias, coloreadas según el porcentaje de voto (es decir, los votos a ese partido / los votos válidos en la provincia) obtenido en cada una de ellas. Incluye una leyenda para poder interpretarlo fácilmente. 363 | * Un gráfico de barras de `plotly` mostrando el número de votos por provincia, ordenado de mayor a menor número de votos. 364 | 365 | La función de tratamiento y filtrado de los datos para obtener el número de votos (absoluto y porcentual) por provincia al partido seleccionado deberá ejecutarse una única vez, y no repetirse para cada salida. 366 | 367 | ### Actividad 3 368 | 369 | Como comentamos en el capítulo anterior, una aplicación de Shiny necesita de un servidor que esté continuamente corriendo la aplicación, contestando a las peticiones de los usuarios. Lee en [este link](https://shiny.rstudio.com/tutorial/written-tutorial/lesson7/) las diferentes opciones que hay para desplegar aplicaciones en Shiny. Créate una cuenta gratuita en Shinyapps.io y despliega la aplicación de la actividad 2 siguiendo [este tutorial](https://shiny.rstudio.com/articles/shinyapps.html). 370 | -------------------------------------------------------------------------------- /10_shiny_avanzado_soluciones.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Soluciones capítulo 10" 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | output: 8 | html_document: 9 | highlight: null 10 | --- 11 | 12 | Para probar correctamente las aplicaciones shiny, tendrás que copiar y pegar el código a un intérprete de R. 13 | 14 | 15 | ```{r, include=FALSE} 16 | library(dplyr) 17 | library(tidyr) 18 | library(shiny) 19 | library(palmerpenguins) 20 | library(plotly) 21 | library(leaflet) 22 | library(DT) 23 | library(sf) 24 | ``` 25 | 26 | 27 | ### Actividad 1 28 | 29 | Partiendo del ejemplo `examples/02_fibonacci_con_conductor`, añade un botón al menú lateral y cambia la implementación para que los resultados se actualicen al pulsarlo, y no al cambiar el parámetro de entrada. 30 | 31 | ```{r} 32 | # Función para calcular el enésimo número de la serie de fibonacci 33 | fibonacci <- function(n) { 34 | if (n < 1) { 35 | return(NA) 36 | } 37 | if (n < 3) { 38 | return(1) 39 | } 40 | fibonacci(n - 1) + fibonacci(n - 2) 41 | } 42 | 43 | 44 | # La interfaz gráfica 45 | ui <- fluidPage( 46 | 47 | # El título de la aplicación 48 | titlePanel("Serie de Fibonacci"), 49 | 50 | # Un panel que tiene una zona más pequeña en el lateral izquierdo, 51 | # y un panel principal más grande a la derecha 52 | sidebarLayout( 53 | 54 | # Usaremos el panel izquierdo para los inputs 55 | sidebarPanel( 56 | 57 | # Input de tipo slide 58 | numericInput(inputId = "numero", 59 | label = h3("Número"), 60 | value = 10, 61 | min = 1, 62 | max = 30), 63 | 64 | # El botón 65 | actionButton(inputId = "boton", label = "Calcular") 66 | ), 67 | 68 | # El panel principal con los outputs 69 | mainPanel( 70 | 71 | h4("Serie: ", textOutput(outputId = "serie")), 72 | h4("Suma: ", textOutput(outputId = "suma")), 73 | h4("Media: ", textOutput(outputId = "media")), 74 | 75 | ) 76 | ) 77 | ) 78 | 79 | # El servidor 80 | server <- function(input, output) { 81 | 82 | # El conductor, que devuelve la serie. 83 | # Hay que encapsularlo dentro de una expresión en la función reactive 84 | serie <- reactive({ 85 | input$boton 86 | numero <- isolate(input$numero) 87 | sapply(1:numero, fibonacci) 88 | }) 89 | 90 | # El output serie contiene toda la serie 91 | output$serie <- renderText({ 92 | paste(serie(), collapse = ", ") 93 | }) 94 | 95 | # El output suma contiene toda la suma de todos los valores de la serie 96 | output$suma <- renderText({ 97 | sum(serie()) 98 | }) 99 | 100 | # El output media contiene toda la media de todos los valores de la serie 101 | output$media <- renderText({ 102 | mean(serie()) 103 | }) 104 | 105 | } 106 | 107 | # Generamos la aplicación 108 | shinyApp(ui = ui, server = server) 109 | ``` 110 | 111 | ### Actividad 2 112 | 113 | Crea una aplicación de shiny para visualizar el porcentaje de voto a cada uno de los partidos en las últimas elecciones. 114 | 115 | La aplicación tendrá: 116 | 117 | * Como inputs, el listado de partidos disponibles. 118 | * Como outputs: 119 | 120 | * Un mapa de `leaflet` mostrando las provincias, coloreadas según el porcentaje de voto (es decir, los votos a ese partido / los votos válidos en la provincia) obtenido en cada una de ellas. Incluye una leyenda para poder interpretarlo fácilmente. 121 | * Un gráfico de barras de `plotly` mostrando el número de votos por provincia, ordenado de mayor a menor número de votos. 122 | 123 | La función de tratamiento y filtrado de los datos para obtener el número de votos (absoluto y porcentual) por provincia al partido seleccionado deberá ejecutarse una única vez, y no repetirse para cada salida. 124 | 125 | ```{r} 126 | 127 | # La interfaz gráfica 128 | ui <- fluidPage( 129 | 130 | titlePanel("Elecciones España"), 131 | 132 | sidebarLayout( 133 | 134 | sidebarPanel( 135 | 136 | selectInput( 137 | inputId = "partido", 138 | label = "Partido", 139 | choices = c("psoe", "pp", "vox", "podemos") 140 | ) 141 | ), 142 | 143 | mainPanel( 144 | leafletOutput("map"), 145 | plotlyOutput("chart") 146 | ) 147 | ) 148 | ) 149 | 150 | # El servidor 151 | server <- function(input, output) { 152 | 153 | provincias <- read_sf("dat/spain_provinces.geojson") 154 | elecciones <- read.csv("dat/elecciones_2019_provincias.csv") 155 | votos <- read.csv("dat/elecciones_2019_votos.csv") 156 | 157 | colores <- c("psoe" = "Reds", "pp" = "Blues", "vox" = "Greens", "podemos" = "Purples") 158 | 159 | # Procesamiento de datos 160 | datos <- reactive({ 161 | votos %>% 162 | filter(partido == input$partido) %>% 163 | inner_join(elecciones) %>% 164 | mutate(ratio_votos = round(votos / votos_validos, 3)) %>% 165 | select(provincia_cod_ine, provincia_nombre, votos, ratio_votos) 166 | }) 167 | 168 | # El output serie contiene toda la serie 169 | output$map <- renderLeaflet({ 170 | # Recupero los datos ya procesados del conductor 171 | votos <- datos() 172 | 173 | # Provincias con su info geográfica 174 | mapa_votos <- provincias %>% 175 | left_join(votos, by = c("codigo" = "provincia_cod_ine")) 176 | 177 | # Leyenda 178 | pal_votos <- colorBin( 179 | palette = colores[input$partido], 180 | domain = mapa_votos$ratio_votos, 181 | bins = 5 182 | ) 183 | 184 | # Mapa 185 | leaflet(mapa_votos) %>% 186 | addPolygons( 187 | color = ~pal_votos(ratio_votos), 188 | stroke = FALSE, 189 | fillOpacity = 1) %>% 190 | addLegend( 191 | position = "bottomright", 192 | pal = pal_votos, 193 | values = ~ratio_votos, 194 | title = "% votos", 195 | labFormat = labelFormat(suffix = "%", transform = function(x) 100 * x), 196 | ) 197 | }) 198 | 199 | # El output suma contiene toda la suma de todos los valores de la serie 200 | output$chart <- renderPlotly({ 201 | # Recupero los datos ya procesados del conductor 202 | votos <- datos() 203 | 204 | # Ordeno por número de votos 205 | votos <- arrange(votos, votos) 206 | votos$provincia_nombre <- factor(votos$provincia_nombre, levels = votos$provincia_nombre) 207 | plot_ly(votos, type = "bar", x = ~votos, y = ~provincia_nombre, height = 1200) 208 | }) 209 | 210 | } 211 | 212 | # Generamos la aplicación 213 | shinyApp(ui = ui, server = server) 214 | ``` 215 | -------------------------------------------------------------------------------- /11_proyecto.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: '11 - Proyecto' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ## Proyecto - Cuadro de mando de BiciMAD 10 | 11 | ### Objetivos 12 | 13 | El objetivo de este proyecto final es realizar un cuadro de mando interactivo de análisis sobre los datos de BiciMAD, aplicando los conceptos adquiridos durante el curso. 14 | 15 | ### Dataset 16 | 17 | Los datos provienen del portal de datos abiertos de la EMT. Son los correspondientes al mes de junio de 2019. Existen estos ficheros de datos: 18 | 19 | * stations.csv: contiene las propiedades de cada estación. Sus columnas son: 20 | 21 | * station_id: el ID de la estación 22 | * name: su nombre 23 | * total_bases: el número de bases (anclajes) que tiene para bicis 24 | * address: la dirección 25 | * number: el número de estación 26 | * latitude: latitud de su localización 27 | * longitude: longitud de su localización 28 | 29 | * stations_status.csv: correspondiente al estado guardado por hora de cada una de las estaciones. Sus columnas son: 30 | * date: la fecha en la que se guardó el estado 31 | * hour: la hora en la que se guardó el estado 32 | * station_id: el ID de la estación 33 | * activate: indica si la estación está activa (1) o inactiva (0) 34 | * no_available: indica si la estación está disponible (0) o no disponible (1) 35 | * reservations_count: indica el número de reservas activas 36 | * free_bases: indicael número de bases (anclajes) libres, es decir, aquellas en las que se puede dejar la bici para finalizar un viaje 37 | * dock_bikes: indica el número de bicicletas ancladas, es decir, aquellas disponibles para iniciar un viaje 38 | * light: indica el grado de ocupación (desde 0 = baja hasta 3 = alta) 39 | 40 | * trips.csv: con el detalle de viajes realizados. Las columnas son: 41 | 42 | * date_unplug: la fecha en la que se inicia el viaje 43 | * hour_unplug: la hora en la que se inicia el viaje 44 | * station_id_unplug: elIDde la estación desde la que se inicia el viaje (donde se coge la bici) 45 | * station_id_plug: el ID de la estación donde se finaliza el viaje (donde se deja la bici) 46 | * travel_time: el tiempo de viaje en segundos 47 | * user_type: el tipo de usuario (0: Desconocido, 1: Usuario anual (poseedor de un pase anual), 2: Usuario ocasional, 3: Trabajador de la empresa) 48 | * user_age_range: el rango de edad del usuario (0: Desconocido, 1: entre 0 y 16 años, 2: entre 17 y 18 años, 3: entre 19 y 26 años, 4: entre 27 y 40 años, 5: entre 41 y 65 años, 6: 66 años o más) 49 | * user_zip_code: el código postal del usuario 50 | 51 | ### Cuadro de mando 52 | 53 | Como aspectos generales: 54 | 55 | * El cuadro de mando será un documento de flexdashboard generado con R Markdown. 56 | * Puedes generar los gráficos con ggplot2 (estáticos) o plotly (interactivos). Aunque, en este tipo de visualizaciones interactivas, es más recomendable usar plotly. 57 | * Ídem con los mapas, puedes generarlos con ggplot2 (estáticos) o leaflet (interactivos). Ídem, es más adecuado leaflet. 58 | * Los indicadores superiores deberán ser value boxes. Puedes acompañarlos con un icono de fondo representativo o un color determinado para que den más información (p.e. si todos los cuadros son azules y pones uno naranja, este último indicará "alerta"). 59 | * En algunos casos, no detallo el tipo de gráfico a pintar. Elige el tipo (líneas, puntos, barras, histogramas, ...) que represente mejor la información que se pide representar. 60 | 61 | El objetivo de este cuadro de mando es hacer un análisis de un mes de BiciMAD, en este caso, junio de 2019. El cuadro de mando deberá tener las siguientes páginas: 62 | 63 | * Operativa. Esta página contendrá: 64 | 65 | * Indicadores superiores: 66 | 67 | * Número de estaciones 68 | * Número de bases: corresponde a la suma de las bases de todas las estaciones 69 | * % tiempo sin disponibilidad: corresponde al porcentaje de tiempo en el que las estaciones se encontraban no disponibles (es decir, al número de veces que veas en los datos de estado de estaciones que no está disponible, con respecto al total de observaciones de estado de estaciones). 70 | 71 | * Gráficos: 72 | 73 | * Mapa con todas las estaciones. El color del marcador con el que se representan deberá ser verde si esa estación ha estado sin disponibilidad < 24 horas, naranja si lo ha estado entre 24 y 72 horas, y roja si lo ha estado > 72 horas. El tooltip deberá mostrar el ID de estación, nombre, número total de bases y horas no disponibles. 74 | * Gráfico de barras que muestre las 15 estaciones con mayor número de horas no disponibles, y dicha cantidad de horas. 75 | 76 | * Actividad. Esta página contendrá: 77 | 78 | * Indicadores superiores: 79 | 80 | * Número de viajes 81 | * % viajes con pase anual 82 | * % viajes ocasionales 83 | * % viajes de trabajadores 84 | 85 | * Gráficos: 86 | 87 | * Número de viajes realizados por cada rango de edad. Nota: pon variables que identifiquen bien a estos grupos de edad (p.e. “19-26”, “27-40”, y no 1, 2, 3, ...) 88 | * Evolución del número de viajes por fecha, con granularidad diaria (es decir, agregado por día). 89 | * Comparación del número de viajes medios por hora según el día de la semana (lunes, martes, ... domingo). La idea de este gráfico es ver si cambia el uso según el día de la semana, a qué horas hay más y menos viajes dependiendo de ello. 90 | * Comparación del número de viajes medios por hora según el rango de edad. La idea de este gráfico es ver si cambia el uso según la edad, a qué horas usan más y menos el servicio. 91 | * Distribución del número de minutos por viaje. Nota: piensa cómo tratar los outliers (la cola larga, es decir, unos pocos viajes muy largos), puedes eliminarlos o utilizar otro tipo de escala. 92 | Gráfico de barras con las 15 estaciones desde la que más se inician los viajes (junto con el número de viajes iniciados desde ellas) 93 | Gráfico de barras con las 15 estaciones en la que se finalizan más los viajes (junto con el número de viajes finalizados desde ellas) 94 | 95 | * Estado estaciones. Nota: las páginas anteriores no requerían utilizar shiny, ya que no dependen de entradas de usuario. Esta página es la única que sí lo necesita. Puedes investigar un poco más sobre esto en las referencias de apoyo. Esta página contendrá: 96 | 97 | * Menú lateral con inputs de usuario: 98 | 99 | * La estación 100 | 101 | * Indicadores superiores: 102 | 103 | * Número de viajes iniciados en ella 104 | * Número de viajes finalizados en ella 105 | 106 | * Gráficos: 107 | 108 | * Evolución del % de bicis con respecto al total de bases (anclajes) por fecha y hora. Nos mostrará la capacidad a lo largo del tiempo para poder iniciar / finalizar viajes desde / en ella (100% es que todas las bases tienen bici, y 0% es que todas las bases están libres) 109 | * Evolución del número de viajes por fecha y hora. 110 | 111 | Puedes añadir nuevas páginas, indicadores superiores o gráficas con análisis que resulten de tu interés. 112 | 113 | 114 | ### Referencias de apoyo 115 | 116 | Puedes consultar [esta referencia](https://rstudio.github.io/flexdashboard/articles/shiny.html) de cómo integrar shiny en un cuadro de mando de flexdashboard. 117 | 118 | 119 | ### Estructura del proyecto 120 | 121 | Es recomendable estructurarlo de la siguiente manera: 122 | 123 | * dashboard.Rmd: El informe en R Markdown. 124 | * dat/: una carpeta con los datos (los .csv). 125 | * resources/ (opcional): si necesitas otros recursos para tu informe (imágenes, un css, ...) los puedes situar en una carpeta con este nombre. 126 | 127 | 128 | ### Recomendaciones 129 | 130 | Al abordar este proyecto, cuida los siguientes aspectos: 131 | 132 | #### Reproducibilidad 133 | 134 | Es importante que tu código sea portable, y que otra persona (un compañero de equipo, un cliente, ...) pueda ejecutarlo en otro sistema. Esto es, en una sesión nueva de R, se debe generar el html resultante sin errores. Ten cuidado con las rutas a ficheros. Deben ser relativas (p.e. dat/xxxx.csv), y apuntar a ficheros contenidos en tu carpeta de proyecto. Si tienes una ruta absoluta del estilo c:/users/pepa/blabla.csv, fallará en otro ordenador. 135 | 136 | #### Gráficos 137 | 138 | Los gráficos incluidos deberán representar correctamente su objetivo (mediante el uso correcto de su tipología, el mapeo de propiedades, ...) y además tendrán una presentación correcta, con nombrado de ejes adecuado al usuario (en lugar de utilizar nombres de columna), un uso adecuado de escalas de colores, etc. 139 | 140 | Los números deben estar redondeados a cierto número de cifras significativas. No muestres, por ejemplo, un porcentaje como 5.287368%. En su lugar, utiliza 5.3% o 5%. 141 | 142 | #### Limpieza y calidad del código 143 | 144 | Se evaluará también que el código se pueda leer fácilmente y esté correctamente modularizado. Asegúrate de cuidar los siguientes aspectos: 145 | 146 | * Nomenclatura del código: buenos nombres a columnas, variables, funciones, ... 147 | * DRY (Don't repeat yourself): si utilizas el mismo código varias veces, debería estar encapsulado en una función y no copiado y pegado varias veces. 148 | * Código limpio: el código debe ser fácilmente interpretable, no intentes hacer muchas cosas en una sola línea muy compleja; sepáralo y ve nombrando adecuadamente a las variables intermedias. 149 | * Comentarios adecuados: comenta tu código adecuadamente indicando lo que estás haciendo en cada bloque. 150 | 151 | #### Aspecto visual 152 | 153 | Intenta que tu cuadro de mando tenga un aspecto visual cuidado y personalizado. 154 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Curso de visualización de datos en R 2 | 3 | El curso está disponible en [https://rdataviz.luzfrias.com/](https://rdataviz.luzfrias.com/) 4 | 5 | ## Presentación del curso 6 | 7 | La visualización es una parte esencial de cualquier proyecto de datos. Nos ayuda a comprender la estructura de nuestro dataset y a detectar patrones y outliers. 8 | 9 | El objetivo de esta asignatura es conocer en líneas generales la teoría de la visualización y utilizar las herramientas que nos provee R. Exploraremos herramientas como ggplot para el diseño de gráficos estáticos, leaflet para datos espaciales y shiny para montar cuadros de mando interactivos. 10 | 11 | ## Índice 12 | 13 | ### Tema 1. Gráficos estáticos con ggplot: nivel básico 14 | 15 | * Introducción a la visualización 16 | * Mapeos y geometrías 17 | * Gráficos de puntos 18 | * Gráficos de líneas 19 | 20 | ### Tema 2. Gráficos estáticos con ggplot: nivel intermedio 21 | 22 | * Escalas 23 | * Transformaciones estadísticas 24 | * Gráficos de barras 25 | * Zoom 26 | 27 | ### Tema 3. Gráficos estáticos con ggplot: nivel avanzado 28 | 29 | * Títulos, etiquetas y textos 30 | * Temas 31 | * Mapas 32 | * Guardar los gráficos 33 | 34 | ### Tema 4. Mapas interactivos con leaflet 35 | 36 | * Mapas base y controles del mapa 37 | * Marcadores 38 | * Coropletas 39 | 40 | ### Tema 5. Gráficos interactivos con plotly: nivel básico 41 | 42 | * Gráficos estáticos vs interactivos 43 | * Primeros gráficos interactivos 44 | * Controles y personalización 45 | * Gráficos de puntos, líneas y barras 46 | 47 | ### Tema 6. Gráficos interactivos con plotly: nivel avanzado 48 | 49 | * Controles 50 | * Animaciones 51 | 52 | ### Tema 7. Diseño de informes estáticos con rmarkdown 53 | 54 | * Markdown 55 | * Bloques de código 56 | * Renderizado 57 | * Parámetros 58 | 59 | ### Tema 8. Diseño de informes web con flexdashboard 60 | 61 | * Layouts 62 | * Componentes 63 | * Personalización avanzada 64 | 65 | ### Tema 9. Diseño de cuadros de mando con shiny: nivel básico 66 | 67 | * Arquitectura 68 | * Aplicación básica y conceptos 69 | * Interfaz de usuario 70 | 71 | ### Tema 10. Diseño de cuadros de mando con shiny: nivel avanzado 72 | 73 | * Controles de usuario 74 | * Salida reactiva 75 | * Una aplicación completa 76 | 77 | ### Tema 11. Proyecto 78 | 79 | ## 3. Material audiovisual y complementario 80 | 81 | Para seguir este curso, es necesario contar con los siguientes paquetes de R instalados: ggplot2, scales, rjson, leaflet, dplyr, plotly, rmarkdown, flexdashboard y shiny. 82 | 83 | Además, nos resultará muy útil tener a mano las siguientes "chuletas" de uso de las herramientas que vamos a utilizar: 84 | 85 | * [ggplot2](https://posit.co/wp-content/uploads/2022/10/data-visualization-1.pdf) 86 | * [leaflet](https://posit.co/wp-content/uploads/2022/10/leaflet.pdf) 87 | * [plotly](https://images.plot.ly/plotly-documentation/images/r_cheat_sheet.pdf) 88 | * [rmarkdown](https://posit.co/wp-content/uploads/2022/10/rmarkdown-1.pdf) 89 | * [shiny](https://posit.co/wp-content/uploads/2022/10/shiny-1.pdf) 90 | 91 | ## Contribuye 92 | 93 | Si ves algo incorrecto, que no se entiende bien, crees que falta alguna explicación o tienes alguna idea que compartir, puedes crear una `issue` en el repositorio. 94 | 95 | ## Licencia 96 | 97 | [![](http://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) 98 | 99 | Puedes utilizar libremente este material, con las siguientes condiciones: 100 | 101 | * Atribuir la autoría a este repositorio. 102 | * Si lo utilizas y haces cambios, deberás liberarlo también bajo la misma licencia. 103 | -------------------------------------------------------------------------------- /_quarto.yml: -------------------------------------------------------------------------------- 1 | project: 2 | type: book 3 | render: 4 | - "*.qmd" 5 | - "!webinars/" 6 | 7 | number-sections: false 8 | 9 | book: 10 | title: "R para visualización de datos" 11 | author: "Luz Frias" 12 | date: "2022-12-15" 13 | site-url: https://rdataviz.luzfrias.com 14 | description: Curso abierto, gratuito y en español. Recorre las principales 15 | herramientas de visualización de generación de gráficos, mapas, informes y 16 | cuadros de mando en R 17 | sidebar: 18 | style: docked 19 | background: light 20 | chapters: 21 | - index.qmd 22 | - part: "Gráficos estáticos - ggplot" 23 | chapters: 24 | - 01_ggplot_basico.qmd 25 | - 01_ggplot_basico_soluciones.qmd 26 | - 02_ggplot_intermedio.qmd 27 | - 02_ggplot_intermedio_soluciones.qmd 28 | - 03_ggplot_avanzado.qmd 29 | - 03_ggplot_avanzado_soluciones.qmd 30 | - part: "Mapas interactivos - leaflet" 31 | chapters: 32 | - 04_leaflet.qmd 33 | - 04_leaflet_soluciones.qmd 34 | - part: "Gráficos interactivos - plotly" 35 | chapters: 36 | - 05_plotly_basico.qmd 37 | - 05_plotly_basico_soluciones.qmd 38 | - 06_plotly_avanzado.qmd 39 | - 06_plotly_avanzado_soluciones.qmd 40 | - part: "Documentos - RMarkdown" 41 | chapters: 42 | - 07_rmarkdown.qmd 43 | - part: "Cuadros de mando - flexdashboard" 44 | chapters: 45 | - 08_flexdashboard.qmd 46 | - 08_flexdashboard_soluciones.qmd 47 | - part: "Aplicaciones web - Shiny" 48 | chapters: 49 | - 09_shiny_basico.qmd 50 | - 09_shiny_basico_soluciones.qmd 51 | - 10_shiny_avanzado.qmd 52 | - 10_shiny_avanzado_soluciones.qmd 53 | page-navigation: true 54 | search: true 55 | repo-url: https://github.com/koldLight/curso-r-dataviz/ 56 | twitter-card: 57 | creator: "@koldLight" 58 | open-graph: 59 | locale: es_ES 60 | google-analytics: 61 | tracking-id: "G-PP4E1G1J71" 62 | anonymize-ip: true 63 | version: 4 64 | 65 | comments: 66 | hypothesis: false 67 | 68 | format: 69 | html: 70 | theme: pulse 71 | 72 | -------------------------------------------------------------------------------- /dat/defunciones_espana.csv: -------------------------------------------------------------------------------- 1 | "fecha_defuncion","defunciones_observadas","defunciones_observadas_lim_inf","defunciones_observadas_lim_sup","defunciones_esperadas","defunciones_esperadas_q01","defunciones_esperadas_q99" 2 | 2019-08-01,999,999,999,1016,908.24,1117.62 3 | 2019-08-02,1002,1002,1002,1011,918.92,1152.18 4 | 2019-08-03,942,942,942,1026,908.24,1171.54 5 | 2019-08-04,904,904,904,1028,908.24,1192.38 6 | 2019-08-05,909,909,909,1027,905.86,1192.38 7 | 2019-08-06,984,984,984,1011,905.86,1192.38 8 | 2019-08-07,1051,1051,1051,1017,905.86,1192.38 9 | 2019-08-08,1072,1072,1072,1014.5,905.86,1192.38 10 | 2019-08-09,1037,1037,1037,1021.5,905.86,1192.38 11 | 2019-08-10,964,964,964,1013.75,910.3,1145.75 12 | 2019-08-11,919,919,919,1011,910.4,1112.88 13 | 2019-08-12,895,895,895,1011.5,914,1095.9 14 | 2019-08-13,972,972,972,1011,911.28,1095.56 15 | 2019-08-14,953,953,953,1007,911.36,1067.31 16 | 2019-08-15,1018,1018,1018,1002,911.44,1073.32 17 | 2019-08-16,902,902,902,993.75,911.52,1102.16 18 | 2019-08-17,1036,1036,1036,992,904.45,1106.99 19 | 2019-08-18,969,969,969,992,900.38,1108.37 20 | 2019-08-19,922,922,922,991,900.38,1108.37 21 | 2019-08-20,934,934,934,996,900.38,1108.37 22 | 2019-08-21,922,922,922,997,900.38,1108.37 23 | 2019-08-22,925,925,925,1000.5,900.38,1108.37 24 | 2019-08-23,966,966,966,1005,884.01,1098.62 25 | 2019-08-24,915,915,915,1003,884.01,1091.03 26 | 2019-08-25,910,910,910,1005,884.01,1086.655 27 | 2019-08-26,924,924,924,1005,884.01,1086.655 28 | 2019-08-27,947,947,947,999,884.01,1074.24 29 | 2019-08-28,910,910,910,999,884.01,1065.96 30 | 2019-08-29,947,947,947,995,884.01,1071.825 31 | 2019-08-30,990,990,990,990.5,900.42,1079.79 32 | 2019-08-31,978,978,978,986.5,896.97,1079.79 33 | 2019-09-01,815,815,815,982.5,892.83,1074.615 34 | 2019-09-02,935,935,935,977.5,892.83,1074.615 35 | 2019-09-03,940,940,940,976.5,892.83,1074.615 36 | 2019-09-04,998,998,998,976.5,892.83,1074.615 37 | 2019-09-05,990,990,990,970,892.83,1079.79 38 | 2019-09-06,950,950,950,967,890.04,1062.51 39 | 2019-09-07,889,889,889,966,871.87,1067.34 40 | 2019-09-08,900,900,900,964.5,871.87,1067.34 41 | 2019-09-09,905,905,905,965.5,871.87,1067.34 42 | 2019-09-10,971,971,971,966.5,871.87,1067.34 43 | 2019-09-11,912,912,912,965.5,862.21,1067.34 44 | 2019-09-12,950,950,950,967,862.21,1057.135 45 | 2019-09-13,1008,1008,1008,964.5,862.21,1045.06 46 | 2019-09-14,977,977,977,964.5,875.35,1027.205 47 | 2019-09-15,895,895,895,964.5,875.35,1027.825 48 | 2019-09-16,918,918,918,966,849.5,1038.58 49 | 2019-09-17,991,991,991,964.5,849.5,1041.34 50 | 2019-09-18,929,929,929,966,859.85,1053.17 51 | 2019-09-19,1010,1010,1010,967,859.85,1060.48 52 | 2019-09-20,920,920,920,969.5,859.85,1063.24 53 | 2019-09-21,941,941,941,973.5,865.37,1063.24 54 | 2019-09-22,912,912,912,983.75,875.72,1068.17 55 | 2019-09-23,916,916,916,985,893.7,1070.24 56 | 2019-09-24,954,954,954,989.25,893.7,1070.24 57 | 2019-09-25,960,960,960,991.5,890.94,1076.41 58 | 2019-09-26,940,940,940,993.5,890.94,1089.27 59 | 2019-09-27,1018,1018,1018,991.75,890.94,1094.1 60 | 2019-09-28,960,960,960,991.25,890.94,1094.1 61 | 2019-09-29,915,915,915,993.5,890.94,1094.1 62 | 2019-09-30,910,910,910,998.5,901.76,1098.24 63 | 2019-10-01,1027,1027,1027,999.5,901.76,1098.24 64 | 2019-10-02,997,997,997,1000.5,907.14,1098.24 65 | 2019-10-03,940,940,940,1005.75,907.14,1100.1 66 | 2019-10-04,987,987,987,1014.5,922.32,1100.1 67 | 2019-10-05,931,931,931,1015,930.07,1100.1 68 | 2019-10-06,873,873,873,1017,930.07,1100.1 69 | 2019-10-07,950,950,950,1019,930.07,1097.34 70 | 2019-10-08,988,988,988,1020.5,927.69,1097.34 71 | 2019-10-09,1032,1032,1032,1021.5,927.69,1100.1 72 | 2019-10-10,999,999,999,1020.5,927.69,1090.1 73 | 2019-10-11,1069,1069,1069,1015.25,927.69,1090.1 74 | 2019-10-12,1030,1030,1030,1014.25,930.45,1098.705 75 | 2019-10-13,919,919,919,1015.75,930.45,1110.715 76 | 2019-10-14,979,979,979,1018,930.45,1129.31 77 | 2019-10-15,969,969,969,1023.25,932.69,1129.31 78 | 2019-10-16,1065,1065,1065,1024,938.52,1129.31 79 | 2019-10-17,1067,1067,1067,1024.75,938.52,1129.31 80 | 2019-10-18,1046,1046,1046,1027,948.52,1129.31 81 | 2019-10-19,954,954,954,1035.5,953.52,1129.31 82 | 2019-10-20,915,915,915,1039.5,931.35,1121.72 83 | 2019-10-21,978,978,978,1038,931.35,1113.86 84 | 2019-10-22,1103,1103,1103,1037,931.35,1111.31 85 | 2019-10-23,988,988,988,1042.5,931.35,1111.31 86 | 2019-10-24,1050,1050,1050,1044,931.35,1121.3 87 | 2019-10-25,1011,1011,1011,1047,931.35,1135.79 88 | 2019-10-26,1047,1047,1047,1053.5,931.35,1135.79 89 | 2019-10-27,949,949,949,1053.5,960.25,1135.79 90 | 2019-10-28,1013,1013,1013,1058,963.35,1135.79 91 | 2019-10-29,1068,1068,1068,1065,961.97,1138.55 92 | 2019-10-30,991,991,991,1065,961.97,1138.55 93 | 2019-10-31,1054,1054,1054,1065,961.97,1141.65 94 | 2019-11-01,1106,1106,1106,1065,961.97,1147.86 95 | 2019-11-02,1097,1097,1097,1065,961.97,1147.86 96 | 2019-11-03,993,993,993,1068,961.97,1147.86 97 | 2019-11-04,1061,1061,1061,1067,966.69,1147.86 98 | 2019-11-05,1071,1071,1071,1065,973.21,1155.41 99 | 2019-11-06,1005,1005,1005,1064,973.21,1164.86 100 | 2019-11-07,1012,1012,1012,1064,979.42,1164.86 101 | 2019-11-08,1108,1108,1108,1075.25,979.42,1164.86 102 | 2019-11-09,1061,1061,1061,1077.75,979.42,1164.86 103 | 2019-11-10,1026,1026,1026,1078.75,979.42,1164.86 104 | 2019-11-11,1018,1018,1018,1088.5,987.07,1171.17 105 | 2019-11-12,1102,1102,1102,1090.5,987.07,1171.17 106 | 2019-11-13,1119,1119,1119,1099.25,994.9,1170.48 107 | 2019-11-14,1161,1161,1161,1102,993.35,1172.55 108 | 2019-11-15,1107,1107,1107,1095,993.35,1180.96 109 | 2019-11-16,1095,1095,1095,1095,999.56,1197.58 110 | 2019-11-17,1058,1058,1058,1096.5,999.56,1197.58 111 | 2019-11-18,1055,1055,1055,1097,1004.39,1197.58 112 | 2019-11-19,1152,1152,1152,1093.5,1004.39,1197.58 113 | 2019-11-20,1162,1162,1162,1095,988.52,1197.58 114 | 2019-11-21,1131,1131,1131,1099.5,1006.87,1210.31 115 | 2019-11-22,1178,1178,1178,1099.5,1011.01,1210.31 116 | 2019-11-23,1151,1151,1151,1102.5,996.865,1195.82 117 | 2019-11-24,987,987,987,1103.5,996.865,1195.82 118 | 2019-11-25,1084,1084,1084,1106,996.865,1226.19 119 | 2019-11-26,1181,1181,1181,1111.25,996.865,1226.19 120 | 2019-11-27,1145,1145,1145,1110.25,1023.995,1226.19 121 | 2019-11-28,1172,1172,1172,1122.5,1024.34,1224.81 122 | 2019-11-29,1180,1180,1180,1129.5,1024.34,1227.57 123 | 2019-11-30,1087,1087,1087,1132.5,1030.695,1242.75 124 | 2019-12-01,1061,1061,1061,1136,1027.245,1242.75 125 | 2019-12-02,1061,1061,1061,1138,1027.245,1250 126 | 2019-12-03,1135,1135,1135,1138,1027.245,1250 127 | 2019-12-04,1099,1099,1099,1144,1027.245,1250 128 | 2019-12-05,1102,1102,1102,1148,1027.245,1250 129 | 2019-12-06,1099,1099,1099,1141,1014.42,1250 130 | 2019-12-07,1046,1046,1046,1143.5,1021.665,1250 131 | 2019-12-08,1068,1068,1068,1143.5,1050.99,1272.01 132 | 2019-12-09,1091,1091,1091,1143.5,1049.61,1274.08 133 | 2019-12-10,1084,1084,1084,1151.5,1049.61,1305.82 134 | 2019-12-11,1166,1166,1166,1155,1049.61,1314.1 135 | 2019-12-12,1157,1157,1157,1159.5,1044.09,1329.99 136 | 2019-12-13,1215,1215,1215,1166,1068.52,1333.44 137 | 2019-12-14,1114,1114,1114,1177,1068.52,1333.44 138 | 2019-12-15,1104,1104,1104,1182.5,1068.52,1333.44 139 | 2019-12-16,1088,1088,1088,1187,1069.21,1333.44 140 | 2019-12-17,1086,1086,1086,1189.5,1080.94,1352.48 141 | 2019-12-18,1162,1162,1162,1192.5,1080.94,1367.92 142 | 2019-12-19,1108,1108,1108,1209,1097.97,1401.47 143 | 2019-12-20,1217,1217,1217,1206,1107.07,1415.96 144 | 2019-12-21,1130,1130,1130,1210,1105.52,1415.96 145 | 2019-12-22,1042,1042,1042,1212,1105.52,1415.96 146 | 2019-12-23,1066,1066,1066,1216.5,1096.59,1427.93 147 | 2019-12-24,1114,1114,1114,1218.5,1096.59,1456.66 148 | 2019-12-25,1080,1080,1080,1219.25,1096.59,1480.12 149 | 2019-12-26,1065,1065,1065,1245.5,1096.59,1520.03 150 | 2019-12-27,1154,1154,1154,1249.5,1096.59,1520.03 151 | 2019-12-28,1056,1056,1056,1249.5,1100.73,1520.03 152 | 2019-12-29,1038,1038,1038,1253.75,1100.73,1520.03 153 | 2019-12-30,1042,1042,1042,1253.75,1125.14,1520.72 154 | 2019-12-31,1105,1105,1105,1277,1125.14,1529.93 155 | 2020-01-01,1159,1159,1159,1279,1125.14,1564.55 156 | 2020-01-02,1224,1224,1224,1285.5,1125.14,1646.92 157 | 2020-01-03,1226,1226,1226,1284.75,1125.14,1646.92 158 | 2020-01-04,1240,1240,1240,1285.75,1109.22,1646.92 159 | 2020-01-05,1197,1197,1197,1285.75,1113.36,1646.92 160 | 2020-01-06,1166,1166,1166,1291.5,1123.71,1646.92 161 | 2020-01-07,1181,1181,1181,1298.5,1131.99,1646.92 162 | 2020-01-08,1333,1333,1333,1301.5,1131.99,1677.37 163 | 2020-01-09,1271,1271,1271,1306.5,1131.99,1632.52 164 | 2020-01-10,1376,1376,1376,1308.5,1131.99,1642.18 165 | 2020-01-11,1350,1350,1350,1332.5,1155.38,1701.27 166 | 2020-01-12,1259,1259,1259,1329,1161.52,1701.27 167 | 2020-01-13,1260,1260,1260,1331.5,1172.97,1701.27 168 | 2020-01-14,1337,1337,1337,1331.5,1154.37,1701.27 169 | 2020-01-15,1353,1353,1353,1328.5,1144.02,1682.64 170 | 2020-01-16,1332,1332,1332,1332,1144.02,1682.64 171 | 2020-01-17,1478,1478,1478,1332,1144.02,1682.64 172 | 2020-01-18,1377,1377,1377,1328.5,1144.02,1653.82 173 | 2020-01-19,1291,1291,1291,1341.5,1131.945,1653.82 174 | 2020-01-20,1231,1231,1231,1337.5,1131.945,1653.82 175 | 2020-01-21,1388,1388,1388,1338,1138.11,1646.92 176 | 2020-01-22,1388,1388,1388,1330.75,1124.69,1630.79 177 | 2020-01-23,1360,1360,1360,1330.25,1124.69,1630.79 178 | 2020-01-24,1403,1403,1403,1326.25,1124.69,1617.68 179 | 2020-01-25,1334,1334,1334,1322.5,1124.69,1597.96 180 | 2020-01-26,1295,1295,1295,1310.25,1124.69,1616.13 181 | 2020-01-27,1334,1334,1334,1301,1124.69,1616.13 182 | 2020-01-28,1354,1354,1354,1300.75,1130.21,1616.13 183 | 2020-01-29,1399,1399,1399,1300.75,1132.38,1616.13 184 | 2020-01-30,1395,1395,1395,1300.25,1132.38,1614.06 185 | 2020-01-31,1406,1406,1406,1299,1132.38,1614.06 186 | 2020-02-01,1314,1314,1314,1294.75,1121.39,1614.06 187 | 2020-02-02,1272,1272,1272,1299,1121.39,1587.37 188 | 2020-02-03,1284,1284,1284,1294.25,1121.39,1566.58 189 | 2020-02-04,1305,1305,1305,1306.75,1121.39,1566.58 190 | 2020-02-05,1303,1303,1303,1306.75,1126.22,1566.58 191 | 2020-02-06,1264,1264,1264,1306.75,1131.74,1566.58 192 | 2020-02-07,1270,1270,1270,1297.25,1120.7,1555.54 193 | 2020-02-08,1193,1193,1193,1314.5,1138.28,1546.55 194 | 2020-02-09,1151,1151,1151,1297.25,1138.28,1546.55 195 | 2020-02-10,1152,1152,1152,1302.75,1123.8,1546.55 196 | 2020-02-11,1236,1236,1236,1297.75,1123.8,1571.03 197 | 2020-02-12,1234,1234,1234,1293,1102.25,1580.93 198 | 2020-02-13,1285,1285,1285,1289.5,1102.25,1614.62 199 | 2020-02-14,1192,1192,1192,1289.5,1102.25,1694.92 200 | 2020-02-15,1209,1209,1209,1284,1102.25,1694.92 201 | 2020-02-16,1075,1075,1075,1280.75,1102.25,1694.92 202 | 2020-02-17,1121,1121,1121,1276.25,1112.6,1694.92 203 | 2020-02-18,1129,1129,1129,1264,1112.6,1694.92 204 | 2020-02-19,1090,1090,1090,1258.75,1141.905,1694.92 205 | 2020-02-20,1184,1184,1184,1249.5,1151.225,1672.15 206 | 2020-02-21,1158,1158,1158,1239.5,1137.04,1638.89 207 | 2020-02-22,1173,1173,1173,1233,1126.69,1638.89 208 | 2020-02-23,1089,1089,1089,1233,1126.69,1638.89 209 | 2020-02-24,1141,1141,1141,1233,1088.175,1638.89 210 | 2020-02-25,1125,1125,1125,1229,1082.69,1653.86 211 | 2020-02-26,1127,1127,1127,1228.25,1076.73,1640.75 212 | 2020-02-27,1225,1225,1225,1223,1076.73,1640.75 213 | 2020-02-28,1130,1130,1130,1218,1076.73,1622.12 214 | 2020-02-29,1153,1153,1153,1218,1076.73,1595.9 215 | 2020-03-01,1061,1061,1061,1213,1076.73,1595.9 216 | 2020-03-02,1125,1125,1125,1214.5,1076.73,1593.83 217 | 2020-03-03,1156,1156,1156,1213,1062.83,1544.3 218 | 2020-03-04,1151,1151,1151,1206,1071.11,1514.99 219 | 2020-03-05,1184,1184,1184,1208.5,1071.11,1499.1 220 | 2020-03-06,1187,1187,1187,1209.25,1054.59,1448.04 221 | 2020-03-07,1157,1157,1157,1206,1054.59,1419.93 222 | 2020-03-08,1132,1132,1132,1203.75,1054.59,1419.93 223 | 2020-03-09,1108,1108,1108,1200.5,1054.59,1407.27 224 | 2020-03-10,1212,1212,1212,1197.5,1057.35,1407.27 225 | 2020-03-11,1279,1279,1279,1182.5,1057.35,1407.27 226 | 2020-03-12,1279,1279,1279,1176,1057.35,1382.68 227 | 2020-03-13,1380,1380,1380,1172.75,1052.39,1341.57 228 | 2020-03-14,1370,1370,1370,1172.75,1052.39,1341.57 229 | 2020-03-15,1374,1374,1374,1171,1052.39,1341.57 230 | 2020-03-16,1403,1403,1403,1171,1052.39,1341.57 231 | 2020-03-17,1497,1497,1497,1166.5,1057.22,1329.84 232 | 2020-03-18,1584,1584,1584,1166.5,1057.22,1305.17 233 | 2020-03-19,1690,1690,1690,1165.5,1040.66,1305.17 234 | 2020-03-20,1905,1905,1905,1161,1038.8,1305.17 235 | 2020-03-21,2006,2006,2006,1153,1038.8,1294.13 236 | 2020-03-22,2039,2039,2039,1152.75,1036.385,1266.3 237 | 2020-03-23,2315,2315,2315,1150.75,1021.745,1266.3 238 | 2020-03-24,2546,2546,2546,1147.75,1021.745,1255.93 239 | 2020-03-25,2662,2662,2662,1147.75,1021.745,1251.1 240 | 2020-03-26,2617,2617,2617,1144.25,1021.745,1251.1 241 | 2020-03-27,2848,2848,2848,1140.5,1025.195,1261.72 242 | 2020-03-28,2807,2807,2807,1140.5,1025.195,1261.72 243 | 2020-03-29,2662,2662,2662,1133,1025.195,1261.72 244 | 2020-03-30,2797,2797,2797,1133,1029.9,1261.72 245 | 2020-03-31,2965,2965,2965,1133,1029.9,1255.51 246 | 2020-04-01,2893,2893,2893,1132.5,1025.76,1255.51 247 | 2020-04-02,2755,2755,2755,1126.5,1025.76,1255.51 248 | 2020-04-03,2747,2747,2747,1126.5,1021.45,1244.17 249 | 2020-04-04,2474,2474,2474,1112,1021.45,1228.99 250 | 2020-04-05,2528,2528,2528,1111,1021.45,1228.99 251 | 2020-04-06,2457,2457,2457,1110,1024.21,1205.51 252 | 2020-04-07,2537,2537,2537,1109.5,1021.45,1196.54 253 | 2020-04-08,2418,2418,2418,1111,1020.07,1196.54 254 | 2020-04-09,2234,2234,2234,1107.5,1020.07,1196.54 255 | 2020-04-10,2186,2186,2186,1105.5,1022.38,1193.09 256 | 2020-04-11,2069,2069,2069,1108.5,1022.38,1193.09 257 | 2020-04-12,1978,1978,1978,1107.5,1015.575,1193.09 258 | 2020-04-13,1942,1942,1942,1105.5,999.78,1197.23 259 | 2020-04-14,1909,1909,1909,1104,981.425,1197.23 260 | 2020-04-15,1831,1831,1831,1093,981.425,1209.05 261 | 2020-04-16,1715,1715,1715,1089.5,981.425,1209.05 262 | 2020-04-17,1758,1758,1758,1082,976.25,1211.12 263 | 2020-04-18,1658,1658,1658,1080.5,958.69,1211.12 264 | 2020-04-19,1526,1526,1526,1072,958.69,1211.12 265 | 2020-04-20,1487,1487,1487,1062.5,958.69,1211.12 266 | 2020-04-21,1594,1594,1594,1064,959.035,1211.12 267 | 2020-04-22,1397,1397,1397,1065,959.035,1172.23 268 | 2020-04-23,1341,1341,1341,1064,959.035,1172.23 269 | 2020-04-24,1438,1438,1438,1062,959.035,1160.62 270 | 2020-04-25,1340,1340,1340,1062.5,960.535,1160.62 271 | 2020-04-26,1231,1231,1231,1065.5,960.535,1160.62 272 | 2020-04-27,1270,1270,1270,1066,963.07,1160.62 273 | 2020-04-28,1293,1293,1293,1061,951.7,1148.96 274 | 2020-04-29,1204,1204,1204,1051.5,951.7,1148.96 275 | 2020-04-30,1209,1209,1209,1053.25,951.7,1126.55 276 | 2020-05-01,1182,1182,1182,1054.5,949.63,1161.1 277 | 2020-05-02,1202,1202,1202,1054.5,949.63,1161.1 278 | 2020-05-03,1158,1158,1158,1047.75,949.63,1161.1 279 | 2020-05-04,1132,1132,1132,1048,949.63,1161.1 280 | 2020-05-05,1278,1278,1278,1055.5,969.04,1161.1 281 | 2020-05-06,1168,1168,1168,1057,953.97,1175.75 282 | 2020-05-07,1175,1175,1175,1058,953.97,1175.75 283 | 2020-05-08,1194,1194,1194,1058,971.91,1205.71 284 | 2020-05-09,1108,1108,1108,1052,952.59,1205.71 285 | 2020-05-10,949,949,949,1052,952.59,1205.71 286 | 2020-05-11,1017,1017,1017,1052,952.59,1205.71 287 | 2020-05-12,1047,1047,1047,1049,949.14,1205.71 288 | 2020-05-13,1077,1077,1077,1046.5,954.45,1180.87 289 | 2020-05-14,1023,1023,1023,1043.75,954.45,1172.59 290 | 2020-05-15,1052,1052,1052,1040.25,950.07,1144.31 291 | 2020-05-16,949,949,949,1039.75,947.69,1142.93 292 | 2020-05-17,968,968,968,1032,947.69,1142.93 293 | 2020-05-18,942,942,942,1032,942.97,1142.93 294 | 2020-05-19,995,995,995,1031.75,942.97,1141.31 295 | 2020-05-20,1056,1056,1056,1038.5,942.97,1128.89 296 | 2020-05-21,1072,1072,1072,1035,942.97,1134.17 297 | 2020-05-22,1143,1143,1143,1039,942.97,1134.17 298 | 2020-05-23,1034,1034,1034,1035,930.28,1139.775 299 | 2020-05-24,1034,1034,1034,1037,930.28,1139.775 300 | 2020-05-25,1015,1015,1015,1033,940.63,1139.775 301 | 2020-05-26,1025,1025,1025,1031.5,932.35,1139.775 302 | 2020-05-27,1052,1052,1052,1023,932.35,1139.775 303 | 2020-05-28,1038,1038,1038,1022,932.35,1134.945 304 | 2020-05-29,1066,1066,1066,1021,932.35,1132.875 305 | 2020-05-30,1063,1063,1063,1021.5,948.04,1113.82 306 | 2020-05-31,966,966,966,1021,931.42,1124.86 307 | 2020-06-01,992,992,992,1024.5,925.9,1124.86 308 | 2020-06-02,1009,1009,1009,1024.5,916.83,1124.86 309 | 2020-06-03,991,991,991,1028.5,916.83,1124.86 310 | 2020-06-04,1011,1011,1011,1021,916.83,1124.86 311 | 2020-06-05,965,965,965,1027.5,916.83,1103.68 312 | 2020-06-06,915,915,915,1027.5,916.83,1102.3 313 | 2020-06-07,867,867,867,1018.5,917.52,1101.68 314 | 2020-06-08,887,887,887,1011.5,917.52,1118.24 315 | 2020-06-09,915,915,915,1010,918.14,1118.24 316 | 2020-06-10,979,979,979,1008.5,918.14,1125.65 317 | 2020-06-11,924,924,924,1016.5,918.14,1137.55 318 | 2020-06-12,1027,1027,1027,1006.5,900.67,1137.55 319 | 2020-06-13,921,921,921,1006.5,900.67,1137.55 320 | 2020-06-14,843,843,843,1009.75,900.67,1138.93 321 | 2020-06-15,952,952,952,1014.75,900.67,1138.93 322 | 2020-06-16,960,960,960,1023,898.6,1138.93 323 | 2020-06-17,947,947,947,1014.25,898.6,1138.93 324 | 2020-06-18,1002,1002,1002,1006.5,898.6,1144.51 325 | 2020-06-19,918,918,918,1009.75,920.66,1144.51 326 | 2020-06-20,976,976,976,1010.5,920.66,1148.65 327 | 2020-06-21,922,922,922,1011,927.56,1148.65 328 | 2020-06-22,924,924,924,1011,927.56,1148.65 329 | 2020-06-23,1085,1085,1085,1011,923.84,1148.65 330 | 2020-06-24,1062,1062,1062,1016,914.18,1148.65 331 | 2020-06-25,1031,1031,1031,1019,914.18,1144 332 | 2020-06-26,1066,1066,1066,1022,914.18,1145.86 333 | 2020-06-27,1031,1031,1031,1034.5,914.18,1159.61 334 | 2020-06-28,908,908,908,1046.5,914.18,1173.41 335 | 2020-06-29,968,968,968,1054.25,905.9,1173.41 336 | 2020-06-30,1079,1079,1079,1049,917.28,1173.41 337 | 2020-07-01,1062,1062,1062,1039.5,915.21,1173.41 338 | 2020-07-02,1080,1080,1080,1038.5,915.21,1173.41 339 | 2020-07-03,1037,1037,1037,1043.5,915.21,1190.3 340 | 2020-07-04,1001,1001,1001,1041.5,915.21,1219.06 341 | 2020-07-05,995,995,995,1036,907.76,1220.44 342 | 2020-07-06,1009,1009,1009,1035.5,913.97,1225.96 343 | 2020-07-07,1052,1052,1052,1039.25,913.97,1225.96 344 | 2020-07-08,1033,1033,1033,1040.75,916.04,1225.96 345 | 2020-07-09,1099,1099,1099,1042.5,916.04,1225.96 346 | 2020-07-10,1105,1105,1105,1039.75,916.04,1225.96 347 | 2020-07-11,1057,1057,1057,1038.75,916.04,1215.48 348 | 2020-07-12,957,957,957,1037.5,929.28,1208.58 349 | 2020-07-13,1003,1003,1003,1035.5,929.28,1182.3 350 | 2020-07-14,1029,1029,1029,1029.75,940.59,1199.55 351 | 2020-07-15,1009,1009,1009,1029,940.59,1199.55 352 | 2020-07-16,1007,1007,1007,1023,940.59,1199.55 353 | 2020-07-17,1073,1073,1073,1022,937.83,1180.75 354 | 2020-07-18,1090,1090,1090,1016.75,928.53,1180.75 355 | 2020-07-19,966,966,966,1016,904.38,1180.75 356 | 2020-07-20,1035,1035,1035,1015.25,904.38,1155.91 357 | 2020-07-21,1044,1044,1044,1014.5,904.38,1133.55 358 | 2020-07-22,1076,1072.52006921336,1079.70386834482,1015,904.38,1133.55 359 | 2020-07-23,1049,1045.73542285861,1052.47922204886,1015.5,904.38,1125.96 360 | 2020-07-24,1097,1093.50170442111,1100.72174009631,1015,904.38,1125.96 361 | 2020-07-25,1121,1117.38939910818,1124.84215334365,1015.5,906.38,1098.23 362 | 2020-07-26,1037,1032.94102769568,1041.31582812554,1015,915.28,1098.23 363 | 2020-07-27,1047,1042.90293608532,1051.35216426816,1008.5,915.28,1085.93 364 | 2020-07-28,1130,1125.96195366219,1134.28358782271,1008.5,908.38,1076.93 365 | 2020-07-29,1203,1199.12436558425,1207.11599423598,1012,908.38,1083.65 366 | 2020-07-30,1189,1185.37712463074,1192.85315020031,1008.5,908.38,1095.55 367 | 2020-07-31,1177,1173.18268340375,1181.05397657059,1008.5,908.38,1114.19 368 | 2020-08-01,1195,1190.9930293307,1199.25469605461,1007.5,916.59,1151.41 369 | -------------------------------------------------------------------------------- /dat/economist.csv: -------------------------------------------------------------------------------- 1 | "","Country","HDI.Rank","HDI","CPI","Region" 2 | "1","Afghanistan",172,0.398,1.5,"Asia Pacific" 3 | "2","Albania",70,0.739,3.1,"East EU Cemt Asia" 4 | "3","Algeria",96,0.698,2.9,"MENA" 5 | "4","Angola",148,0.486,2,"SSA" 6 | "5","Argentina",45,0.797,3,"Americas" 7 | "6","Armenia",86,0.716,2.6,"East EU Cemt Asia" 8 | "7","Australia",2,0.929,8.8,"Asia Pacific" 9 | "8","Austria",19,0.885,7.8,"EU W. Europe" 10 | "9","Azerbaijan",91,0.7,2.4,"East EU Cemt Asia" 11 | "10","Bahamas",53,0.771,7.3,"Americas" 12 | "11","Bahrain",42,0.806,5.1,"MENA" 13 | "12","Bangladesh",146,0.5,2.7,"Asia Pacific" 14 | "13","Barbados",47,0.793,7.8,"Americas" 15 | "14","Belarus",65,0.756,2.4,"East EU Cemt Asia" 16 | "15","Belgium",18,0.886,7.5,"EU W. Europe" 17 | "16","Benin",167,0.427,3,"SSA" 18 | "17","Bhutan",141,0.522,5.7,"Asia Pacific" 19 | "18","Bolivia",108,0.663,2.8,"Americas" 20 | "19","Bosnia and Herzegovina",74,0.733,3.2,"East EU Cemt Asia" 21 | "20","Botswana",118,0.633,6.1,"SSA" 22 | "21","Brazil",84,0.718,3.8,"Americas" 23 | "22","Britain",28,0.863,7.8,"EU W. Europe" 24 | "23","Bulgaria",55,0.771,3.3,"EU W. Europe" 25 | "24","Burkina Faso",181,0.331,3,"SSA" 26 | "25","Burundi",185,0.316,1.9,"SSA" 27 | "26","Cambodia",139,0.523,2.1,"Asia Pacific" 28 | "27","Cameroon",150,0.482,2.5,"SSA" 29 | "28","Canada",6,0.908,8.7,"Americas" 30 | "29","Cape Verde",133,0.568,5.5,"SSA" 31 | "30","Central African Republic",179,0.343,2.2,"SSA" 32 | "31","Chad",183,0.328,2,"SSA" 33 | "32","Chile",44,0.805,7.2,"Americas" 34 | "33","China",101,0.687,3.6,"Asia Pacific" 35 | "34","Colombia",87,0.71,3.4,"Americas" 36 | "35","Comoros",163,0.433,2.4,"SSA" 37 | "36","Congo",187,0.286,2,"SSA" 38 | "37","Congo Republic",137,0.533,2.2,"SSA" 39 | "38","Costa Rica",69,0.744,4.8,"Americas" 40 | "39","Côte d'Ivoire",170,0.4,2.2,"SSA" 41 | "40","Croatia",46,0.796,4,"East EU Cemt Asia" 42 | "41","Cuba",51,0.776,4.2,"Americas" 43 | "42","Cyprus",31,0.84,6.3,"EU W. Europe" 44 | "43","Czech Republic",27,0.865,4.4,"EU W. Europe" 45 | "44","Denmark",16,0.895,9.4,"EU W. Europe" 46 | "45","Djibouti",165,0.43,3,"SSA" 47 | "46","Dominica",81,0.724,5.2,"Americas" 48 | "47","Dominican Republic",98,0.689,2.6,"Americas" 49 | "48","Ecuador",83,0.72,2.7,"Americas" 50 | "49","Egypt",113,0.644,2.9,"MENA" 51 | "50","El Salvador",105,0.674,3.4,"Americas" 52 | "51","Equatorial Guinea",136,0.537,1.9,"SSA" 53 | "52","Eritrea",177,0.349,2.5,"SSA" 54 | "53","Estonia",34,0.835,6.4,"EU W. Europe" 55 | "54","Ethiopia",174,0.363,2.7,"SSA" 56 | "55","Finland",22,0.882,9.4,"EU W. Europe" 57 | "56","France",20,0.884,7,"EU W. Europe" 58 | "57","Gabon",106,0.674,3,"SSA" 59 | "58","Gambia",168,0.42,3.5,"SSA" 60 | "59","Georgia",75,0.733,4.1,"East EU Cemt Asia" 61 | "60","Germany",9,0.905,8,"EU W. Europe" 62 | "61","Ghana",135,0.541,3.9,"SSA" 63 | "62","Greece",29,0.861,3.4,"EU W. Europe" 64 | "63","Guatemala",131,0.574,2.7,"Americas" 65 | "64","Guinea",178,0.344,2.1,"SSA" 66 | "65","Guinea-Bissau",176,0.353,2.2,"SSA" 67 | "66","Guyana",117,0.633,2.5,"Americas" 68 | "67","Haiti",158,0.454,1.8,"Americas" 69 | "68","Honduras",121,0.625,2.6,"Americas" 70 | "69","Hong Kong",13,0.898,8.4,"Asia Pacific" 71 | "70","Hungary",38,0.816,4.6,"EU W. Europe" 72 | "71","Iceland",14,0.898,8.3,"EU W. Europe" 73 | "72","India",134,0.547,3.1,"Asia Pacific" 74 | "73","Indonesia",124,0.617,3,"Asia Pacific" 75 | "74","Iran",88,0.707,2.7,"MENA" 76 | "75","Iraq",132,0.573,1.8,"MENA" 77 | "76","Ireland",7,0.908,7.5,"EU W. Europe" 78 | "77","Israel",17,0.888,5.8,"MENA" 79 | "78","Italy",24,0.874,3.9,"EU W. Europe" 80 | "79","Jamaica",79,0.727,3.3,"Americas" 81 | "80","Japan",12,0.901,8,"Asia Pacific" 82 | "81","Jordan",95,0.698,4.5,"MENA" 83 | "82","Kazakhstan",68,0.745,2.7,"East EU Cemt Asia" 84 | "83","Kenya",143,0.509,2.2,"SSA" 85 | "84","Kiribati",122,0.624,3.1,"Asia Pacific" 86 | "85","Korea (South)",15,0.897,5.4,"Asia Pacific" 87 | "86","Kuwait",63,0.76,4.6,"MENA" 88 | "87","Kyrgyzstan",126,0.615,2.1,"East EU Cemt Asia" 89 | "88","Laos",138,0.524,2.2,"Asia Pacific" 90 | "89","Latvia",43,0.805,4.2,"EU W. Europe" 91 | "90","Lebanon",71,0.739,2.5,"MENA" 92 | "91","Lesotho",160,0.45,3.5,"SSA" 93 | "92","Liberia",182,0.329,3.2,"SSA" 94 | "93","Libya",64,0.76,2,"MENA" 95 | "94","Lithuania",40,0.81,4.8,"EU W. Europe" 96 | "95","Luxembourg",25,0.867,8.5,"EU W. Europe" 97 | "96","Madagascar",151,0.48,3,"SSA" 98 | "97","Malawi",171,0.4,3,"SSA" 99 | "98","Malaysia",61,0.761,4.3,"Asia Pacific" 100 | "99","Maldives",109,0.661,2.5,"Asia Pacific" 101 | "100","Mali",175,0.359,2.8,"SSA" 102 | "101","Malta",36,0.832,5.6,"EU W. Europe" 103 | "102","Mauritania",159,0.453,2.4,"SSA" 104 | "103","Mauritius",77,0.728,5.1,"SSA" 105 | "104","Mexico",57,0.77,3,"Americas" 106 | "105","Moldova",111,0.649,2.9,"East EU Cemt Asia" 107 | "106","Mongolia",110,0.653,2.7,"Asia Pacific" 108 | "107","Montenegro",54,0.771,4,"East EU Cemt Asia" 109 | "108","Morocco",130,0.582,3.4,"MENA" 110 | "109","Mozambique",184,0.322,2.7,"SSA" 111 | "110","Myanmar",149,0.483,1.5,"Asia Pacific" 112 | "111","Namibia",120,0.625,4.4,"SSA" 113 | "112","Nepal",157,0.458,2.2,"Asia Pacific" 114 | "113","Netherlands",3,0.91,8.9,"EU W. Europe" 115 | "114","New Zealand",5,0.908,9.5,"Asia Pacific" 116 | "115","Nicaragua",129,0.589,2.5,"Americas" 117 | "116","Niger",186,0.295,2.5,"SSA" 118 | "117","Nigeria",156,0.459,2.4,"SSA" 119 | "118","Norway",1,0.943,9,"EU W. Europe" 120 | "119","Oman",89,0.705,4.8,"MENA" 121 | "120","Pakistan",145,0.504,2.5,"Asia Pacific" 122 | "121","Panama",58,0.768,3.3,"Americas" 123 | "122","Papua New Guinea",153,0.466,2.2,"Asia Pacific" 124 | "123","Paraguay",107,0.665,2.2,"Americas" 125 | "124","Peru",80,0.725,3.4,"Americas" 126 | "125","Philippines",112,0.644,2.6,"Asia Pacific" 127 | "126","Poland",39,0.813,5.5,"EU W. Europe" 128 | "127","Portugal",41,0.809,6.1,"EU W. Europe" 129 | "128","Qatar",37,0.831,7.2,"MENA" 130 | "129","Romania",50,0.781,3.6,"EU W. Europe" 131 | "130","Russia",66,0.755,2.4,"East EU Cemt Asia" 132 | "131","Rwanda",166,0.429,5,"SSA" 133 | "132","Saint Lucia",82,0.723,7,"Americas" 134 | "133","Saint Vincent and the Grenadines",85,0.717,5.8,"Americas" 135 | "134","Samoa",99,0.688,3.9,"Asia Pacific" 136 | "135","Saudi Arabia",56,0.77,4.4,"MENA" 137 | "136","Senegal",155,0.459,2.9,"SSA" 138 | "137","Serbia",59,0.766,3.3,"East EU Cemt Asia" 139 | "138","Seychelles",52,0.773,4.8,"SSA" 140 | "139","Sierra Leone",180,0.336,2.5,"SSA" 141 | "140","Singapore",26,0.866,9.2,"Asia Pacific" 142 | "141","Slovakia",35,0.834,4,"EU W. Europe" 143 | "142","Slovenia",21,0.884,5.9,"EU W. Europe" 144 | "143","Solomon Islands",142,0.51,2.7,"Asia Pacific" 145 | "144","South Africa",123,0.619,4.1,"SSA" 146 | "145","Spain",23,0.878,6.2,"EU W. Europe" 147 | "146","Sri Lanka",97,0.691,3.3,"Asia Pacific" 148 | "147","Sudan",169,0.408,1.6,"SSA" 149 | "148","Suriname",104,0.68,3,"Americas" 150 | "149","Swaziland",140,0.522,3.1,"SSA" 151 | "150","Sweden",10,0.904,9.3,"EU W. Europe" 152 | "151","Switzerland",11,0.903,8.8,"EU W. Europe" 153 | "152","Syria",119,0.632,2.6,"MENA" 154 | "153","Tajikistan",127,0.607,2.3,"East EU Cemt Asia" 155 | "154","Tanzania",152,0.466,3,"SSA" 156 | "155","Thailand",103,0.682,3.4,"Asia Pacific" 157 | "156","Timor-Leste",147,0.495,2.4,"Asia Pacific" 158 | "157","Togo",162,0.435,2.4,"SSA" 159 | "158","Tonga",90,0.704,3.1,"Asia Pacific" 160 | "159","Trinidad and Tobago",62,0.76,3.2,"Americas" 161 | "160","Tunisia",94,0.698,3.8,"MENA" 162 | "161","Turkey",92,0.699,4.2,"East EU Cemt Asia" 163 | "162","Turkmenistan",102,0.686,1.6,"East EU Cemt Asia" 164 | "163","Uganda",161,0.446,2.4,"SSA" 165 | "164","Ukraine",76,0.729,2.3,"East EU Cemt Asia" 166 | "165","United Arab Emirates",30,0.846,6.8,"MENA" 167 | "166","United States",4,0.91,7.1,"Americas" 168 | "167","Uruguay",48,0.783,7,"Americas" 169 | "168","Uzbekistan",115,0.641,1.6,"East EU Cemt Asia" 170 | "169","Vanuatu",125,0.617,3.5,"Asia Pacific" 171 | "170","Venezuela",73,0.735,1.9,"Americas" 172 | "171","Yemen",154,0.462,2.1,"MENA" 173 | "172","Zambia",164,0.43,3.2,"SSA" 174 | "173","Zimbabwe",173,0.376,2.2,"SSA" 175 | -------------------------------------------------------------------------------- /dat/elecciones_2019_provincias.csv: -------------------------------------------------------------------------------- 1 | "ccaa_nombre","provincia_cod_ine","provincia_nombre","poblacion","censo_electoral","votos_validos","votos_candidaturas","votos_blanco","votos_nulos" 2 | "Andalucía",4,"Almería",709340,502627,302424,299763,2661,2990 3 | "Andalucía",11,"Cádiz",1238714,1002295,616079,606858,9221,8116 4 | "Andalucía",14,"Córdoba",785240,648341,444376,438971,5405,7399 5 | "Andalucía",18,"Granada",912075,755007,482779,478251,4528,8123 6 | "Andalucía",21,"Huelva",519932,399019,250681,247336,3345,4648 7 | "Andalucía",23,"Jaén",638099,526659,365106,361745,3361,5937 8 | "Andalucía",29,"Málaga",1641121,1197688,756721,748363,8358,10098 9 | "Andalucía",41,"Sevilla",1939887,1547744,1053518,1039725,13793,17729 10 | "Aragón",22,"Huesca",219345,172722,113597,112234,1363,1194 11 | "Aragón",44,"Teruel",134572,107467,74130,73727,403,531 12 | "Aragón",50,"Zaragoza",954811,739573,513284,508295,4989,4355 13 | "Principado de Asturias",33,"Asturias",1028244,972580,559745,552704,7041,5486 14 | "Illes Balears",7,"Illes Balears",1128908,807170,454199,449531,4668,4393 15 | "Canarias",35,"Las Palmas",1109175,871728,483928,479953,3975,5426 16 | "Canarias",38,"Santa Cruz de Tenerife",1018510,855138,463579,460199,3380,4443 17 | "Cantabria",39,"Cantabria",580229,501676,327089,325422,1667,2732 18 | "Castilla - La Mancha",2,"Albacete",388786,309996,214304,212482,1822,2613 19 | "Castilla - La Mancha",13,"Ciudad Real",499100,395785,268594,266237,2357,3876 20 | "Castilla - La Mancha",16,"Cuenca",197222,154441,109119,108117,1002,1418 21 | "Castilla - La Mancha",19,"Guadalajara",254308,187371,132154,131006,1148,1642 22 | "Castilla - La Mancha",45,"Toledo",687391,525752,363474,360813,2661,5145 23 | "Castilla y León",5,"Ávila",158498,136717,93496,92741,755,1297 24 | "Castilla y León",9,"Burgos",357070,298989,198971,196345,2626,2693 25 | "Castilla y León",24,"León",463746,432073,262679,259969,2710,3032 26 | "Castilla y León",34,"Palencia",162035,141321,95788,94773,1015,1250 27 | "Castilla y León",37,"Salamanca",331473,305536,195170,193188,1982,2503 28 | "Castilla y León",40,"Segovia",153342,119492,85039,84034,1005,1412 29 | "Castilla y León",42,"Soria",88600,76827,46410,45689,721,838 30 | "Castilla y León",47,"Valladolid",519851,432655,311454,308307,3147,3333 31 | "Castilla y León",49,"Zamora",174549,168268,99791,98585,1206,1543 32 | "Cataluña",8,"Barcelona",5609350,4201151,2927755,2907298,20457,14599 33 | "Cataluña",17,"Girona",761947,524978,355702,353395,2307,2099 34 | "Cataluña",25,"Lleida",432866,314425,207356,205816,1540,1375 35 | "Cataluña",43,"Tarragona",795902,574866,385419,382704,2715,2669 36 | "Extremadura",6,"Badajoz",676376,554994,370159,366560,3599,6781 37 | "Extremadura",10,"Cáceres",396487,344445,223257,221363,1894,4364 38 | "Galicia",15,"A Coruña",1119351,1087839,613494,606187,7307,7056 39 | "Galicia",27,"Lugo",331327,344446,180145,178051,2094,2996 40 | "Galicia",32,"Ourense",309293,360302,171471,169805,1666,2127 41 | "Galicia",36,"Pontevedra",941772,906111,522997,517855,5142,7080 42 | "Comunidad de Madrid",28,"Madrid",6578079,5088093,3563147,3534364,28783,28317 43 | "Comunidad Foral de Navarra",31,"Navarra",647554,512826,334982,331531,3451,3014 44 | "País Vasco",1,"Araba / Álava",328868,258495,170855,169944,911,1344 45 | "País Vasco",20,"Gipuzkoa",720592,584461,382868,380961,1907,1678 46 | "País Vasco",48,"Bizkaia",1149628,949598,630312,626506,3806,3665 47 | "Región de Murcia",30,"Murcia",1478509,1061841,714927,709674,5253,7418 48 | "La Rioja",26,"La Rioja",315675,250213,164934,163177,1757,2615 49 | "Comunitat Valenciana",3,"Alicante / Alacant",1838819,1276691,851716,844938,6778,8334 50 | "Comunitat Valenciana",12,"Castellón / Castelló",576898,420741,294469,292231,2238,3023 51 | "Comunitat Valenciana",46,"Valencia / València",2547986,1970196,1390258,1379460,10798,12147 52 | "Ciudad de Ceuta",51,"Ceuta",85144,62513,33395,33071,324,351 53 | "Ciudad de Melilla",52,"Melilla",86384,59497,30932,30747,185,240 54 | -------------------------------------------------------------------------------- /dat/elecciones_2019_votos.csv: -------------------------------------------------------------------------------- 1 | "provincia_cod_ine","partido","votos" 2 | 4,"psoe",89295 3 | 11,"psoe",188271 4 | 14,"psoe",146761 5 | 18,"psoe",160190 6 | 21,"psoe",91656 7 | 23,"psoe",141737 8 | 29,"psoe",226831 9 | 41,"psoe",380385 10 | 22,"psoe",38101 11 | 44,"psoe",18934 12 | 50,"psoe",158326 13 | 33,"psoe",186211 14 | 7,"psoe",115567 15 | 35,"psoe",141078 16 | 38,"psoe",132518 17 | 39,"psoe",76028 18 | 2,"psoe",69848 19 | 13,"psoe",92046 20 | 16,"psoe",40670 21 | 19,"psoe",41167 22 | 45,"psoe",116282 23 | 5,"psoe",24474 24 | 9,"psoe",64182 25 | 24,"psoe",87896 26 | 34,"psoe",31847 27 | 37,"psoe",57481 28 | 40,"psoe",25233 29 | 42,"psoe",16043 30 | 47,"psoe",94384 31 | 49,"psoe",32747 32 | 8,"psoe",638319 33 | 17,"psoe",52723 34 | 25,"psoe",29983 35 | 43,"psoe",73641 36 | 6,"psoe",142312 37 | 10,"psoe",85135 38 | 15,"psoe",184178 39 | 27,"psoe",57537 40 | 32,"psoe",56934 41 | 36,"psoe",166377 42 | 28,"psoe",957401 43 | 31,"psoe",83734 44 | 1,"psoe",37488 45 | 20,"psoe",69342 46 | 48,"psoe",120566 47 | 30,"psoe",177154 48 | 26,"psoe",57485 49 | 3,"psoe",240202 50 | 12,"psoe",84078 51 | 46,"psoe",375879 52 | 51,"psoe",10455 53 | 52,"psoe",5087 54 | 4,"pp",78072 55 | 11,"pp",111089 56 | 14,"pp",99999 57 | 18,"pp",105192 58 | 21,"pp",49452 59 | 23,"pp",82055 60 | 29,"pp",163177 61 | 41,"pp",188166 62 | 22,"pp",29804 63 | 44,"pp",17520 64 | 50,"pp",119909 65 | 33,"pp",129945 66 | 7,"pp",103722 67 | 35,"pp",103375 68 | 38,"pp",93434 69 | 39,"pp",84583 70 | 2,"pp",58835 71 | 13,"pp",74835 72 | 16,"pp",33721 73 | 19,"pp",30443 74 | 45,"pp",94378 75 | 5,"pp",32527 76 | 9,"pp",61228 77 | 24,"pp",74672 78 | 34,"pp",34195 79 | 37,"pp",67715 80 | 40,"pp",28057 81 | 42,"pp",15247 82 | 47,"pp",91857 83 | 49,"pp",33495 84 | 8,"pp",225645 85 | 17,"pp",17449 86 | 25,"pp",14697 87 | 43,"pp",29923 88 | 6,"pp",92742 89 | 10,"pp",61527 90 | 15,"pp",187127 91 | 27,"pp",68530 92 | 32,"pp",67580 93 | 36,"pp",151961 94 | 28,"pp",887474 95 | 1,"pp",25506 96 | 20,"pp",23619 97 | 48,"pp",55621 98 | 30,"pp",189500 99 | 26,"pp",56450 100 | 3,"pp",207310 101 | 12,"pp",70176 102 | 46,"pp",306929 103 | 51,"pp",7439 104 | 52,"pp",9136 105 | 4,"vox",80714 106 | 11,"vox",131205 107 | 14,"vox",82534 108 | 18,"vox",99928 109 | 21,"vox",52485 110 | 23,"vox",71950 111 | 29,"vox",162280 112 | 41,"vox",188813 113 | 22,"vox",17237 114 | 44,"vox",9346 115 | 50,"vox",92353 116 | 33,"vox",88788 117 | 7,"vox",77520 118 | 35,"vox",64515 119 | 38,"vox",53491 120 | 39,"vox",48827 121 | 2,"vox",44306 122 | 13,"vox",56050 123 | 16,"vox",20108 124 | 19,"vox",31683 125 | 45,"vox",86049 126 | 5,"vox",17313 127 | 9,"vox",29579 128 | 24,"vox",40884 129 | 34,"vox",13816 130 | 37,"vox",34929 131 | 40,"vox",14569 132 | 42,"vox",6264 133 | 47,"vox",56353 134 | 49,"vox",17036 135 | 8,"vox",184715 136 | 17,"vox",18489 137 | 25,"vox",9312 138 | 43,"vox",31124 139 | 6,"vox",64016 140 | 10,"vox",35807 141 | 15,"vox",50325 142 | 27,"vox",14652 143 | 32,"vox",13285 144 | 36,"vox",38119 145 | 28,"vox",653476 146 | 31,"vox",19440 147 | 1,"vox",6421 148 | 20,"vox",7274 149 | 48,"vox",15284 150 | 30,"vox",199829 151 | 26,"vox",18908 152 | 3,"vox",167395 153 | 12,"vox",54849 154 | 46,"vox",245890 155 | 51,"vox",11752 156 | 52,"vox",5692 157 | 4,"podemos",24400 158 | 11,"podemos",93541 159 | 14,"podemos",64769 160 | 18,"podemos",59331 161 | 21,"podemos",30389 162 | 23,"podemos",35962 163 | 29,"podemos",97801 164 | 41,"podemos",153435 165 | 22,"podemos",14035 166 | 44,"podemos",3982 167 | 50,"podemos",57875 168 | 33,"podemos",89301 169 | 7,"podemos",82225 170 | 35,"podemos",74648 171 | 38,"podemos",64613 172 | 39,"podemos",28376 173 | 2,"podemos",20771 174 | 13,"podemos",22250 175 | 16,"podemos",7529 176 | 19,"podemos",14897 177 | 45,"podemos",34837 178 | 5,"podemos",6059 179 | 9,"podemos",22058 180 | 24,"podemos",27478 181 | 34,"podemos",7746 182 | 37,"podemos",13608 183 | 40,"podemos",7901 184 | 42,"podemos",3517 185 | 47,"podemos",34313 186 | 49,"podemos",7001 187 | 6,"podemos",33971 188 | 10,"podemos",20101 189 | 28,"podemos",463629 190 | 31,"podemos",55498 191 | 1,"podemos",28186 192 | 20,"podemos",57363 193 | 48,"podemos",97125 194 | 30,"podemos",63461 195 | 26,"podemos",16273 196 | 3,"podemos",108533 197 | 12,"podemos",39251 198 | 46,"podemos",191812 199 | 51,"podemos",1300 200 | 52,"podemos",809 201 | 8,"erc",618909 202 | 17,"erc",91932 203 | 25,"erc",65236 204 | 43,"erc",98782 205 | 4,"ciudadanos",22835 206 | 11,"ciudadanos",55490 207 | 14,"ciudadanos",36229 208 | 18,"ciudadanos",37772 209 | 21,"ciudadanos",18382 210 | 23,"ciudadanos",24816 211 | 29,"ciudadanos",66995 212 | 41,"ciudadanos",83575 213 | 22,"ciudadanos",9244 214 | 44,"ciudadanos",3732 215 | 50,"ciudadanos",47001 216 | 33,"ciudadanos",37374 217 | 7,"ciudadanos",33451 218 | 35,"ciudadanos",28018 219 | 38,"ciudadanos",22979 220 | 39,"ciudadanos",15609 221 | 2,"ciudadanos",15947 222 | 13,"ciudadanos",18337 223 | 16,"ciudadanos",5094 224 | 19,"ciudadanos",10169 225 | 45,"ciudadanos",24871 226 | 5,"ciudadanos",6119 227 | 9,"ciudadanos",16214 228 | 24,"ciudadanos",16731 229 | 34,"ciudadanos",5937 230 | 37,"ciudadanos",16886 231 | 40,"ciudadanos",6861 232 | 42,"ciudadanos",2670 233 | 47,"ciudadanos",26947 234 | 49,"ciudadanos",6835 235 | 8,"ciudadanos",174124 236 | 17,"ciudadanos",13869 237 | 25,"ciudadanos",7128 238 | 43,"ciudadanos",22814 239 | 6,"ciudadanos",29520 240 | 10,"ciudadanos",15533 241 | 15,"ciudadanos",28469 242 | 27,"ciudadanos",5811 243 | 32,"ciudadanos",6397 244 | 36,"ciudadanos",23984 245 | 28,"ciudadanos",323076 246 | 1,"ciudadanos",2526 247 | 20,"ciudadanos",3824 248 | 48,"ciudadanos",6929 249 | 30,"ciudadanos",53201 250 | 26,"ciudadanos",11673 251 | 3,"ciudadanos",69143 252 | 12,"ciudadanos",20302 253 | 46,"ciudadanos",106820 254 | 51,"ciudadanos",1138 255 | 52,"ciudadanos",917 256 | 8,"jxcat",343931 257 | 17,"jxcat",88060 258 | 25,"jxcat",46773 259 | 43,"jxcat",51461 260 | 8,"encomupodem",452482 261 | 17,"encomupodem",33710 262 | 25,"encomupodem",16337 263 | 43,"encomupodem",46644 264 | 1,"pnv",40262 265 | 20,"pnv",116761 266 | 48,"pnv",221979 267 | 31,"ehbildu",56548 268 | 1,"ehbildu",27453 269 | 20,"ehbildu",98951 270 | 48,"ehbildu",94669 271 | 11,"maspais_equo",11316 272 | 18,"maspais_equo",8629 273 | 29,"maspais_equo",14112 274 | 41,"maspais_equo",22388 275 | 33,"maspais_equo",12732 276 | 35,"maspais_equo",8389 277 | 38,"maspais_equo",6583 278 | 15,"maspais_equo",12619 279 | 36,"maspais_equo",10207 280 | 28,"maspais_equo",201389 281 | 48,"maspais_equo",8542 282 | 30,"maspais_equo",13439 283 | 8,"cup",179041 284 | 17,"cup",31703 285 | 25,"cup",14098 286 | 43,"cup",22129 287 | 15,"podemos_encomun",77069 288 | 27,"podemos_encomun",16548 289 | 32,"podemos_encomun",13573 290 | 36,"podemos_encomun",81041 291 | 35,"coalicioncanaria_nuevacanarias",48028 292 | 38,"coalicioncanaria_nuevacanarias",76261 293 | 31,"navarra_suma",99078 294 | 3,"compromis",35612 295 | 12,"compromis",18140 296 | 46,"compromis",122535 297 | 15,"bng",58135 298 | 27,"bng",12940 299 | 32,"bng",10256 300 | 36,"bng",39125 301 | 39,"prc",68830 302 | 44,"teruelexiste",19761 303 | -------------------------------------------------------------------------------- /dat/poblacion_espana.csv: -------------------------------------------------------------------------------- 1 | "anio","edad_desde","edad_hasta","rango_edad","poblacion" 2 | 1998,0,4,"0-4",1710012 3 | 1998,5,9,"5-9",2047675 4 | 1998,10,14,"10-14",2286899 5 | 1998,15,19,"15-19",2932680 6 | 1998,20,24,"20-24",3353725 7 | 1998,25,29,"25-29",3255862 8 | 1998,30,34,"30-34",3245232 9 | 1998,35,39,"35-39",3024704 10 | 1998,40,44,"40-44",2674025 11 | 1998,45,49,"45-49",2483115 12 | 1998,50,54,"50-54",2333650 13 | 1998,55,59,"55-59",1870903 14 | 1998,60,64,"60-64",2132725 15 | 1998,65,69,"65-69",2067657 16 | 1998,70,74,"70-74",1720303 17 | 1998,75,79,"75-79",1254202 18 | 1998,80,84,"80-84",801932 19 | 1998,85,89,"85-89",457565 20 | 1998,90,94,"90-94",160721 21 | 1998,95,99,"95-99",35589 22 | 1998,100,,">100",3474 23 | 1999,0,4,"0-4",1688935 24 | 1999,5,9,"5-9",2007620 25 | 1999,10,14,"10-14",2248148 26 | 1999,15,19,"15-19",2805795 27 | 1999,20,24,"20-24",3354877 28 | 1999,25,29,"25-29",3284084 29 | 1999,30,34,"30-34",3264850 30 | 1999,35,39,"35-39",3085977 31 | 1999,40,44,"40-44",2772113 32 | 1999,45,49,"45-49",2492883 33 | 1999,50,54,"50-54",2417520 34 | 1999,55,59,"55-59",1991834 35 | 1999,60,64,"60-64",2047961 36 | 1999,65,69,"65-69",2114237 37 | 1999,70,74,"70-74",1778835 38 | 1999,75,79,"75-79",1330590 39 | 1999,80,84,"80-84",823764 40 | 1999,85,89,"85-89",476735 41 | 1999,90,94,"90-94",171651 42 | 1999,95,99,"95-99",39069 43 | 1999,100,,">100",4680 44 | 2000,0,4,"0-4",1680988 45 | 2000,5,9,"5-9",1984020 46 | 2000,10,14,"10-14",2198661 47 | 2000,15,19,"15-19",2682891 48 | 2000,20,24,"20-24",3310735 49 | 2000,25,29,"25-29",3375782 50 | 2000,30,34,"30-34",3321008 51 | 2000,35,39,"35-39",3192124 52 | 2000,40,44,"40-44",2884950 53 | 2000,45,49,"45-49",2511877 54 | 2000,50,54,"50-54",2446733 55 | 2000,55,59,"55-59",2137750 56 | 2000,60,64,"60-64",1909525 57 | 2000,65,69,"65-69",2114370 58 | 2000,70,74,"70-74",1799716 59 | 2000,75,79,"75-79",1393425 60 | 2000,80,84,"80-84",830766 61 | 2000,85,89,"85-89",492338 62 | 2000,90,94,"90-94",183751 63 | 2000,95,99,"95-99",42620 64 | 2000,100,,">100",5760 65 | 2001,0,4,"0-4",1719673 66 | 2001,5,9,"5-9",1964789 67 | 2001,10,14,"10-14",2165410 68 | 2001,15,19,"15-19",2581186 69 | 2001,20,24,"20-24",3288805 70 | 2001,25,29,"25-29",3493759 71 | 2001,30,34,"30-34",3405724 72 | 2001,35,39,"35-39",3291772 73 | 2001,40,44,"40-44",3013529 74 | 2001,45,49,"45-49",2593676 75 | 2001,50,54,"50-54",2449081 76 | 2001,55,59,"55-59",2172174 77 | 2001,60,64,"60-64",1939712 78 | 2001,65,69,"65-69",2110393 79 | 2001,70,74,"70-74",1853382 80 | 2001,75,79,"75-79",1440738 81 | 2001,80,84,"80-84",873270 82 | 2001,85,89,"85-89",507174 83 | 2001,90,94,"90-94",198702 84 | 2001,95,99,"95-99",45128 85 | 2001,100,,">100",8766 86 | 2002,0,4,"0-4",1794363 87 | 2002,5,9,"5-9",1957983 88 | 2002,10,14,"10-14",2156157 89 | 2002,15,19,"15-19",2502700 90 | 2002,20,24,"20-24",3249598 91 | 2002,25,29,"25-29",3626324 92 | 2002,30,34,"30-34",3515143 93 | 2002,35,39,"35-39",3415251 94 | 2002,40,44,"40-44",3130560 95 | 2002,45,49,"45-49",2690755 96 | 2002,50,54,"50-54",2490175 97 | 2002,55,59,"55-59",2271441 98 | 2002,60,64,"60-64",1868006 99 | 2002,65,69,"65-69",2125295 100 | 2002,70,74,"70-74",1879222 101 | 2002,75,79,"75-79",1481879 102 | 2002,80,84,"80-84",917393 103 | 2002,85,89,"85-89",507618 104 | 2002,90,94,"90-94",203179 105 | 2002,95,99,"95-99",46132 106 | 2002,100,,">100",8719 107 | 2003,0,4,"0-4",1901859 108 | 2003,5,9,"5-9",1967866 109 | 2003,10,14,"10-14",2173754 110 | 2003,15,19,"15-19",2444387 111 | 2003,20,24,"20-24",3202594 112 | 2003,25,29,"25-29",3739772 113 | 2003,30,34,"30-34",3631764 114 | 2003,35,39,"35-39",3543043 115 | 2003,40,44,"40-44",3231439 116 | 2003,45,49,"45-49",2801243 117 | 2003,50,54,"50-54",2553834 118 | 2003,55,59,"55-59",2368915 119 | 2003,60,64,"60-64",1879974 120 | 2003,65,69,"65-69",2084403 121 | 2003,70,74,"70-74",1931919 122 | 2003,75,79,"75-79",1503454 123 | 2003,80,84,"80-84",978020 124 | 2003,85,89,"85-89",510743 125 | 2003,90,94,"90-94",211121 126 | 2003,95,99,"95-99",47786 127 | 2003,100,,">100",9174 128 | 2004,0,4,"0-4",1974428 129 | 2004,5,9,"5-9",1975123 130 | 2004,10,14,"10-14",2169159 131 | 2004,15,19,"15-19",2396346 132 | 2004,20,24,"20-24",3093882 133 | 2004,25,29,"25-29",3787336 134 | 2004,30,34,"30-34",3707232 135 | 2004,35,39,"35-39",3603286 136 | 2004,40,44,"40-44",3309804 137 | 2004,45,49,"45-49",2903980 138 | 2004,50,54,"50-54",2556084 139 | 2004,55,59,"55-59",2436629 140 | 2004,60,64,"60-64",1983386 141 | 2004,65,69,"65-69",1985775 142 | 2004,70,74,"70-74",1957443 143 | 2004,75,79,"75-79",1538219 144 | 2004,80,84,"80-84",1026585 145 | 2004,85,89,"85-89",517089 146 | 2004,90,94,"90-94",216853 147 | 2004,95,99,"95-99",49885 148 | 2004,100,,">100",9160 149 | 2005,0,4,"0-4",2094582 150 | 2005,5,9,"5-9",2013087 151 | 2005,10,14,"10-14",2157484 152 | 2005,15,19,"15-19",2371423 153 | 2005,20,24,"20-24",3031633 154 | 2005,25,29,"25-29",3842364 155 | 2005,30,34,"30-34",3850837 156 | 2005,35,39,"35-39",3682374 157 | 2005,40,44,"40-44",3443083 158 | 2005,45,49,"45-49",3046559 159 | 2005,50,54,"50-54",2601811 160 | 2005,55,59,"55-59",2491301 161 | 2005,60,64,"60-64",2149725 162 | 2005,65,69,"65-69",1874237 163 | 2005,70,74,"70-74",1979735 164 | 2005,75,79,"75-79",1575076 165 | 2005,80,84,"80-84",1087466 166 | 2005,85,89,"85-89",526849 167 | 2005,90,94,"90-94",226052 168 | 2005,95,99,"95-99",53911 169 | 2005,100,,">100",8941 170 | 2006,0,4,"0-4",2174969 171 | 2006,5,9,"5-9",2060028 172 | 2006,10,14,"10-14",2140398 173 | 2006,15,19,"15-19",2345244 174 | 2006,20,24,"20-24",2936593 175 | 2006,25,29,"25-29",3817716 176 | 2006,30,34,"30-34",3947739 177 | 2006,35,39,"35-39",3748977 178 | 2006,40,44,"40-44",3524506 179 | 2006,45,49,"45-49",3167423 180 | 2006,50,54,"50-54",2680316 181 | 2006,55,59,"55-59",2495236 182 | 2006,60,64,"60-64",2185427 183 | 2006,65,69,"65-69",1907893 184 | 2006,70,74,"70-74",1978398 185 | 2006,75,79,"75-79",1623278 186 | 2006,80,84,"80-84",1123199 187 | 2006,85,89,"85-89",554010 188 | 2006,90,94,"90-94",230129 189 | 2006,95,99,"95-99",57408 190 | 2006,100,,">100",10077 191 | 2007,0,4,"0-4",2237527 192 | 2007,5,9,"5-9",2114658 193 | 2007,10,14,"10-14",2128647 194 | 2007,15,19,"15-19",2330877 195 | 2007,20,24,"20-24",2854845 196 | 2007,25,29,"25-29",3736671 197 | 2007,30,34,"30-34",4022221 198 | 2007,35,39,"35-39",3806556 199 | 2007,40,44,"40-44",3606689 200 | 2007,45,49,"45-49",3259587 201 | 2007,50,54,"50-54",2762877 202 | 2007,55,59,"55-59",2527275 203 | 2007,60,64,"60-64",2280481 204 | 2007,65,69,"65-69",1839464 205 | 2007,70,74,"70-74",1993753 206 | 2007,75,79,"75-79",1652055 207 | 2007,80,84,"80-84",1161073 208 | 2007,85,89,"85-89",588436 209 | 2007,90,94,"90-94",231800 210 | 2007,95,99,"95-99",57286 211 | 2007,100,,">100",7959 212 | 2008,0,4,"0-4",2339646 213 | 2008,5,9,"5-9",2180874 214 | 2008,10,14,"10-14",2135369 215 | 2008,15,19,"15-19",2354504 216 | 2008,20,24,"20-24",2839138 217 | 2008,25,29,"25-29",3714625 218 | 2008,30,34,"30-34",4136460 219 | 2008,35,39,"35-39",3914570 220 | 2008,40,44,"40-44",3728828 221 | 2008,45,49,"45-49",3353450 222 | 2008,50,54,"50-54",2870373 223 | 2008,55,59,"55-59",2584456 224 | 2008,60,64,"60-64",2372604 225 | 2008,65,69,"65-69",1848880 226 | 2008,70,74,"70-74",1956942 227 | 2008,75,79,"75-79",1703318 228 | 2008,80,84,"80-84",1185745 229 | 2008,85,89,"85-89",634516 230 | 2008,90,94,"90-94",235648 231 | 2008,95,99,"95-99",60548 232 | 2008,100,,">100",7328 233 | 2009,0,4,"0-4",2424045 234 | 2009,5,9,"5-9",2255617 235 | 2009,10,14,"10-14",2138218 236 | 2009,15,19,"15-19",2339181 237 | 2009,20,24,"20-24",2785825 238 | 2009,25,29,"25-29",3601767 239 | 2009,30,34,"30-34",4190045 240 | 2009,35,39,"35-39",3987219 241 | 2009,40,44,"40-44",3799492 242 | 2009,45,49,"45-49",3434704 243 | 2009,50,54,"50-54",2976008 244 | 2009,55,59,"55-59",2588971 245 | 2009,60,64,"60-64",2441811 246 | 2009,65,69,"65-69",1955343 247 | 2009,70,74,"70-74",1875198 248 | 2009,75,79,"75-79",1738241 249 | 2009,80,84,"80-84",1225193 250 | 2009,85,89,"85-89",674868 251 | 2009,90,94,"90-94",242126 252 | 2009,95,99,"95-99",63686 253 | 2009,100,,">100",8249 254 | 2010,0,4,"0-4",2463563 255 | 2010,5,9,"5-9",2314437 256 | 2010,10,14,"10-14",2158340 257 | 2010,15,19,"15-19",2303428 258 | 2010,20,24,"20-24",2695223 259 | 2010,25,29,"25-29",3444435 260 | 2010,30,34,"30-34",4143573 261 | 2010,35,39,"35-39",4046119 262 | 2010,40,44,"40-44",3819461 263 | 2010,45,49,"45-49",3523150 264 | 2010,50,54,"50-54",3088530 265 | 2010,55,59,"55-59",2611876 266 | 2010,60,64,"60-64",2477732 267 | 2010,65,69,"65-69",2105634 268 | 2010,70,74,"70-74",1763966 269 | 2010,75,79,"75-79",1758358 270 | 2010,80,84,"80-84",1259560 271 | 2010,85,89,"85-89",717935 272 | 2010,90,94,"90-94",249131 273 | 2010,95,99,"95-99",67313 274 | 2010,100,,">100",9267 275 | 2011,0,4,"0-4",2470560 276 | 2011,5,9,"5-9",2356355 277 | 2011,10,14,"10-14",2187263 278 | 2011,15,19,"15-19",2267904 279 | 2011,20,24,"20-24",2611257 280 | 2011,25,29,"25-29",3274267 281 | 2011,30,34,"30-34",4059412 282 | 2011,35,39,"35-39",4095793 283 | 2011,40,44,"40-44",3853445 284 | 2011,45,49,"45-49",3580521 285 | 2011,50,54,"50-54",3191434 286 | 2011,55,59,"55-59",2677814 287 | 2011,60,64,"60-64",2470911 288 | 2011,65,69,"65-69",2132734 289 | 2011,70,74,"70-74",1794140 290 | 2011,75,79,"75-79",1762589 291 | 2011,80,84,"80-84",1306383 292 | 2011,85,89,"85-89",749265 293 | 2011,90,94,"90-94",268100 294 | 2011,95,99,"95-99",70073 295 | 2011,100,,">100",10273 296 | 2012,0,4,"0-4",2443703 297 | 2012,5,9,"5-9",2404312 298 | 2012,10,14,"10-14",2214708 299 | 2012,15,19,"15-19",2227550 300 | 2012,20,24,"20-24",2538898 301 | 2012,25,29,"25-29",3115511 302 | 2012,30,34,"30-34",3924173 303 | 2012,35,39,"35-39",4136270 304 | 2012,40,44,"40-44",3885959 305 | 2012,45,49,"45-49",3643293 306 | 2012,50,54,"50-54",3267701 307 | 2012,55,59,"55-59",2747759 308 | 2012,60,64,"60-64",2493288 309 | 2012,65,69,"65-69",2218660 310 | 2012,70,74,"70-74",1733751 311 | 2012,75,79,"75-79",1778125 312 | 2012,80,84,"80-84",1337575 313 | 2012,85,89,"85-89",781087 314 | 2012,90,94,"90-94",289805 315 | 2012,95,99,"95-99",72037 316 | 2012,100,,">100",11156 317 | 2013,0,4,"0-4",2395732 318 | 2013,5,9,"5-9",2444955 319 | 2013,10,14,"10-14",2234950 320 | 2013,15,19,"15-19",2181316 321 | 2013,20,24,"20-24",2476109 322 | 2013,25,29,"25-29",2953136 323 | 2013,30,34,"30-34",3746504 324 | 2013,35,39,"35-39",4125053 325 | 2013,40,44,"40-44",3891290 326 | 2013,45,49,"45-49",3696951 327 | 2013,50,54,"50-54",3309343 328 | 2013,55,59,"55-59",2816529 329 | 2013,60,64,"60-64",2522054 330 | 2013,65,69,"65-69",2289339 331 | 2013,70,74,"70-74",1731551 332 | 2013,75,79,"75-79",1739868 333 | 2013,80,84,"80-84",1379673 334 | 2013,85,89,"85-89",798065 335 | 2013,90,94,"90-94",312427 336 | 2013,95,99,"95-99",72851 337 | 2013,100,,">100",12087 338 | 2014,0,4,"0-4",2302053 339 | 2014,5,9,"5-9",2476203 340 | 2014,10,14,"10-14",2268715 341 | 2014,15,19,"15-19",2150727 342 | 2014,20,24,"20-24",2409523 343 | 2014,25,29,"25-29",2808721 344 | 2014,30,34,"30-34",3520289 345 | 2014,35,39,"35-39",4077813 346 | 2014,40,44,"40-44",3885075 347 | 2014,45,49,"45-49",3706753 348 | 2014,50,54,"50-54",3343247 349 | 2014,55,59,"55-59",2884552 350 | 2014,60,64,"60-64",2495243 351 | 2014,65,69,"65-69",2329338 352 | 2014,70,74,"70-74",1809996 353 | 2014,75,79,"75-79",1652101 354 | 2014,80,84,"80-84",1403973 355 | 2014,85,89,"85-89",825357 356 | 2014,90,94,"90-94",333139 357 | 2014,95,99,"95-99",75358 358 | 2014,100,,">100",13165 359 | 2015,0,4,"0-4",2230847 360 | 2015,5,9,"5-9",2482175 361 | 2015,10,14,"10-14",2306902 362 | 2015,15,19,"15-19",2155056 363 | 2015,20,24,"20-24",2354598 364 | 2015,25,29,"25-29",2695630 365 | 2015,30,34,"30-34",3328153 366 | 2015,35,39,"35-39",3989889 367 | 2015,40,44,"40-44",3909699 368 | 2015,45,49,"45-49",3699662 369 | 2015,50,54,"50-54",3412600 370 | 2015,55,59,"55-59",2979243 371 | 2015,60,64,"60-64",2505943 372 | 2015,65,69,"65-69",2354952 373 | 2015,70,74,"70-74",1944885 374 | 2015,75,79,"75-79",1548072 375 | 2015,80,84,"80-84",1423331 376 | 2015,85,89,"85-89",854272 377 | 2015,90,94,"90-94",355574 378 | 2015,95,99,"95-99",78412 379 | 2015,100,,">100",14487 380 | 2016,0,4,"0-4",2174491 381 | 2016,5,9,"5-9",2477473 382 | 2016,10,14,"10-14",2338899 383 | 2016,15,19,"15-19",2183869 384 | 2016,20,24,"20-24",2316981 385 | 2016,25,29,"25-29",2616684 386 | 2016,30,34,"30-34",3154713 387 | 2016,35,39,"35-39",3888273 388 | 2016,40,44,"40-44",3941053 389 | 2016,45,49,"45-49",3716166 390 | 2016,50,54,"50-54",3459524 391 | 2016,55,59,"55-59",3069211 392 | 2016,60,64,"60-64",2561966 393 | 2016,65,69,"65-69",2340046 394 | 2016,70,74,"70-74",1965457 395 | 2016,75,79,"75-79",1573274 396 | 2016,80,84,"80-84",1425954 397 | 2016,85,89,"85-89",886389 398 | 2016,90,94,"90-94",368545 399 | 2016,95,99,"95-99",83177 400 | 2016,100,,">100",14863 401 | 2017,0,4,"0-4",2126890 402 | 2017,5,9,"5-9",2452597 403 | 2017,10,14,"10-14",2384213 404 | 2017,15,19,"15-19",2215796 405 | 2017,20,24,"20-24",2293337 406 | 2017,25,29,"25-29",2567258 407 | 2017,30,34,"30-34",3012895 408 | 2017,35,39,"35-39",3754948 409 | 2017,40,44,"40-44",3973640 410 | 2017,45,49,"45-49",3740547 411 | 2017,50,54,"50-54",3517607 412 | 2017,55,59,"55-59",3142339 413 | 2017,60,64,"60-64",2625861 414 | 2017,65,69,"65-69",2358764 415 | 2017,70,74,"70-74",2041693 416 | 2017,75,79,"75-79",1519877 417 | 2017,80,84,"80-84",1439758 418 | 2017,85,89,"85-89",912917 419 | 2017,90,94,"90-94",385916 420 | 2017,95,99,"95-99",89898 421 | 2017,100,,">100",15381 422 | -------------------------------------------------------------------------------- /dat/provincias_ccaas.csv: -------------------------------------------------------------------------------- 1 | cod_ine_provincia,cod_ine_ccaa 2 | 4,1 3 | 11,1 4 | 14,1 5 | 18,1 6 | 21,1 7 | 23,1 8 | 29,1 9 | 41,1 10 | 22,2 11 | 44,2 12 | 50,2 13 | 33,3 14 | 7,4 15 | 35,5 16 | 38,5 17 | 39,6 18 | 5,7 19 | 9,7 20 | 24,7 21 | 34,7 22 | 37,7 23 | 40,7 24 | 42,7 25 | 47,7 26 | 49,7 27 | 2,8 28 | 13,8 29 | 16,8 30 | 19,8 31 | 45,8 32 | 8,9 33 | 17,9 34 | 25,9 35 | 43,9 36 | 3,10 37 | 12,10 38 | 46,10 39 | 6,11 40 | 10,11 41 | 15,12 42 | 27,12 43 | 32,12 44 | 36,12 45 | 28,13 46 | 30,14 47 | 31,15 48 | 1,16 49 | 48,16 50 | 20,16 51 | 26,17 52 | 51,18 53 | 52,19 54 | -------------------------------------------------------------------------------- /dat/stations.csv: -------------------------------------------------------------------------------- 1 | "station_id","name","total_bases","number","longitude","address","latitude" 2 | 1,"Puerta del Sol A",24,"1a",-3.7024255,"Puerta del Sol nº 1",40.4168961 3 | 2,"Puerta del Sol B",24,"1b",-3.7024207,"Puerta del Sol nº 1",40.4170009 4 | 3,"Miguel Moya",24,"2",-3.7058415,"Calle Miguel Moya nº 1",40.4205886 5 | 4,"Plaza Conde Suchil",18,"3",-3.7069171,"Plaza del Conde Suchil nº 2-4",40.4302937 6 | 5,"Malasaña",24,"4",-3.7025875,"Calle Manuela Malasaña nº 5",40.4285524 7 | 6,"Fuencarral",27,"5",-3.7020599,"Calle Fuencarral nº 108",40.428528 8 | 7,"Colegio Arquitectos",24,"6",-3.698447,"Calle Hortaleza nº 63",40.424148 9 | 8,"Hortaleza",21,"7",-3.6977715,"Calle Hortaleza nº 75",40.4251906 10 | 9,"Alonso Martínez",24,"8",-3.6954403,"Plaza de Alonso Martínez nº 5",40.4278682 11 | 10,"Plaza de San Miguel",24,"9",-3.7095084,"Plaza de San Miguel nº 9",40.4156057 12 | 11,"Marqués de la Ensenada",24,"10",-3.6918807,"Calle Marqués de la Ensenada nº 16",40.4250863 13 | 12,"San Andrés",24,"11",-3.7035918,"Calle San Andrés nº 18",40.4269483 14 | 13,"San Hermenegildo",24,"12",-3.7061931,"Calle San Bernardo nº 85",40.4284246 15 | 14,"Conde Duque",24,"13",-3.7104417,"Calle Conde Duque nº 22",40.4273264 16 | 15,"Ventura Rodríguez",24,"14",-3.713479,"Calle Ventura Rodríguez nº 2",40.4260957 17 | 16,"San Vicente Ferrer",21,"15",-3.7073764,"Calle San Vicente Ferrer nº 64",40.4261649 18 | 17,"San Bernardo",21,"16",-3.7075065,"Calle San Bernardo nº 22",40.4230721 19 | 18,"Carlos Cambronero",24,"17",-3.7038312,"Plaza de Carlos Cambronero nº 2",40.4232649 20 | 19,"Plaza de Pedro Zerolo",24,"18",-3.6996502,"Plaza de Pedro Zerolo",40.4207773 21 | 20,"Prim",24,"19",-3.6954983,"Calle Prim nº 2",40.4218616 22 | 21,"Banco de España A",30,"20a",-3.6954615,"Calle Alcalá nº 49",40.4192342 23 | 23,"Red de San Luis A",24,"21a",-3.7014814,"Calle Montera nº 48",40.4197872 24 | 24,"Red de San Luis B",24,"21b",-3.7015235,"Calle Montera nº 47",40.4197204 25 | 25,"Jacometrezo",24,"22",-3.7065376,"Calle Jacometrezo nº 3",40.4200783 26 | 26,"Santo Domingo",24,"23",-3.7080733,"Plaza de Santo Domingo nº 1",40.4197429 27 | 27,"Palacio de Oriente",24,"24",-3.710692,"Calle Carlos III nº 1",40.417908 28 | 28,"Plaza de Celenque A",24,"25a",-3.7064809,"Plaza de Celenque nº 1",40.4173114 29 | 29,"Plaza de Celenque B",24,"25b",-3.7063837,"Plaza de Celenque nº 1",40.4172781 30 | 30,"Plaza de las Salesas",24,"26",-3.694475,"Plaza de las Salesas 7",40.423855 31 | 31,"Huertas",24,"27",-3.6956178,"Calle Jesús nº 1",40.4132798 32 | 32,"Sevilla",24,"28",-3.69926,"Calle Alcalá nº 27",40.4181663 33 | 33,"Marqués de Cubas",24,"29",-3.6957355,"Calle del Marqués de Cubas nº 25",40.4162619 34 | 34,"San Quintín",27,"30",-3.711504,"Calle Pavía nº 6",40.4192095 35 | 35,"Calle Mayor",27,"31",-3.7068969,"Calle Mayor nº 20",40.4163638 36 | 36,"Plaza de la Provincia",18,"32",-3.7061032,"Plaza de la Provincia nº 1",40.4150099 37 | 37,"Carretas",24,"33",-3.7031808,"Calle Carretas nº 8",40.4157138 38 | 38,"Jacinto Benavente",24,"34",-3.7036825,"Plaza de Jacinto Benavente",40.4146755 39 | 39,"Plaza del Cordón",24,"35",-3.7103285,"Plaza del Cordón nº 1",40.4141931 40 | 40,"Plaza de Ramales",24,"36",-3.7124038,"Plaza de Ramales nº 1",40.4167281 41 | 41,"Plaza San Francisco",24,"37",-3.7144964,"Plaza de San Francisco nº 5",40.4108442 42 | 42,"Plaza de los Carros",24,"38",-3.7120734,"Carrera de San Francisco nº 1",40.4110406 43 | 43,"Plaza de la Cebada",27,"39",-3.7088337,"Plaza de la Cebada nº 16 ",40.4112744 44 | 44,"Conde de Romanones",24,"40",-3.7049407,"Plaza del Conde de Romanones nº 9",40.4138846 45 | 45,"Antón Martín",21,"41",-3.6991147,"Calle Atocha nº 54",40.4122047 46 | 46,"Santa Isabel",24,"42",-3.6982318,"Calle Santa Isabel nº 32",40.4107085 47 | 47,"Jesús y María",24,"43",-3.7025024,"Calle Lavapiés nº 34-36",40.4101564 48 | 48,"Plaza de Nelson Mandela",21,"44",-3.7040666,"Calle Mesón de Paredes nº 35",40.4097617 49 | 49,"Puerta de Toledo",21,"45",-3.7110513,"Glorieta de la Puerta de Toledo nº 1",40.4070358 50 | 50,"Ribera de Curtidores",24,"46",-3.7071259,"Calle Ribera de Curtidores nº 28",40.4053153 51 | 51,"Embajadores 1",24,"47",-3.7028265,"Glorieta de Embajadores nº 6",40.4047851 52 | 52,"Embajadores 2",24,"48",-3.7022591,"Glorieta de Embajadores nº 2",40.4056107 53 | 53,"Casa Encendida",24,"49",-3.6992759,"Ronda de Atocha nº 34",40.4060941 54 | 54,"Museo Reina Sofía",24,"50",-3.6933463,"Calle Santa Isabel nº 57",40.4083684 55 | 55,"Ronda de Atocha",27,"51",-3.6935205,"Ronda de Atocha nº 2",40.4075606 56 | 56,"Plaza de Santa Ana",24,"52",-3.7007164,"Plaza de Santa Ana nº 10",40.4144226 57 | 57,"Plaza de Lavapiés",24,"53",-3.7008803,"Calle Valencia nº 1",40.4089282 58 | 58,"Barceló",21,"54",-3.700423,"Calle Barceló nº 7",40.4266828 59 | 59,"Plaza de San Ildefonso",24,"55",-3.7020842,"Plaza de San Ildefonso nº 3",40.4239757 60 | 60,"Plaza del Carmen ",24,"56",-3.7032414,"Plaza del Carmen nº 1",40.4184192 61 | 61,"Santa Cruz del Marcenado",24,"57",-3.7126299,"Calle Santa Cruz del Marcenado nº 24",40.4295658 62 | 62,"Augusto Figueroa",24,"58",-3.697895,"Calle Augusto Figueroa nº 33",40.4222862 63 | 63,"Plaza de Juan Pujol",21,"59",-3.7043418,"Calle Espíritu Santo nº 30",40.4255495 64 | 64,"Plaza de la Independencia",24,"60",-3.688398,"Plaza de la Independencia nº 6",40.419752 65 | 65,"Narváez",24,"61",-3.6752045,"Calle O'Donnell nº 28",40.4213983 66 | 66,"O'Donnell",24,"62",-3.6724968,"Calle O'Donnell nº 50",40.4213148 67 | 67,"Ibiza",24,"63",-3.6708959,"Calle Ibiza nº 62",40.4179237 68 | 69,"Antonio Maura",24,"65",-3.6904525,"Calle Antonio Maura nº 15",40.4165605 69 | 71,"Almadén",24,"67",-3.693225,"Calle Almadén nº 28",40.4108472 70 | 72,"Espalter",21,"68",-3.6912023,"Calle Espalter nº 1",40.4128372 71 | 73,"Puerta del Ángel Caído",27,"69",-3.688822,"Avenida de Alfonso XII nº 54",40.409808 72 | 74,"Puerta del Doce de Octubre",24,"70",-3.6779232,"Avenida de Menéndez Pelayo nº 63",40.4153053 73 | 75,"Doce de Octubre",24,"71",-3.6738865,"Calle Doce de Octubre nº 28",40.4159569 74 | 76,"Sainz de Baranda",24,"72",-3.6691838,"Calle Doctor Esquerdo nº 99",40.4157413 75 | 77,"Plaza de los Astros",24,"73",-3.6689089,"Avenida de Nazaret nº 7",40.4114475 76 | 78,"Puerta del Pacífico ",24,"74",-3.6766813,"Avenida de Menéndez Pelayo nº 73",40.4117627 77 | 79,"Menéndez Pelayo",24,"75",-3.6784838,"Avenida de Menéndez Pelayo nº 90",40.4082805 78 | 80,"Puerta de Mariano de Cavia",24,"76",-3.6750121,"Avenida del Mediterráneo nº 19",40.4076726 79 | 81,"Conde de Casal",22,"77",-3.670422,"Plaza del Conde de Casal nº 8",40.40635 80 | 82,"Pedro Bosch",24,"78",-3.6744804,"Calle Cerro de la Plata nº 2",40.4009101 81 | 83,"Puerta de Granada",24,"79",-3.6803874,"Avenida de Menéndez Pelayo nº 38",40.4051451 82 | 84,"Atocha A",24,"80a",-3.6902255,"Paseo de la Infanta Isabel nº 3",40.4075685 83 | 85,"Atocha B",27,"80b",-3.6901234,"Paseo de la Infanta Isabel nº 3",40.4074902 84 | 86,"Cuesta de Moyano",24,"81",-3.691987,"Plaza del Emperador Carlos V nº 11",40.409297 85 | 87,"Niño Jesús",24,"82",-3.6697526,"Calle Doctor Esquerdo nº 161",40.4084556 86 | 88,"Pío Baroja",24,"83",-3.6751105,"Calle Pío Baroja nº 10",40.4130243 87 | 89,"Valderribas",24,"84",-3.6726019,"Calle Doctor Esquerdo nº 191",40.4032501 88 | 90,"Puerta de Madrid",27,"85",-3.680008,"Avenida de Menéndez Pelayo nº 11",40.421501 89 | 91,"Cibeles",21,"86",-3.6926217,"Paseo del Prado nº 1",40.4186148 90 | 92,"Ayala",24,"87",-3.6832566,"Calle Ayala nº 44",40.427736 91 | 93,"Embajada de Italia",24,"88",-3.6838303,"Calle Velázquez nº 75",40.4313576 92 | 94,"Conde Peñalver",24,"89",-3.6752024,"Calle Ayala nº 102",40.4272582 93 | 95,"General Pardiñas",30,"90",-3.6837876,"Calle Goya nº 18",40.4250361 94 | 96,"Príncipe de Vergara",24,"91",-3.6787441,"Calle Hermosilla nº 70",40.426134 95 | 97,"Claudio Coello",24,"92",-3.6865463,"Calle Claudio Coello nº 45",40.4262945 96 | 98,"Plaza de Colón",24,"93",-3.6893698,"Calle Goya nº 1",40.4257046 97 | 99,"Biblioteca Nacional",21,"94",-3.6909648,"Paseo de Recoletos nº 32-34",40.422699 98 | 100,"Villanueva",24,"95",-3.6870548,"Calle Claudio Coello nº 109",40.4226584 99 | 101,"Castelló",27,"96",-3.6821793,"Calle Alcalá nº 111",40.422064 100 | 102,"Alcalá",27,"97",-3.6801307,"Avenida de Menéndez Pelayo nº 3",40.4226906 101 | 103,"Plaza de Felipe II",24,"98",-3.6753567,"Plaza de Felipe II",40.4242625 102 | 104,"Alcántara",24,"99",-3.6738714,"Calle Alcántara nº 2",40.4261851 103 | 105,"Palacio de Deportes",24,"100",-3.6738635,"Calle Goya nº 99",40.4248457 104 | 106,"Jorge Juan",24,"101",-3.6691523,"Calle Jorge Juan nº 131",40.4231526 105 | 107,"Velázquez",24,"102",-3.6840229,"Calle Alcalá nº 95",40.4211802 106 | 108,"Ortega y Gasset",24,"103",-3.6865654,"Calle Ortega y Gasset nº 6",40.4303057 107 | 109,"Castellana",21,"104",-3.6895336,"Paseo de la Castellana nº 4",40.4268331 108 | 110,"Serrano",24,"105",-3.6873922,"Calle Serrano nº 54",40.4267905 109 | 111,"Colón A",18,"106a",-3.6877227,"Calle Serrano nº 34",40.4251002 110 | 112,"Colón B",18,"106b",-3.687745,"Calle Serrano nº 34",40.424963 111 | 113,"Columela",24,"107",-3.6884369,"Calle Serrano nº 6",40.4215246 112 | 114,"Mártires Concepcionistas",27,"108",-3.6706024,"Calle Mártires Concepcionistas nº 2",40.4273005 113 | 115,"Marqués de Salamanca",24,"109",-3.6816402,"Calle José Ortega y Gasset nº 30",40.4300481 114 | 116,"Moncloa",24,"110",-3.7206893,"Paseo de Moret nº 2",40.4344969 115 | 117,"Arcipreste de Hita A",24,"111a",-3.7175435,"Calle Arcipreste de Hita nº 12",40.4337322 116 | 118,"Arcipreste de Hita B",24,"111b",-3.7175115,"Calle Arcipreste de Hita nº 12",40.4337036 117 | 119,"Paseo de Moret",24,"112",-3.7246532,"Paseo de Moret nº 11",40.4325991 118 | 120,"Pintor Rosales",24,"113",-3.7205129,"Paseo del Pintor Rosales nº 38",40.427657 119 | 121,"Quintana",24,"114",-3.7174158,"Calle Quintana nº 11-13",40.4277456 120 | 122,"Ferraz",24,"115",-3.7170448,"Calle Evaristo San Miguel nº 2",40.4253944 121 | 123,"Plaza de España A",24,"116a",-3.711603,"Plaza de España",40.42402 122 | 124,"Plaza de España B",24,"116b",-3.711703,"Plaza de España",40.42412 123 | 125,"Altamirano",24,"117",-3.7188898,"Calle Altamirano nº 24",40.4309797 124 | 126,"Juan Martín",24,"118",-3.6882407,"Calle Juan Martín el Empecinado nº 14",40.400781 125 | 127,"Méndez Álvaro",24,"119",-3.6863218,"Calle Méndez Álvaro nº 11",40.4013216 126 | 128,"Palos de la Frontera",24,"120",-3.6944768,"Calle Palos de la Frontera nº 40",40.4032208 127 | 129,"Santa María de la Cabeza",24,"121",-3.6987665,"Paseo de Santa María de la Cabeza nº 58",40.4017926 128 | 130,"Santa Engracia 14",24,"122",-3.6963983,"Calle Santa Engracia nº 14",40.4295863 129 | 131,"Guzmán el Bueno",24,"123",-3.7133412,"Calle Guzmán el Bueno nº 2",40.4306458 130 | 169,"Manuel Silvela",24,"124",-3.6993465,"Calle Manuel Silvela nº 20",40.4309524 131 | 164,"General Martínez Campos ",24,"125",-3.6948626,"Calle Fernández de la Hoz nº 29",40.435285 132 | 163,"General Álvarez de Castro",24,"126",-3.7015686,"Calle del General Álvarez de Castro nº 2",40.4344731 133 | 168,"Fernando el Católico",24,"127",-3.708439,"Calle Fernando el Católico nº 19",40.4338516 134 | 160,"Cea Bermúdez",27,"128",-3.7154329,"Calle Cea Bermúdez nº 59",40.438994 135 | 161,"José Abascal",24,"129",-3.6982209,"Calle José Abascal nº 33",40.4385316 136 | 157,"Santa Engracia 127",20,"130",-3.7016321,"Calle Santa Engracia nº 127",40.441386 137 | 156,"Bravo Murillo 44",24,"131",-3.7039582,"Calle Bravo Murillo nº 44",40.4412115 138 | 149,"Glorieta de los Cuatro Caminos",24,"132",-3.7036675,"Calle Santa Engracia nº 168",40.4463667 139 | 150,"Raimundo Fernández",24,"133",-3.7001669,"Calle Raimundo Fernández Villaverde nº 33-35",40.447125 140 | 153,"Agustín de Betancourt",24,"134",-3.6956047,"Calle María de Guzmán nº 58",40.4440297 141 | 158,"Plaza de San Juan de la Cruz",24,"135",-3.6927821,"Plaza de San Juan de la Cruz nº 11",40.4415974 142 | 151,"Castellana 106",24,"136",-3.690861,"Paseo de la Castellana nº 106",40.4453307 143 | 152,"Plaza de la República Argentina",24,"137",-3.6853312,"Plaza de la República Argentina nº 6-7",40.445411 144 | 154,"Paseo de la Castellana con Raimundo Fernández",24,"138",-3.6917932,"Paseo de la Castellana nº 67",40.4457414 145 | 159,"José Gutiérrez Abascal ",24,"139",-3.6907784,"Calle José Gutiérrez Abascal nº 2",40.4396792 146 | 162,"Velázquez 130",24,"140",-3.682862,"Calle Velázquez nº 130",40.4379444 147 | 165,"Pº Castellana - Glorieta de Emilio Castelar",12,"141",-3.6892368,"Paseo de la Castellana nº 43",40.4355143 148 | 167,"Castellana 42",24,"142",-3.6879154,"Paseo de la Castellana nº 42",40.4334087 149 | 166,"Diego de León 52",24,"143",-3.678492,"Calle Diego de León nº 52",40.4345973 150 | 170,"Juan Bravo 50",24,"144",-3.6758555,"Calle Juan Bravo nº 50",40.4323655 151 | 171,"Ortega y Gasset 87",24,"145",-3.6712823,"Calle Ortega y Gasset nº 87",40.429887 152 | 155,"María Francisca 1",18,"146",-3.6787169,"Calle María Francisca nº 1",40.4442258 153 | 148,"Doctor Arce 45",24,"147",-3.6797296,"Avenida del Doctor Arce nº 45",40.4483269 154 | 144,"Serrano 210",24,"148",-3.6817962,"Calle Serrano nº 210",40.4510188 155 | 146,"Paseo de la Habana 42",24,"149",-3.6881689,"Paseo de la Habana nº 42",40.4498613 156 | 147,"Castellana frente a Hermanos Pinzón",24,"150",-3.6905604,"Paseo de la Castellana nº 124",40.4488924 157 | 145,"Orense 12",24,"151",-3.695286,"Calle Orense nº 12",40.4480662 158 | 142,"General Perón 1",24,"152",-3.6990077,"Avenida del General Perón nº 1-4",40.4527164 159 | 143,"General Perón con Poeta Joan Maragall",24,"153",-3.692651,"Avenida del General Perón nº 36",40.4522938 160 | 141,"Orense 36",24,"154",-3.6946218,"Calle Orense nº 36",40.4548456 161 | 139,"San Germán",24,"155",-3.7009675,"Calle del General Yagüe nº 57",40.4572824 162 | 140,"Sor Ángela de la Cruz",24,"156",-3.691533,"Calle Sor Ángela de la Cruz nº 2",40.4592351 163 | 137,"Castellana 164",24,"157",-3.6894151,"Paseo de la Castellana nº 164",40.4591366 164 | 138,"Alberto Alcocer",24,"158",-3.684715,"Avenida de Alberto Alcocer nº 22",40.4585318 165 | 173,"Paseo de la Habana 63",24,"159",-3.6835926,"Paseo de la Habana nº 63",40.4543852 166 | 172,"Colombia",24,"160",-3.6763439,"Calle Colombia nº 7",40.4572466 167 | 132,"Paseo de la Florida",27,"161",-3.7218482,"Paseo de la Florida nº 8",40.4220812 168 | 133,"Metro Pirámides",24,"162",-3.7108108,"Paseo de los Olmos nº 28",40.4034076 169 | 134,"Paseo de la Esperanza",21,"163",-3.7064516,"Paseo de la Esperanza nº 2",40.4035988 170 | 136,"Paseo de las Delicias",24,"164",-3.6945025,"Paseo de las Delicias nº 92-94",40.3972616 171 | 135,"Entrada Matadero",27,"165",-3.6971829,"Paseo de la Chopera nº 14",40.3919385 172 | 174,"Segovia 26",24,"166",-3.7135833,"Calle Segovia, 26",40.4138333 173 | 175,"Segovia 45",24,"167",-3.717487,"Calle Segovia, 45",40.413736 174 | 190,"Parque Roma",24,"182",-3.6657777,"Sainz de Baranda, frente al nº 107",40.4186666 175 | 211,"San Francisco de Sales",24,"203",-3.7144722,"General Ampudia, 2",40.44175 176 | 189,"Retiro-Ibiza",27,"181",-3.6766111,"Ibiza, 18",40.41825 177 | 184,"Beata",27,"176",-3.6937222,"Alicante, 3",40.39425 178 | 200,"Avenida de los Toreros",27,"192",-3.6714166,"Avda. Toreros,3",40.4318611 179 | 185,"Legazpi",24,"177",-3.6941944,"Bolivar, 3",40.3914722 180 | 201,"Ventas",27,"193",-3.6655555,"Avda. Toreros, 49",40.4324722 181 | 213,"Estrecho",27,"205",-3.7032777,"Navarra, 1",40.4535 182 | 207,"Fernando el Católico",27,"199",-3.7149166,"Fernando el Católico, 61",40.4343611 183 | 183,"Jaime el Conquistador",21,"175",-3.6983055,"Jaime I el Conquistador, 30",40.3962222 184 | 179,"Embajadores-Cáceres",24,"171",-3.6983888,"Embajadores, 101",40.39975 185 | 191,"Doctor Esquerdo-Hermosilla",24,"183",-3.669339,"Hermosilla, 135",40.425635 186 | -------------------------------------------------------------------------------- /index.qmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Visualización de datos con R' 3 | author: "Luz Frias" 4 | execute: 5 | message: false 6 | warning: false 7 | --- 8 | 9 | ## Presentación {.unnumbered} 10 | 11 | La visualización es una parte esencial de cualquier proyecto de datos. Nos ayuda a comprender la estructura de nuestro 12 | dataset y a detectar patrones y outliers. 13 | 14 | El objetivo de este curso es conocer en líneas generales la teoría de la visualización y utilizar las herramientas 15 | que nos provee R. Exploraremos herramientas como ggplot para el diseño de gráficos estáticos, leaflet para datos 16 | espaciales y shiny para montar cuadros de mando interactivos. 17 | 18 | 19 | ### Seguir el material 20 | 21 | Este curso está disponible en GitHub, en [koldLight/curso-r-dataviz](https://github.com/koldLight/curso-r-dataviz). Para 22 | seguirlo, lo más recomendable es que te descargues el repositorio completo y sitúes el workspace de R en él. Así te 23 | funcionarán bien tanto los notebooks de quarto, como las rutas relativas para leer ficheros de datos en `dat/`. 24 | 25 | Todos los documentos usan el encoding UTF-8. Si lo abres desde windows, es posible que veas mal los caracteres 26 | especiales (tildes, eñes, ...). Lo puedes arreglar, en RStudio, haciendo click en File / Reopen with encoding y 27 | eligiendo UTF-8. 28 | 29 | Las rutas a los ficheros suponen que, en la misma carpeta en la que tienes este documento, está `dat/` con los archivos 30 | de datos necesarios. Si no te funciona, es que los tienes en otra parte y tendrás que modificar esas rutas. 31 | 32 | ### Requisitos 33 | 34 | Para seguir este curso, es necesario contar con los siguientes paquetes de R instalados: ggplot2, rjson, leaflet, 35 | scales, dplyr, plotly, rmarkdown, flexdashboard y shiny. 36 | 37 | El curso presupone que sabes manipular datos utilizando dplyr. Si no, puedes seguir este 38 | [tutorial](https://cran.r-project.org/web/packages/dplyr/vignettes/dplyr.html) antes. 39 | 40 | Además, nos resultará muy útil tener a mano las siguientes "chuletas" de uso de las herramientas que vamos a utilizar: 41 | 42 | * [ggplot2](https://posit.co/wp-content/uploads/2022/10/data-visualization-1.pdf) 43 | * [leaflet](https://posit.co/wp-content/uploads/2022/10/leaflet.pdf) 44 | * [plotly](https://images.plot.ly/plotly-documentation/images/r_cheat_sheet.pdf) 45 | * [rmarkdown](https://posit.co/wp-content/uploads/2022/10/rmarkdown-1.pdf) 46 | * [shiny](https://posit.co/wp-content/uploads/2022/10/shiny-1.pdf) 47 | 48 | 49 | ### Licencia 50 | 51 | [![](http://i.creativecommons.org/l/by-sa/4.0/88x31.png)](http://creativecommons.org/licenses/by-sa/4.0/) 52 | 53 | Puedes utilizar libremente este material, con las siguientes condiciones: 54 | 55 | * Atribuir la autoría correctamente, indicando autor y repositorio de GitHub [koldLight/curso-r-dataviz](https://github.com/koldLight/curso-r-dataviz). 56 | * Si lo utilizas y haces cambios, deberás liberarlo también bajo la misma licencia, y citando la fuente original. 57 | 58 | El detalle sobre la licencia está en el [GitHub](https://github.com/koldLight/curso-r-dataviz). 59 | 60 | ### Sobre mi 61 | 62 | Soy Luz Frias, apasionada de la tecnología y los datos. Actualmente soy ingeniera informática freelance y me dedico a 63 | hacer proyectos de software. Mi especialidad, aquellos con alta complejidad, en los que encaja mejor un equipo pequeño 64 | con perfiles end-to-end que un gran equipo de expertos en herramientas concretas. Puedes saber un poco más sobre 65 | mi [aquí](https://luzfrias.notion.site/luzfrias/Luz-Frias-ES-2efe28d1f6454d39b8f29a352fdee6d1). Si crees que mi equipo 66 | y yo podemos encajar en un proyecto de tu empresa, puedes contactarme en `luzfrias arroba circiter punto es`. 67 | -------------------------------------------------------------------------------- /rdataviz.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | -------------------------------------------------------------------------------- /resources/01_ggplot_basico/banana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/banana.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/barplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/barplot.jpg -------------------------------------------------------------------------------- /resources/01_ggplot_basico/boxplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/boxplot.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/chart_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/chart_type.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/dinos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/dinos.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/lineplot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/lineplot.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/log.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/log.jpg -------------------------------------------------------------------------------- /resources/01_ggplot_basico/pie_vs_bar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/pie_vs_bar.png -------------------------------------------------------------------------------- /resources/01_ggplot_basico/scatterplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/scatterplot.jpg -------------------------------------------------------------------------------- /resources/01_ggplot_basico/stacked.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/stacked.jpg -------------------------------------------------------------------------------- /resources/01_ggplot_basico/stacked100.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/stacked100.jpg -------------------------------------------------------------------------------- /resources/01_ggplot_basico/zero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/01_ggplot_basico/zero.png -------------------------------------------------------------------------------- /resources/02_ggplot_intermedio/2_apiladas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/02_ggplot_intermedio/2_apiladas.png -------------------------------------------------------------------------------- /resources/02_ggplot_intermedio/3_rep_preference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/02_ggplot_intermedio/3_rep_preference.png -------------------------------------------------------------------------------- /resources/03_ggplot_avanzado/export_from_rstudio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/03_ggplot_avanzado/export_from_rstudio.png -------------------------------------------------------------------------------- /resources/04_leaflet/popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/04_leaflet/popup.png -------------------------------------------------------------------------------- /resources/04_leaflet/projection.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/04_leaflet/projection.gif -------------------------------------------------------------------------------- /resources/07_rmarkdown/knit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/07_rmarkdown/knit.png -------------------------------------------------------------------------------- /resources/07_rmarkdown/knit_params.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/07_rmarkdown/knit_params.png -------------------------------------------------------------------------------- /resources/07_rmarkdown/new_rmarkdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/07_rmarkdown/new_rmarkdown.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/elementos_html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/elementos_html.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/layout_columnas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/layout_columnas.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/layout_filas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/layout_filas.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/layout_pestanas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/layout_pestanas.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/layout_tamano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/layout_tamano.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/value_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/value_box.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/varias_paginas.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/varias_paginas.png -------------------------------------------------------------------------------- /resources/08_flexdashboard/varias_paginas_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/08_flexdashboard/varias_paginas_menu.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/01_histograma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/01_histograma.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/02_plotly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/02_plotly.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/03_leaflet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/03_leaflet.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/04_widget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/04_widget.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/control_widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/control_widgets.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/layout_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/layout_01.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/layout_02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/layout_02.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/run_app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/run_app.png -------------------------------------------------------------------------------- /resources/09_shiny_basico/run_shiny.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/09_shiny_basico/run_shiny.png -------------------------------------------------------------------------------- /resources/10_shiny_avanzado/1_fibonacci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/10_shiny_avanzado/1_fibonacci.png -------------------------------------------------------------------------------- /resources/10_shiny_avanzado/2_boton.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koldLight/curso-r-dataviz/52b8799deb803b2d831ce83dcaf63a3c5cd908c9/resources/10_shiny_avanzado/2_boton.png -------------------------------------------------------------------------------- /scripts/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Fail if something returns an error 4 | set -e 5 | 6 | # Render the quarto book 7 | quarto render --to html 8 | 9 | # Copy to server 10 | scp -r _book/* luzfrias:/apps/rdataviz/ 11 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | p.caption { 2 | color: #777; 3 | margin-top: 10px; 4 | } 5 | p code { 6 | white-space: inherit; 7 | } 8 | pre { 9 | word-break: normal; 10 | word-wrap: normal; 11 | } 12 | pre code { 13 | white-space: inherit; 14 | } 15 | --------------------------------------------------------------------------------