Escribir Scripts Python para el Marco de Procesamiento

Advertencia

Una nueva versión de este tutorial está disponible en Escribir Scripts Python para el Marco de Procesamiento (QGIS3)

Uno puede escribir scripts pyqgis autónomos que pueden ser ejecutados mediante la Consola Python en QGIS. Con unos pocos ajustes, puede hacer que sus scripts autónomos corran mediante el Marco de Procesamiento. Esto tiene varias ventajas. Primero, tomar la entrada de usuario y escribir archivos de salida es de lejos más fácil debido a que el Marco de Procesamiento ofrece un interfaz de usuario estandarizado para éstos. Segundo, el tener un script en la Caja de Herramientas de Procesamiento también le permite ser parte de cualquier Modelo de Procesamiento o ser ejecutado como un trabajo por Lote con múltiples entradas. Este tutorial mostrará cómo escribir un script python personalizado que puede ser parte de un Marco de Procesamiento en QGIS.

Vista general de la tarea

Nuestro script realizará una operación de disolución basada en un campo escogido por el usuario. También sumará valores para otro campo para las entidades disueltas. En el ejemplo, disolveremos un archivo shape del mundo basado en un atributo SUBREGION y sumaremos el campo POP_EST para calcular la población total en la región disuelta.

Nota

Si está buscando hacer una operación Disolución junto con Estadísticas, puede usar el excelente complemento DissolveWithStats. Este script es una demostración de cómo implementar una funcionalidad similar mediante un script de Procesamiento.

Obtener los datos

Usaremos el conjunto de datos Admin 0 - Countries de Natural Earth.

Descargue el archivo shape Admin 0 - countries..

Fuente de Datos [NATURALEARTH]

Para su comodidad, puede descargar directamente una copia de los conjuntos de datos de los enlaces abajo:

ne_10_admin_0_countries.zip

Procedimiento

  1. Abra QGIS y vaya a Capa ‣ Añadir capa ‣ Añadir Capa Vectorial. Explore el archivo descargado ne_10_admin_0_countries.zip y cargue la capa ne_10_admin_0_countries. Vaya a Procesos ‣ Caja de Herramientas.

../_images/1204.png
  1. Expanda el grupo Scripts en la Caja de herramientas de Procesos y seleccione Crear script nuevo.

../_images/2169.png
  1. Para que un script python sea reconocido como un script de Procesamiento, el inicio del script debe ser las especificaciones de la entrada y salidas. Esto será usado para construir el interfaz de usuario para ejecutar el script. Puede aprender más acerca del formato de estas líneas de la QGIS Documentación de Procesamiento. Ingrese las siguientes líneas en el Editor de Script. Aquí estamos especificando 3 entradas de usuario: dissolve_layer, dissolve_field y sum_field. Note que estamos agregando dissolve_layer después de ambas definiciones de entrada de campo. Esto significa que la entrada será pre-poblada con una selección de campos de dissolve_layer. También especificamos la output_layer como la capa vectorial de salida. Clic en el botón Guardar.

##dissolve_layer=vector
##dissolve_field=field dissolve_layer
##sum_field=field dissolve_layer
##output_layer=output vector
../_images/3107.png
  1. Nombre el script como dissolve_with_sum y guárdelo en la ubicación predeterminada bajo la carpeta .qgis2 ‣ processing ‣ scripts.

../_images/470.png
  1. De vuelta en el Editor de scripts, clic en el botón Ejecutar script para previsualizar el interfaz de usuario.

../_images/564.png
  1. Puede ver que con solo agregar unas pocas líneas, tenemos un agradable interfaz de usuario para que se especifiquen las entradas. Esto es también consistente con todos los algoritmo de Procesos, por lo que nos existe una curva de aprendizaje involucrada en el uso de su algoritmo personalizado.

../_images/661.png
  1. En el Editor de scripts, ingrese el siguiente código. Notará que estamos usandos algunos métodos especiales como processing.getObject() y processing.features(). Estos son wrappers convenientes para facilitan el trabajo con datos. Puede aprender más acerca de éstos de la sección Additional functions for handling data de la Documentación de Procesamiento QGIS. Clic en Guardar para guardar el código recientemente ingresado y luego el botón X para cerrar el editor.

Nota

Este script usa extensamente del entendimiento de lista de python. Déle una mirada a este tutorial de entendimiento de lista para familiarizarse con la sintáxis.

from qgis.core import *
from PyQt4.QtCore import *

inlayer = processing.getObject(dissolve_layer)
dissolve_field_index = inlayer.fieldNameIndex(dissolve_field)
sum_field_index = inlayer.fieldNameIndex(sum_field)

# Find unique values present in the dissolve field
unique_values = set([f[dissolve_field] for f in
processing.features(inlayer)])

print unique_values
../_images/760.png
  1. Mientras escribe código, es importante que sea capaz de ver errores y depure su código. Sus scripts de procesamiento pueden ser fácilmente depurados mediante la Consola de Python incorporada. En la ventana principal QGIS, vaya a Plugins ‣ Consola de Python. Una vez esté abierta la consola, encuentre su script en la Caja de herramientas de Procesos y doble-clic para iniciarlo.

../_images/858.png
  1. Seleccione SUBREGION como el campo de disolución. Puede elegir cualquier campo como el campo de suma ya que el script aún no tiene ningún código para lidiar con ello. Clic en Ejecutar.

../_images/957.png
  1. Verá un diálogo de error. Esto era esperado ya que el script está incompleto y aún no genera ninguna salida.

../_images/1065.png
  1. En la ventana principal QGIS, verá la salida de depuración del script impresa en la consola. Esta es una forma útil para agregar instrucciones de impresión y ver valores intermedios de variable.

../_images/11104.png
  1. Volvamos a la edición del script haciendo clic derecho al script y seleccionando Editar Script.

../_images/1266.png
  1. Ingrese el siguiente código para completar el script. Note que estamos usando el algoritmo existente de disolución en QGIS mediante el procesamiento usando el método processing.runalg().

# Create a dictionary to hold values from the sum field
sum_unique_values = {}
attrs = [f.attributes() for f in processing.features(inlayer)]

for unique_value in unique_values:
    val_list = [ f_attr[sum_field_index] for f_attr in attrs if f_attr[dissolve_field_index] == unique_value]
    sum_unique_values[unique_value] = sum(val_list)

# Run the regular Dissolve algorithm
processing.runalg("qgis:dissolve", dissolve_layer, "false",
    dissolve_field, output_layer)

# Add a new attribute called 'SUM' in the output layer
outlayer = processing.getObject(output_layer)
provider = outlayer.dataProvider()
provider.addAttributes([QgsField('SUM', QVariant.Double)])
outlayer.updateFields()

# Set the value of the 'SUM' field for each feature
outlayer.startEditing()
new_field_index = outlayer.fieldNameIndex('SUM')
for f in processing.features(outlayer):
  outlayer.changeAttributeValue(f.id(), new_field_index, sum_unique_values[f[dissolve_field]])
outlayer.commitChanges()
../_images/1363.png
  1. Ejecute el algoritmo seleccionado SUBREGION como el campo de disolución y POP_EST como el campo de suma. Clic en Ejecutar.

Nota

El algoritmo de procesamiento puede tomar hasta 10 minutos para finalizar dependiendo de su sistema.

../_images/1460.png
  1. Una vez que termine el procesamiento, puede usar la herramienta Identificar y hacer clic en cualquier polígono. Verá el campo recién agregado SUM con los valores POP_EST de todos los polígonos originales sumados.

../_images/1555.png
  1. Notará que todos los otros campos en la salida aún están presentes. Cuando disuelve varios objetos espaciales para crear un solo objeto, no toma en cuenta la mantención de los campos originales en la salida. Vuelva al Editor de script y agregue el siguiente código para borrar todos los campos excepto el campo SUM y el campo que fue usado para disolver la capa original. Clic en el botón Guardar y cierre la ventana.

# Delete all fields except dissolve field and the newly created 'SUM' field.
outlayer.startEditing()

fields_to_delete = [fid for fid in range(len(provider.fields())) if fid != new_field_index and fid != dissolve_field_index]
provider.deleteAttributes(fields_to_delete)
outlayer.updateFields()

outlayer.commitChanges()
../_images/1652.png
  1. Una de las funcionalidades escondidas del Marco de Procesamiento es que todos los algoritmos pueden trabajar sobre los objetos espaciales seleccionados de una capa. Esto es muy útil cuando quiere ejecutar un algoritmo en un subconjunto de una capa. Como nuestro script usa el método processing.features() para leer los objetos, respetará la selección actual. Para demostrar eso, hagamos primero una selección. Clic en el botón Seleccionar objetos espaciales usando una expresión.

../_images/1749.png
  1. Ingrese la siguiente expresión para seleccionar objetos espaciales de Norte y Sud América y clic en Seleccionar.

"CONTINENT" = 'North America' OR "CONTINENT" = 'South America'
../_images/1846.png
  1. Verá que los objetos seleccionados son resaltados en amarillo. Clic-derecho el script dissolve_with_sum y seleccione Ejecutar.

../_images/1937.png
  1. Seleccione las entradas como antes y clic en Ejecutar.

../_images/2032.png
  1. Una nueva capa de salida se agregará a QGIS. Esto contendrá geometrías disueltas sólo de los objetos seleccionados en la capa de entrada. También notará que la capa de salida contendrá sólo 2 campos como se espera.

../_images/2170.png
  1. Un trabajo final importante es documentar nuestro algoritmo. El Marco de Procesamiento tiene buenas herramientas para escribir y acceder a ayuda. Vaya a Editor de scipt y clic el botón Editar ayuda de script.

../_images/2232.png
  1. Llene los detalles para diferentes elementos y clic en Aceptar. Ahora una ayuda detallada estará disponible para todos los usuarios de su script en la pestaña Ayuda cuando inicie el algoritmo.

../_images/2329.png

Abajo está el script completo para referencia. Puede modificarlo para ajustarlo a sus necesidades.

##dissolve_layer=vector
##dissolve_field=field dissolve_layer
##sum_field=field dissolve_layer
##output_layer=output vector

from qgis.core import *
from PyQt4.QtCore import *

inlayer = processing.getObject(dissolve_layer)
dissolve_field_index = inlayer.fieldNameIndex(dissolve_field)
sum_field_index = inlayer.fieldNameIndex(sum_field)

# Find unique values present in the dissolve field
unique_values = set([f[dissolve_field] for f in processing.features(inlayer)])

# Create a dictionary to hold values from the sum field
sum_unique_values = {}
attrs = [f.attributes() for f in processing.features(inlayer)]
 
for unique_value in unique_values:
    val_list = [ f_attr[sum_field_index] for f_attr in attrs if f_attr[dissolve_field_index] == unique_value]
    sum_unique_values[unique_value] = sum(val_list)

# Run the regular Dissolve algorithm
processing.runalg("qgis:dissolve", dissolve_layer, "false",
    dissolve_field, output_layer)

# Add a new attribute called 'SUM' in the output layer
outlayer = processing.getObject(output_layer)
provider = outlayer.dataProvider()
provider.addAttributes([QgsField('SUM', QVariant.Double)])
outlayer.updateFields()

# Set the value of the 'SUM' field for each feature
outlayer.startEditing()
new_field_index = outlayer.fieldNameIndex('SUM')
for f in processing.features(outlayer):
  outlayer.changeAttributeValue(f.id(), new_field_index, sum_unique_values[f[dissolve_field]])
outlayer.commitChanges()

# Delete all fields except dissolve field and the newly created 'SUM' field
outlayer.startEditing()
fields_to_delete = [fid for fid in range(len(provider.fields())) if fid != new_field_index and fid != dissolve_field_index]
provider.deleteAttributes(fields_to_delete)
outlayer.updateFields()
outlayer.commitChanges()

If you want to give feedback or share your experience with this tutorial, please comment below. (requires GitHub account)