Introducción

A lo largo de este documento se utilizará RStudio para transformar bases de datos gubernamentales en en mapas interactivos para su correcta visualización a través de 3 etapas:

  1. Procesaremos el registro masivo de víctimas de la Fiscalía General de Justicia de la CDMX utilizando Tidyverse.

  2. Transitaremos a la detección de “focos rojos” mediante clústeres y mapas de calor para los delitos de robo, violencia familiar y delitos sexuales.

  3. Conectaremos nuestro código en tiempo real con la API del Directorio Estadístico Nacional de Unidades Económicas (DENUE - INEGI) para mapear la infraestructura comercial y financiera sobre imágenes satelitales.

Nota sobre el uso del pipe (%>%)

Para Mac, el atajo de teclado es Command + Shift + M.

Para Windows, el atajo es Control + Shift + M.


1. Carga de Librerías y Datos (FGJ CDMX)

Comenzaremos por cargar las herramientas necesarias y extraer los datos abiertos de víctimas de la Fiscalía General de Justicia de la CDMX.

# CARGA DE LIBRERÍAS
# install.packages(c("tidyverse", "leaflet", "leaflet.extras", "jsonlite")) 
library(tidyverse)      # Ecosistema para manipulación de datos
library(leaflet)        # Creación de mapas interactivos
library(leaflet.extras) # Extensión de leaflet (por addHeatmap)
library(jsonlite)       # Permite leer datos desde las APIs en formato JSON

# DESCARGA Y PREPARACIÓN DE DATOS
# read_csv lee el archivo directamente desde el portal de datos abiertos
fgj = read_csv("https://archivo.datos.cdmx.gob.mx/FGJ/victimas/victimasFGJ_2024.csv")


# Creamos una base más ligera conservando solo 3 columnas clave
fgj_corto = fgj %>% 
  select(delito, latitud, longitud) 

# Exploramos la frecuencia de los delitos
fgj_corto %>% 
  count(delito, sort = TRUE) %>% 
  head(10)
## # A tibble: 10 × 2
##    delito                                             n
##    <chr>                                          <int>
##  1 VIOLENCIA FAMILIAR                             23841
##  2 FRAUDE                                         13795
##  3 AMENAZAS                                       12711
##  4 ROBO DE ACCESORIOS DE AUTO                      5694
##  5 ROBO DE OBJETOS                                 5228
##  6 USURPACIÓN DE IDENTIDAD                         4480
##  7 ROBO DE OBJETOS DEL INTERIOR DE UN VEHICULO     3763
##  8 ROBO A TRANSEUNTE EN VIA PUBLICA CON VIOLENCIA  3667
##  9 ABUSO SEXUAL                                    2798
## 10 DESPOJO                                         2285


2. Exploración Espacial: Robo a Casa Habitación

d1 = fgj_corto %>% 
  filter(delito == "ROBO A CASA HABITACION SIN VIOLENCIA") %>% 
  filter(!is.na(latitud)) %>%  
  filter(!is.na(longitud))     

2.1 Mapa con puntos simples

Utilidad: Es la visualización más directa. Sirve para identificar la dispersión general o patrones geométricos muy evidentes como los delitos que ocurren a lo largo de una avenida. Su principal desventaja es que, ante una gran cantidad de datos, los puntos se enciman y el mapa se vuelve ilegible.

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircles(                             
    data = d1,                            
    lng = ~longitud,                      
    lat = ~latitud                        
  )

2.2 Mapa con agrupación de clústeres

Utilidad: Resuelve el problema de la saturación visual. Agrupa los eventos cercanos en “burbujas” numéricas dinámicas. Es ideal para tableros de control directivos porque permite cuantificar rápidamente el volumen de incidentes en una zona sin perder la capacidad de hacer zoom hasta el nivel de calle.

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircleMarkers(                       
    data = d1,
    lng = ~longitud, 
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )

2.3 Mapa multicapa: Calor + Clústeres

Utilidad: La herramienta analítica más potente. La capa de calor resalta de inmediato los “focos rojos” mediante densidad de color, guiando la atención del analista. La capa de clústeres superpuesta permite conservar el rigor cuantitativo, logrando un balance entre la intuición visual y el dato.

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addHeatmap(                             
    data = d1,
    lng = ~longitud,
    lat = ~latitud,
    radius = 60                           
  ) %>% 
  addCircleMarkers(                       
    data = d1,
    lng = ~longitud,
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )


3. Exploración Espacial: Violencia Familiar

d2 = fgj_corto %>% 
  filter(delito == "VIOLENCIA FAMILIAR") %>% 
  filter(!is.na(latitud)) %>%  
  filter(!is.na(longitud))     

3.1 Mapa con puntos simples

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircles(                             
    data = d2,                            
    lng = ~longitud,                      
    lat = ~latitud                        
  )

3.2 Mapa con agrupación de clústeres

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircleMarkers(                       
    data = d2,
    lng = ~longitud, 
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )

3.3 Mapa multicapa: Calor + Clústeres

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addHeatmap(                             
    data = d2,
    lng = ~longitud,
    lat = ~latitud,
    radius = 60                           
  ) %>% 
  addCircleMarkers(                       
    data = d2,
    lng = ~longitud,
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )


4. Exploración Espacial: Delitos Sexuales

A diferencia de los casos anteriores, emplearemos str_detect() para capturar todas las variantes tipológicas que contengan la raíz de la palabra.

base_limpia <- fgj %>% 
  select(delito, latitud, longitud) %>% 
  filter(str_detect(delito, "SEX")) %>%   
  na.omit()                               

4.1 Mapa con puntos simples

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircles(                             
    data = base_limpia,                            
    lng = ~longitud,                      
    lat = ~latitud                        
  )

4.2 Mapa con agrupación de clústeres

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addCircleMarkers(                       
    data = base_limpia,
    lng = ~longitud, 
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )

4.3 Mapa multicapa: Calor + Clústeres

leaflet() %>% 
  addProviderTiles(providers$CartoDB) %>% 
  addHeatmap(                             
    data = base_limpia,
    lng = ~longitud,
    lat = ~latitud,
    radius = 60                           
  ) %>% 
  addCircleMarkers(                       
    data = base_limpia,
    lng = ~longitud,
    lat = ~latitud,
    clusterOptions = markerClusterOptions() 
  )


5. Mapa Satelital de Negocios (API DENUE - INEGI)

Las políticas de prevención requieren cruzar datos de seguridad con el entorno económico. Para obtener el censo de negocios en tiempo real, conectaremos R directamente con los servidores del INEGI mediante su API.

¿Cómo funciona el servidor del INEGI?

La instrucción se envía a través de una URL estructurada de la siguiente manera:

  1. Base: .../Buscar/ Le indica al sistema que haremos una consulta de texto.

  2. Palabra clave: bancos El giro comercial que nos interesa.

  3. Coordenadas: 19.4408544561198,-99.20399200125259 Ubicación mediante latitud y longitud, en este caso, el Museo Soumaya.

  4. Radio: 500 Metros a la redonda desde la ubicación.

  5. Token: 5782893c... Nuestra llave de acceso a la base de datos.

Utilidad del mapa satelital: Proyectar estos datos sobre una imagen de satélite (Esri.WorldImagery) nos permite verificar la infraestructura urbana real como avenidas y parques que rodea a estas unidades económicas.

# 1. Ejecutamos la petición a la API del INEGI para obtener los bancos alrededor del Museo Soumaya en un radio de 500 metros
soumaya <- fromJSON("https://www.inegi.org.mx/app/api/denue/v1/consulta/Buscar/bancos/19.4408544561198,-99.20399200125259/500/5782893c-bfe7-42da-8ee4-02d141d52797")

# 2. Conversión a formato numérico
soumaya$Longitud <- as.numeric(soumaya$Longitud)
soumaya$Latitud <- as.numeric(soumaya$Latitud)

# 3. Mapeo satelital de los bancos encontrados
leaflet() %>%
  addProviderTiles(providers$Esri.WorldImagery) %>% 
  addCircles(
    data = soumaya, 
    lng = ~Longitud,     
    lat = ~Latitud,      
    color = "red",       
    label = ~paste(Nombre, "-", Clase_actividad)
  )


6. Visualización de otras ubicaciones y unidades económicas

Modifica la URL de la función fromJSON() en la sección anterior con las siguientes rutas para visualizar otras ubicaciones en la República Mexicana:

  • Estadio BBVA en Monterrey: Busca alrededor de las coordenadas: 25.669295827488895, -100.24388500476128.

  • Farmacias alrededor del Ángel de la Independencia con un radio de 750 metros: https://www.inegi.org.mx/app/api/denue/v1/consulta/Buscar/farmacia/19.427141997797538,-99.16727748910374/750/5782893c-bfe7-42da-8ee4-02d141d52797

  • Restaurantes alrededor de la Pirámide de Chichén Itzá con un radio de 1000 metros: https://www.inegi.org.mx/app/api/denue/v1/consulta/Buscar/restaurante/20.68319666510934,-88.56821995095045/1000/5782893c-bfe7-42da-8ee4-02d141d52797