Introducción práctica a la librería ggplot2 y su integración con ggmap

Roger Borràs, Lluís Ramon, Andreu Vall

Barcelona, noviembre 2012


Quién somos

Contenidos


Por qué usar ggplot2?

Qué es Grammar of graphics y los componentes de ggplot2

Requisitos de ggplot2


La BD de ejemplo

##  [1] "id"                 "country_code"       "country_name"      
##  [4] "continent"          "region"             "income_group"      
##  [7] "year"               "ease_of_business"   "foreign_investment"
## [10] "gdp"                "gni_per_capita"     "population"

De plot a qplot

El diagrama de dispersión

plot(climate_2010$ease_of_business, climate_2010$gni_per_capita)

plot of chunk Gràfic de dispersio base

El mismo gráfico con qplot de ggplot2

qplot(climate_2010$ease_of_business, climate_2010$gni_per_capita)

plot of chunk Grafic de dispersio amb qplot


Gráfico con modificación de las etiquetas y los límites de los ejes

qplot(ease_of_business, gni_per_capita, xlab = "EASE OF BUSINESS", ylab = "GNI PER CAPITA ($)", 
    xlim = c(0, 200), size = I(4), data = climate_2010)

plot of chunk Modifiacio limits i eixos amb qplot


El ejemplo por continentes:

climate_africa <- subset(climate_2010, continent == "AFRICA")
climate_asia <- subset(climate_2010, continent == "ASIA")
climate_europa <- subset(climate_2010, continent == "EUROPE")
climate_namerica <- subset(climate_2010, continent == "N.AMERICA")
climate_oceania <- subset(climate_2010, continent == "OCEANIA")
climate_samerica <- subset(climate_2010, continent == "S.AMERICA")

plot(climate_africa$ease_of_business, climate_africa$gni_per_capita, pch = 16, 
    col = "red", ylim = c(0, 90000), xlab = "EASE OF BUSINESS", ylab = "GNI PER CAPITA ($)")
points(climate_asia$ease_of_business, climate_asia$gni_per_capita, pch = 16, 
    col = "blue")
points(climate_europa$ease_of_business, climate_europa$gni_per_capita, pch = 16, 
    col = "green")
points(climate_namerica$ease_of_business, climate_namerica$gni_per_capita, pch = 16, 
    col = "magenta")
points(climate_oceania$ease_of_business, climate_oceania$gni_per_capita, pch = 16, 
    col = "yellow")
points(climate_samerica$ease_of_business, climate_samerica$gni_per_capita, pch = 16)
legend(150, 85000, c("AFRICA", "ASIA", "EUROPA", "N.AMERICA", "OCEANIA", "S.AMERICA"), 
    col = c("red", "blue", "green", "magenta", "yellow", "black"), pch = c(16, 
        16, 16, 16, 16, 16))

plot of chunk Dispersio per continents base

Con ggplot2 el gráfico tiene una sintaxis mas simple y clara:

qplot(ease_of_business, gni_per_capita, colour = continent, data = climate_2010, 
    xlab = "EASE OF BUSINESS", ylab = "GNI PER CAPITA ($)")

plot of chunk Dispersio per continents amb qplot


Modificación con leyenda tipo shape

qplot(ease_of_business, gni_per_capita, shape = continent, xlab = "EASE OF BUSINESS", 
    ylab = "GNI PER CAPITA ($)", data = climate_2010)

plot of chunk Dispersio amb modifiacio shape

Modificación con leyenda tipo shape y colour

qplot(ease_of_business, gni_per_capita, shape = continent, colour = continent, 
    xlab = "EASE OF BUSINESS", ylab = "GNI PER CAPITA ($)", data = climate_2010)

plot of chunk Dispersio amb modifiacio shape i colour

Definimos con geom, añadimos una regresión loess y lo guardamos en una variable:

p1 <- qplot(ease_of_business, gni_per_capita, geom = c("smooth", "point"), xlab = "EASE OF BUSINESS", 
    ylab = "GNI PER CAPITA ($)", data = climate_2010)
p1

plot of chunk Dispersio amb regressió loess


El gráfico de boxplot

p2 <- qplot(continent, ease_of_business, geom = c("boxplot"), fill = I("deepskyblue1"), 
    alpha = I(0.25), xlab = "CONTINENT", ylab = "EASE OF BUSINESS", data = climate_2010)
p2

plot of chunk Grafic boxplot amb qplot


El gráfico de densidad

p3 <- qplot(gni_per_capita, geom = c("density"), fill = I("gold"), alpha = I(0.85), 
    xlab = "GNI PER CAPITA ($)", ylab = "DENSITY", data = climate_2010)
p3

plot of chunk Grafic de densitat amb qplot


Los facets

p4 <- qplot(ease_of_business, gni_per_capita, facets = ~continent, ncol = 3, 
    xlab = "EASE OF BUSINESS", ylab = "GNI PER CAPITA ($)", data = climate_2010)
p4

plot of chunk Facets amb qplot


Integración de los gráficos en un mismo panel

library(gridExtra)
grid.arrange(p1, p2, p3, p4, ncol = 2)

plot of chunk Integracio panell


De qplot a ggplot

qplot nos da una sintaxis breve y parecida a plot.

climate_2010 <- subset(climate, year == 2010)
qplot(ease_of_business, gni_per_capita, geom = c("smooth", "point"), xlab = "EASE OF BUSINESS", 
    ylab = "GNI PER CAPITA ($)", data = climate_2010)

plot of chunk qplot: una linia


Sin embargo, el anterior gráfico se compone de varias capas.

qplot(ease_of_business, gni_per_capita, data = climate_2010) +  
  # geom_point() por defecto en qplot  
  geom_smooth() +  
  xlab("EASE OF BUSINESS") +  
  ylab("GNI PER CAPITA ($)")

plot of chunk qplot: diverses linies


O usando ggplot

ggplot(data = climate_2010, aes(x = ease_of_business, y = gni_per_capita)) +  
  geom_point() +       
  geom_smooth() +  
  xlab("EASE OF BUSINESS") +  
  ylab("GNI PER CAPITA ($)")

plot of chunk ggplot: com qplot diverses linies


¡Atención!

¿Diferencia en la sintaxis?

¿Diferencia en el uso?


Seguiremos trabajando con el gráfico de dispersión ease_of_business vs gni_per_capita.

p <- ggplot(data = climate_2010, aes(x = ease_of_business, y = gni_per_capita))
p + geom_point()

plot of chunk plot basic: ease_of_business vs gni_per_capita


Las geometrías

Las geometrías (geom) definen literalmente lo que vemos en el gráfico: puntos, lineas, polígonos, …

p1 <- p + geom_point()
p2 <- p + geom_line()
p3 <- p + geom_area()
grid.arrange(p1, p2, p3)

plot of chunk plot basic: canvi de geoms


Correspondencia vs asignación

p + geom_point(aes(color = continent))

plot of chunk diferencia assignar i correspondre

p + geom_point(color = "blue")

plot of chunk diferencia assignar i correspondre

# ¡atención!
p + geom_point(aes(color = "blue"))

plot of chunk diferencia assignar i correspondre


La leyenda

La leyenda se genera automáticamente a partir de las variables que definen una característica estética del gráfico (las que van dentro de la función aes).

p + geom_point(aes(color = continent))

plot of chunk llegenda: per defecte

p + geom_point(aes(color = continent, size = income_group))

plot of chunk llegenda: per defecte

p + geom_point(aes(color = continent, shape = continent, size = income_group))

plot of chunk llegenda: per defecte


Las funciones scale

Nos permiten controlar la correspondencia entre una variable y su representación gráfica.

p1 <- p + geom_point(aes(color = continent, size = income_group))
# leyenda generada automáticamente
p1

plot of chunk llegenda: modificacio de la llegenda

# edición del nombre las variables
p1 + scale_size_discrete("Income group") +
     scale_color_discrete("Continent")

plot of chunk llegenda: modificacio de la llegenda

# correspondencia entre la variable y su representación
p1 + scale_size_discrete("Income group", range = c(10,1)) +
     scale_color_brewer("Continent", palette = "Spectral")

plot of chunk llegenda: modificacio de la llegenda


**geom_line** y el uso de group

Vamos a analizar la evolución temporal del PIB de los países de Europa.

climate_europe <- subset(climate, continent == "EUROPE")

ggplot(climate_europe, aes(x = year, y = gdp/population)) +
  geom_line()

plot of chunk grafic linia: error no fer servir group


¡Atención!

Un solo elemento gráfico puede contener uno o muchos datos. Por ejemplo:

Con group controlamos qué observaciones pertenecen a cada elemento gráfico individual.


Usando group

ggplot(climate_europe, aes(x = year, y = gdp/population)) +
  geom_line(aes(group = country_code))

plot of chunk grafic linia: error arreglat fent servir group


Comprobamos la distribución de acuerdo con la variable income_group.

ggplot(climate_europe, aes(x = year, y = gdp/population)) +
  geom_line(aes(group = country_code, color = income_group))

plot of chunk grafic linia: distribucio per income_group

Añadimos una aproximación para cada grupo. Atención al uso de group diferente en cada capa del gráfico!

ggplot(climate_europe, aes(x = year, y = gdp/population)) +
  geom_line(aes(group = country_code, color = income_group)) +
  geom_smooth(aes(group = income_group, colour = income_group), size = 2)

plot of chunk grafic linia: aproximacio per cada grup


**geom_tile** y la edición manual de la leyenda

Estudiamos la inversión extranjera en cada país. Para simplificar, seleccionamos unos cuantos países europeos.

countries <- c("Finland", "Germany", "Italy", "Netherlands", "Greece")
climate_countries <- subset(climate_europe, country_name %in% countries)

ggplot(climate_countries, aes(x = year, y = foreign_investment)) +
  geom_line(aes(color = country_code, group = country_code))

plot of chunk grafic tile: subset de paisos


También podemos representar la altura de las ordenadas mediante un mapa de calor.

# atención al valor NA de Grecia
p <- ggplot(climate_countries, aes(x = year, y = country_code))
p + geom_tile(aes(fill = foreign_investment))

plot of chunk grafic tile: calor


Queremos representar el año de máxima inversión extranjera para cada país. Podemos calcular esta información y representarla en el gráfico.

max_investment <- function(df){
  max_investment <- rep("no_max", nrow(df))
  max_investment[which.max(df$foreign_investment)] <- "max"
  result <- data.frame(df, max_investment)
  return(result)
}

climate_countries <- ddply(climate_countries, .(country_code), max_investment)

head(climate_countries)
##     id country_code country_name continent                region
## 1 1043          DEU      Germany    EUROPE Europe & Central Asia
## 2 1044          DEU      Germany    EUROPE Europe & Central Asia
## 3 1045          DEU      Germany    EUROPE Europe & Central Asia
## 4 1046          DEU      Germany    EUROPE Europe & Central Asia
## 5 1047          DEU      Germany    EUROPE Europe & Central Asia
## 6 1048          DEU      Germany    EUROPE Europe & Central Asia
##        income_group year ease_of_business foreign_investment      gdp
## 1 High income: OECD 1990               NA               0.18 1.71e+12
## 2 High income: OECD 1991               NA               0.26 1.81e+12
## 3 High income: OECD 1992               NA              -0.10 2.06e+12
## 4 High income: OECD 1993               NA               0.02 2.00e+12
## 5 High income: OECD 1994               NA               0.34 2.15e+12
## 6 High income: OECD 1995               NA               0.48 2.52e+12
##   gni_per_capita population max_investment
## 1          20630   79433000         no_max
## 2          22170   80014000         no_max
## 3          25050   80624000         no_max
## 4          25200   81156000         no_max
## 5          26590   81516000         no_max
## 6          28630   81642000         no_max

# actualizar los datos de p
p <- p %+% climate_countries

Para visualizar el año de máxima inversión usamos color (con geom_tile, se trata del color del borde).

p +  geom_tile(aes(fill = foreign_investment, color = max_investment))

plot of chunk Grafic tiles: complet sense llegenda editada


Editamos manualmente la leyenda para conseguir unos colores fáciles de distinguir.

p + geom_tile(aes(fill = foreign_investment, color = max_investment)) + 
  scale_fill_gradient(low = "white", high = "red") +
  scale_color_manual(breaks = c("max","no_max"), values = c("darkblue","white"))

plot of chunk Grafic tiles: complet amb llegenda editada


Ejemplos de mapas con ggplot2

Geometría de polígonos

library(ggplot2)
library(maptools)
data(wrld_simpl)
is(wrld_simpl)
## [1] "SpatialPolygonsDataFrame" "SpatialPolygons"         
## [3] "Spatial"                  "SpatialPolygonsNULL"
head(wrld_simpl@data)
##     FIPS ISO2 ISO3 UN                NAME   AREA  POP2005 REGION SUBREGION
## ATG   AC   AG  ATG 28 Antigua and Barbuda     44    83039     19        29
## DZA   AG   DZ  DZA 12             Algeria 238174 32854159      2        15
## AZE   AJ   AZ  AZE 31          Azerbaijan   8260  8352021    142       145
## ALB   AL   AL  ALB  8             Albania   2740  3153731    150        39
## ARM   AM   AM  ARM 51             Armenia   2820  3017661    142       145
## AGO   AO   AO  AGO 24              Angola 124670 16095214      2        17
##         LON    LAT
## ATG -61.783  17.08
## DZA   2.632  28.16
## AZE  47.395  40.43
## ALB  20.068  41.14
## ARM  44.563  40.53
## AGO  17.544 -12.30
# fortify sirve con objetos maps, sp, etc
world_ggmap <- fortify(wrld_simpl, region = "ISO3")
head(world_ggmap)
##     long   lat order  hole piece group  id
## 1 -69.88 12.41     1 FALSE     1 ABW.1 ABW
## 2 -70.06 12.54     2 FALSE     1 ABW.1 ABW
## 3 -70.06 12.63     3 FALSE     1 ABW.1 ABW
## 4 -69.88 12.41     4 FALSE     1 ABW.1 ABW
## 5  74.92 37.24     5 FALSE     1 AFG.1 AFG
## 6  74.39 37.18     6 FALSE     1 AFG.1 AFG
ggplot(data = world_ggmap, aes(x = long, y = lat, group = group)) + geom_polygon()

plot of chunk ejemplo geom_polygon: grafico

Para representar información de climate seria necesario cruzar los datos de world_ggmap y climate.


Geometría de mapas

geom_map: usa geom_polygon, mucho más rápida y cruza los datos de mapa con la información del data.frame

ggplot(climate_2010) +
  geom_map(aes(map_id = country_code), map = world_ggmap) +
  expand_limits(x = world_ggmap$long, y = world_ggmap$lat)

plot of chunk ejemplo geom_map

Congo no ha cruzado correctamente porque tienen diferentes identificadores


Podemos usar los aesthetics de climate_2010

climate_2010 <- subset(climate, year == 2010)
ggplot(climate_2010) +
  geom_map(aes(map_id = country_code, fill = continent), map = world_ggmap) +
  expand_limits(x = world_ggmap$long, y = world_ggmap$lat)

plot of chunk ejemplo continente


Nueva capa con nuevo data.frame

q <- ggplot(climate_2010) +
     geom_map(aes(map_id = country_code, fill = ease_of_business), map = world_ggmap) +
     expand_limits(x = world_ggmap$long, y = world_ggmap$lat)

q

plot of chunk mapa_con_ciudades

library(maps)
data(world.cities)
head(world.cities)
##                 name country.etc   pop   lat  long capital
## 1 'Abasan al-Jadidah   Palestine  5629 31.31 34.34       0
## 2 'Abasan al-Kabirah   Palestine 18999 31.32 34.35       0
## 3       'Abdul Hakim    Pakistan 47788 30.55 72.11       0
## 4 'Abdullah-as-Salam      Kuwait 21817 29.36 47.98       0
## 5              'Abud   Palestine  2456 32.03 35.07       0
## 6            'Abwein   Palestine  3434 32.03 35.20       0
q + geom_point(aes(long, lat), colour = "red", size = 0.3,  data = world.cities)

plot of chunk mapa_con_ciudades


Podemos usar facets

climate_1995_2010 <- subset(climate, year %in% c(1995, 2000, 2005, 2010))

q <- ggplot(climate_1995_2010) +
     geom_map(aes(map_id = country_code, fill = gdp), map = world_ggmap) +
     expand_limits(x = world_ggmap$long, y = world_ggmap$lat) +
     facet_wrap(~ year, ncol = 2) +
     scale_fill_continuous(low = "blue", high = "red")

q

plot of chunk mapas_con_facets


Mapas con ggmap

Diferentes fuentes de mapas

library(ggmap)
qmap("barcelona", zoom = 14)

plot of chunk origenes_base_mapa

qmap("barcelona", zoom = 14, source = "osm")

plot of chunk origenes_base_mapa


Formas de solicitar un mapa

qmap("barcelona", zoom = 14)
qmap(c(lon = 2.17, lat = 41.38), zoom = 14)
qmap(c(2.172, 41.39, 2.186, 41.38), zoom = 14)

De qmap a ggmap

qmap = get_map + ggmap

En la documentación los parámetros están definidos en get_map y ggmap

barcelona_map <- get_map("barcelona", zoom = 14)
ggmap(barcelona_map)

plot of chunk De qmap a ggmap


Funciones interesantes

geocode("Central UB, Barcelona")
##     lon   lat
## 1 2.164 41.39
revgeocode(c(2.164033, 41.38655), output = "address")
## [1] "Gran Via de les Corts Catalanes, 585, University of Barcelona, 08007 Barcelona, Province of Barcelona, Spain"
mapdist("Tarragona", "Barcelona")
##        from        to     m km miles seconds minutes hours
## 1 Tarragona Barcelona 96998 97 60.27    4143   69.05 1.151
route("Central UB, Barcelona", "Plaça Catalunya, Barcelona", alternatives = FALSE)
##     m    km   miles seconds minutes    hours startLon startLat endLon
## 1 269 0.269 0.16716      39  0.6500 0.010833    2.164    41.39  2.162
## 2 285 0.285 0.17710     159  2.6500 0.044167    2.162    41.38  2.164
## 3  45 0.045 0.02796      17  0.2833 0.004722    2.164    41.39  2.165
## 4 336 0.336 0.20879      56  0.9333 0.015556    2.165    41.39  2.169
##   endLat leg
## 1  41.38   1
## 2  41.39   2
## 3  41.39   3
## 4  41.39   4

Ejemplo de uso de qmap y ggplot2

desde <- 'Carrer del Doctor Aiguader 88, Barcelona'
hasta <- 'Plaça Catalunya, Barcelona'

rutas <- route(desde, hasta, alternatives = TRUE)
head(rutas)
##      m    km   miles seconds minutes    hours startLon startLat endLon
## 1  123 0.123 0.07643      10  0.1667 0.002778    2.193    41.39  2.194
## 2  223 0.223 0.13857      42  0.7000 0.011667    2.194    41.39  2.196
## 3 1172 1.172 0.72828     136  2.2667 0.037778    2.196    41.39  2.187
## 4  626 0.626 0.38900     110  1.8333 0.030556    2.187    41.39  2.182
## 5  127 0.127 0.07892      23  0.3833 0.006389    2.182    41.39  2.181
## 6  123 0.123 0.07643      50  0.8333 0.013889    2.181    41.39  2.180
##   endLat leg route
## 1  41.39   1     A
## 2  41.39   2     A
## 3  41.39   3     A
## 4  41.39   4     A
## 5  41.39   5     A
## 6  41.39   6     A
ggplot() +
  geom_segment(aes(x = startLon, y = startLat, xend = endLon, yend = endLat, colour = route), size = 1.5, data = rutas)

plot of chunk Comparar un gráfico ggplot2 con el fondo de google maps

qmap('Plaça Sant Jaume, Barcelona', zoom = 14,  maptype = "roadmap", extent = "panel") +
  geom_segment(aes(x = startLon, y = startLat, xend = endLon, yend = endLat, colour = route), size = 1.5, data = rutas)

plot of chunk Comparar un gráfico ggplot2 con el fondo de google maps


Podemos usar facets

qmap('Plaça Sant Jaume, Barcelona', zoom = 14,  maptype = "roadmap", extent = "panel") +
  geom_segment(aes(x = startLon, y = startLat, xend = endLon, yend = endLat, colour = route), size = 1.5, data = rutas) +
  facet_grid(.~ route)

plot of chunk ggmap con facets



Más información


Cómo hemos hecho la presentación?

sessionInfo()
## R version 2.15.2 (2012-10-26)
## Platform: i486-pc-linux-gnu (32-bit)
## 
## locale:
##  [1] LC_CTYPE=es_ES.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=es_ES.UTF-8        LC_COLLATE=es_ES.UTF-8    
##  [5] LC_MONETARY=es_ES.UTF-8    LC_MESSAGES=es_ES.UTF-8   
##  [7] LC_PAPER=C                 LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=es_ES.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
## [1] grid      stats     graphics  grDevices utils     datasets  methods  
## [8] base     
## 
## other attached packages:
##  [1] maptools_0.8-16 lattice_0.20-10 foreign_0.8-51  mapproj_1.1-8.3
##  [5] rgeos_0.2-7     stringr_0.6.1   sp_0.9-99       maps_2.2-6     
##  [9] ggmap_2.2       gridExtra_0.9.1 scales_0.2.2    plyr_1.7.1     
## [13] ggplot2_0.9.2.1 knitr_0.8.1    
## 
## loaded via a namespace (and not attached):
##  [1] colorspace_1.1-1    dichromat_1.2-4     digest_0.5.2       
##  [4] evaluate_0.4.2      formatR_0.6         gtable_0.1.1       
##  [7] labeling_0.1        MASS_7.3-22         memoise_0.1        
## [10] munsell_0.4         png_0.1-4           proto_0.3-9.2      
## [13] RColorBrewer_1.0-5  reshape2_1.2.1      RgoogleMaps_1.2.0.2
## [16] rjson_0.2.10        tools_2.15.2