osm-codes / BR_IBGE

Grade Estatística IBGE em Representação Compacta
http://git.osm.codes/BR_IBGE#readme
Apache License 2.0
2 stars 0 forks source link
geocode ibge

  Atenção: git LFS. Para recuperar zip ou gz, instlar git LFS antes de fazer o clone desse git.

Grade Estatística IBGE em Representação Compacta

Sumário:

ATALHOS PARA A DISTRIBUIÇÃO DOS DADOS:


O presente projeto oferece scripts para redistribuir mais eficientemente a Grade Estatística oficial do IBGE, e para aprimorar seu uso em bancos de dados. Resultou em uma versão otimizada, com os mesmos dados, porém viabilizando novas aplicações.

O principal objetivo foi oferecer uma estrutura de dados alternativa à estrutura original, batizada de Grade Estatística IBGE Compacta, com as seguintes vantagens:

  1. indexar a grade diretamente pelos seus geocódigos: o identificador interno de célula, gid, pode ser o próprio nome ou geocódigo binário da célula, tornando as operações de busca e recuperação muito mais simples e rápidas.

  2. reduzir o tamanho da distribuição da geometria da grade, de 849 Mb (56 arquivos zip) para um só arquivo zip de 44 Mb (5% dos 849).

  3. estruturar de forma mais simples, capaz de reproduzir funcionalmente os dados da estrutura original, e capaz ainda de ser utilizada:

    3.1. em qualquer banco de dados SQL simples (por ex. SQLite), sem necessidade de extensões GIS ou geometria.

    3.2. no PostGIS com as mesmas (ou mais) aplicações que a distribuição original.
    Em particular otimizar os algoritmos de "resolução dos identificadores de célula" (encode/decode), e de posição espacial em identificador de célula.

  4. reduzir a ocupação em disco no banco de dados SQL (a 20% ou menos do tamanho original).

  5. distribuir em formato mais aberto (não-proprietário) e mais simples e interoperável do que o Shapefile: o formato CSV é legível até por planilha (ex. Excel) e é um padrão aberto universal.

CONVENÇÕES DO IBGE

Em janeiro de 2016 o IBGE publicou mais formalmente a sua Grade Estatística em grade_estatistica/censo_2010, do site IBGE.gov.br, onde podemos acessar livremente o documento de justificativas (que infelizmente não pode ser utilizado como referência técnica) e os arquivos da geometria da grade em shapefile.

Se você nunca havia antes ouvido falar, veja o filminho didáco sobre ela, ou explore o Censo 2010 através da grade online (ilustração abaixo).

A "grade" do IBGE é na verdade um conjunto hierarquizado de grades (ou "grid system"), aparentemente seguindo as recomendações INSPIRE D2.8.I.2, "Data Specification on Geographical Grid Systems – Technical Guidelines" de 2014, ou anterior.

Cada quadrante da grade IBGE de menor escala (na ilustração do sumário a grade nível L0) é subdividido em quadrados com lado medindo 1/5 ou 1/2 do seu tamanho para formar a grade seguinte, de menor escala e maior resolução. A grade seguinte à L0, a L1, tem quadrados com 500/5 km = 100 km de lado; a seguinte L2 com 100/2 km = 50 km; L3 com 50/5 km = 10 km; L4 com 10/2 km = 5 km; L6 com 5/5 km = 1 km.

Na distribuição da geometria das grades de 200m e 1km foram acrescentados dados relevantes do Censo de 2010. A seguir a descrição dessa grade mesclada aos dados. Dada a precariedade da documentação, algumas dúvidas permanecem, e outras foram deduzidas por reengenharia, também descrita a seguir.

Estrutura das tabelas

Todas as tabelas criadas pelos shapefiles originais do IBGE (vide grade_estatistica/censo_2010) possuem a estrutura:

Column Type Comments
gid integer ID de tabelas de geometria, gerado por antigo padrão.
Nota: é otimizável como indexador porém redundante com id_unico.
id_unico character varying(50) ID real da célula. String do tipo {lado}E{X}N{Y}, com referência XY na projeção Albers.
nome_1km character varying(16) (redundante) Apoio na agregação de 1 km.
nome_5km character varying(16) (redundante) Apoio na agregação de 5 km.
nome_10km character varying(16) (redundante) Apoio na agregação de 10 km.
nome_50km character varying(16) (redundante) Apoio na agregação de 50 km.
nome_100km character varying(16) (redundante) Apoio na agregação de 100 km.
nome_500km character varying(16) (redundante) Apoio na agregação de 500 km.
quadrante character varying(50) (redundante) Localiza o quadrante ou apoia a agregação de 500 km.
masc integer população do sexo masculino
fem integer população do sexo feminino
pop integer população total (conforme Censo 2010) no interior da célula
dom_ocu integer domicílios ocupados (conforme Censo 2010)
shape_leng numeric (redundante)
shape_area numeric (redundante)
geom geometry(MultiPolygon,4326) geometria da célula em coordenadas LatLong WGS84 (sem projeção)

Nomenclatura das células

Em qualquer quadrante qq o resultado de SELECT DISTINCT substr(id_unico,1,4) id_prefix FROM grade_IDqq será o conjunto {"1KME", "200M"}. Isso significa que todos os demais atributos nome_* (e quadrante) da estrutura acima, são reduntantes. Só existem esses dois tipos de célula, sendo a menor delas, 200 m, usada para o meio urbano, onde se faz necessária uma cobertura mais densa. No caso das células com id_prefix "1KME", de 1 km de lado, teremos id_unico=nome_1km.

Quanto ao significado do valor de id_unico, ele segue a URI Template {lado}E{X}N{Y}, onde lado é o tamanho do lado da célula, X e Y as "coordenadas da célula" tendo como referência o seu canto... Qual canto? Tomando como referência as coordenadas do centro da geometria (função PostGIS ST_Centroid) percebemos que o IBGE não adotou uma convenção regular: para células de 1 km basta truncar ou usar o canto inferior direito, mas para células de 200 metros é o canto superior direito (vide SRC/INTRODUÇÃO).

SELECT * FROM (
  SELECT is_200m, id_unico_parts,
       round( ST_x(ST_Transform(geom,952019)) + iif(is_200m,-100,-500) )::int x,
       round( ST_y(ST_Transform(geom,952019)) + iif(is_200m,+100,-500) )::int y
  FROM (
    SELECT substr(id_unico,1,4)='200M' AS is_200m,
      CASE
        WHEN id_unico=nome_1km THEN array[substr(id_unico,5,4), substr(id_unico,10)]
        ELSE  array[substr(id_unico,6,5), substr(id_unico,12)]
        END id_unico_parts,
      ST_centroid(st_transform(geom,952019)) as geom
    FROM grade_id45
  ) t1
) t2 -- WHERE homologando a heuristica da nomenclatura das células:
WHERE substr(x::text,1,length(id_unico_parts[1]))!=id_unico_parts[1]
   OR substr(y::text,1,length(id_unico_parts[2]))!=id_unico_parts[2]
ORDER BY 1;

O algoritmo foi validado contra células de 200m (flag is_200m) e 1km. conforme id_unico. Para as células de 200m foram validadas as coordenadas "X_centro-100" e "Y_centro+100", para células de 1km as coordenadas "X_centro-500" e "Y_centro-500".

A mesma heurística pode ser utilizada para a recuperação de dados a partir do identificador IBGE das células de 200 m e de 1 km. A generalização para células maiores (10 km, 50 km etc.) requer uma avaliação mais detalhada, a seguir.

DECISÕES DE PROJETO

Mesmo sendo uma reprodução fiel e completa da grade original, alinhada aos objetivos apresentados acima, algumas decisões são arbitrárias e se tornam convenções, que não podem ser revisadas depois de homologada a proposta:

ALGORITMOS IMPLANTADOS

Foram desenvolvidos desde simples "instaladores" a algorimos complexos, com as seguintes finalidades:

  1. Popular uma base de dados PostgreSQL com as tabelas dos shapefiles originais da distribuição IBGE.

  2. Criar e popular com os dados originais uma nova estrutura, mais compacta e eficiente para a indexação de outros dados e a resolução dos identificadores de célula.

Na seção INSTALAÇÃO abaixo, descreve-se como cada uma dessas estruturas de dados pode ser intaladas com um simples comando make e o número da alternativa (1 ou 2).

A seguir a descrição dos algoritmos que geram a conversão da grade original em compacta, e vice-versa, que transformam a compacta em original, e outros recursos.

Estrutura compacta

Com rótulo e geometria compactados em um simples inteiro de 64 bits (bigint no PostgreSQL), e eliminando outras redundâncias, as informações da grade original podem ser transferidas, sem perdas, para a seguinte estrutura:

Column Type Comments
gid bigint NOT NULL PRIMARY KEY "Geometric IDentifier" com informação embutida (4 bits do nível da grade e ~60 bits para o ponto XY de referência da célula)
pop integer NOT NULL população total dentro da célula
pop_fem_perc smallint NOT NULL percentual da população do sexo feminino
dom_ocu smallint NOT NULL domicílios ocupados

O codificador de coordenadas consegue compactar toda a informação de localização do ponto de referência da célula em um só número inteiro de 64 bits.

Como os valores mínimo e máximo das coordenadas XY dos centros de célula de todo o conjunto são, respectivamente, (2809500,7599500) e (7620500,11920500), duas ordens de grandeza abaixo de 2^30-1 = 1073741823. Cabem folgadamente em 30 bits e ainda sobram 3 bits para codificar o nível hierárquico da grade na qual se encontra o ponto. A representação final para o gid proposto é um número inteiro positivo de 16 dígitos (ex. 4881000078490005), estruturado em três partes:

Por exemplo, o valor do gid da célula de 200M que contém o Marco Zero de São Paulo é 5756000087008006, portanto X=5756000, Y=08700800 e L=6.

Com isso, podemos indexar além das células fornecidas pelos shapefiles do IBGE, todas as demais, criando um grande e econômico cache das grades de sumarização.

Visualização dos identificadores

Na biblioteca são oferecidas funções geradoras da geometria da célula, não há necessidade de se armazenar a geometria da célula. As funções, principalmente aquelas que tomam como argumento apenas o gid, são simples e rápidas o bastante no PostGIS. No QGIS, um grande número de células podem ser vistas simultaneamente através de uma VIEW SQL, sem cache. Por exemplo a grade L1 inteira:

CREATE VIEW test_grade_level1 AS
  SELECT gid, grid_ibge.draw_cell(gid) geom
  FROM grid_ibge.censo2010_info
  WHERE grid_ibge.gid_to_level(gid)=1;

Abaixo ilustradas as grades L0 e L1 com respectivamente células de lado 500KM e 100KM, em seguida um zoom para destacar a VIEW da grade L2 de 50KM.

As grades L0 e L1 podem também ser visualizadas no repositório git, respectivamente como grid_ibge500km.geojson e grid_ibge100km.geojson.

Resolução dos identificadores de célula

Cada célula da grade tem seu nome, ou seja, um identificador único expresso conforme convenções do IBGE. O nome pode ser "resolvido" em geometria da célula. Essa resolução é realizada por funções de biblioteca. Exemplos:

Resolução de ponto em célula

A solução proposta na presente versão indexada por XY permite usar a representação interna invez da busca geométrica.

Por exemplo o ponto XY=(4580490.89,8849499.5) pode primeiramente ser arredondado para inteiros e depois aproximado para a célula mais próxima, conforme algoritmo tradicional de "snap to grid". A função geoURI_to_gid() implementa a resolução do ponto dado por geoURI.

Adaptações para outros países

Conforme necessidades, os scripts SQL podem ser facilmente adaptados, desde que refatorando nos diversos scripts. As adaptações mais comuns são:

API

As funções de resolução para uso na API são descritas no README do /src. Com devidas configurações no NGINX elas se tornam os seguintes endpoints:

Ilustrando através de pontos de controle:

municipality name geo_uri wikidata_id osm.codes/geoURI
São Paulo Marco Zero de São Paulo geo:-23.550385,-46.633956 10325364 link API
Amazonas Teatro Amazonas geo:-3.130278,-60.023333 1434444 link API
Brasília Palácio Nereu Ramos geo:-15.799717,-47.864131 4155889 link API
... ... ... .... ... ...

Demais exemplos no dataset data/ptCtrl.csv.


INSTALAÇÃO, COMPATIBILIDADE, BIBLIOTECA, ETC

Documentação para demais detalhes, ver /src/README.md:


DISTRIBUIÇÃO DA GRADE COMPACTA

Na pasta /data temos:

Resumo das metas alcançadas pelo projeto: