Membuat bidang tabel atribut QGIS otomatis?

9

Saya sedang bekerja dengan cara membuat proyek hidrologi menggunakan QGIS dan lembar kerja Excel yang saya miliki. Untuk melakukan ini, saya ingin mengekstraksi beberapa informasi dari garis, termasuk dalam lapisan vektor, yang mewakili bagian pipa.

Informasi yang perlu saya ekstrak adalah:

  • Nomor ID
  • Panjangnya
  • X, Y memulai dan mengakhiri koordinat

Saya telah menemukan cara untuk menangkap bidang ini menggunakan "$ length" dan algoritma lain untuk koordinat X dan Y, tetapi untuk itu saya perlu membuka tabel Attributes, meletakkan ekspresi di setiap kolom atribut dan klik untuk memperbarui bidang.

Apakah ada cara ketika saya menggambar garis bidang ini diisi secara otomatis? Yaitu, saya menggambar / mengedit garis (mulai mengedit atau mengakhiri node) dan ketika saya membuka tabel atribut, bidang panjang dan koordinat X, Y diisi dan diperbarui.

LeoNazareth
sumber
1
Tidak yakin apakah itu mungkin saat dalam mode edit seperti yang dilakukan dalam tabel sementara. Tapi Anda mungkin melihat aksi. Anda dapat menggunakannya misalnya untuk menjalankan kode python untuk mengisi perhitungan Anda. Yah Anda harus menekan tombol ekstra untuk menjalankannya dari tabel atribusi sekalipun. Anda dapat melihat kemungkinan yang ada dan melihat apakah itu sesuai dengan ide Anda.
Matte

Jawaban:

7

Jika Anda hanya membutuhkan bidang ini di dalam QGIS , Anda dapat menggunakan bidang virtual. Ini memungkinkan menggunakan ekspresi (seperti $length) yang tergantung pada nilai-nilai lain atau geometri.

Buka kalkulator bidang, tambahkan bidang baru dengan panjang nama, centang kotak "Bidang Virtual" dan masukkan $lengthsebagai ekspresi (atau yang lainnya untuk bidang lainnya).

Namun ini tidak akan disimpan ke file excel.

Jika Anda ingin menyimpan file excel dalam sinkronisasi dengan file shp untuk geometri dan menyertakan bidang turunan dalam file excel, ada sebuah plugin bernama ShpSync yang mengetahui konsep ini dan memperbarui bidang secara otomatis ketika fitur diubah, ditambahkan atau dihapus.

Matthias Kuhn
sumber
Sebenarnya, jawaban di bawah ini berfungsi persis seperti yang saya inginkan, tetapi plugin yang Anda katakan ini akan berfungsi untuk langkah selanjutnya dari proyek saya. Terima kasih atas bantuan Anda
LeoNazareth
15

Pertanyaan menarik! Saya tidak mengetahui cara lain untuk mencapai apa yang Anda inginkan, tetapi menggunakan PyQGIS.

Baca kode di bawah ini. Ini memiliki beberapa teks di dalamnya: 'lines', 'length', 'startX', 'startY', 'endX', 'endY'. Anda dapat menyesuaikan nama-nama itu dalam skrip agar dapat berfungsi pada data Anda. Yang pertama adalah Anda nama lapisan, sedangkan sisanya sesuai dengan nama bidang. Saya menganggap layer baris Anda memiliki bidang-bidang tersebut (setelah semua, Anda ingin nilai ditulis di sana).

Setelah Anda menyesuaikan nama layer Anda dan nama-nama bidang yang ingin Anda perbarui secara otomatis, salin dan tempel skrip ke konsol Python QGIS.

Jika semuanya berjalan dengan baik, Anda harus dapat melihat bahwa nilai-nilai bidang secara otomatis diperbarui dalam dua skenario: 1) Ketika fitur baru ditambahkan, dan 2) Ketika geometri dimodifikasi.

# Initialize required variables
myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
lengthField = myLayer.fieldNameIndex( 'length' )
startXField = myLayer.fieldNameIndex( 'startX' )
startYField = myLayer.fieldNameIndex( 'startY' )
endXField = myLayer.fieldNameIndex( 'endX' )
endYField = myLayer.fieldNameIndex( 'endY' )

# Slot, updates field values
def updateFeatureAttrs( fId, geom=None ):
    f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
    if not geom:
        geom = f.geometry() 
    myLayer.changeAttributeValue( fId, lengthField, geom.length() )
    myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
    myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
    myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
    myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )

# Update feature attributes when new features are added or geometry changes
myLayer.featureAdded.connect( updateFeatureAttrs )
myLayer.geometryChanged.connect( updateFeatureAttrs )

Begini Cara kerjanya:

Pembaruan otomatis bidang dalam QGIS

Jika Anda memiliki masalah saat menjalankan skrip, tambahkan komentar di bawah jawaban ini.

Mungkin berguna bagi Anda untuk memiliki fungsi ini sudah tersedia ketika Anda membuka proyek QGIS Anda. Jika itu masalahnya, katakan padaku, aku bisa mengirim instruksi untuk melakukan itu.


EDIT:

Agar fungsionalitas ini tersedia setiap kali Anda membuka proyek QGIS Anda (yaitu, .qgsfile yang berisi, antara lain, lapisan baris Anda), Anda perlu mengikuti langkah-langkah ini:

  1. Pergi ke QGIS->Project->Project Properties->Macros, periksa Python macrosopsi, dan ganti seluruh kode dengan yang ini (sesuaikan nilai yang menunjukkan nama layer dan field Anda):

    from qgis.core import QgsMapLayerRegistry, QgsFeatureRequest
    def openProject():    
        # Initialize required variables
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
    
        # Update feature attributes when new features are added or geometry changes
        myLayer.featureAdded.connect( updateFeatureAttrs )
        myLayer.geometryChanged.connect( updateFeatureAttrs )
    
    # Slot, updates field values
    def updateFeatureAttrs( fId, geom=None ):
        myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'lines' )[0]
        lengthField = myLayer.fieldNameIndex( 'length' )
        startXField = myLayer.fieldNameIndex( 'startX' )
        startYField = myLayer.fieldNameIndex( 'startY' )
        endXField = myLayer.fieldNameIndex( 'endX' )
        endYField = myLayer.fieldNameIndex( 'endY' )
        f = myLayer.getFeatures( QgsFeatureRequest( fId ) ).next()    
        if not geom:
            geom = f.geometry() 
        myLayer.changeAttributeValue( fId, lengthField, geom.length() )
        myLayer.changeAttributeValue( fId, startXField, geom.vertexAt( 0 )[0] )
        myLayer.changeAttributeValue( fId, startYField, geom.vertexAt( 0 )[1] )
        myLayer.changeAttributeValue( fId, endXField, geom.asPolyline()[-1][0] )
        myLayer.changeAttributeValue( fId, endYField, geom.asPolyline()[-1][1] )
    
    def saveProject():
        pass
    
    def closeProject():
        pass
    
  2. Pastikan Anda mengaktifkan macro pada proyek Anda, cara ini: Settings->Options->General->Enable macros: Always.

  3. Simpan proyek QGIS Anda.

Sekarang, setiap kali Anda membuka .qgsfile yang baru saja Anda simpan, atribut dari layer garis Anda akan secara otomatis diperbarui ketika Anda menambahkan fitur baru atau memodifikasi geometri (yaitu, tidak perlu menyalin apa pun ke dalam Konsol Python QGIS lagi).


EDIT ke-2:

Saya baru saja menerbitkan sebuah plugin yang disebut AutoFields untuk membantu orang menyelesaikan masalah seperti ini. Saya bahkan membuat video yang menunjukkan bagaimana menyelesaikan masalah Anda, Anda dapat menontonnya di:

https://vimeo.com/germap/autofields-geometric-properties

Dokumentasi AutoFields: http://geotux.tuxfamily.org/index.php/en/geo-blogs/item/333-autofields-plugin-for-qgis

Germán Carrillo
sumber
2
Inilah yang saya cari. Sebenarnya saya menggunakan kode Anda untuk menangkap koordinat X, Y, yang saya temukan di jawaban lama Anda di tautan posting ini , sama dengan yang Anda posting sekarang. Saya sudah menguji otomasi dan berfungsi dengan baik. Saya menyimpan kode Python sebagai file ".pycl". Jika Anda bisa menjelaskan kepada saya bagaimana itu bisa tersedia ketika saya membuka proyek QGIS saya akan menjadi luar biasa. Terima kasih atas bantuannya.
LeoNazareth
1
Jerman, itu jawaban yang luar biasa! Terima kasih! Saya belajar banyak dari Anda dengan apa yang Anda posting!
jbgramm
1
Saya sebenarnya sedang mengerjakan sebuah plugin yang akan memungkinkan Anda untuk melakukan hal itu. Karena saya hanya dapat mencurahkan waktu luang untuk pengembangannya, saya tidak dapat memberi tahu Anda tanggal rilis yang diharapkan. Sementara itu, Anda dapat menjalankan cuplikan kode 1 saya setelah Anda menambahkan Tramo.shp, menyesuaikan: myLayer = QgsMapLayerRegistry.instance().mapLayersByName( 'Tramo' )[0]Jika Anda benar-benar tertarik dengan plugin saya di masa depan, silakan kirim saran apa pun yang Anda miliki, saya menghargai itu. Anda dapat menghubungi saya di GeoTux .
Germán Carrillo
1
Itu akan bagus untuk saya (dan untuk banyak orang, tentu saja), saya sudah menggunakan kode dengan penyesuaian yang Anda sarankan. Saya akan menunggu dengan cemas plugin baru Anda, dan jika saya pikir dalam sesuatu yang bermanfaat saya menghubungi Anda. Terimakasih untuk semuanya.
LeoNazareth
1
@ LeoNazareth, apakah Anda ingin menguji plugin? Sudah bersiap, tapi saya ingin melakukan beberapa tes sebelum merilisnya. Jika Anda bersedia mengujinya, silakan kirim saya email .
Germán Carrillo
2

Untuk QGIS 3 pergi ke Layers Properties=> Attributes Form=> pilih bidang Anda dengan nilai-nilai geometri (misalnya, area) => ketik $areadalam Defaults valuekotak dan centang Apply default value on update. Ini juga bisa menjadi berguna: $perimeter, $y, $x,$id

Kamerad Che
sumber
1

Saya akan meletakkan data dalam database (PostGIS) dan mengekstrak data ke QGIS dengan tampilan (mungkin terwujud).

nielsgerrits
sumber