Módulo 1: Geoprocesamiento

library(tidyverse)
## ── Attaching packages ────────────────────────────────────────────────── tidyverse 1.3.0 ──
## ✓ ggplot2 3.3.0     ✓ purrr   0.3.3
## ✓ tibble  3.0.1     ✓ dplyr   0.8.5
## ✓ tidyr   1.0.2     ✓ stringr 1.4.0
## ✓ readr   1.3.1     ✓ forcats 0.5.0
## ── Conflicts ───────────────────────────────────────────────────── tidyverse_conflicts() ──
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(sf)
## Linking to GEOS 3.7.2, GDAL 2.4.2, PROJ 5.2.0

I. Deberán elegir una ciudad en cualquier parte del mundo que les interese y que disponga de un portal de datos abiertos que ofrece un shapefile con sus barrios. Elegimos la ciudad de Barcelona y a continuación cargaremos el dataframe que brinda la página del Ayuntamiento con los límites de sus barrios y distritos (comunas).

Barcelona_distritos <- st_read("bcn_UNITATS_ADM_POLIGONS.json") 
## Reading layer `bcn_UNITATS_ADM_POLIGONS' from data source `/Users/lousil/Google Drive/Formación Académica/ECONOMIA URBANA/14. CIENCIA DE DATOS PARA CIUDADES/Ciencia de Datos para Ciudades I/Clase 1/Ciencia de Datos para ciudades 2/bcn_UNITATS_ADM_POLIGONS.json' using driver `GeoJSON'
## Simple feature collection with 1501 features and 35 fields
## geometry type:  MULTIPOLYGON
## dimension:      XY
## bbox:           xmin: 420812.5 ymin: 4574282 xmax: 435480.4 ymax: 4591066
## CRS:            25831

Vemos que el sistema de coordenadas de referencia (CRS) es 25831, por lo tanto no es Merkator. Vamos a cambiarlo:

Barcelona_distritos <- st_transform(Barcelona_distritos, crs = 4326) 
names(Barcelona_distritos)
##  [1] "FID"        "ID_ANNEX"   "ANNEXDESCR" "ID_TEMA"    "TEMA_DESCR"
##  [6] "ID_CONJUNT" "CONJ_DESCR" "ID_SUBCONJ" "SCONJ_DESC" "ID_ELEMENT"
## [11] "ELEM_DESCR" "NIVELL"     "NDESCR_CA"  "NDESCR_ES"  "NDESCR_EN" 
## [16] "TERME"      "DISTRICTE"  "BARRI"      "AEB"        "SEC_CENS"  
## [21] "GRANBARRI"  "ZUA"        "AREA_I"     "LITERAL"    "PERIMETRE" 
## [26] "AREA"       "CODI_UA"    "TIPUS_UA"   "NOM"        "WEB1"      
## [31] "WEB2"       "WEB3"       "FHEX_COLOR" "Shape_Leng" "Shape_Area"
## [36] "geometry"

Como el dataset posee 36 variables, de las cual necesitamos solo unas pocas, seleccionaremos y filtraremos solo lo que necesitamos para disminuir el gran tamaño del archivo:

Barcelona_distritos <- Barcelona_distritos %>% 
  filter(!(DISTRICTE =="-")) %>% 
  group_by(DISTRICTE) %>% 
  summarise()
  1. Del mismo portal de datos elegirán un dataset con registros geo-referenciados. Por ejemplo, las escuelas de la ciudad (o las comisarías, o las propiedades en alquiler) con sus coordenadas. Elegimos un dataset que contiene los museos y bibliotecas:
Equipamientos <- read.csv("bcn_Biblioteques_i_museus.csv")

Por alguna razón que desconocemos, aparecen varias observaciones del mismo equipamiento. Por tal motivo, agruparemos segun equipamiento para que nos quede una observación para cada uno y luego las cuente correctamente.

Equipamientos <- Equipamientos %>% 
  group_by(EQUIPAMENT, LONGITUD, LATITUD) %>% 
  summarise()

Visualicemos ambos datasets superpuestos:

ggplot()+
  geom_sf(data = Barcelona_distritos, aes(fill=DISTRICTE), color = NA) + 
  geom_point(data = Equipamientos, aes(x=LONGITUD, y=LATITUD), alpha=.8) +
         labs(title = "Equipamiento por distrito ",
         subtitle = "(museos, bibliotecas, universidades, etc)",
         fill = "Distritos",
         caption= "Fuente: Ajuntament de Barcelona | 2020",
         y="",
         x="")

  1. Realizando un join espacial, asignar a cada registro geo-referenciado el barrio/distrito que le corresponde:

Convertimos el dataset de Bibliotecas y Museos a espacial:

Equipamientos <- Equipamientos %>%
    st_as_sf(coords = c("LONGITUD", "LATITUD"), crs = 4326)

…Y unimos al dataset que contiene los límites de barrios y distritos (comunas) de Barcelona:

Equipamientos <- st_join(Barcelona_distritos, Equipamientos)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
  1. Utilizando ggplot():
Equipamientos_distritos <- Equipamientos %>% 
      group_by(DISTRICTE) %>%
      summarise(Frecuencia = n())
ggplot(Equipamientos_distritos) +
  geom_bar(aes( x = DISTRICTE, weight = Frecuencia), fill="#69b3a2") +
  labs(title = "Cantidad de Equipamiento por distrito",
         subtitle = "(museos, bibliotecas, universidades, etc)",
         caption= "Fuente: Ajuntament de Barcelona | 2020",
         y="Cantidad",
         x="Distritos")

Ahora ponderaremos según cantidad de Museos y Bibliotecas por distrito con scale_viridis:

ggplot(Equipamientos_distritos) +
  geom_bar(aes( x = DISTRICTE, weight = Frecuencia, fill=Frecuencia)) +
  scale_fill_viridis_c() +
  labs(title = "Cantidad de Equipamiento por distrito",
       subtitle = "(museos, bibliotecas, universidades, etc)",
       fill = "Escala",
       caption= "Fuente: Ajuntament de Barcelona | 2020",
       y="Cantidad",
       x="Distritos")

ggplot() + 
  geom_sf(data = Equipamientos_distritos, aes(fill=Frecuencia), color = NA) + 
  geom_sf_text(data = Equipamientos_distritos, aes(label = DISTRICTE), size = 2, colour = "white") +
  scale_fill_viridis_c() +
  labs(title = "Cantidad de Equipamiento por distrito",
         subtitle = "(museos, bibliotecas, universidades, etc)",
         fill = "Escala",
         caption= "Fuente: Ajuntament de Barcelona | 2020",
         y="",
         x="")
## Warning in st_point_on_surface.sfc(sf::st_zm(x)): st_point_on_surface may not
## give correct results for longitude/latitude data

Módulo 2: Acceso a información urbana georeferenciada en repositorios online

I. Descargar de OpenStreetMap la grilla de calles para la Ciudad elegida en el ejercicio 1 y mapearla por uno de sus atributos (velocidad mínima, velocidad máxima, cantidad de carriles, etc).

library(osmdata)
## Data (c) OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright
library(leaflet)
Barcelona <- getbb("Barcelona, España")

Barcelona
##         min       max
## x  2.052498  2.228356
## y 41.317035 41.467914
ciudad <- "Barcelona"
posicion <- 1
url <- URLencode(paste0("https://nominatim.openstreetmap.org/search.php?q=",
ciudad, "&polygon_geojson=1&format=geojson"))
destfile = paste0(tempdir(), "/limits.json")
download.file(url, destfile)
Barcelona_frontera <- st_read(destfile)[posicion,]
## Reading layer `limits' from data source `/private/var/folders/lg/vhfpqlf52vj3nv4pgd4px5pm0000gn/T/Rtmp8OMREb/limits.json' using driver `GeoJSON'
## Simple feature collection with 10 features and 9 fields
## geometry type:  GEOMETRY
## dimension:      XY
## bbox:           xmin: -80.6871 ymin: -6.069389 xmax: 124.1419 ymax: 50.3547
## CRS:            4326
leaflet(Barcelona_frontera) %>% 
  addTiles() %>% 
  addPolygons()

A continuación construiremos la consulta, especificando los datos que queremos descargar:

Barcelona_calles <- opq(Barcelona) %>% 
  add_osm_feature(key="highway")

Con osmdata() recolectamos la información de la consulta en forma de dataset espacial:

Barcelona_calles <- Barcelona_calles %>% 
  osmdata_sf()

Barcelona_calles
## Object of class 'osmdata' with:
##                  $bbox : 41.3170353,2.0524977,41.4679135,2.2283555
##         $overpass_call : The call submitted to the overpass API
##                  $meta : metadata including timestamp and version numbers
##            $osm_points : 'sf' Simple Features Collection with 245460 points
##             $osm_lines : 'sf' Simple Features Collection with 46106 linestrings
##          $osm_polygons : 'sf' Simple Features Collection with 1632 polygons
##        $osm_multilines : NULL
##     $osm_multipolygons : 'sf' Simple Features Collection with 87 multipolygons

Extraemos las calles en forma de línea:

Barcelona_calles <- Barcelona_calles$osm_lines

Y graficamos:

ggplot() + 
  geom_sf(data = Barcelona_calles, color = "gray20")

A continuación haremos una interesección entre los límites de la ciudad y las calles obtenidas a través de OSM:

Barcelona_calles <- st_intersection(Barcelona_calles, Barcelona_frontera)
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries

Y graficamos:

ggplot()+
  geom_sf(data=Barcelona_calles, color = "gray20")

Para mapearla por el atributo de velocidad máxima, haremos:

Barcelona_callesmax <- Barcelona_calles %>% 
  mutate(maxspeed = as.numeric(maxspeed),
         lanes = ifelse(is.na(lanes), 1, as.numeric(lanes)))

Y graficamos:

ggplot(Barcelona_callesmax) +
    geom_sf(aes(color = maxspeed), alpha = 0.5) +
    scale_color_viridis_c() +
      theme_void() +
    labs(title = "Barcelona",
         subtitle = "Vías de circulación",
         caption = "fuente: OpenStreetMap",
         color = "velocidad máxima")

  1. Descargar de OpenStreetMap una (o más) capas de datos de tipo puntos o polígonos.

Elegimos descargar la capa de datos de las bibliotecas:

Barcelona_bibliotecas <- opq(Barcelona) %>% 
  add_osm_feature(key = "amenity", value = "library") %>%
  osmdata_sf() 

Y la de museos:

Barcelona_museos <- opq(Barcelona) %>% 
  add_osm_feature(key = "tourism", value = "museum") %>%
  osmdata_sf() 

Y la de universidades:

Barcelona_universidades <- opq(Barcelona) %>% 
  add_osm_feature(key = "amenity", value = "university") %>%
  osmdata_sf() 
    1. Proyectar los datos descargados en un mapa y comentar los resultados: ¿Cómo se distribuyen en la Ciudad?
Barcelona_bibliotecas <- Barcelona_bibliotecas$osm_points
Barcelona_museos <- Barcelona_museos$osm_points
Barcelona_universidades <- Barcelona_universidades$osm_points
Barcelona_bibliotecas <- st_intersection(Barcelona_bibliotecas, Barcelona_frontera) %>% 
  select(name, geometry) %>% 
  filter(!is.na(name))
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
Barcelona_museos <- st_intersection(Barcelona_museos, Barcelona_frontera) %>% 
  select(name, geometry) %>% 
  filter(!is.na(name))
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
Barcelona_universidades <- st_intersection(Barcelona_universidades, Barcelona_frontera) %>% 
  select(name, geometry) %>% 
  filter(!is.na(name))
## although coordinates are longitude/latitude, st_intersection assumes that they are planar
## Warning: attribute variables are assumed to be spatially constant throughout all
## geometries
ggplot()+
  geom_sf(data = Barcelona_calles, color = "gray20") +
  geom_sf(data = Barcelona_bibliotecas, color = "purple") +
  geom_sf(data = Barcelona_museos, color = "salmon") +
  geom_sf(data = Barcelona_universidades, color = "royalblue") +
   labs(title = "Barcelona",
         subtitle = "Bibliotecas, Museos y Universidades",
         caption = "fuente: OpenStreetMap")

Como podemos observar, los museos parecen estar agrupados en lugares específicos y turísticos, como ser en la antigua ciudad amurallada (Ciutat Vella) y la Rambla, así como en la montaña Montjuic. Respecto a las universidades, podemos ver un gran concentración en un extremo de la ciudad, siendo la menor distribución del lado opuesto. Sin embargo, las bibliotecas tienen una distribución más pareja en el territorio. Podemos suponer que exista alguna política pública que asegure una distribución pareja de bibliotecas por barrio.

Cargamos las siguientes librerías:

library(devtools)
## Loading required package: usethis
library(ggsflabel)
## 
## Attaching package: 'ggsflabel'
## The following objects are masked from 'package:ggplot2':
## 
##     geom_sf_label, geom_sf_text, StatSfCoordinates

Y ahora agregamos las etiquetas, sólo para el caso de las bibliotecas:

ggplot() +
  geom_sf(data = Barcelona_calles, color = "gray20") +
  geom_sf_label_repel(data = Barcelona_bibliotecas, aes(label = name), size = 2, color = "purple") +
  theme_void() +
  labs(title = "Barcelona",
       subtitle = "Bibliotecas con etiquetas",
       caption = "fuente: OpenStreetMap")
## Warning in st_point_on_surface.sfc(data$geometry): st_point_on_surface may not
## give correct results for longitude/latitude data

    1. Hacer un conteo de los ítems de la capa descargada por barrio, mapearlo y compararlo con el conteo de los ítems descargados en el ejercicio anterior: ¿La distribución es similar o hay diferencias? ¿A qué se puede deber?

Primero que nada vamos a unir los shapes de bibliotecas, museos y universidades en un solo:

Barcelona_bibliotecas_museos_universidades <- rbind(Barcelona_bibliotecas, Barcelona_museos, Barcelona_universidades)

Haremos un join espacial entre el shape de bibliotecas, universidades y museos unido anteriormente y el shape que contiene los distritos:

osm_bmu_distritos <- st_join(Barcelona_bibliotecas_museos_universidades, Barcelona_distritos)
## although coordinates are longitude/latitude, st_intersects assumes that they are planar
## although coordinates are longitude/latitude, st_intersects assumes that they are planar

Hacemos un conteo agrupando por distrito y sacándole la geometría:

osm_bmu_distritos <- osm_bmu_distritos %>%
group_by(DISTRICTE) %>%
summarise(Frecuencia = n()) %>%
st_set_geometry(NULL)

Con left_join() unimos el conteo anterior con el shape que tiene los límites de los distritos:

osm_bmu_distritos <- left_join(Barcelona_distritos, osm_bmu_distritos, by="DISTRICTE")

Y graficamos:

ggplot() +
  geom_sf(data = osm_bmu_distritos, aes(fill = Frecuencia), color=NA) +
  geom_sf_text(data = osm_bmu_distritos, aes(label = Frecuencia), size = 2, colour = "white") +
  scale_fill_viridis_c() +
  labs(title = "Barcelona",
       subtitle = "Bibliotecas, Museos y Universidades por Distritos",
       caption = "fuente: OpenStreetMap",
        y="",
        x="")
## Warning in st_point_on_surface.sfc(data$geometry): st_point_on_surface may not
## give correct results for longitude/latitude data

Vemos que la frecuencia máxima es de 31 para el Distrito Nº1, coloreado en amarillo.

Comparemos ahora con el gráfico hecho anteriormente:

ggplot() + 
  geom_sf(data = Equipamientos_distritos, aes(fill=Frecuencia), color = NA) + 
  geom_sf_text(data = Equipamientos_distritos, aes(label = Frecuencia), size = 2, colour = "white") +
  scale_fill_viridis_c() +
  labs(title = "Barcelona",
         subtitle = "Bibliotecas, Museos y Universidades por Distritos",
         fill = "Escala",
         caption= "Fuente: Ajuntament de Barcelona | 2020",
         y="",
         x="")
## Warning in st_point_on_surface.sfc(data$geometry): st_point_on_surface may not
## give correct results for longitude/latitude data

En este mapa, hecho en el módulo anterior con data abierta que brinda el Ayuntamiento de Barcelona, la Frecuencia máxima llega a los 70. Además, la cantidad de observaciones en cada Distrito es mayor a la observada con los datos de OSM. Por tal motivo entendemos que los datos brindados por el ayuntamiento incluyen otros equipamientos, además de bibliotecas museos y universidades, y esto hace que difiera la frecuencia en cada distrito.

Comprobémemoslo ahora numéricamente:

summary(Equipamientos_distritos)
##    DISTRICTE   Frecuencia             geometry
##  01     :1   Min.   : 7.00   MULTIPOLYGON :2  
##  02     :1   1st Qu.:10.75   POLYGON      :8  
##  03     :1   Median :20.50   epsg:4326    :0  
##  04     :1   Mean   :26.20   +proj=long...:0  
##  05     :1   3rd Qu.:26.00                    
##  06     :1   Max.   :70.00                    
##  (Other):4

En este dataset hecho en el módulo Nº1, la frecuencia máxima alcanza las 70 observaciones en el Distrito 1 y además el promedio es 26.20.

summary(osm_bmu_distritos)
##    DISTRICTE          geometry   Frecuencia   
##  01     :1   MULTIPOLYGON :2   Min.   : 2.00  
##  02     :1   POLYGON      :8   1st Qu.: 3.50  
##  03     :1   epsg:4326    :0   Median : 7.00  
##  04     :1   +proj=long...:0   Mean   :10.70  
##  05     :1                     3rd Qu.:17.25  
##  06     :1                     Max.   :32.00  
##  (Other):4

En cambio, en este dataset hecho con información de OSM vemos que la frecuencia máxima es 31 y el promedio es 10,60.

Módulo 3: Descargando y analizando datos de redes sociales: Twitter

Activemos este paquete para interactuar con Twitter.

library(rtweet)
## 
## Attaching package: 'rtweet'
## The following object is masked from 'package:purrr':
## 
##     flatten

I. Descargar tweets que se originen en los alrededores de la Ciudad con la que están trabajando, y explorar las columnas/variables que contiene.

Como no obtuvimos la autorización de Twitter, utilizaremos un dataset de la Región Metropolitana de Buenos Aires:

Tweets_rmba <- read.csv("Clase 8_tweets_rmba.csv")

Ahora quedémosnos sólo con el 50% de las observaciones y filtremos las que provengan de la fuente Twitter, excluyendo las de Instagram y otras redes sociales:

Tweets_rmba <- sample_frac(Tweets_rmba, 0.5) %>% 
filter(str_detect(source, "Twitter"))
names(Tweets_rmba)
##  [1] "X"                     "Y"                     "id"                   
##  [4] "in_reply_to_status_id" "in_reply_to_user_id"   "text"                 
##  [7] "created"               "lang"                  "source"               
## [10] "user_name"             "user_id"               "user_created"         
## [13] "user_description"      "user_location"         "user_followers"       
## [16] "user_followed"

Vemos que el dataset solo tiene 16 variables, de las cuales se destacan las coordenadas (x e y), el Id y nombre de usuario, el contenido del Tweet y la ubicación, cantidad de seguidores y seguidos del usuario.

  1. Analizar:
  1. ¿Cuáles son los mensajes con más repercusión? ¿Qué dicen?

Como el dataset no contiene la cantidad de retweets, ni likes, reformulemos la pregunta: ¿Cuáles son los 10 lugares donde más twitteó la gente?

  ggplot(Tweets_rmba) +
  geom_bar(aes(user_location)) + 
    coord_flip() +
     labs(title = "Procedencia de los usuarios",
          x = "Cantidad",
          y = "Ubicación")

Dado que la variable “user_location” refleja el texto que cada usuario eligió para describir su ubicación (no de las coordenadas de origen del tweet) las variabilidad es grande. Algunos eligen su verdadera ubicación y otros se ponen creativos: “For now: Vicente Lopez” o “No Te Va Gustar,LVP y La Beriso, mis bandas queridas”.

Probemos extraer el top 10 de lugares más frecuentes, eliminando los tweets de usuarios sin “user_location”:

Tweets_rmba %>%
    filter(user_location != "", !is.na(user_location)) %>% 
    count(user_location) %>% 
    top_n(10, n) %>% 
    ggplot() +
      geom_col(aes(x = reorder(user_location, n), y = n), fill="salmon") +
      coord_flip() +
      labs(title = "Procedencia de los usuarios",
           x = "Ubicación",
           y = "Cantidad")

Vemos que las ubicaciones más utilizadas son Buenos Aires, Argentina, Ramos Mejía, La Plata y la Ciudad de Buenos Aires.

  1. ¿En qué momento del día se realiza la mayor cantidad de tweets? Graficar.

Primero lo transformaremos al formato fecha. Luego filtraremos los tweets realizados en un día determinado (01/06/2018) y grafiquemos por horas:

library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:dplyr':
## 
##     intersect, setdiff, union
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
Tweets_rmba_0106 <-Tweets_rmba %>% 
  mutate(created=ymd_hms(created)) %>% 
  filter(str_detect(created,"2018-06-01"))

ts_plot(Tweets_rmba_0106, "hours") +
  labs(title = "Distribución de Tweets 01/06/2018",
          x = "Horario",
          y = "Cantidad")

En el gráfico podemos observar la cantidad de tweets distribuídos a lo largo del día 01/06/2018, en el cual se puede observar el pico a las 15:00hs. A su vez, podemos observar la ausencia de tweets a partir de las 18:00hs.

  1. ¿Cómo se distribuye la popularidad de los usuarios? ¿Quiénes son los 5 que más seguidores tienen? Graficar.

Veamos los usuarios más populares (según la cantidad de seguidores):

ggplot(Tweets_rmba) +
    geom_histogram(aes(x = user_followers), bins = 30, fill = "salmon", color = "salmon") + 
          labs(title = "Usuarios según cantidad de seguidores",
          x = "Usuarios",
          y = "Cantidad de Seguidores")

La distribución es de tipo “power law” típica en los rankings de popularidad. Esto demuestra una enorme masa de usuarios con popularidad mínima y un número muy pequeño de usuarios con una gran cantidad de seguidores.

Ahora veámoslo en escala logarítmica:

ggplot(Tweets_rmba) +
    geom_histogram(aes(x = user_followers), bins = 30, fill = "salmon", color = "salmon") +
    scale_x_log10() + 
    labs(title = "Usuarios según cantidad de seguidores",
         subtitle = "en escala logarítmica",
          x = "Usuarios",
          y = "Cantidad de Seguidores")
## Warning: Transformation introduced infinite values in continuous x-axis
## Warning: Removed 189 rows containing non-finite values (stat_bin).

Obtengamos un top 5 de los usuarios más populares, su location, y el contenido del tweet:

Tweets_rmba %>% 
    top_n(5, user_followers) %>% 
    arrange(desc(user_followers)) %>% 
    select(user_name, user_followers, user_location, text) 
##       user_name user_followers             user_location
## 1 Tato_Aguilera         403819 ÜT: -34.604765,-58.393853
## 2       Nakagol         157990                 Argentina
## 3    waldonavia         116935         Argentina-Uruguay
## 4  crescentegus          76534   Buenos Aires, Argentina
## 5   SamantaCaso          66872   Buenos Aires, Argentina
##                                                                                                                                                                                text
## 1                                          Les deseo un gran día! Desde el Complejo Pedro Pompilio arrancamos el vivo en el móvil de @TyCSports. Aireee en… https://t.co/H4q9d2sK4G
## 2                                                                                                                                                #VamosLosPibes\nAguante @clublanus
## 3                                        Buen día!!! Aquí estamos en Family Pets!!! De todo para ellos porque son Familia!!! En Instagram nos encontras en… https://t.co/6j7HUTijG6
## 4                                                                                                                                               Siga todos que FAV e RT esse tweet!
## 5 Thank you all for the ßïr†hdαψ ωïšhεš! \U0001f382\U0001f389\U0001f38a\U0001f388\nTruly appreciate you all so much!\nThank you for always putting a smile… https://t.co/frQtH0nrPn
  1. Crear mapas que muestren posición de los tweets y cantidad de seguidores del usuario que tuitea:
library(ggmap)
## Google's Terms of Service: https://cloud.google.com/maps-platform/terms/.
## Please cite ggmap if you use it! See citation("ggmap") for details.

Antes que nada filtremos los tweets que no tienen coordenadas.

Tweets_rmba <- Tweets_rmba %>% 
    filter(!is.na(X), !is.na(Y))

Y definamos la bounding box de los tweets para poder mapear:

bboxtweets_Tweets_rmba <- make_bbox(lon = Tweets_rmba$X, lat = Tweets_rmba$Y)

bboxtweets_Tweets_rmba
##      left    bottom     right       top 
## -59.33560 -35.37155 -57.78585 -33.87864

Definamos el mapa base segun las coordenadas obtenidas y grafiquemos las observaciones:

mapa_Tweets_rmba <- get_stamenmap(bboxtweets_Tweets_rmba, zoom = 10)
## Source : http://tile.stamen.com/terrain/10/343/614.png
## Source : http://tile.stamen.com/terrain/10/344/614.png
## Source : http://tile.stamen.com/terrain/10/345/614.png
## Source : http://tile.stamen.com/terrain/10/346/614.png
## Source : http://tile.stamen.com/terrain/10/347/614.png
## Source : http://tile.stamen.com/terrain/10/343/615.png
## Source : http://tile.stamen.com/terrain/10/344/615.png
## Source : http://tile.stamen.com/terrain/10/345/615.png
## Source : http://tile.stamen.com/terrain/10/346/615.png
## Source : http://tile.stamen.com/terrain/10/347/615.png
## Source : http://tile.stamen.com/terrain/10/343/616.png
## Source : http://tile.stamen.com/terrain/10/344/616.png
## Source : http://tile.stamen.com/terrain/10/345/616.png
## Source : http://tile.stamen.com/terrain/10/346/616.png
## Source : http://tile.stamen.com/terrain/10/347/616.png
## Source : http://tile.stamen.com/terrain/10/343/617.png
## Source : http://tile.stamen.com/terrain/10/344/617.png
## Source : http://tile.stamen.com/terrain/10/345/617.png
## Source : http://tile.stamen.com/terrain/10/346/617.png
## Source : http://tile.stamen.com/terrain/10/347/617.png
## Source : http://tile.stamen.com/terrain/10/343/618.png
## Source : http://tile.stamen.com/terrain/10/344/618.png
## Source : http://tile.stamen.com/terrain/10/345/618.png
## Source : http://tile.stamen.com/terrain/10/346/618.png
## Source : http://tile.stamen.com/terrain/10/347/618.png
## Source : http://tile.stamen.com/terrain/10/343/619.png
## Source : http://tile.stamen.com/terrain/10/344/619.png
## Source : http://tile.stamen.com/terrain/10/345/619.png
## Source : http://tile.stamen.com/terrain/10/346/619.png
## Source : http://tile.stamen.com/terrain/10/347/619.png
ggmap(mapa_Tweets_rmba) +
    geom_point(data = Tweets_rmba, aes(x = X, y = Y), color = "salmon", alpha=.5) +  labs(title = "Tweets en la RMBA",
          x = "Longitud",
          y = "Latitud")

Dada la gran cantidad de Tweets, graficaremos solo las que ocurrieron el día 01/06 de 2018. Volvamos a definir la bounding box de los tweets ocurridos en esa fecha:

bboxtweets_Tweets_rmba_0106 <- make_bbox(lon = Tweets_rmba_0106$X, lat = Tweets_rmba_0106$Y)

bboxtweets_Tweets_rmba_0106
##      left    bottom     right       top 
## -58.94038 -34.97769 -57.92611 -34.40365

Definamos la base segun las coordenadas obtenidas y grafiquemos las observaciones:

mapa_Tweets_rmba_0106_terrainlines <- get_stamenmap(bboxtweets_Tweets_rmba_0106, maptype = "terrain-lines", zoom = 11)
## Source : http://tile.stamen.com/terrain-lines/11/688/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/689/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/690/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/691/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/692/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/693/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/694/1232.png
## Source : http://tile.stamen.com/terrain-lines/11/688/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/689/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/690/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/691/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/692/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/693/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/694/1233.png
## Source : http://tile.stamen.com/terrain-lines/11/688/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/689/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/690/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/691/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/692/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/693/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/694/1234.png
## Source : http://tile.stamen.com/terrain-lines/11/688/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/689/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/690/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/691/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/692/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/693/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/694/1235.png
## Source : http://tile.stamen.com/terrain-lines/11/688/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/689/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/690/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/691/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/692/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/693/1236.png
## Source : http://tile.stamen.com/terrain-lines/11/694/1236.png
ggmap(mapa_Tweets_rmba_0106_terrainlines) +
    geom_point(data = Tweets_rmba_0106, aes(x = X, y = Y), color = "red", alpha=.5) +
          labs(title = "Tweets en la RMBA",
               subtitle = "01/06/2018",
          x = "Longitud",
          y = "Latitud")

También probemos colorear según la popularidad del usuario:

ggmap(mapa_Tweets_rmba_0106_terrainlines) + 
    geom_point(data = Tweets_rmba_0106, 
               aes(x = X, y = Y, color = user_followers)) +
    scale_color_distiller(palette = "Spectral") +
    labs(title = "Tweets en la RMBA segun popularidad del usuario",
         subtitle = "01/06/2018",
         color = "Seguidores",
         x = "Longitud",
         y = "Latitud")

A continuación haremos mapas interactivos con leaflet:

library(leaflet)

Renombremos las variables que contienen las coordenadas para que el leaflet nos la reconozca:

Tweets_rmba_0106 <- Tweets_rmba_0106 %>% 
  rename(longitude = X) %>% 
  rename(latitude = Y)

Y ahora grafiquemos:

leaflet(Tweets_rmba_0106) %>% 
    addTiles() %>%
    addMarkers()
## Assuming "longitude" and "latitude" are longitude and latitude, respectively

Agreguemos “popup” para ver el texto en cada tweet cliqueando sobre el pin:

leaflet(Tweets_rmba_0106) %>% 
    addTiles() %>% 
    addMarkers(popup = ~text)
## Assuming "longitude" and "latitude" are longitude and latitude, respectively

Ahora usemos el color para indicar la cantidad de seguidores del autor de cada tweet. Primero definamos la paleta:

paleta <- colorNumeric(
  palette = "viridis",
  domain = Tweets_rmba_0106$user_followers)

Y luego la usamos en nuestro mapa:

leaflet(Tweets_rmba_0106) %>% 
    addTiles() %>% 
    addCircleMarkers(popup = ~text,
                     color = ~paleta(user_followers))
## Assuming "longitude" and "latitude" are longitude and latitude, respectively

Por último agreguemos una leyenda que explique la codificación de los datos.

leaflet(Tweets_rmba_0106) %>% 
    addTiles() %>% 
    addCircleMarkers(popup = ~text,
                     color = ~paleta(user_followers)) %>% 
    addLegend(title = "Seguidores", pal = paleta, values = ~user_followers)
## Assuming "longitude" and "latitude" are longitude and latitude, respectively

Modulo 4: Analizando dinámicas espacio-temporales

I. Utilizar los tweets que descargaron en el ejercicio anterior o elegir algún dataset open data de la Ciudad que tenga tanto coordenadas como fecha.

Cargamos un dataset bajado del Open Data de la ciudad de Barcelona que contiene los reclamos de los ciudadanos finalizados en 2019:

bcn_reclamos <- read.csv("Clase_9_2019_peticions_ciutadanes.csv")
names(bcn_reclamos)
##  [1] "FITXA_ID"           "TIPUS"              "AREA"              
##  [4] "ELEMENT"            "DETALL"             "DIA_DATA_ALTA"     
##  [7] "MES_DATA_ALTA"      "ANY_DATA_ALTA"      "DIA_DATA_TANCAMENT"
## [10] "MES_DATA_TANCAMENT" "ANY_DATA_TANCAMENT" "CODI_DISTRICTE"    
## [13] "DISTRICTE"          "CODI_BARRI"         "BARRI"             
## [16] "SECCIO_CENSAL"      "TIPUS_VIA"          "CARRER"            
## [19] "NUMERO"             "COORDENADA_X"       "COORDENADA_Y"      
## [22] "LONGITUD"           "LATITUD"            "SUPORT"            
## [25] "CANALS_RESPOSTA"

Vemos que el dataset contiene 2 fechas, la del origen del reclamo y la fecha de cierre del mismo. A su vez, estas fechas estan divididas por columnas, es decir, hay una columna para el día, una para el mes y otra para el año.

Componemos ahora la variable fecha (de alta y cierre) y las transformamos al formato fecha(día-mes-año):

bcn_reclamos <- bcn_reclamos %>% 
    mutate(fecha_alta = paste(DIA_DATA_ALTA, MES_DATA_ALTA, ANY_DATA_ALTA)) %>% 
    mutate(fecha_alta = dmy(fecha_alta)) %>% 
    mutate(fecha_cierre = paste(DIA_DATA_TANCAMENT, MES_DATA_TANCAMENT, ANY_DATA_TANCAMENT)) %>% 
    mutate(fecha_cierre = dmy(fecha_cierre))
  1. Realizar 2 gráficos que les permitan analizar la temporalidad de los datos.¿Detectan algún patrón temporal? ¿A qué puede deberse?

Hagamos un gráfico de barras que nos permita analizar el mes de origen de los reclamos en 2019:

ggplot(bcn_reclamos %>% filter(year(fecha_alta) == 2019)) +
        geom_bar(aes(x = month(fecha_alta, label = TRUE)), fill = "salmon") +
  labs(title = "Reclamos dados de alta en 2019",
         subtitle = "Barcelona",
         x = "Mes",
         y = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Podemos observar una tendencia creciente a efectuar reclamos a medida que se acerca el verano europeo, y una tendencia decresciente hacia el invierno. Hay una clara excepción que es el mes de Agosto, podemos deducir que algunas oficinas se encuentren cerradas durante este mes, o que la población se encuentre de vacaciones.

Analicemos ahora el mes de cierre de estos reclamos:

ggplot(bcn_reclamos) +
        geom_bar(aes(x = month(fecha_cierre, label = TRUE)), fill = "#69b3a2") +
  labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona",
         x = "Mes",
         y = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Acá la distribución es más pareja, destacándose algunos meses como mayo, julio y octubre.

Quedémosnos con los reclamos dados de alta en 2019 y mostremos su composición. Hagamos primero un top 5 de los reclamos por frecuencia:

bcn_reclamos %>% 
    count(TIPUS) %>% 
    top_n(5) %>% 
    arrange(desc(n))
## Selecting by n
## # A tibble: 5 x 2
##   TIPUS                  n
##   <fct>              <int>
## 1 INCIDENCIA        131348
## 2 CONSULTA           53299
## 3 QUEIXA             37984
## 4 SUGGERIMENT        13339
## 5 PETICIO DE SERVEI  10562

Ahora guardemoslo como un vector con pull():

reclamos_frecuentes <- bcn_reclamos %>% 
    count(TIPUS) %>% 
    top_n(5) %>% 
    pull(TIPUS)
## Selecting by n

Y grafiquemos con un gráfico de barras apilado mostrando en la composición de las barras el tipo de reclamo:

bcn_reclamos %>% 
  filter(year(fecha_alta) == 2019,
         TIPUS %in% reclamos_frecuentes) %>% 
ggplot() +
        geom_bar(aes(x = month(fecha_alta, label = TRUE), fill =TIPUS)) + 
  labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de barras apilado",
         x = "Mes",
         y = "Cantidad",
         fill = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Y sin apilar:

bcn_reclamos %>% 
  filter(year(fecha_alta) == 2019,
         TIPUS %in% reclamos_frecuentes) %>% 
ggplot() +
        geom_bar(aes(x = month(fecha_alta, label = TRUE), fill =TIPUS), position = "dodge") + 
  labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de barras sin apilar",
         x = "Mes",
         y = "Cantidad",
         fill = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos que el tipo de reclamo con mayor frecuencia es sin dudas la Incidencia, seguida de la queja y la consulta.

Hagamos ahora un gráfico de líneas:

conteo_mensual <-  bcn_reclamos %>% 
   filter(year(fecha_alta) == 2019,
               TIPUS %in% reclamos_frecuentes) %>% 
    count(TIPUS, mes = month(fecha_alta, label = TRUE))
   
ggplot(conteo_mensual) +
    geom_line(aes(x = mes, y = n, group = TIPUS, color = TIPUS))+
   labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de líneas",
         x = "Mes",
         y = "Cantidad",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Ésta última opción es sin dudas la más clara, tanto para mostrar la diferencia relativa en el volumen de incidentes, como para indicar si existen fluctuaciones.

Grafiquemos según el día de la semana:

conteo_semanal <-  bcn_reclamos %>% 
  filter(year(fecha_alta) == 2019,
               TIPUS %in% reclamos_frecuentes) %>% 
    count(TIPUS, diasemana = wday(fecha_alta, label = TRUE))
   
ggplot(conteo_semanal) +
    geom_line(aes(x = diasemana, y = n, group = TIPUS, color = TIPUS)) + 
    labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de líneas",
         x = "Día de la semana",
         y = "Cantidad",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos que el lunes es el día con mayor cantidad de reclamos y va disminuyendo paulatinamente a lo largo de la semana. Durante el fin de sema las observaciones son mucho menores.

Veamoslo en porcentaje:

conteo_porcentual <- conteo_semanal  %>% 
    group_by(TIPUS) %>%
    mutate(pct = n / sum(n) * 100)

ggplot(conteo_porcentual) +
    geom_line(aes(x = diasemana, y = pct, group = TIPUS, color = TIPUS)) + 
  labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de líneas Porcentual %",
         x = "Día de la semana",
         y = "Cantidad",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos que todos los tipos de reclamo tienen el mismo comportamiento, en cuanto a la distribución de la semana. Forcemos al gráfico a comenzar desde 0 el eje y:

ggplot(conteo_porcentual) +
    geom_line(aes(x = diasemana, y = pct, group = TIPUS, color = TIPUS))+
    expand_limits(y = 0) + 
   labs(title = "Reclamos finalizados en 2019",
         subtitle = "Barcelona, Gráfico de líneas Porcentual %",
         x = "Día de la semana",
         y = "Cantidad",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos que en este caso la respuesta es muy parecida.

  1. Analizar la distribución espacial de los datos a partir de:
  1. Un mapa de densidad que muestre donde se concentran la mayor cantidad de observaciones.

Antes que nada filtremos las observaciones que no tienen coordenadas.

bcn_reclamos <- bcn_reclamos %>% 
    filter(!is.na(LONGITUD), !is.na(LATITUD))

Ahora obtengamos la “bounding box” de nuestros datos, y luego se los pasamos a get_stamenmap() para hacer el mapa:.

bbox <- make_bbox(bcn_reclamos$LONGITUD, bcn_reclamos$LATITUD)

MAPA <- get_stamenmap(bbox = bbox, maptype = "toner-lite", zoom = 12)
## Source : http://tile.stamen.com/toner-lite/12/2071/1528.png
## Source : http://tile.stamen.com/toner-lite/12/2072/1528.png
## Source : http://tile.stamen.com/toner-lite/12/2073/1528.png
## Source : http://tile.stamen.com/toner-lite/12/2071/1529.png
## Source : http://tile.stamen.com/toner-lite/12/2072/1529.png
## Source : http://tile.stamen.com/toner-lite/12/2073/1529.png
## Source : http://tile.stamen.com/toner-lite/12/2071/1530.png
## Source : http://tile.stamen.com/toner-lite/12/2072/1530.png
## Source : http://tile.stamen.com/toner-lite/12/2073/1530.png
ggmap(MAPA)

Hagamos ahora el mapa de densidad:

ggmap(MAPA) +
    geom_bin2d(data = bcn_reclamos, 
               aes(x = LONGITUD, y = LATITUD), alpha=.9) +
   labs(title = "Densidad de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         fill = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Mejorémoslo aumentando la cantidad de celdas para aumentar la resolución y utilicemos la escala viridis para detecter diferencias por tonalidad con mayor facilidad:

ggmap(MAPA) +
    geom_bin2d(data = bcn_reclamos, 
               aes(x = LONGITUD, y = LATITUD), bins=100, alpha=.9) +
   scale_fill_viridis_c() +
   labs(title = "Densidad de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         fill = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos según el grafico que en los limites de la ciudad es donde menor cantidad de reclamos hay, destándose varias zonas que alcanzan un color verde amarillento.

Utilicemos ahora Kernel Density Estimation, muy utilizada en aplicaciones GIS para estimar la intensidad de una determinada variable en cualquier punto del área analizada, incluso en aquellos donde no hay observaciones:

ggmap(MAPA) +
    geom_density2d(data = bcn_reclamos, 
               aes(x = LONGITUD, y = LATITUD, color=stat(level))) +
   scale_color_viridis_c() +
   labs(title = "Densidad de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         color = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos con mayor claridad que la mayor cantidad de observaciones se da en el barrio de Sant Antoni, que alcanza el color amarillo en la escala viridis. Luego existen otros puntos que se destacan en la ciudad, y decrecen su valor a medida que se acercan a los límites de la ciudad.

  1. Un facetado del mapa del punto III.a. que permita discenir patrones espaciales dentro de las categorías de una variable. ¿El patrón espacial de los datos elegidos se mantiene o varía según las categorías?

Visualicemos entonces un facetado de las categorías vistas anteriormente:

ggmap(MAPA) +
    geom_point(data = filter(bcn_reclamos, TIPUS %in% reclamos_frecuentes), 
               aes(x = LONGITUD, y = LATITUD, color = TIPUS),
               size = 0.1, alpha = 0.1) +
    guides(color = guide_legend(override.aes = list(size=2, alpha = 1))) +
    scale_color_brewer(palette = "Set1") +
    facet_wrap(~TIPUS) +
    labs(title = "Facetado de tipos de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

¿Que pasó con Consultas? Al filtrar las observacines que no tenían coordenadas, todas las observaciones de la categoría Consultas desaparecieron. Al mirar con atención el dataset original vemos que el canal por el cual se hicieron todas estas Consultas es por la Web y suponemos no debe ser necesario, al tratarse solo de una Consulta y no de un reclamo puntual, de establecer ninguna dirección. Respecto a los otros tipos de reclamo, en general vemos que la distribución es más bien homogenea. En el caso de Petición de Servicio la cantidad es considerablemente menor al de los otros tipos de reclamo y, además, sí se reconoce mayor concentración el centro de la ciudad. En cambio en Incidenca, Quejas y Sugerencias alcanza todo el territorio de forma más pareja.

Para hacer las diferencias aún mas nítidas, podemos facetar con la estimación de densidad Kensel:

ggmap(MAPA) +
    geom_density2d(data = filter(bcn_reclamos, TIPUS %in% reclamos_frecuentes), 
               aes(x = LONGITUD, y = LATITUD, color = stat(level)))+
    scale_color_viridis_c() +
    facet_wrap(~TIPUS) +
    labs(title = "Facetado de densidad por tipos de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         color = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")
## Warning: Computation failed in `stat_density2d()`:
## missing value where TRUE/FALSE needed

Vemos de forma más clara como varían las variaciones del patrón espacial de los datos elegidos. Si bien Incidencia Sugerencia y Queja se parecen un poco, la categoría de Petición de Servicios es considerablemente distinta a la de las demás.

  1. Comparar la densidad de los datos en el tiempo (facetar). ¿Los patrones espaciales de los datos elegidos se mantienen o varían en el tiempo?

Comparemos dos tipos de reclamo (Sugerencia y Queja) mostrando dónde ocurren en cada día de la semana.

bcn_reclamos <- bcn_reclamos %>% 
    mutate(dia_semana = wday(fecha_alta, label = TRUE))

ggmap(MAPA) +
    geom_point(data = filter(bcn_reclamos, 
                             TIPUS %in% c("SUGGERIMENT", "QUEIXA")),
               aes(x = LONGITUD, y = LATITUD, color = TIPUS), alpha = .4, size = .1) +
   guides(color = guide_legend(override.aes = list(size=2, alpha = 1))) +
    facet_wrap(~dia_semana, nrow = 2) + 
    labs(title = "Facetado de 2 tipos de reclamos",
         subtitle = "Barcelona",
         x = "Longitud",
         y = "Latitud",
         color = "Tipo",
         caption = "Fuente: Ajuntament de Barcelona")

Se ve claramente la disminución de las observaciones durante el fin de semana. Pero espacialmente no se llega a detectar un patrón específico.

Mejor concentrmosnos en un tipo de reclamo en particular y evaluemos en que zonas se concentra de acuerdo al día de la semana:

ggmap(MAPA) +
     geom_density2d(data = filter(bcn_reclamos, TIPUS %in% "QUEIXA"), 
               aes(x = LONGITUD, y = LATITUD, color=stat(level))) +
    scale_color_viridis_c() +
    facet_wrap(~dia_semana, nrow = 2) + 
    labs(title = "Concentración espacial de Sugerencias",
         subtitle = "Barcelona, según día de la semana",
         x = "Longitud",
         y = "Latitud",
         color = "Cantidad",
         caption = "Fuente: Ajuntament de Barcelona")

Vemos que la mayor concentración espacial es el día jueves en una zona alejada del centro, cosa que se mantiene el día viernes pero en menor intensidad. En cambio el resto de los días la mayor concentración se encuentra del lado opuesta de la ciudad, alcanzando su pico el día martes.