Atenção: git LFS. Para recuperar zip ou gz, instlar git LFS antes de fazer o clone desse git.
Sumário:
ATALHOS PARA A DISTRIBUIÇÃO DOS DADOS:
grid_ibge_censo2010_info.zip
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:
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.
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).
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.
reduzir a ocupação em disco no banco de dados SQL (a 20% ou menos do tamanho original).
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.
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.
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) |
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.
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:
Níveis hierárquicos numerados de 0 a 6: zero é o quadrante de origem, 1 a 6 são os níveis de subdivisão.
Informação embutida no gid de 64 bits: porém codificação decimal, para debug e legibilidade humana. Apenas a operação bitwise gid&7
retornando o nível hierárquico, um valor que varia de 0 a 7 no último dígito decimal (3 bits).
Uso do nome original da célula presente no gid: mera conversão de string em bigint, mantendo em decimal a mesma legibilidade para humanos.
Uso do centro da célula nos mecanismos de busca: uniformiza a operação e mantém, nos algoritmos otimizados, a tradição das demais bibliotecas de geocódigo indexador, como Geohash binário, S2geometry e outras.
Valores fem
e masc
arredondados: por serem antigos e mais imprecisos que pop
, não nos preocupamos com a precisão em arredondamentos.
Foram desenvolvidos desde simples "instaladores" a algorimos complexos, com as seguintes finalidades:
Popular uma base de dados PostgreSQL com as tabelas dos shapefiles originais da distribuição IBGE.
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.
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.
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
.
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:
name_to_gid()
.name_to_parts()
, name_to_xyLcenter()
, draw_cell()
e outras.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.
Conforme necessidades, os scripts SQL podem ser facilmente adaptados, desde que refatorando nos diversos scripts. As adaptações mais comuns são:
SRID da projeção Albers do IBGE: mude o valor 952019 para o valor desejado.
Uso do SQL schema public
(sem schema) no lugar de : basta eliminar os comandos DROP SCHEMA e CREATE SCHEMA correspondentes, e alterar todas as ocorrências de grid_ibge.
para public.
.
Discarte do preparo: a operação de DROP CASCADE
pode ser comentada caso esteja realizando testes, fazendo por partes, ou reusando o schema em outras partes do seu sistema.
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:
br_ibge.osm.org/{cell_id}
: retorna célula solicitada na sintaxe original, por exemplo 5KME5300N9630
.br_ibge.osm.org/geo:{lat},{long}
: efeua search_cell(p_x,p_y,5)
, ou seja, retorna célula de 1km.br_ibge.osm.org/geo:{lat},{long};u={uncertainty}
: usa a incerteza para deduzir o nível mais próximo e efeuar search_cell(p_x,p_y,p_level)
. Por exemplo erro de 5km a 10km retorna células de 10 km.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
.
Documentação para demais detalhes, ver /src/README.md
:
Na pasta /data
temos:
Resumo das metas alcançadas pelo projeto:
grid_ibge_censo2010_info.csv
tem ~340 Mb, que zipado resulta em 47 Mb (14% de 339Mb).