¿Cómo puedo crear y agregar funciones programáticamente a una capa de memoria en QGIS 1.9?


13

Tenía un complemento de trabajo en QGIS 1.8 que leía datos de una base de datos MSAccess y los agregaba a una serie de capas de memoria. Hay algo de procesamiento involucrado en el ínterin, así que no creo que usar QGIS para leer directamente desde la base de datos sea una opción.

Me gustaría pasar de QGIS 1.8 a 1.9 (principalmente debido a la calidad mejorada del compositor de impresión). El complemento no funciona con la nueva API.

He intentado una variedad de métodos que surgieron en las búsquedas de google. Uno, modificando el código a continuación, de http://www.qgis.org/pyqgis-cookbook/vector.html#memory-provider , es decir, agregando geometría y atributos al proveedor de datos y luego actualizando la capa, para adaptarlo al nuevo API trabajado un poco, pero los atributos no eran visibles hasta que ingresé manualmente al modo de edición (similar a http://hub.qgis.org/issues/3713 ). Un enfoque alternativo, detallado en la respuesta n. ° 1 del enlace anterior, agregó la capa y los atributos correctamente, pero no pude agregar características a la capa.

Dado que debería ser una tarea bastante simple, espero que alguien aquí pueda ofrecer un ejemplo práctico de cómo se debe hacer esto. (PD: No soy un programador profesional y la mayor parte de mi codificación es bastante tosca; agradezco cualquier orientación, pero le pido que disculpe un poco de ignorancia de mi parte)

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

Eche un vistazo al complemento PinPoint. Agrega características con atributos a una capa de memoria y funciona con la API 2.0.
gsherman

Muy bien, funciona como un encanto. Usé este ejemplo para agregar una capa con puntos de un servicio restfull. QGis es genial
Peter Venema

Respuestas:


8

Gracias a gsherman, el ejemplo del complemento PinPoint es perfecto.

Según tengo entendido, el proceso es:

  1. Cree la capa con los atributos en la cadena de construcción.
  2. Agregue dicha capa al registro del mapa
  3. Comience a editar en esa capa
  4. Agregue funciones y confirme los cambios

Aquí hay un extracto de mi código que ahora funciona.

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

6

Según la respuesta de Adam Bioletti, las pruebas adicionales del proceso descrito muestran que el único requisito esencial es comenzar a editar la capa de memoria antes de realizar cambios, como crear atributos y características, y luego confirmar los cambios. Esto se puede hacer antes de agregar la capa al mapa de registro.

Aquí hay una actualización del código del Cookbook que funciona con la 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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.