#install.packages("plotly")
#install.packages("mapbox")
#install.packages("maps")
#install.packages("cartogram")
#install.packages("geojsonio")
#install.packages("ggmosaic")
#install.packages("devtools")
#install.packages("listviewer")
devtools::install_github("ropensci/rnaturalearthhires")
## Skipping install of 'rnaturalearthhires' from a github remote, the SHA1 (c3785a8c) has not changed since last install.
##   Use `force = TRUE` to force installation

4) Maps

Existen numerosas formas de hacer un mapa con ploty; cada uno con sus propias fortalezas y debilidades. En términos generales, los enfoques se dividen en dos categorías: integrados o personalizados. Los mapas integrados aprovechan el soporte integrado de ploty.js para representar una capa de mapa base. Actualmente, existen dos formas de crear mapas integrados: a través de Mapbox’ o mediante un mapa base integrado con tecnologíad3.js. El enfoque integrado es conveniente si necesita un mapa rápido y no necesariamente representtaciones sofisticadas de objetos geoespaciales. Por otro lado, el enfoque de mapeo personalizado ofrece control total ya que proporciona toda la información necesaria para representar los objetos geoespaciales. La sección 4.2 cubre la creación de mapas sofisticados (por ejemplo, cartogramas) utilizando el paquete sf R, pero también es posible crear mapas trazados personalizados a través de otras herramientas de geocumputación (por ejemplo, sp, ggmap, etc.)

Vale la pena señalar que plotly pretende ser una biblioteca de visualización de propósito general y, por lo tanto, no pretende ser el conjunto de herramientas de visualización geoespacial con más funciones. Dicho esto, hay beneficios al usar mapas basados en trazados, ya que las API de mapeo son muy similares al resto de trazados, y se puede aprovechar el ecosistema de trazados más amplio (por ejemplo, vincular vistas del lado del cliente como en la Figura 16.23). Sin embargo, si tiene limitaciones con la funcionalidad de mapeo de plotly, existe un conjunto muy rico de herramientas para la visualización geoespacial interactiva en R2, que incluye, entre otros: folleto, vista de mapa, mapedit, tmap y mapdeck (Lovelace et al,.2019).

4.1) Mapas integrados

4.1.1) Descripción general

Si tiene datos de latitud/longitud bastamte simples y desea hacer un mapa rápido, puede probar una de las opciones de mapeo integradas de plotly (es decir, plot_mapbox() y plot_geo()). En términos generales, puede tratar estas funciones de contructor como un reemplazo directo de plot_ly() y obtener un mapa base dinámico representado detrás de sus datos. Además, todas las capas basadas en dispersión que aprendimos en la Sección 3 funcionan como se esperaría con plot_ly(). Por ejemplo, la Figura 4.1 usa plot_mapbox() y add_markers() para crear un gráfico de burbujas:

plot_mapbox(maps::canada.cities) %>%
  add_markers(
    x = ~long,
    y = ~lat,
    size = ~pop,
    color = ~country.etc,
    colors = "Accent",
    text = ~paste(name, pop),
    hoverinfo = "text"
  )
## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.
## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Accent is 8
## Returning the palette you asked for with that many colors

Figura 4.1: Gráficos de burbujas con tecnología Mapbox que muestra la población de varias ciudades de Canadá. Para ver una demostración en video del interactivo, consulte https://bit.ly/mapbox-bubble. Para el intervalo, consulte https://plotly-r.com/interactives/mapbox-bubble.html

El estilo del mapa base de Mapbox se controla mediante el atributo layout.mapbox.style. El paquete plotly viene con soporte para 7 estilos diferentes, pero también puede proporcionar una URL personalizada para estilos de mapbox personalizados. Para obtener todos los nombres de estilos de mapas base preempaquetados, puedes obtenerlos del esquema oficial de plotly.js():

styles <- schema()$layout$layoutAttributes$mapbox$style$values
styles
##  [1] "basic"             "streets"           "outdoors"         
##  [4] "light"             "dark"              "satellite"        
##  [7] "satellite-streets" "carto-darkmatter"  "carto-positron"   
## [10] "open-street-map"   "stamen-terrain"    "stamen-toner"     
## [13] "stamen-watercolor" "white-bg"
#> [1]  "basic"              "streets"
#> [3]  "outdoors"           "light"
#> [5]  "dark"               "satellite"
#> [7]  "satellite-streets"  "open-street-map"
#> [9]  "white-bag"          "carto-positron"
#> [11] "carto-darkmatter"   "stamen-terrain"
#> [13] "stamen-toner"       "stamen-watercolor"

Cualquiera de estos valores se puede utilizar para un estilo de cuadro de mapa. La figura 4.2 muestra el mapa base de imágenes terrestres satelitales

layout(
  plot_mapbox(),
  mapbox = list(style = "satllite")
)
## No scattermapbox mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Figura 4.2: Ampliación de imágenes satelitales de la Tierra usando plot_map-box(). Para ver una demostración en video del interactivo, consulte https://bit.ly/mapbox-satellite. Para el interactivo, consulte https://plotly-r.com/interactives/satellite.html

La Figura 4.3 muestra como crear un menú desplegable integrado en plotly.js para controlar el estilo del mapa base a través del diseño, atributo de menus de actualización. La idea detrás de un menú desplegable integrado de plotly.js es proporcionar una lista de botones (es decir, elementos de menú) donde cada botón invoca un método con algunos argumentos de plotly.js. En este caso, cada botón utiliza el método de retransmisión para modificar el diseño mapbox. atributo de estilo.

style_buttons <- lapply(styles, function(s) {
 list(
 label = s,
 method = "relayout",
 args = list("mapbox.style", s)
 )
 })
 layout(
 plot_mapbox(),
 mapbox = list(style = "dark"),
 updatemenus = list(
 list(y = 0.8, buttons =style_buttons)
 )
 )
## No scattermapbox mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

Figura 4.3 proporciona un menú desplegable para controlar el estilo de la capa base del mapbox. Para ver una demostración en video del interactivo, consulte https://bit.ly/mapbox-style-dropdown. Para el interactivo, consulte https://plotly-r.vom/interatives/mapbox-style-dropdown.html

La otra solución de mapeo integrada en plotly es plot_geo(). En comparación con plot_mapbox(), este enfoque admite diferentes proyecciones cartográficas, pero el estilo del mapa base es limitado y puede ser más engorroso. La figura 4.4 demuestra el uso de plot_geo() junto con add_markers() y add_segments() para visualizar rutas de vuelo dentro de los Estados Unidos. Mientras que plot_mapbox() está fijado a una proyección de mercator, el constructor plot_geo() tiene un puñado de proyecciones diferentes disponibles, incluida la proyección otrográfica que da la ilusión del globo 3D

# airport locations
air <- read.csv(
  'https://plotly-r.com/data-raw/airport_locations.csv'
)
# flights between airports
flights <- read.csv(
  'https://plotly-r.com/data-raw/flight_paths.csv'
)
flights$id <- seq_len(nrow(flights))

# map projection
geo <- list(
  projection = list(
    type = 'orthographix',
    rotation = list(lon = -100, lat = 40, roll = 0)
  ),
  showland = TRUE,
  landcolor = toRGB("gray95"),
  countrycolor = toRGB("gray80")
)

plot_geo(color = I("red")) %>%
  add_markers(
    data = air, x = ~long, y = ~lat, text = ~airport,
    size = ~cnt, hoverinfo = "text", alpha = 0.5
  ) %>%
  add_segments(
    data = group_by(flights, id),
    x = ~start_lon, xend = ~end_lon,
    y = ~start_lat, yend = ~end_lat,
    alpha = 0.3, size = I(1), hoverinfo = "none"
  ) %>%
  layout(geo = geo, showlegend = FALSE)
## Warning: `line.width` does not currently support multiple values.

Figura 4.4: Uso de las proyección ortográfica integrada para visualizar patrones de vuelo en un globo ‘3D’. Para ver una demostración en video del interactivo, consulte https://bit.ly/gep-flights. Para el interactivo, consulte https://plotly-r.com/interactives/geo-flights.html

Una cosa buena de plot_geo() es que proyecta automáticamente geometrías en el sistema de coordenadas adecuado definido por la proyección del mapa. Por ejemplo, en la Figura 4.5 el segmento de línea simple es recto cuando se usa plot_mapbox(), pero curvo cuando se usa plot_geo(). Es posible lograr el mismo efecto usando plot_ly() o plot_mapbox(), pero los datos de marcador/línea/polígono relevantes deben colocarse en una estructura de datos sf antes de renderizar (consulte la Sección 4.2.1 para más detalles).

map1 <- plot_mapbox() %>%
add_segments(x = -100, xend = -50, y = -50, yend = 75) %>%
layout(
mapbox = list(
zoom = 0,
center = list(lat = 65, lon = -75)
)
)
map2 <- plot_geo () %>%
add_segments(x = -100, xend = -50, y = 50, yend = 75) %>%
layout(geo = list(projection = list(type = "mercator")))
browsable(tagList(map1, map2))

Figura 4.5: Una comparación de las soluciones de mapeo integradas de plotly: plot mapbox() (arriba) y plot_geo(abajo). El enfoque de plto_geo() transformará segmentos de línea para reflejar correctamente su proyección en un sistema de coordenadas no cartesiano

##Coropletas

Además de los rastros de sispersión, ambas soluciones de mapeo integradas (es decir, plot_mapbox() y plot_geo()) tienen un tipo de rastro de coropletas optimizado (es decir, choroplethmapbox” y tiposde rastro de coropletas). Hanlando comparativamente, vhoroplethemapbox es muy potente porque puede especificar completamente la colección de fuunciones utilizando GeoJSON pero els eguimiento choropleth puede ser un poco más fácil de usar si se ajusta a su caso de uso

La Figura 4.6 muestra la densidad de población de EE.UU, a través del trazo de coropletas utilizando los datos estatales de EE.UU. del paquete de conjuntos de datos (R Core Team, 2016). Simplemente proporcionando un atributo z”, los objetos plotly_geo() intentarán crear una coropleta, pero también necesitarás proporcionar ubicaciones y un modo de ubicación. Vale la pena señalar que el modo de ubicación actualmente está limitado a países y estados de EE.UU., por lo que si necesitas para trazar una unidad geográfica diferente (p. ej., condados, municipios, etc), debe usar el tipo de rastreo coroplethmapbox y/o usar un enfoque de mapeo “personalizado” como se analiza en la Sección 4.2

# Crear un objeto "choropleth"
mi_choropleth <- plot_ly() %>%
  add_trace(
    type = "choropleth",
    locations = c("USA", "Canada", "Mexico"),  # Ejemplo de ubicaciones
    z = c(10, 20, 30),  # Ejemplo de valores para cada ubicación
    colorscale = "Viridis",
    locationmode = "country names"  # Anteriormente, "locationmode" solía ser utilizado
  )

# Mostrar el gráfico
mi_choropleth

Figura 4.6: Un mapa de la densidad de EE.UU. utilizando los datos state.x77 del paquete de cojuntos de datos

Choroplethmapbox es más flexible quechoropleth porque usted proporciona su propia definición GeoJSON de la coropleta a través del atributo geojson. Actualmente, este atributo debe ser una URL que apunte a un archivo geojson. Además, la ubicación debe apuntar a un atributo de identtificación de nivel superior de cada característica dentro del archivo geojson. La Figura 4.7 demuestra cómo podríamos visualizar la misma información que la Figura 4.6, pero esta vez usando choroplethmapbox.

mapa <- plot_ly() %>%
  add_trace(
    type = "choroplethmapbox",
    geojson = paste(c(
      "https://gist.githubusercontent.com/cpsievert/",
      "7cdcb44fb2670bd2767de49379ae886/raw/",
      "cf5631bfd2e385891bb0a9788a179d7f023bf6c8/",
      "us-states.json"
    ), collapse = ""),
    locations = row.names(state.x77),
    z = state.x77[, "Population"] / state.x77[, "Area"],
    featureidkey = "properties.NAME",  # Clave para relacionar datos con geometrías
    span = I(0)
  ) %>%
  layout(
    mapbox = list(
      style = "light",
      zoom = 4,
      center = list(lon = -98.58, lat = 39.82)  # Corregimos el signo en latitud
    )
  ) %>%
  config(
    mapboxAccessToken = Sys.getenv("MAPBOX_TOKEN"),
    toImageButtonOptions = list(
      format = "svg",
      width = NULL,
      height = NULL
    )
  )

mapa  # Mostrar el mapa

Figura 4.7: Otro mapa de la densidad de población de EE.UU., esta vez usando choroplethmapbox con un activo GeoJSON personalizado.

Las figuras 4.6 y 4.7 no son una forma ideal de visualizar la población del estado desde un punto de vista de percepción gráfica. generalmente usamos el color en coropletas para codificar una variable numérica (por ejemplo, PIB, exportaciones netas, puntaje promedio del SAT, etc) y el ojo percibe naturalmente el área que cubre un color particular como proporcional a su efecto general. Estotermina siendo engañoso ya que el área que cubre el color genealmente no tiene una relación sensible con los datos codificados por el color. Un ejemplo clásico de este efecto engañoso en acción son los mapas electorales en Estado Unidos: la proporción de color rojo a azul no es representativamente del voto popular general (Newman, 2016).

Los cartogramas son un enfoque para reducir este efecto engañoso y otorgar otra dimensión para codificar datos a través del tamaño de las característica geoespaciales. La sección 4.4.4 cubre cómo representar cartogramas en plotly usand sf y cartogram.

##4.2) Mapas personalizados

###4.2.1) Funciones simples (sf)

El paquete sf R es un enfoque moderno para trabajar con estructura de datos geoespaciales basado en principios de datos ordenados (Pebesma, 2018; Wicham, 2014b). La idea clave detrás de sf es que almacena geometrías geoespaciales en una lista-columna de un marco de datos. Esto permie que cada fila represente la unidad real de ibservaciones/interés, ya sea un polígono, un multipolígono, un punto, una línea, o incluso una colección de estas caracterísitcas y, como resultado funciona perfectamente dentro de flujos de trabajo más grande y ordenados. El paquete sf si no proporciona realmente datos geoespaciales, sino que proporciona el marco y las utilidades para almacenar y calcular estructuras de datos geoespaciales de manera obstinada.

Existen numeroros paquetes para acceder a datos geoespaciales como estructuras de datos de características simples. Un par de ejemplos notables incluyen la tierra natural y los límites de Estados Unidos. El paquete rnaturalearth es mejor para obtener cualquier dato de mapas del mundo a través de una API proporcionada por https//:www.naturalearthdata.coom/ (South, 2017). El paquete USAboundaries es excelente para obtener datos cartográficos de los Estados Unidos en cualquier momento de la historia (Mullen y Bratt, 2018). Realmente no importa que herramienta uses para obtener o crear un objeto sf; una vez que tienes plot_ly sabes como renderizarlo:

world <- ne_countries(returnclass = "sf")
class(world)
## [1] "sf"         "data.frame"
#> [1] "sf"      "data. Frame"
plot_ly(world, color = I("gray90"), stroke = I("black"), span = I(1))
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter

Figura 4.8: Representación de datos los países del mundo usando plot_ly y la función ne_countries() del paquete naturalearth.

¿Cómo sabe plot_ly() como representar los países? Es porque las características geoespaciales están codificadas en una columna de lista espacial (geometría). Además, los metadatos sobre la estructura geoespacial se conservaran como atributos espaciales de los datos. La figura 4.9 aumenta el método de impresión de sf a marcos de datos para demostrar que toda la información necesaria para renderizar los países (es decir, los polígonos)en la Figura 4.8 están contenidos dentro del marco de datos mundials. Tenga en cuenta ta,bién que sf proporciona métodos dplyr especiales para esta clase especial de marco de datos para que pueda tratar la manipulación de datos como si fuera una “estructura de datos ordenada”. Una característica de este método es que la columna de geometría especial siempre se conserva; si intentamos seleccionar simplemente la columna de nombre, obtenemos tanto el nombre como la geometría.

world %>%
  select(name) %>%
  print(n = 4)
## Simple feature collection with 177 features and 1 field
## Geometry type: MULTIPOLYGON
## Dimension:     XY
## Bounding box:  xmin: -180 ymin: -90 xmax: 180 ymax: 83.64513
## Geodetic CRS:  WGS 84
## First 4 features:
##        name                       geometry
## 1      Fiji MULTIPOLYGON (((180 -16.067...
## 2  Tanzania MULTIPOLYGON (((33.90371 -0...
## 3 W. Sahara MULTIPOLYGON (((-8.66559 27...
## 4    Canada MULTIPOLYGON (((-122.84 49,...

FIGURA 4.9: Un diagrama de un marco de datos de características simples. La columna de geometría rastrea las características espaciales adjuntas a cada fila en el marco de datos.

En realidad, hay 4 formas diferentes de representar objetos sf con plotly: plot_ly (), plot_mapbox (), plot_geo () y mediante geom_sf () de ggplot2. Estas funciones representan múltiples polígonos utilizando un único seguimiento de forma predeterminada, lo cual es rápido, pero es posible que desee aprovechar la flexibilidad adicional de múltiples seguimientos. Por ejemplo, un trazo determinado solo puede tener un color de relleno, por lo que es imposible representar múltiples polígonos con diferentes colores usando un solo trazo. Por esta razón, si desea variar el color de varios polígonos, asegúrese de dividirlos mediante un identificador único (por ejemplo, nombre), como se hace en la Figura 4.10. Tenga en cuenta que, como se analizó para los gráficos de líneas en la Figura 3.2, el uso de múltiples seguimientos agrega automáticamente la capacidad de filtrar el nombre mediante entradas de leyenda.

canada <- ne_states(country = "Canada", returnclass = "sf")
plot_ly(canada, split = ~name, color = ~provnum_ne)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter

FIGURA 4.10: Uso de división y color para crear un mapa coroplético de provincias de Canadá.

Otra característica importante para los mapas que pueden requerir que usted divida múltiples polígonos en múltiples trazas es la capacidad de mostrar un mapa diferente. Colocar el cursor sobre el relleno de forma diferente para cada polígono. Al proporcionar texto que es único dentro de cada polígono y especificar hoveron=‘fills’, como en la Figura 4.11, el comportamiento de la información sobre herramientas está vinculado al relleno del trazado (en lugar de mostrarse en cada punto a lo largo del polígono).

{r plot_ly( canada, split = ~name, color = I("gray90"), text = ~paste(name, "is in province number", provnum_ne), hoveron = "fills", hoverinfo = "text", showlegend = FALSE ) Texto alternativo FIGURA 4.11: Uso de división, texto y hoveron=‘fills’ para mostrar información sobre herramientas específica de cada provincia canadiense.

Aunque los enfoques de mapeo integrados (plot_mapbox o y plot_geoO) pueden representar objetos de ciencia ficción, los enfoques de mapeo personalizados (plot_ly() y geom_sfO) son más flexibles porque permiten cualquier proyección de mapeo bien definida. Trabajar y comprender las proyecciones cartográficas puede resultar intimidante para un cartógrafo causal. Afortunadamente, existen buenos recursos para buscar proyecciones de mapas en una interfaz amigable para los humanos, como http://spatialreference. org/. A través de este sitio web, uno puede buscar proyecciones deseables para una porción determinada del globo y extraer comandos para proyectar sus objetos geoespaciales en esa proyección. Como se muestra en la Figura 4.12, una forma de realizar forma la proyección es suministrar el comando PROJ4 relevante al Función st_transform() en sf (colaboradores de PROJ, 2018).

# filter the world sf object down to Canada
canada <- filter(world, name == "Canada")

# coerce cities lat/long data to an official sf object
cities <- st_as_sf(
  maps::canada.cities,
  coords = c("long", "lat"),
  crs = 4326
)

# A PROJ4 projection designed for Canada
# https://spatialreference.org/ref/sr-org/7/
# https://spatialreference.org/ref/sr-org/7/proj4/
moll_proj <- "+proj=moll +lon_0=0 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs"

# perform the projections
canada <- st_transform(canada, moll_proj)
cities <- st_transform(cities, moll_proj)

# plot with geom_sf()
p <- ggplot() +
  geom_sf(data = canada) +
  geom_sf(data = cities, aes(size = pop), color = "red", alpha = 0.3)  # Corregido 'aplha' a 'alpha'
  
# Utiliza ggplotly para convertir el gráfico de ggplot a uno interactivo
ggplotly(p)

FIGURA 4.12: La población de varias ciudades canadienses representada en un mapa base personalizado utilizando una proyección Mollweide.

Algunos objetos geoespaciales tienen una resolución innecesariamente alta para una visualización determinada. En estos casos, es posible que desee considerar simplificar el objeto geoespacial para mejorar la velocidad del código R y la capacidad de respuesta de la visualización. Por ejemplo, podríamos recrear la figura 4.8 con una resolución mucho mayor especificando escala = “grande” en ne_countri es(); esto nos da un objeto sf con más de 50 veces más espacio coordenadas que la escala predeterminada. La resolución más alta nos permite acercarnos mejor a regiones geoespaciales más complejas, pero genera un código R más lento, archivos HTML más grandes y una capacidad de respuesta más lenta. Sievert (2018b) explora este tema con más profundidad y demuestra cómo usar la función st_simplify() de sf para simplificar características antes de trazarlas.

# Calcula la suma de las filas en la geometría de world
sum(rapply(world$geometry, nrow))
## [1] 10654
# Debe imprimir 10586

# Carga los países a una escala "large" con la clase de retorno "sf"
world_large <- ne_countries(scale = "large", returnclass = "sf")

# Calcula la suma de las filas en la geometría de world_large
sum(rapply(world_large$geometry, nrow))
## [1] 548471
# Debe imprimir 548121

Los cartogramas distorsionan el tamaño de los polígonos geoespaciales para codificar una variable numérica distinta del tamaño del terreno. Existen numerosos tipos de cartogramas y normalmente se clasifican por su capacidad para preservar la forma y mantener regiones contiguas. Se ha demostrado que los cartogramas son un enfoque eficaz tanto para codificar como para enseñar datos geoespaciales, aunque los efectos ciertamente varían según el tipo de cartograma (Nusrat et al., 2016). El cartograma del paquete R proporciona una interfaz para varios algoritmos de cartogramas populares (Jeworutzki, 2018). Varios otros paquetes de R proporcionan algoritmos de cartogramas, pero lo bueno de cartograma es que todas las funciones pueden tomar un objeto sf (o sp) como entrada y devolver un objeto sf. Esto hace que sea increíblemente fácil pasar de objetos espaciales en bruto a objetos transformados y visuales. La Figura 4.13 muestra un cartograma de área continua de la población de EE. UU. en 2014 utilizando un algoritmo de distorsión de lámina de caucho de Dougenik et al. (1985).

{r plot_ly() %>% add_sf( data = us_cont, color = ~pop_2014, split = ~name, span = I(1), text = ~paste(name, scales::number_si(pop_2014)), hoverinfo = "text", hoveron = "fills" ) %>% layout(showlegend = FALSE) %>% colorbar(title = "population \n 2014") Texto alternativo

FIGURA 4.13: Un cartograma de la población de EE. UU. en 2014. Un cartograma dimensiona el área de los objetos geoespaciales proporcionalmente a alguna métrica (por ejemplo, población).

La Figura 4,14 muestra un cartograma de Dorling discontinuo de la población de EE. UU. en 2014 de Dorling D. (1996). Este cartograma no intenta preservar la forma de los polígonos (es decir, estados), sino que utiliza círculos para representar cada objeto geoespacial y luego codifica la variable de interés (es decir, población) utilizando el área del círculo.

```{r us_dor <- cartogram_dorling(us, “pop_2014”)

plot_ly(stroke = I(“black”), span = I(1)) %>% add_sf( data = us, color = I(“gray95”), hoverinfo = “none” ) %>% add_sf( data = us_dor, color = ~pop_2014, split = ~name, text = ~paste(name, scales::number_si(pop_2014)), hoverinfo = “text”, hoveron = “fills” ) %>% layout(showlegend = FALSE)

![Texto alternativo](Captura de pantalla 2023-09-18 160938.png)
![Texto alternativo](Captura de pantalla 2023-09-18 161115.png)

FIGURA 4.14: Un cartograma de Dorling de la población de EE. UU. en 2014. Un cartograma de Dorling dimensiona los círculos proporcionalmente a alguna métrica (por ejemplo, población).

La Figura 4.15 muestra un cartograma discontinuo de la población de Estados Unidos en 2014 de Olson (1976). A diferencia del cartograma Darling, este enfoque conserva la forma de los polígonos. La implementación detrás de la Figura 4.15 es simplemente tomar la implementación de la Figura
4.14 y cambie cartogram_dorling() a cartogram_ncont().

FIGURA 4.15: Un cartograma no contiguo de la población de EE. UU. en
2014 que conserva la forma.
 
Una clase popular de cartogramas contiguos que no conservan la forma a veces se denominan cartogramas en mosaico (también conocidos como mosaicos). En el momento de escribir este artículo, no parece haber un gran paquete R para calcular mosaicos, pero Pitch Interactive proporciona un buen servicio web donde puedes generar mosaicos a partir de datos https existentes o personalizados:
//pitchi nteractivei nc.github.io/tilegrams/. Además, el servicio permite descargar un archivo TopoJSON del mosaico generado, que podemos leer en R y convertir en un objeto sf mediante geojsonio (Chamber lain y Teucher, 2018). La Figura 4.16 muestra un mosaico de la población de EE. UU. en 2016 exportado directamente desde el servicio web gratuito de Pitch.


```{r
tiles <- geojson_read("~/Downloads/tiles.topo.json", what = "sp")
tiles_sf <- st_as_sf(tiles)

# Crear un gráfico Plotly
plot_ly(
  tiles_sf, color = ~name,
  colors = "paired", stroke = I("transparent")
)

Texto alternativo FIGURA 4.16: Cartograma en mosaico de la población de EE. UU. en 2016.

5) Bars and histograms

Las funciones add_bars () y add_hi stogram () envuelven los tipos de seguimiento bar1 y togram2 plotly.js. La principal diferencia entre ellos es que los trazos de barra requieren alturas de barra (tanto x como y), mientras que los trazos de histograma requieren solo una variable, y plotly.js maneja la agrupación en el navegador.3 Y quizás de manera confusa, ambas funciones se pueden usar para visualizar la distribución de una variable numérica o discreta. Entonces, esencialmente, la única diferencia entre ellos es dónde ocurre la agrupación. La Figura 5.1 compara el algoritmo de agrupación predeterminado en plotly.js con algunos algoritmos diferentes disponibles en R mediante la función hi st c). Aunque plotly.js tiene la capacidad de personalizar contenedores de histograma a través de xbi ns4/ybi ns5, R tiene diversas funciones para estimar el número óptimo de contenedores en un histograma que podemos aprovechar fácilmente.6 La función hi st () por sí sola nos permite hacer referencia Hay 3 algoritmos famosos por su nombre (Sturges, 1926; Freedman y Diaconis, 1981; Scott, 1979), pero también hay paquetes (por ejemplo, el paquete de histogramas) que amplían esta interfaz para incorporar más metodología (Mildenberger et al., 2009). La siguiente función price_hist() envuelve la función hi st() para obtener los resultados de agrupación y asigna esos contenedores a una versión gráfica del histograma usando add_bars().

p1 <- plot_ly(diamonds, x = ~price) %>%
  add_histogram(name = "plot.js")

price_hist <- function(method = "FD") {
  h <- hist(diamonds$price, breaks = method, plot = FALSE)
  plot_ly(x = h$mids, y = h$counts) %>% add_bars(name = method)
}


subplot(
  p1, price_hist(), price_hist("Sturges"), price_hist("Scott"),
  nrows = 4, shareX = TRUE
)

FIGURA 5.1: algoritmo de agrupación predeterminado de plotly.js versus el hist c) predeterminado de R.

La figura 5.2 muestra dos formas de crear un gráfico de barras básico. Aunque los resultados visuales son los mismos, vale la pena señalar la diferencia en la implementación. La función add_histogram o envía todos los valores observados al navegador y permite que plotly.js realice la agrupación. Él

5.1 109 Se necesita más esfuerzo humano para realizar la agrupación en R, pero hacerlo tiene la ventaja de enviar menos datos y requerir menos trabajo de cálculo por parte del navegador web. En este caso, solo tenemos unos 50.000 registros, por lo que no hay mucha diferencia en los tiempos de carga de la página o el tamaño de la página. Sin embargo, con un millón de registros, el tiempo de carga de la página se duplica y el tamaño de la página casi se duplica.7

p1 <- plot_ly(diamonds, x = ~cut) %>%
  add_histogram()

p2 <- diamonds %>%
  count(cut) %>%
  plot_ly(x = ~cut, y = ~n) %>%
  add_bars()

subplot(p1, p2) %>% hide_legend()

FIGURA 5.2: Número de diamantes por talla.

5.1) Multiples distribuciones numéricas

A menudo resulta útil ver cómo cambia la distribución numérica con respecto a una variable discreta. Cuando utilice barras para visualizar múltiples distribuciones numéricas, recomiendo trazar cada distribución en su propio eje usando una visualización de múltiplos pequeños, en lugar de intentar superponerlas en un solo eje.8 El Capítulo 13, y específicamente la Sección 13.1.2.3, analiza los múltiplos pequeños en más detalles, pero la Figura 13.9 demuestra cómo se hace con plot_ly() y subplot(). Observe cómo la función one_plot() define qué mostrar en cada panel, luego se emplea una estrategia de recombinación de aplicación dividida (es decir, división o, lapply o, subtrama o) para generar la visualización enrejada.

one_plot <- function(d) {
  plot_ly(d, x = ~price) %>%
    add_annotations(
      ~unique(clarity), x = 0.5, y = 1,
      xref = "paper", yref = "paper", showarrow = FALSE
    )
}

diamonds %>%
  split(.$clarity) %>%
  lapply(one_plot) %>%
  subplot(nrows = 2, shareX = TRUE, titleX = FALSE) %>%
  hide_legend()
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram

FIGURA 5.3: Visualización enrejada del precio del diamante según la claridad del diamante.

5.2) 5.2 Distribuciones discretas múltiples

Visualizar múltiples distribuciones discretas es difícil. La sutil complejidad se debe al hecho de que tanto los recuentos como las proporciones son importantes para comprender las distribuciones discretas multivariadas. La Figura 5.4 presenta el recuento de diamantes, dividido tanto por talla como por claridad, utilizando un gráfico de barras agrupadas.

plot_ly(diamonds, x = ~cut, color = ~clarity) %>%
  add_histogram()

FIGURA 5.4: Gráfico de barras agrupadas de recuentos de diamantes por talla y claridad.

La Figura 5-4 es útil para comparar la cantidad de diamantes por claridad, dado un tipo de talla. Por ejemplo, dentro de los diamantes “Ideales”, la talla “VS!” es la más popular, “VS2” es la segunda más popular y “II” la menos popular. La distribución de la claridad dentro de los diamantes “Ideales” parece ser bastante similar a otros diamantes, pero es difícil hacer esta comparación usando recuentos brutos. La figura 5.5 facilita esta comparación al mostrar la frecuencia relativa de los diamantes por claridad, dada una talla.

# number of diamonds by cut and clarity (n)
cc <- count(diamonds, cut, clarity)
# number of diamonds by cut (nn)
cc2 <- left_join(cc, count(cc, cut, wt = n, name = 'nn'))
## Joining with `by = join_by(cut)`
cc2 %>%
  mutate(prop = n / nn) %>%
  plot_ly(x = ~cut, y = ~prop, color = ~clarity) %>%
  add_bars() %>%
  layout(barmode = "stack")

FIGURE 5.5: A stacked bar chart showing the proportion of diamond clarity within cut.

This type of plot, also known as a spine plot, is a special case of a mo­ saic plot. In a mosaic plot, you can scale both bar widths and heights according to discrete distributions. For mosaic plots, I recommend using the ggmosaic package (Jeppson et al., 2016), which implements a custom ggplot2 geom designed for mosaic plots, which we can convert to plotly via ggplotly C). Figure 5.6 shows a mosaic plot of cut by clarity. Notice how the bar widths are scaled proportional to the cut frequency.

p <- ggplot(data = cc) +
  geom_mosaic(aes(weight = n, x = product(cut), fill = clarity))
ggplotly(p)
## Warning: `unite_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `unite()` instead.
## ℹ The deprecated feature was likely used in the ggmosaic package.
##   Please report the issue at <https://github.com/haleyjeppson/ggmosaic>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

FIGURA 5.6: Uso de ggmosaic y ggplotly() para crear visualizaciones interactivas avanzadas de datos categóricos.