Conversão Centroid do recurso de polígono para pontos usando Python

9

Gostaria de converter alguns arquivos shp baseados em polígono que possuem vários recursos de polígono em pontos para cada recurso que representariam essencialmente o centríodo de cada recurso de polígono. Eu sei que no mundo ArcGIS eu poderia usar a ferramenta Feature To Point, mas gostaria de manter isso em um script que possa ser executado em PCs que não possuam arcpy, então estou procurando uma alternativa de código aberto. Alguém está ciente de uma biblioteca que eu poderia usar para isso, juntamente com alguma orientação sobre como alavancá-lo para fazer isso?

wilbev
fonte
Ainda estou tendo vários problemas com a resposta que Gene forneceu abaixo. A questão é como ele reordena os atributos, de sua ordem original para a alfabética, o que é um problema. Em segundo lugar, o arquivo de forma fica corrompido, possivelmente devido ao arquivo que estou tentando converter com mais de 250 atributos.
Wilbev
Existe uma ferramenta padrão chamada 'Centroides de polígonos' no QGIS que faz exatamente isso - você precisa de um script? Seria fácil o suficiente para script usando PyQGIS eu pensaria.
Dùn Caan
Ele precisa ser um script e funcionar em PCs que não possuam QGIS.
Wilbev 10/01

Respostas:

9

Você pode executar um ogr2ogrcomando (por exemplo, a partir de um OSGeo4w Shell). Por exemplo, em um shapefile de países:

cd path/to/shapefiles
ogr2ogr -sql "SELECT ST_Centroid(geometry), * FROM countries" -dialect sqlite countries_centroid.shp countries.shp

O novo shapefile countries_centroid.shpdeve ser semelhante à entrada, mas conter apenas um ponto por [Multi] Polígono.

O @PEL também mostra um bom exemplo com ST_PointOnSurface, que é simples de substituir neste comando.


Algo semelhante pode ser feito em Python, se necessário, mas pode levar algumas linhas de código a mais:

import os
from osgeo import ogr

ogr.UseExceptions()
os.chdir('path/to/shapefiles')

ds = ogr.Open('countries.shp')
ly = ds.ExecuteSQL('SELECT ST_Centroid(geometry), * FROM countries', dialect='sqlite')
drv = ogr.GetDriverByName('Esri shapefile')
ds2 = drv.CreateDataSource('countries_centroid.shp')
ds2.CopyLayer(ly, '')
ly = ds = ds2 = None  # save, close
Mike T
fonte
Eu acho que você propôs uma solução mais simples com OGR e SQL. Eu acho que é mais seguro adicionar um parâmetro ao OGR com -nlt Point
PEL
Infelizmente não consigo fazer isso funcionar. Eu recebo um erro alegando que o ST_Centroid não está funcionando.
wilbev
1
Ele precisa da opção de dialeto SQLite (como mostrado) e do Spatialite integrados ao GDAL, o que nem sempre é garantido. O OSGeo4W possui uma boa versão do GDAL que executará esse comando corretamente.
Mike T
Posso obter o seu script principal dentro do ogr2ogr para que funcione sem problemas. No entanto, preciso fazer isso em um script python autônomo, portanto, estou tentando fazer com que seu segundo conjunto de códigos funcione, que é onde eu continuo no ST_Centroid não é um erro de função. Meu código é idêntico ao que você tem acima, incluindo o dialeto sqlite.
wilbev
1
O erro que você descreve é ​​quando o GDAL foi criado sem o suporte do Spatialite. Alguns pacotes gdal-python suportam isso, mas não todos. Tente abrir um shell OSGeo4W e executar o script Python nesse ambiente. Eu acho que o conjunto padrão de pacotes relacionados a gdal-binincluir esse suporte.
Mike T
9

Simplesmente use Fiona ou GeoPandas (Python 2.7.xe 3.x)

Alguns polígonos

insira a descrição da imagem aqui

import geopandas as gpd
# GeoDataFrame creation
poly = gpd.read_file("geoch_poly.shp")
poly.head()

insira a descrição da imagem aqui

Transformação em pontos (centróides)

# copy poly to new GeoDataFrame
points = poly.copy()
# change the geometry
points.geometry = points['geometry'].centroid
# same crs
points.crs =poly.crs
points.head()

insira a descrição da imagem aqui

# save the shapefile
points.to_file('geoch_centroid.shp')

Resultado

insira a descrição da imagem aqui

gene
fonte
Obrigado pela resposta gene. Eu acho que você pode ter um erro de digitação acima, onde a variável 'gdf' deve ser 'poly ", certo? No código points.crs = gdf.crs. Também estou enfrentando alguns outros problemas em que o arquivo .prj não está recebendo criado, ele aparece vazio e a ordem dos campos dos atributos está alterando a ordem dos dados do polígono, pois agora parecem alfabéticos. É importante que eles permaneçam na mesma ordem. Você sabe como manter o atributo do campo na mesma ordem?
wilbev
Obrigado, corrigido. Para a ordem dos campos de atributos, basta alterar a ordem do GeoPandas GeoDataFrame (= Pandas DataFrame)
gene
Obrigado Gene, mas não tenho certeza se entendo onde alteraria essa ordem no código aqui. Também estou enfrentando dois outros problemas com isso. Primeiro, o arquivo * .prj está em branco no novo arquivo shp. Em segundo lugar, quando tento abrir o arquivo shp no shp reader, ocorre um erro ao abrir o arquivo como se estivesse corrompido. Parece funcionar sem ficar corrompido se o arquivo shp tiver apenas um único recurso, mas múltiplos é onde está tendo problemas.
Wilbev 7/11
Desculpe, mas você precisa conhecer o Pandas para isso e não tenho nenhum problema com o script com meus dados (eu uso as versões mais recentes do GeoPandas, Fiona e Numpy)
gene
Posso enviar o arquivo shp para que você possa ver por si mesmo, mas esse arquivo shp possui mais de 250 colunas de dados que, imagino, estão criando problemas para ele. Eu tentei isso em um arquivo shp com muito menos atributos e não parece ter nenhum problema.
Wilbev 8/11
5

Outra maneira, talvez mais "de baixo nível", seria usar diretamente fionae shapelypara processamento de E / S e geometria.

import fiona
from shapely.geometry import shape, mapping

with fiona.open('input_shapefile.shp') as src:
    meta = src.meta
    meta['schema']['geometry'] = 'Point'
    with fiona.open('output_shapefile.shp', 'w', **meta) as dst:
        for f in src:
            centroid = shape(f['geometry']).centroid
            f['geometry'] = mapping(centroid)
            dst.write(f)
Loïc Dutrieux
fonte
Obrigado Loic. Isso definitivamente corrige o problema de classificação que eu estava tendo, mas não o corrige com tantos atributos que causam a corrupção do arquivo. Você teria outras idéias sobre como superar esse problema? Eu acho que talvez precise excluir atributos. Posso enviar um arquivo de exemplo, se isso ajudar.
wilbev
@wilbev Envie um link de download para seus dados, se puder. Caso contrário, não vejo o que poderia estar errado.
Loïc Dutrieux
Loic, enviei um e-mail com um arquivo de exemplo. Espero que isso lhe dê uma boa idéia do problema que estou enfrentando.
wilbev
@wilbev, o que você quer dizer com 'o arquivo fica corrompido'? Usando o arquivo que você enviou, eu pude produzir os centróides e abrir o shapefile de saída no QGIS sem problemas. A tabela de atributos permanece inalterada entre os dois arquivos.
Loïc Dutrieux
Por corrompido, quero dizer que é essencialmente um arquivo dbf vazio, pois depois que eu executo o script, ele cria um arquivo dbf de 1 KB e, quando você abre, ele fica completamente vazio. Se eu executar o mesmo script exato, o que você listou acima, em um arquivo com menos atributos, ele funcionará sem problemas. Eu até tentei em um segundo PC e obtive o mesmo resultado. Eu não entendo.
wilbev
2

Eu acho que a maneira mais fácil é usar o formato virtual gdal / ogr. ( http://www.gdal.org/drv_vrt.html ) e dialeto SQL / SQLITE ( http://www.gdal.org/ogr_sql.html e https://www.gaia-gis.it/spatialite-3.0 .0-BETA / spatialite-sql-3.0.0.html )

Meu shapefile de polígono é nomeado poly.shp. Então eu crio esse XML como um arquivo chamado vrt.vrt. Dentro deste arquivo (vrt.vrt), aqui o conteúdo a ser convertido em pontos

<OGRVRTDataSource>
    <OGRVRTLayer name="poly">
        <SrcDataSource relativeToVRT="1">poly.shp</SrcDataSource>
        <SrcSQL dialect="sqlite">SELECT ST_PointOnSurface(geometry) as geom_point, poly.* from poly</SrcSQL>
        <GeometryType>wkbPoints</GeometryType> 
        <GeometryField name="geom_point" />
    </OGRVRTLayer>
</OGRVRTDataSource>

No momento, você pode integrar esse arquivo ao Qgis para validar. Com certeza, a renderização é mais lenta que a fonte bruta, pois cada recurso é convertido como ponto em cada consulta de renderização.

Depois, converta esse arquivo (vrt.vrt) em outra coisa usando os utilitários gdal / ogr de um shell / script python

os.system("ogr2ogr point_from_vrt.shp vrt.vrt poly")

Você obtém um shapefile de ponto chamado point_from_vrt.shp.

PEL
fonte
Consegui fazer isso funcionar, mas gostaria de manter tudo isso dentro de um script python, pois preciso converter centenas de arquivos, todos com nomes de arquivos diferentes. Gostaria de usar a solução @ Mike T, mas recebo a mensagem "Não existe essa função: ST_Centroid, se eu usar isso, e também tentei o ST_PointOnSurface, que também diz que não existe essa função. ()?
wilbev
Eu recebo'wkbPoints' is not a valid value of the atomic type
Ben Sinclair