Konversi Centroid Fitur Polygon ke Poin menggunakan Python

9

Saya ingin mengonversi beberapa file shp berbasis poligon yang memiliki beberapa fitur poligon menjadi poin untuk setiap fitur yang pada dasarnya akan mewakili centriod dari setiap fitur poligon. Saya tahu di dunia ArcGIS saya bisa menggunakan alat Feature To Point tetapi saya ingin menyimpannya dalam skrip yang dapat dijalankan di PC yang tidak memiliki arcpy di atasnya, jadi saya mencari alternatif open source untuk itu. Adakah yang tahu perpustakaan yang bisa saya gunakan untuk ini bersama dengan beberapa arahan tentang bagaimana memanfaatkan itu?

wilbev
sumber
Saya masih mengalami beberapa masalah dengan jawaban yang diberikan Gene di bawah ini. Masalahnya adalah bagaimana itu menata ulang atribut dari urutan aslinya ke alfabet yang merupakan masalah. Kedua, file bentuk menjadi rusak kemungkinan karena file yang saya coba konversi memiliki lebih dari 250 atribut.
wilbev
Ada alat standar yang disebut 'Polygon Centroids' di QGIS yang melakukan hal ini - apakah Anda memerlukan skrip? Akan cukup mudah untuk skrip menggunakan PyQGIS saya pikir.
Dùn Caan
Itu harus berupa skrip dan berfungsi pada PC yang tidak memiliki QGIS pada mereka.
wilbev

Jawaban:

9

Anda dapat menjalankan ogr2ogrperintah (mis. Dari OSGeo4w Shell). Misalnya pada shapefile negara:

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

Shapefile baru countries_centroid.shpharus mirip dengan input, tetapi hanya berisi satu titik per [Multi] Polygon.

@PEL juga menunjukkan contoh yang baik dengan ST_PointOnSurface, yang mudah untuk diganti dalam perintah ini.


Hal serupa dapat dilakukan dengan Python, jika diperlukan, tetapi mungkin perlu beberapa baris kode lagi:

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
sumber
Saya pikir Anda sudah mengusulkan dan solusi paling sederhana dengan OGR dan SQL. Saya pikir lebih aman untuk menambahkan parameter ke OGR dengan -nlt Point
PEL
Sayangnya saya tidak bisa membuatnya bekerja. Saya mendapatkan pesan kesalahan yang menyatakan bahwa ST_Centroid tidak berfungsi.
wilbev
1
Perlu opsi dialek SQLite (seperti yang ditunjukkan) dan Spatialite dibangun ke dalam GDAL, yang tidak selalu dijamin. OSGeo4W memiliki versi GDAL yang baik yang akan menjalankan perintah ini dengan benar.
Mike T
Saya bisa mendapatkan skrip teratas Anda dalam ogr2ogr yang memuji untuk bekerja tanpa masalah. Namun, saya perlu melakukan ini dalam skrip python yang berdiri sendiri jadi saya mencoba untuk mendapatkan set kode 2 Anda untuk bekerja yang mana saya melanjutkan ke ST_Centroid bukan kesalahan fungsi. Kode saya identik dengan apa yang Anda miliki di atas termasuk dialek sqlite.
wilbev
1
Kesalahan yang Anda uraikan adalah ketika GDAL dibangun tanpa dukungan Spatialite. Beberapa paket gdal-python mendukung ini, tetapi tidak semua. Coba buka shell OSGeo4W dan jalankan skrip Python dari lingkungan itu. Saya pikir paket default yang terkait untuk gdal-binmenyertakan dukungan ini.
Mike T
9

Cukup gunakan Fiona atau GeoPandas (Python 2.7.x dan 3.x)

Beberapa poligon

masukkan deskripsi gambar di sini

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

masukkan deskripsi gambar di sini

Transformasi ke titik (centroid)

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

masukkan deskripsi gambar di sini

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

Hasil

masukkan deskripsi gambar di sini

gen
sumber
Terima kasih atas gen jawabannya. Saya pikir Anda mungkin memiliki satu kesalahan ketik di atas di mana variabel 'gdf' harus 'poly "benar? Di points.crs = kode gdf.crs. Saya juga mengalami beberapa masalah lain di mana file .prj tidak mendapatkan dibuat, itu muncul kosong dan urutan bidang atribut mengubah urutan mereka dari data poligon karena mereka sekarang menjadi abjad. Penting mereka tetap dalam urutan yang sama. Anda tahu cara untuk menjaga atribut bidang tetap sama memesan?
wilbev
Terima kasih sudah dikoreksi. Untuk urutan bidang atribut, cukup ubah urutan GeoPandas GeoDataFrame (= Pandas DataFrame)
gen
Terima kasih Gene, tapi saya tidak yakin saya mengerti di mana saya akan mengubah urutan kode di sini. Saya juga mengalami dua masalah lain dengan ini. Pertama file * .prj kosong pada file shp baru. Kedua, ketika saya mencoba untuk membuka file shp di shp reader itu memberikan kesalahan membuka file seperti itu rusak. Tampaknya berfungsi tanpa menjadi korup jika file shp hanya memiliki fitur tunggal tetapi kelipatannya merupakan tempat yang sepertinya bermasalah.
wilbev
Maaf, tetapi Anda perlu tahu Pandas untuk itu dan saya tidak punya masalah dengan skrip dengan data saya (saya menggunakan versi terbaru GeoPandas, Fiona dan Numpy)
gen
Saya dapat mengirimkan Anda file shp sehingga Anda dapat melihat sendiri tetapi file shp ini memiliki lebih dari 250 kolom data yang saya bayangkan menciptakan masalah untuknya. Saya mencoba ini pada file shp dengan atribut yang jauh lebih sedikit dan sepertinya tidak ada masalah.
wilbev
5

Cara lain, mungkin lebih 'rendah', adalah dengan langsung menggunakan fionadan shapelyuntuk I / O dan pemrosesan geometri.

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
sumber
Terima kasih Loic. Itu pasti memperbaiki masalah semacam yang saya alami tetapi itu tidak memperbaiki masalah dengan begitu banyak atribut yang menyebabkan file menjadi rusak. Apakah Anda punya ide lain tentang cara mengatasi masalah itu? Saya kira saya mungkin perlu menghapus atribut. Saya dapat mengirimkan Anda sebuah file contoh jika itu akan membantu.
wilbev
@wilbev Kirim tautan unduhan ke data Anda jika Anda bisa. Kalau tidak, saya tidak melihat apa yang salah.
Loïc Dutrieux
Loic, saya mengirimi Anda email contoh file. Semoga itu memberi Anda ide bagus tentang masalah yang saya hadapi.
wilbev
@wilbev apa yang Anda maksud dengan 'file menjadi korup'? Dengan menggunakan file yang Anda kirim, saya dapat menghasilkan centroid dan membuka shapefile output di QGIS tanpa masalah. Tabel atribut tetap tidak berubah di antara kedua file.
Loïc Dutrieux
Oleh korup, maksud saya itu pada dasarnya file dbf kosong karena setelah saya menjalankan skrip itu menciptakan file dbf berukuran 1 KB dan ketika Anda membuka itu benar-benar kosong. Jika saya menjalankan skrip persis yang sama, yang Anda daftarkan di atas, pada file dengan atribut lebih sedikit, ia berfungsi tanpa masalah. Saya bahkan mencoba pada PC kedua dan mendapatkan hasil yang sama. Saya tidak mengerti.
wilbev
2

Saya pikir cara termudah adalah dengan menggunakan gdal / ogr Virtual Format. ( http://www.gdal.org/drv_vrt.html ) dan dialek SQL / SQLITE ( http://www.gdal.org/ogr_sql.html dan https://www.gaia-gis.it/spatialite-3.0 .0-BETA / spatialite-sql-3.0.0.html )

Shapefile poligon saya bernama poly.shp. Kemudian saya membuat file seperti XML ini bernama vrt.vrt. Di dalam file ini (vrt.vrt), di sini konten untuk dikonversi ke poin

<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>

Saat ini, Anda dapat mengintegrasikan file ini ke Qgis untuk divalidasi. Yang pasti, rendering lebih lambat dari sumber mentah karena setiap fitur ditampilkan sebagai titik pada setiap permintaan rendering.

Setelah itu, konversikan file ini (vrt.vrt) menjadi sesuatu yang lain menggunakan util gdal / ogr dari python shell / script

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

Anda mendapatkan shapefile titik bernama point_from_vrt.shp.

PEL
sumber
Saya bisa mendapatkan ini berfungsi tetapi saya ingin menyimpan semua ini dalam skrip python karena saya perlu mengkonversi 100-an file semua dengan nama file yang berbeda. Saya ingin menggunakan solusi @Mike T tetapi saya mendapatkan "Tidak ada fungsi seperti itu: ST_Centroid jika saya menggunakannya dan saya juga mencoba ST_PointOnSurface yang juga mengatakan tidak ada fungsi seperti itu. Setiap ide mengapa ini menyatakan bahwa ini bukan fungsi dari ExecuteSQL ()?
wilbev
Saya dapat'wkbPoints' is not a valid value of the atomic type
Ben Sinclair