Bagaimana saya bisa secara programatik membuat dan menambahkan fitur ke lapisan memori di QGIS 1.9?

13

Saya memiliki plugin yang berfungsi di QGIS 1.8 yang membaca data dari database MSAccess dan menambahkannya ke serangkaian lapisan memori. Ada beberapa pemrosesan yang terlibat untuk sementara jadi saya tidak berpikir hanya menggunakan QGIS untuk membaca langsung dari database adalah sebuah pilihan.

Saya ingin beralih dari QGIS 1.8 ke 1.9 (terutama karena peningkatan kualitas komposer cetak). Plugin tidak berfungsi dengan API baru.

Saya sudah mencoba berbagai metode yang muncul dalam pencarian google. Pertama, memodifikasi kode di bawah ini - dari http://www.qgis.org/pyqgis-cookbook/vector.html#memory-provider , yaitu menambahkan geometri dan atribut ke dataprovider dan kemudian memperbarui layer - agar sesuai dengan API baru yang berfungsi sedikit tapi atributnya tidak terlihat sampai saya memasuki mode editing (mirip dengan http://hub.qgis.org/issues/3713 ). Pendekatan alternatif, dirinci dalam balasan # 1 dari tautan di atas, menambahkan layer dan atribut dengan benar tetapi saya tidak dapat menambahkan fitur ke layer.

Mengingat bahwa itu harus menjadi tugas yang cukup sederhana, saya berharap seseorang di sini dapat menawarkan contoh yang baik tentang bagaimana ini harus dilakukan. (PS Saya bukan programmer profesional dan sebagian besar pengkodean saya cukup kasar - saya menyambut bimbingan apa pun tetapi meminta Anda memaafkan ketidaktahuan di pihak saya)

# Receivers = a list of lists returned from a database query

# create layer
vl = QgsVectorLayer("Point", item, "memory")
pr = vl.dataProvider()

# add fields
pr.addAttributes( [ QgsField("Rec_No", QVariant.Int), QgsField("Include",  QVariant.String), QgsField("Label",  QVariant.String), QgsField("X", QVariant.Double),
                    QgsField("Y", QVariant.Double), QgsField("Z", QVariant.Double), QgsField("Height", QVariant.Double),
                    QgsField("Project_Re", QVariant.String), QgsField("NCA", QVariant.String),
                    QgsField("DayCrit", QVariant.Int), QgsField("EveCrit", QVariant.Int), QgsField("NightCrit", QVariant.Int) ] )

for i in range(len(Receivers)):          
  # add a feature
  fet = QgsFeature()
  X = Receivers[i][3]
  Y = Receivers[i][4]
  fet.setGeometry( QgsGeometry.fromPoint(QgsPoint(X,Y)) )

  # Details = a list of results returned from a database query specific to each result in 'Receivers'

  if Receivers[i][3] != 0:
    Include = 'Yes'
  else:
    Include = 'No'

  fet.setAttributeMap( { 0 : QVariant(Receivers[i][0]), 1 : QVariant(Include), 2 : QVariant(Receivers[i][2]),
                         3 : QVariant(Receivers[i][3]), 4 : QVariant(Receivers[i][4]), 5 : QVariant(Receivers[i][5]), 6 : QVariant(Receivers[i][6]),
                         7 : QVariant(Details[0]), 8 : QVariant(Details[1]), 9 : QVariant(Details[2]), 10 : QVariant(Details[3]), 11 : QVariant(Details[4]) } )
  pr.addFeatures( [ fet ] )

# add a style
vl.loadNamedStyle('C:/OSGeo4W/apps/qgis/python/plugins/Gopher2QGIS/styles/Receiver_Style.qml')

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.commitChanges()
vl.updateExtents()
vl.updateFieldMap()

QgsMapLayerRegistry.instance().addMapLayer(vl)
Adam Bioletti
sumber
Lihatlah plugin PinPoint. Ini menambahkan fitur dengan atribut ke lapisan memori dan bekerja dengan API 2.0.
gsherman
Sangat bagus, bekerja seperti pesona. Saya menggunakan contoh ini untuk menambahkan layer dengan poin dari layanan restfull. QGis luar biasa
Peter Venema

Jawaban:

8

Berkat gsherman di atas, contoh plugin PinPoint sempurna.

Seperti yang saya pahami, prosesnya adalah:

  1. Buat layer dengan atribut dalam string konstruksi
  2. Tambahkan kata layer ke registry peta
  3. Mulai mengedit pada layer itu
  4. Tambahkan fitur dan komit perubahan

Ini adalah ekstrak kode saya yang sekarang berfungsi.

layer =  QgsVectorLayer(
          "Point?field=Rec_No:integer&field=Include:string(120)&field=Label:string(120)&field=X:double&field=Y:double&field=Z:double&field=Height:double&field=Project_Re:string(120)&field=NCA:string(120)&field=DayCrit:integer&field=EveCrit:integer&field=NightCrit:integer",
          item,
          "memory")
QgsMapLayerRegistry.instance().addMapLayer(layer)

# Receivers = as in the above example 'Receivers' is a list of results
for i in range(len(Receivers)):

  # add a feature
  feature = QgsFeature()

  X = Receivers[i][3]
  Y = Receivers[i][4]
  feature.setGeometry( QgsGeometry.fromPoint(QgsPoint(X,Y)) )

  # Details = as in the above example 'Details' is a list of results

  if Receivers[i][1] != 0:
    Include = 'Yes'
  else:
    Include = 'No'

  values = [ QVariant(Receivers[i][0]), QVariant(Include), QVariant(Receivers[i][2]),
                         QVariant(Receivers[i][3]), QVariant(Receivers[i][4]), QVariant(Receivers[i][5]), QVariant(Receivers[i][6]),
                         QVariant(Details[0]), QVariant(Details[1]), QVariant(Details[2]), QVariant(Details[3]), QVariant(Details[4]) ]

  feature.setAttributes(values)
  layer.startEditing()
  layer.addFeature(feature, True)
  layer.commitChanges()
Adam Bioletti
sumber
6

Berdasarkan jawaban oleh Adam Bioletti, tes lebih lanjut untuk proses yang dijelaskan menunjukkan bahwa satu-satunya persyaratan penting adalah mulai mengedit lapisan memori sebelum membuat perubahan, seperti membuat atribut dan fitur, dan kemudian melakukan perubahan. Ini dapat dilakukan sebelum menambahkan lapisan ke peta registri.

Berikut pembaruan kode Cookbook yang berfungsi dengan API 2.0:

# create layer
vl = QgsVectorLayer("Point", "temporary_points", "memory")
pr = vl.dataProvider()

# changes are only possible when editing the layer
vl.startEditing()
# add fields
pr.addAttributes([QgsField("name", QVariant.String),QgsField("age", QVariant.Int),QgsField("size", QVariant.Double)])

# add a feature
fet = QgsFeature()
fet.setGeometry(QgsGeometry.fromPoint(QgsPoint(10,10)))
fet.setAttributes(["Johny", 2, 0.3])
pr.addFeatures([fet])

# commit to stop editing the layer
vl.commitChanges()

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

# add layer to the legend
QgsMapLayerRegistry.instance().addMapLayer(vl)
Jorge Gil
sumber