Jak mogę programowo tworzyć i dodawać funkcje do warstwy pamięci w QGIS 1.9?

13

Miałem działającą wtyczkę w QGIS 1.8, która odczytywała dane z bazy danych MSAccess i dodała je do szeregu warstw pamięci. Tymczasowe przetwarzanie wiąże się z pewnym przetwarzaniem, więc nie sądzę, aby używanie QGIS do odczytu bezpośrednio z bazy danych było opcją.

Chciałbym przejść z QGIS 1.8 do 1.9 (głównie ze względu na lepszą jakość kompozytora wydruku). Wtyczka nie działa z nowym interfejsem API.

Wypróbowałem wiele metod, które pojawiły się w wyszukiwaniach Google. Jeden, modyfikując poniższy kod - z http://www.qgis.org/pyqgis-cookbook/vector.html#memory-provider , tj. Dodając geometrię i atrybuty do dostawcy danych, a następnie aktualizując warstwę - w celu dopasowania do nowego API działającego trochę, ale atrybuty nie były widoczne, dopóki ręcznie nie przeszedłem do trybu edycji (podobnie do http://hub.qgis.org/issues/3713 ). Alternatywne podejście, szczegółowo opisane w odpowiedzi nr 1 powyższego łącza, dodało warstwę i atrybuty poprawnie, ale nie mogłem dodać funkcji do warstwy.

Biorąc pod uwagę, że powinno to być dość proste zadanie, mam nadzieję, że ktoś tutaj może zaoferować praktyczny przykład tego, jak należy to zrobić. (PS Nie jestem profesjonalnym programistą i większość mojego kodowania jest dość prymitywna - z zadowoleniem przyjmuję wszelkie wskazówki, ale proszę o usprawiedliwienie mojej niewiedzy)

# 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
źródło
Spójrz na wtyczkę PinPoint. Dodaje funkcje z atrybutami do warstwy pamięci i współpracuje z interfejsem API 2.0.
gsherman
Bardzo dobrze, działa jak urok. Użyłem tego przykładu, aby dodać warstwę z punktami z usługi restfull. QGis jest świetny
Peter Venema

Odpowiedzi:

8

Dzięki gsherman powyżej wtyczki PinPoint przykład jest idealny.

Jak rozumiem, proces jest następujący:

  1. Utwórz warstwę z atrybutami w ciągu konstrukcyjnym
  2. Dodaj wspomnianą warstwę do rejestru map
  3. Rozpocznij edycję na tej warstwie
  4. Dodaj funkcje i zatwierdź zmiany

Oto fragment mojego kodu, który teraz działa.

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
źródło
6

Na podstawie odpowiedzi Adama Biolettiego dalsze testy opisanego procesu pokazują, że jedynym niezbędnym wymogiem jest rozpoczęcie edycji warstwy pamięci przed wprowadzeniem jakichkolwiek zmian, takich jak tworzenie atrybutów i funkcji, a następnie zatwierdzenie zmian. Można to zrobić przed dodaniem warstwy do rejestru map.

Oto aktualizacja kodu Cookbook, który współpracuje z 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
źródło