lunes, 13 de abril de 2020

Cómo crear mapas animados de coropletas usando los datos COVID-19 de la Universidad Johns Hopkins.


Chuck Huber, Director Asociado de Alcance Estadístico.

En mis publicaciones anteriores, mostré cómo descargar los datos COVID-19 del repositorio GitHub Johns Hopkins, graficar los datos a lo largo del tiempo y crear mapas coropléticos. Ahora, le mostraré cómo crear mapas animados de coropletas para explorar la distribución de COVID-19 a lo largo del tiempo y el lugar.

El siguiente video muestra la cantidad acumulada de casos de COVID-19 por cada 100,000 habitantes para cada condado en los Estados Unidos desde el 22 de enero de 2020 hasta el 5 de abril de 2020. El mapa no cambia mucho hasta mediados de marzo, cuando el virus comienza a extenderse más rápido. Entonces, podemos ver cuándo y dónde las personas están siendo infectadas. Puede hacer clic en el icono "Reproducir" en el video para reproducirlo y hacer clic en el icono en la parte inferior derecha para ver el video en modo de pantalla completa.



En mi último post, aprendimos cómo crear un mapa coroplético. Tendremos que aprender dos habilidades adicionales para crear un mapa animado: cómo crear un mapa para cada fecha en el conjunto de datos y cómo combinar la colección de mapas en un archivo de video.

Cómo crear un mapa para cada fecha
Comencemos importando y describiendo los datos sin procesar del repositorio GitHub de Johns Hopkins. Tenga en cuenta que importé estos datos el 5 de abril.



Las variables de v12 a v86 contienen el número acumulado de casos confirmados de COVID-19 en cada condado para cada día a partir del 22 de enero de 2020 y hasta el 5 de abril de 2020. Enlistemos algunas observaciones para ver los datos sin procesar.




Tendremos que incluir de v12 a v86 en nuestro conjunto de datos final. Copié el bloque de código desde el final de mi última publicación y lo pegué a continuación con dos pequeñas modificaciones. La primera modificación se muestra en rojo. El código retiene y formatea los datos del caso para cada fecha guardada en v12 a v86. Tenga en cuenta que me refiero a "v12 a v86" en el código escribiendo v*. El asterisco sirve como comodín, por lo que v* se refiere a cualquier variable que comienza con la letra "v". La segunda modificación es que no creamos una variable para nuestro recuento ajustado por la población en este momento.



// Create the geographic dataset
clear
copy https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_county_500k.zip ///
    cb_2018_us_county_500k.zip
unzipfile cb_2018_us_county_500k.zip
spshape2dta cb_2018_us_county_500k.shp, saving(usacounties) replace
use usacounties.dta, clear
generate fips = real(GEOID)
save usacounties.dta, replace
// Create the COVID-19 case dataset
clear
import delimited https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_US.csv
drop if missing(fips)
save covid19_county, replace
// Create the population dataset
clear
import delimited https://www2.census.gov/programs-surveys/popest/datasets/2010-2019/counties/totals/co-est2019-alldata.csv
generate fips = state*1000 + county
save census_popn, replace
// Merge the datasets
clear
use _ID _CX _CY GEOID fips using usacounties.dta
merge 1:1 fips using covid19_county ///
    
, keepusing(province_state combined_key v*)
keep if _merge == 3
drop _merge
merge 1:1 fips using census_popn ///
    , keepusing(census2010pop popestimate2019)
keep if _merge==3
drop _merge
drop if inlist(province_state, "Alaska", "Hawaii")
format %16.0fc popestimate2019 v*
save covid19_adj, replace

Describamos algunos de nuestros conjuntos de datos finales.


El conjunto de datos contiene todas las variables que necesitaremos para crear nuestro mapa animado: la información geográfica, la población de cada condado y el número de casos para cada día en v12 a v86. Voy a explicar todos los pasos que necesitaremos seguir usando solo tres de estas variables. Luego, los juntaremos usando las 75 variables.

Tendremos que crear un mapa separado para v12, v13, v14, y así sucesivamente hasta v86. Recordemos que aprendimos acerca de los bucles en una de mis publicaciones anteriores. Podemos usar forvalues para realizar ciclos sobre estas variables.

El siguiente ciclo forvalues almacenará los números 12, 13 y 14 en la macro local time. Puede referirse a time dentro del ciclo usando comillas simples izquierda y derecha. El siguiente ejemplo describe cada variable.




También necesitaremos calcular el número de casos ajustados por la población para cada condado para cada día. En el siguiente ejemplo, comenzamos generando una variable llamada confirmed_adj que contiene valores faltantes. Dentro del bucle, reemplazamos confirmed_adj con el recuento ajustado para el día actual y resumimos confirmed_adj. Luego, borramos confirmed_adj cuando finalice el ciclo.




También podríamos querer incluir la fecha en el título de cada mapa. Recuerde que las fechas se almacenan como el número de días desde el 1 de enero de 1960. La variable v12 contiene datos para el 22 de enero de 2020. Podemos calcular el número de días desde el 1 de enero de 1960 utilizando la función date().





Nuestro bucle forvalues comienza en time = 12, y nos gustaría que la fecha para v12 sea 21936. Por lo tanto, debemos restar 12 de la fecha antes de sumar el valor de la macro local time. El siguiente ejemplo recorre los días del 22 de enero de 2020 al 24 de enero de 2020.





Entonces podemos usar la función string() para cambiar el formato de visualización de cada fecha.




También usaremos la exportación de gráficos para exportar nuestros gráficos a archivos Portable Network Graphics (.png). Estos archivos se combinarán más adelante para crear nuestro video, y los nombres de los archivos deben numerarse secuencialmente desde "1" con ceros a la izquierda. El siguiente ejemplo muestra cómo usar la función string() para crear estos nombres de archivo.



Vamos a juntar todas las piezas y mostrar los comandos básicos que usaremos para crear cada mapa.



Cada iteración del bucle hace tres cosas. La primera línea reemplaza la variable confirmed_adj con el recuento ajustado por la población para ese día en particular. La segunda línea usa grmap para crear el mapa con la fecha en el título. La tercera línea exporta el gráfico a un archivo .png con nombres de archivo secuenciales que comienzan en 001.


El siguiente bloque de código hace lo mismo, pero con algunas opciones agregadas a grmap y graph export. La mayoría de las opciones de grmap se discutieron en mi última publicación. He agregado la opción ocolor(gs8) para representar el color del contorno del mapa con una escala de grises claros y la opción osize(vthin) para hacer que las líneas del mapa sean más delgadas. Las opciones width(3840) y height(2160) después de graph export especifican que cada mapa se guarde con una resolución de 4K. Esto creará imágenes claras y detalladas para nuestro video.

generate confirmed_adj = .
forvalues time = 12/86 {
    local date = 21936 - 12 + `time'
    local date = string(`date', "%tdMonth_dd,_CCYY")
    replace confirmed_adj = 100000*(v`time'/popestimate2019)
    grmap confirmed_adj,                                                    ///
        clnumber(8)                                               ///
        clmethod(custom)                                          ///
        clbreaks(0 5 10 15 20 25 50 100 5000)                     ///
        ocolor(gs8)        osize(vthin)                                            ///
        title("Confirmed Cases of COVID-19 in the United States on `date'") ///
        subtitle("cumulative cases per 100,000 population")
    local filenum = string(`time'-11,"%03.0f")
    graph export "map_`filenum'.png", as(png) width(3840) height(2160)
}
drop confirmed_adj

El bloque de código anterior creará 75 mapas y los guardará en 75 archivos.





Veamos el archivo map_001.png, que es el mapa del 22 de enero de 2020.


Figura 1: map_001.png



A continuación, veamos el archivo map_075.png, que es el mapa del 5 de abril de 2020.




Figura 2: map_075.png




Note que la leyenda en la parte inferior izquierda de ambos mapas es la misma. Utilicé la opción clmethod(custom) con grmap para especificar mis propios puntos de corte para los valores de confirmed_adj. La leyenda cambiará de un día a otro si utiliza el clmethod() predeterminado, que selecciona los puntos de corte en función de los cuantiles de confirmed_adj. Los cuantiles cambiarán de un día a otro, y la leyenda no será coherente en todos los mapas. Seleccioné los puntos de corte en clbreaks (0 5 10 15 20 25 50 100 5000) según el mapa del día final.

Puede actualizar su video con datos futuros aumentando el límite superior del ciclo forvalues. Por ejemplo, el 12 de abril de 2020, escribiría forvalues time = 12/91.

Creamos con éxito un mapa para cada día y guardamos cada mapa en un archivo separado. Ahora, necesitamos combinar estos archivos para crear nuestro video.

Cómo crea un vídeo a partir de la colección de mapas

Escribí una publicación de blog en 2014 que describe cómo usar FFmpeg para crear un video a partir de una colección de imágenes. FFmpeg es un paquete de software gratuito con versiones disponibles para Linux, Mac y Windows. Puede ejecutar comandos FFmpeg desde Stata usando shell.

El siguiente ejemplo usa FFmpeg para combinar nuestros archivos de mapas en un video llamado covid19.mp4.

shell "ffmpeg.exe" -framerate 1/.5 -i map_%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p covid19.mp4

Es posible que deba especificar la ubicación de ffmpeg.exe en su computadora como en el ejemplo a continuación.

shell "C:\Program Files\ffmpeg\bin\ffmpeg.exe" -framerate 1/.5 -i map_%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p covid19.mp4

Los nombres de los archivos de imagen se especifican con la opción -i map_% 03d.png, y el nombre del video de salida, covid19.mp4, se especifica al final del comando. La velocidad de fotogramas se especifica con la opción -framerate 1/.5. La relación "1 /.5" especifica una velocidad de cuadro de 2 imágenes por segundo.

FFmpeg puede tardar varios minutos en procesar las imágenes y convertirlas en un video. Su paciencia será recompensada con el siguiente video.






Conclusiones y código recopilado

¡Lo hicimos! Creamos con éxito un mapa animado de coropletas que muestra los casos confirmados ajustados por la población de COVID-19 para cada condado en los Estados Unidos desde el 22 de enero de 2020 hasta el 5 de abril de 2020. Nuestro video es una herramienta poderosa que podemos usar para estudiar La distribución de COVID-19 a lo largo del tiempo y la ubicación.
Me gustaría recordarle que he tomado decisiones algo arbitrarias al limpiar los datos que se utilizan para crear este video. Mi objetivo era mostrarte cómo crear tus propios mapas y videos. Mis resultados deben usarse solo con fines educativos, y deberá verificar los datos cuidadosamente si planea usar los resultados para tomar decisiones.

Puede reproducir el video con el siguiente código.


// Create the geographic dataset
clear
copy https://www2.census.gov/geo/tiger/GENZ2018/shp/cb_2018_us_county_500k.zip ///
    cb_2018_us_county_500k.zip
unzipfile cb_2018_us_county_500k.zip
spshape2dta cb_2018_us_county_500k.shp, saving(usacounties) replace
use usacounties.dta, clear
generate fips = real(GEOID)
save usacounties.dta, replace
// Create the COVID-19 case dataset
clear
import delimited https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_US.csv
drop if missing(fips)
save covid19_county, replace
// Create the population dataset
clear
import delimited https://www2.census.gov/programs-surveys/popest/datasets/2010-2019/counties/totals/co-est2019-alldata.csv
generate fips = state*1000 + county
save census_popn, replace
// Merge the datasets
clear
use _ID _CX _CY GEOID fips using usacounties.dta
merge 1:1 fips using covid19_county ///
    , keepusing(province_state combined_key v*)
keep if _merge == 3
drop _merge
merge 1:1 fips using census_popn ///
    , keepusing(census2010pop popestimate2019)
keep if _merge==3
drop _merge
drop if inlist(province_state, "Alaska", "Hawaii")
format %16.0fc popestimate2019 v*
save covid19_adj, replace
// Create the maps
spset, modify shpfile(usacounties_shp)
generate confirmed_adj = .
forvalues time = 12/86 {
    local date = 21936 - 12 + `time'
    local date = string(`date', "%tdMonth_dd,_CCYY")
    replace confirmed_adj = 100000*(v`time'/popestimate2019)
    grmap confirmed_adj,                                                    ///
        clnumber(8)                                                         ///
        clmethod(custom)                                                    ///
        clbreaks(0 5 10 15 20 25 50 100 5000)                               ///
        ocolor(gs8) osize(vthin)                                            ///
        title("Confirmed Cases of COVID-19 in the United States on `date'") ///
        subtitle("cumulative cases per 100,000 population")
    local filenum = string(`time'-11,"%03.0f")
    graph export "map_`filenum'.png", as(png) width(3840) height(2160)
}
drop confirmed_adj
// Create the video with FFmpeg
shell "C:\Program Files\ffmpeg\bin\ffmpeg.exe" -framerate 1/.5 -i map_%03d.png -c:v libx264 -r 30 -pix_fmt yuv420p covid19.mp4



Huber, Chuck.
(10 de abril del 2020).
How to create animated choropleth maps using the COVID-19 data from Johns Hopkins University. The Stata Blog. Not Elsewhere Classified.



Eso es todo por hoy. ¡Gracias por leernos!

No hay comentarios.:

Publicar un comentario