Instalación de dependencias (Sólo para Google Colab)¶

La mayor parte del taller utilizaremos principalmente la librería Pandas para el análisis de datos, esta librería viene incluida en el stack que nos provee automáticamente COlab. Sin embargo, para poder leer datos geográficos y hacer mapas, vamos a necesitar instalar Geopandas, que es una extensión de Pandas para el manejo de datos geográficos, y un par de librerías más para hacer mapas interactivos.

La instalación de dependencias en Colab es relativamente sencilla, el caso de Geopandas tiene elguna complicación porque requiere de la instalación de un par de librerías del sistema (es decir, librerías que no son sólo de Python). La siguiente celda contiene las instrucciones (al sistema operativo debajo de Colab, noten el símbolo ! al inicio de cada instrucción) para instalar todas las dependencias que necesitamos.

# Important library for many geopython libraries
!apt install gdal-bin python-gdal python3-gdal 
# Install rtree - Geopandas requirment
!apt install python3-rtree 
# Install Geopandas
!pip install git+git://github.com/geopandas/geopandas.git
# Install descartes - Geopandas requirment
!pip install descartes 
# Install Folium for Geographic data visualization
!pip install folium
# Install plotlyExpress
!pip install plotly_express
!pip install mapclassify

Con todas las librerías instaladas, podemos importar lo que vamos a utilizar

In [9]:
import os
import glob
import itertools
from pathlib import Path
import zipfile
import numpy as np
import pandas as pd
import geopandas as gpd
from datetime import timedelta, date, datetime
import csv
import openpyxl
import requests
import matplotlib.pyplot as plt
import mapclassify
import folium

import logging

Mapas¶

En el taller anterior aprendimos a utilizar Geopandas para manejar y visualizar datos geográficos. En esta sección vamos a hacer algunos mapas sobre la evolución del COVID en México.

Vamos a partir de la base de datos ya preprocesada, en este caso contiene sólo los agregados de casos nuevos por semana para todos los municipios del país. Para simplificar el ejercicio y centrarnos en la producción de mapas, vamos a bajar los datos de Dropbox como ya lo hemos hecho antes (la ruta es para Google Colab):

url = "https://www.dropbox.com/s/kf9dldnqgo4eidu/agregados_semana_municipio.pkl?dl=1"
r = requests.get(url, allow_redirects=True)
open('/content/semana_municipio.pkl', 'wb').write(r.content)

Ya con los datos, ahora vamos a necesitar las geometrías de los municipios de México para empezar a hacer mapas, esos los vamos a bajar de:

url = "https://www.dropbox.com/s/2zw0fh3vdl0rxh4/municipios_pob_2020_simple.json?dl=1"
r = requests.get(url, allow_redirects=True)
open('/content/municipios_pob_2020_simple.json', 'wb').write(r.content)

Un mapa sencillo¶

Ahora ya tenemos el shape, vamos a usar GeoPandas para leerlo en un GeoDataFrame

In [4]:
municipios = gpd.read_file('data/municipios_pob_2020_simple.json')
municipios
Out[4]:
id oid municipio_cvegeo municipio pob2020 pob_0a4 pob_0a9 pob60ym entidad_cvegeo geometry
0 827 525 16046 Juárez 15290 1557 3122 1911 16 POLYGON ((-100.45693 19.33414, -100.45818 19.3...
1 828 209 16047 Jungapeo 22358 2470 4920 2608 16 POLYGON ((-100.44063 19.51413, -100.44814 19.5...
2 829 564 16048 Lagunillas 5862 550 1111 844 16 POLYGON ((-101.38329 19.59813, -101.38279 19.6...
3 830 524 16049 Madero 18769 2049 4136 2055 16 POLYGON ((-101.11644 19.53327, -101.11713 19.5...
4 67 44 05035 Torreón 744247 65682 129805 85778 05 MULTIPOLYGON (((-102.98871 24.79622, -102.9930...
... ... ... ... ... ... ... ... ... ... ...
2452 2452 2388 32053 Villa González Ortega 13945 1481 2926 1599 32 POLYGON ((-101.94821 22.65201, -101.95269 22.6...
2453 2453 2417 32054 Villa Hidalgo 20177 2078 4191 2036 32 POLYGON ((-101.65599 22.51381, -101.65651 22.5...
2454 2454 1407 32055 Villanueva 31804 2738 5540 5324 32 POLYGON ((-102.69428 22.62230, -102.69370 22.6...
2455 2455 2411 32056 Zacatecas 155533 12609 25488 15549 32 POLYGON ((-102.58542 22.81149, -102.58522 22.8...
2456 2457 2457 32058 Santa María de la Paz 2855 257 505 536 32 POLYGON ((-103.19774 21.58534, -103.21258 21.5...

2457 rows × 10 columns

Como pueden ver un GeoDataFrame es bastante similar a un DataFrame, la única diferencia es la columna especial geometry. En general cualquier cosa que se puede hacer con un DataFrame de Pandas se puede hacer con un GeoDataFrame (aunque claro, no todas las operaciones regresan algo con geometría!).

Lo primero que vamos a hacer es un mapa rápido de población a nivel municipal. Para eso vamos a usar el métdo plot de geopandas que nos da chance de hacer mapas bien fácil

In [5]:
municipios.plot(column='pob2020', cmap='OrRd',figsize=(15, 10), scheme="quantiles", legend=True)
Out[5]:
<AxesSubplot:>

Si no nos gusta cómo se ve el mapa, es fácil hacer modificaciones de estilo

In [12]:
fig, ax = plt.subplots(1, figsize=(20,10))
municipios.plot(column='pob2020', cmap='OrRd',figsize=(15, 10), scheme="quantiles", legend=True, ax=ax)
ax.set_axis_off() 
fig.suptitle("Población por municipio") # A través de la función '.suptitle()' aplicada a la figura se coloca el título.
plt.show()

Mapas de COVID¶

El primer paso para mapear los casos de covid es leerlos y unirlos a las geometrías de los municipios, empecemos por leer la misma base que hemos usado ya antes

In [19]:
df = pd.read_pickle("data/semana_municipio.pkl")
df.head()
Out[19]:
Nuevos Casos Defunciones
FECHA_SINTOMAS CLAVE_MUNICIPIO_RES MUNICIPIO_RES
2020-01-05 01001 AGUASCALIENTES 11 0
01006 PABELLÓN DE ARTEAGA 1 0
01009 TEPEZALÁ 1 0
02001 ENSENADA 1 0
02002 MEXICALI 11 0

Estos datos corresponden a toda la serie de tiempo, entonces para cada municipio hay toda una serie de valores. Para empezar a hacer mapas entonces vamos a seleccionar una fecha en específico, lo más fácil es seleccionar la última disponible (vamos a seleccionar por FECHA_INGRESO, pero podríamos usar cualquier otra)

In [21]:
ultima_fecha = df.reset_index().loc[df.reset_index()['FECHA_SINTOMAS'] == df.reset_index()['FECHA_SINTOMAS'].max()]
ultima_fecha.head()
Out[21]:
FECHA_SINTOMAS CLAVE_MUNICIPIO_RES MUNICIPIO_RES Nuevos Casos Defunciones
159076 2022-01-23 01001 AGUASCALIENTES 10 0
159077 2022-01-23 01007 RINCÓN DE ROMOS 1 0
159078 2022-01-23 02001 ENSENADA 9 0
159079 2022-01-23 02002 MEXICALI 12 0
159080 2022-01-23 02004 TIJUANA 12 0

Tenemos la lista de los municipios que tuvieron casos en la fecha que estamos analizando, para hacer un mapa necesitamos unir estos datos a la geometría de los municipios.

Primero vamos a seleccionar, a partir del GeoDataFrame que ya tenemos sólo los municipios de la entidad que estamos analizando. A partir de eso podemos realizar una unión via la clave del municipio, sólo tenemos que tener cuiaddo de utilizar el tipo de unión adecuada para no dejar fuera los municipios sin casos.

In [22]:
casos_municipio = (municipios
                   .merge(ultima_fecha, left_on='municipio_cvegeo', right_on='CLAVE_MUNICIPIO_RES', how='left') # Unimos con los municipios
                   .drop(columns=['CLAVE_MUNICIPIO_RES', 'MUNICIPIO_RES']) # eliminamos dos columnas que ya no vamosd a usar
                   .fillna(0) # Los municipios sin casos deben tener 0 en lugar de NaN
                   )
casos_municipio
Out[22]:
id oid municipio_cvegeo municipio pob2020 pob_0a4 pob_0a9 pob60ym entidad_cvegeo geometry FECHA_SINTOMAS Nuevos Casos Defunciones
0 827 525 16046 Juárez 15290 1557 3122 1911 16 POLYGON ((-100.45693 19.33414, -100.45818 19.3... 0 0.0 0.0
1 828 209 16047 Jungapeo 22358 2470 4920 2608 16 POLYGON ((-100.44063 19.51413, -100.44814 19.5... 0 0.0 0.0
2 829 564 16048 Lagunillas 5862 550 1111 844 16 POLYGON ((-101.38329 19.59813, -101.38279 19.6... 0 0.0 0.0
3 830 524 16049 Madero 18769 2049 4136 2055 16 POLYGON ((-101.11644 19.53327, -101.11713 19.5... 0 0.0 0.0
4 67 44 05035 Torreón 744247 65682 129805 85778 05 MULTIPOLYGON (((-102.98871 24.79622, -102.9930... 2022-01-23 00:00:00 13.0 0.0
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2452 2452 2388 32053 Villa González Ortega 13945 1481 2926 1599 32 POLYGON ((-101.94821 22.65201, -101.95269 22.6... 0 0.0 0.0
2453 2453 2417 32054 Villa Hidalgo 20177 2078 4191 2036 32 POLYGON ((-101.65599 22.51381, -101.65651 22.5... 0 0.0 0.0
2454 2454 1407 32055 Villanueva 31804 2738 5540 5324 32 POLYGON ((-102.69428 22.62230, -102.69370 22.6... 0 0.0 0.0
2455 2455 2411 32056 Zacatecas 155533 12609 25488 15549 32 POLYGON ((-102.58542 22.81149, -102.58522 22.8... 2022-01-23 00:00:00 67.0 0.0
2456 2457 2457 32058 Santa María de la Paz 2855 257 505 536 32 POLYGON ((-103.19774 21.58534, -103.21258 21.5... 0 0.0 0.0

2457 rows × 13 columns

In [23]:
fig, ax = plt.subplots(1, figsize=(20,10))
casos_municipio.plot(column='Nuevos Casos', cmap='OrRd',figsize=(15, 10), legend=True, ax=ax)
ax.set_axis_off() 
fig.suptitle("Nuevos Casos por municipio") # A través de la función '.suptitle()' aplicada a la figura se coloca el título.
plt.show()

Mapa interactivo¶

Con los mismos datos podemos usar folium para hacer un mapa interactivo muy fácilmente

In [26]:
m = folium.Map(location=[19.4326018, -99.1332049], zoom_start=5) # Creamos la instancia de folium
folium.Choropleth( # Instanciamos un mapa de coropletas
    geo_data=casos_municipio[["municipio_cvegeo", "Nuevos Casos", "geometry"]], # Pasamos la geometría de los municipios
    data=casos_municipio[["municipio_cvegeo", "Nuevos Casos"]], # Las variables que vamos a usar en el mapa
    columns=["municipio_cvegeo", "Nuevos Casos"], # La primera columna une geometrías y datos, la segunda es la variable que vamos a mapear
    key_on="feature.properties.municipio_cvegeo", # Cómo se unen los datos
    bins=4, # Cuántos intervalos iguales queremos en la clasificación 
    fill_color="OrRd", # La escala de colores
    fill_opacity=0.7, # Opacidad del relleno
    line_opacity=0.2, # opacidad de la línea
    legend_name="Nuevos Casos",
).add_to(m)
m
Out[26]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [ ]: