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
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
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
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
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")
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
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
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
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
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
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")
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
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
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