C. Lente

Misturando Dados Espaciais e Temporais em R

Enquanto criava um Kaggle Kernel para a base de dados Killed by Police, 2015‚Äď2016, eu tive a ideia de visualizar os dados com uma anima√ß√£o. J√° que as tabelas tinham informa√ß√Ķes sobre toda morte causada por policiais entre 2015 e 2016 com as coordenadas de cada morte, pensei que cada frame poderia ser um gr√°fico que representasse todas as mortes at√© um dia em particular. Parecia bastante simples, mas no final demorou mais do que eu imaginava.

Criando o gr√°fico est√°tico

O primeiro passo era criar um gráfico estático para que eu pudesse ter uma ideia de como eu queria que a imagem final ficasse. Eu nunca tinha feito nenhum gráfico em R com dados geográficos, então demorei um pouco antes de ter certeza de que tudo estava funcionando. Eu decidi criar uma camada base para o gráfico e só então me preocupar com os dados.

plot_deaths <- ggplot() +
  geom_polygon(data = map_data("usa"), aes(long, lat, group = group), fill = "#e6e6e6") +
  theme(axis.text.x = element_blank(), axis.text.y = element_blank(),
        axis.title.x = element_blank(), axis.title.y = element_blank(),
        axis.line = element_blank(), axis.ticks = element_blank(),
        panel.background = element_blank(), panel.border = element_blank(),
        panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        legend.position = "none") +
  coord_quickmap()

O código acima cria essa imagem:

Ent√£o filtrei a base para que ela contivesse apenas informa√ß√£o sobre os Estados Unidos continentais, que eu chamei de cont_deaths. Depois de uma limpeza, eu tamb√©m criai a lista de cidades (e suas respectivas localiza√ß√Ķes) que tinha mais de 5 mortes registradas na base: deadly_cities.

plot_deaths +
  geom_text_repel(data = deadly_cities, aes(long, lat, label = city), size = 4) +
  geom_point(data = cont_deaths, aes(longitude, latitude), alpha = 0.2, color = "red") +
  ggtitle("Killed by Police (showing cities with most deaths)")

Eu tentei usar a função geom_text do pacote ggplot mas muitas cidades se sobrepunham, então procurei uma solução e acamei descobrindo o pacote ggrepel. Com ggrepel::geom_text_repel, o gráfico acabou ficando bem legal.

Na imagem abaixo, as cidades nomeadas s√£o as com 5 ou mais mortes.

Eu estava satisfeito com os resultados, então decidi começar a trabalhar na animação.

Criando a animação

Para criar a animação, usei o pacote animation e instalei um programa chamado ImageMagick. Com animation::saveGIF tudo que tive que fazer foi um loop em que gerava o gráfico de fada frame e o pacote cuidava do resto.

saveGIF(for (i in 0:730) {

  # Filter deaths up to a certain date
  time_deaths <- cont_deaths %>%
    filter(date <= ymd("2015-01-01") + i)

  # Get the cities that have already had more than 5 deaths
  time_cities <- deadly_cities %>%
    left_join(time_deaths, c("city" = "city", "country.etc" = "state")) %>%
    group_by(city, country.etc) %>%
    summarise(count = n(), long = long[1], lat = lat[1]) %>%
    ungroup() %>%
    mutate(alph = count > 5)

  # Plot deaths
  print(plot_deaths +
    geom_text_repel(data = time_cities, size = 4, segment.alpha = 0,
                    aes(long, lat, label = city, alpha = factor(alph))) +
    scale_alpha_manual(values = c(0, 1)) +
    geom_point(data = time_deaths, aes(longitude, latitude), alpha = 0.2, color = "red") +
    ggtitle(paste0("Deaths until ", ymd("2015-01-01") + i,
                   " (showing when each city crosses the 5 deaths line)")))

}, "deaths.gif", interval = 0.005, ani.width = 900, ani.height = 630)

Neste código fiz um loop nos 730 dias da base e gerei gráficos somente com as mortes até cada data. Também verifiquei para ver se nenhuma cidade tinha cruzado a linha das 5 mortes para começar a mostrar o seu nome.

Esta é a animação final:

Palavras finais

Tentar criar essa animação foi uma experiência muito interessante. Eu tive que procurar quase tudo que tentava fazer, mas no final aprendi bastante. Créditos especiais para Rob Harrand, pessoa cujo Kernel me ensinou a usar o pacote animation.

A pior parte foi fazer os rótulos das cidades se comportarem. Dado que ggrepel::geom_text_repel acha o melhor lugar para cada rótulo, conforme novas cidades cruzavam a linha das 5 mortes, os outros rótulos pulavam de um lado para o outro por alguns frames. Eu consertei isso fazendo com que todos os rótulos fossem mostrados desde o primeiro frame e deixando os rótulos das cidades que ainda não deveriam aparecer com o texto transparente.

Se você quiser dar uma olhada no código fonte completo, dê uma olhada no meu Kernel.