Introdução

Os dados podem ser dispostos de diversas maneiras, embora, com o predomínio das notações textuais, a representação tabular seja o modelo pictórico convencional, malgrado o aspecto rudimentar, a despeito do desenvolvimento recente de elementos de composição gráfica integrados aos ambientes de programação, análise e visualização de dados disponíveis para estatísticos e programadores.

Objetivo

A análise de dados espaciais em saúde pública é uma metodologia utilizada para estudo da distribuição geográfica de eventos sanitários, identificação de clusters ou agrupamentos, da qual nos apropriamos de algumas ferramentas para avaliar a dinâmica topológica das suspeitas de contaminação pela COVID-19 em Juiz de Fora.

Recursos

Levantamento divulgado pelas Secretaria de Saúde e Desenvolvimento Social de Juiz de Fora:
https://tribunademinas.com.br/wp-content/uploads/2020/05/001_Informe_TS.pdf.

Fonte: https://tribunademinas.com.br/noticias/cidade/06-05-2020/centro-e-o-bairro-com-mais-suspeitas-de-covid-19-em-jf.html

Última atualização dos dados: 24/4/2020

Bibliotecas

Carregamos as seguintes bibilotecas do R, para adicionar funcionalidades extras:

  • tidyverse - para manipulação de dados;
  • gridExtra - para ampliar as possibilidades de manipulação gráfica;
  • DT - para incluir tabelas em relatórios Rmarkdown;
  • leaflet - biblioteca javascript para desenvolvimento de mapas interativos;
  • prettydoc - temas adicionais para documentos Rmarkdown;
  • googleway - para acesso aos mapas do google;
  • htmlwidgets - para salvar cópia local e interativa do mapa no formato html;
  • mapview - para salvar instatâneo do mapa no formato png.

Diretório de trabalho

Definimos o diretório de trabalho:

Coleta e limpeza de dados

Baixamos o relatório semanal, convertemos o arquivo pdf em txt, removemos os espaços excedentes e selecionamos as linhas que casam com o padrão definido:

Criação do dataset

Criamos o dataset contendo a relação de territórios socioassistenciais e o total de casos suspeitos notificados:

Coordenadas geográficas

Para extrairmos as coordenadas, utilizamos a rotina de geolocalização fornecida pela API Google Geocoding, após o registro obrigatório de uma API Key que, depois de salva em um ambiente seguro, pode ser acessada programaticamente para varrer a base de dados do Google Maps.

A geocodificação consiste em transformar endereços, compostos pela combinação dos territórios socioassistenciais, fornecidos pelo arquivo csv importado e transformado em um dataframe, com as constantes que definem o município e a unidade da federação:

Resultados da busca

O resultado da busca é armazenado em um objeto de classe lista, estrutura complexa que pode acondicionar diversos tipos de dados. A resposta retorna dois elementos: o primeiro é results, que fornece diversas informações a respeito do endereço geocodificado; o segundo fornece o status da soliciação. Dentre as informações retornadas pelo primeiro elemento, constam o endereço, abreviado e completo, as coordenadas geográficas - latitude e longitude, a precisão do resultado e o tipo de localidade.

Tratamento de erros

Quando as coordenadas são mescladas com a listagem que representa os bairros onde foram notificadas suspeitas de contaminação pela COVID-19, recebemos uma mensagem de erro:
ts <- cbind(ts, do.call(rbind, lapply(coords, geocode_coordinates)))

Error in data.frame(…, check.names = FALSE) :
arguments imply differing number of rows: 147, 151

Investigação

Investiguemos o motivo da discrepância.
Primeiro, vejamos como se classificam as estruturas de dados:

## [1] "data.frame"
## [1] "list"
## [1] "data.frame"

Depois, qual o tamanho:

## [1] 147
## [1] 147
## [1] 151

Embora o resultado da pesquisa das coordenadas geográficas, armazenado no objeto de classe lista, contenha o mesmo tamanho do objeto onde estão registradas as localidades, a transformação em dataframe resulta em quantidade diferente de registros.

As pistas começam pelos componentes, que podem ser visualizados de forma suscinta:

## List of 2
##  $ results:'data.frame': 1 obs. of  6 variables:
##   ..$ access_points     :List of 1
##   .. ..$ : list()
##   ..$ address_components:List of 1
##   .. ..$ :'data.frame':  4 obs. of  3 variables:
##   ..$ formatted_address : chr "Centro, Juiz de Fora - MG, Brazil"
##   ..$ geometry          :'data.frame':   1 obs. of  4 variables:
##   .. ..$ bounds       :'data.frame': 1 obs. of  2 variables:
##   .. ..$ location     :'data.frame': 1 obs. of  2 variables:
##   .. ..$ location_type: chr "APPROXIMATE"
##   .. ..$ viewport     :'data.frame': 1 obs. of  2 variables:
##   ..$ place_id          : chr "ChIJHYr1vKGcmAARbKiIYVUHpGE"
##   ..$ types             :List of 1
##   .. ..$ : chr [1:3] "political" "sublocality" "sublocality_level_1"
##  $ status : chr "OK"

Ou detalhada:

## List of 2
##  $ results:'data.frame': 1 obs. of  6 variables:
##   ..$ access_points     :List of 1
##   .. ..$ : list()
##   ..$ address_components:List of 1
##   .. ..$ :'data.frame':  4 obs. of  3 variables:
##   .. .. ..$ long_name : chr [1:4] "Centro" "Juiz de Fora" "Minas Gerais" "Brazil"
##   .. .. ..$ short_name: chr [1:4] "Centro" "Juiz de Fora" "MG" "BR"
##   .. .. ..$ types     :List of 4
##   .. .. .. ..$ : chr [1:3] "political" "sublocality" "sublocality_level_1"
##   .. .. .. ..$ : chr [1:2] "administrative_area_level_2" "political"
##   .. .. .. ..$ : chr [1:2] "administrative_area_level_1" "political"
##   .. .. .. ..$ : chr [1:2] "country" "political"
##   ..$ formatted_address : chr "Centro, Juiz de Fora - MG, Brazil"
##   ..$ geometry          :'data.frame':   1 obs. of  4 variables:
##   .. ..$ bounds       :'data.frame': 1 obs. of  2 variables:
##   .. .. ..$ northeast:'data.frame':  1 obs. of  2 variables:
##   .. .. .. ..$ lat: num -21.7
##   .. .. .. ..$ lng: num -43.3
##   .. .. ..$ southwest:'data.frame':  1 obs. of  2 variables:
##   .. .. .. ..$ lat: num -21.8
##   .. .. .. ..$ lng: num -43.4
##   .. ..$ location     :'data.frame': 1 obs. of  2 variables:
##   .. .. ..$ lat: num -21.8
##   .. .. ..$ lng: num -43.3
##   .. ..$ location_type: chr "APPROXIMATE"
##   .. ..$ viewport     :'data.frame': 1 obs. of  2 variables:
##   .. .. ..$ northeast:'data.frame':  1 obs. of  2 variables:
##   .. .. .. ..$ lat: num -21.7
##   .. .. .. ..$ lng: num -43.3
##   .. .. ..$ southwest:'data.frame':  1 obs. of  2 variables:
##   .. .. .. ..$ lat: num -21.8
##   .. .. .. ..$ lng: num -43.4
##   ..$ place_id          : chr "ChIJHYr1vKGcmAARbKiIYVUHpGE"
##   ..$ types             :List of 1
##   .. ..$ : chr [1:3] "political" "sublocality" "sublocality_level_1"
##  $ status : chr "OK"

No presente caso, os dados fornecem informações variadas sobre a entidade político-administrativa pesquisada, dentre as quais coordenadas individualizadas, no formato GMS; contudo, não é o que acontece de maneira inequívoca em todos os itens da lista. Em termos matemáticos, temos: f(x)=y, que é a representação da correspondência unívoca entre os elementos de x, o conjunto dos endereços e y, o conjunto das coordenadas, que vai ser alcançada após a solução dos problemas indicados logo adiante:

##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1
##  [75] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [112] 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 2 1 1 1 1 1

Podemos identificar qual localidade gerou mais de uma coordenada:

## [1]  66 122 138 142

Além do problema da ambiguidade, há também o problema da precisão, pois nem todas as localidades foram identificadas pela API do Google. Bairros e distritos são identificados como entidades politico-administrativas armazenadas no campo types e rotuladas como political ou locality.
Portanto, para apurar o nível de precisão, primeiro extraímos as entidades discriminadas fora do escopo adequado, restringimos o espaço de busca para bairro ou distrito somente e armazenamos à parte as localidades que receberam respostas dissonantes:

Convergência de dados

Uma vez alcançada a convergência dos dados, à medida em que a quantidade de territórios assistenciais corresponde à quantidade de coordenadas fornecidas pela API , executamos novamente a rotina de geocodificação:

Recriamos a base de dados com as informações acopladas:

Acrescentamos as coordenadas obtidas manualmente:

Efetuamos os ajustes finais:

Transposição

Transportamos as coordenadas para o mapa.
Passe o mouse sobre o ícone para exibir o nome da localidade e clique para exibir a quantidade de notificações:

Agrupamento

Agrupamentos automáticos são exibidos como círculos coloridos no mapa, segundo um vetor de cores, formado pelo verde, amarelo e vermelho, que determina o volume de itens do cluster. O nível de agrupamento é inversamente proporcional ao tamanho do zoom. Quanto maior o zoom menor o cluster, até chegar à unidade de análise individual. Ao passar o mouse sobre o círculo, será exibida a extensão da área delimitada pelos marcadores:

Cópia interativa

Por fim, gravamos cópia local dos mapas, sem perder a interatividade:

Referências:

Oldham, Paul. 2018. Exploring Geocoding Scientific Literature with R.
https://www.pauloldham.net/geocoding-scientific-literature-with-r/.

Johnson, Hansen. 2018. Interactive maps in R (with leaflet).
https://hansenjohnson.org/post/interactive-maps-in-r/

Brito, Robison. 2016. Como utilizar a Google Geocoding API para obter endereços.
https://www.devmedia.com.br/como-utilizar-a-google-geocoding-api-para-obter-enderecos/36751