• Non ci sono risultati.

PyQGIS developer cookbook Versión 3.4

N/A
N/A
Protected

Academic year: 2021

Condividi "PyQGIS developer cookbook Versión 3.4"

Copied!
138
0
0

Testo completo

(1)

Versión 3.4

QGIS Project

15 de marzo de 2020

(2)
(3)

1 Introducción 1

1.1 Desarrollar scripts en la consola de Python . . . 2

1.2 Plugins Python . . . 2

1.3 Ejecutar código Python cuando QGIS se inicia. . . 3

1.4 Aplicaciones Python . . . 3

1.5 Notas técnicas sobre PyQt y SIP . . . 6

2 Cargar proyectos 7 3 Cargar capas 9 3.1 Capas Vectoriales. . . 9

3.2 Capas ráster . . . 12

3.3 Instancia QgsProject . . . 13

4 Usar las capas ráster 15 4.1 Detalles de la capa . . . 15

4.2 Renderizador . . . 16

4.3 Valores de consulta . . . 17

5 Usar capas vectoriales 19 5.1 Recuperando información sobre atributos . . . 20

5.2 Iterando sobre la capa vectorial . . . 20

5.3 Seleccionando objetos espaciales . . . 21

5.4 Modificación de capas vectoriales . . . 23

5.5 Usar índice espacial . . . 26

5.6 Creación de capas vectoriales . . . 27

5.7 Apariencia (Simbología) de capas vectoriales . . . 30

5.8 Más Temas . . . 39

6 Manejo de Geometría 41 6.1 Construcción de Geometría . . . 41

6.2 Acceso a Geometría . . . 42

6.3 Geometría predicados y Operaciones . . . 43

7 Soporte de Proyecciones 45 7.1 Sistemas de coordenadas de referencia . . . 45

7.2 CRS Transformation . . . 46

8 Usando el Lienzo de Mapa 49 8.1 Lienzo de mapa insertado . . . 50

8.2 Bandas elásticas y marcadores de vértices . . . 51

8.3 Utilizar las herramientas del mapa con el lienzo. . . 51

i

(4)

9 Representación del Mapa e Impresión 55

9.1 Representación Simple . . . 55

9.2 Representando capas con diferente SRC. . . 56

9.3 Output using print layout. . . 56

10 Expresiones, Filtros y Calculando Valores 59 10.1 Análisis de expresiones . . . 60

10.2 Evaluar expresiones . . . 60

10.3 Handling expression errors . . . 62

11 Configuración de lectura y almacenamiento 63 12 Comunicarse con el usuario 65 12.1 Showing messages. The QgsMessageBar class . . . 65

12.2 Mostrando el progreso . . . 67

12.3 Registro. . . 68

13 Infraestructura de autenticación 69 13.1 Introducción . . . 70

13.2 Glosario . . . 70

13.3 QgsAuthManager the entry point . . . 70

13.4 Adapt plugins to use Authentication infrastructure . . . 73

13.5 Authentication GUIs . . . 73

14 Tasks - doing heavy work in the background 77 14.1 Introducción . . . 77

14.2 Ejemplos . . . 78

15 Developing Python Plugins 83 15.1 Structuring Python Plugins. . . 83

15.2 Fragmentos de código . . . 91

15.3 Utilizar complemento Capas . . . 92

15.4 IDE settings for writing and debugging plugins . . . 93

15.5 Releasing your plugin . . . 99

16 Escribir nuevos complementos de procesamiento 103 17 Biblioteca de análisis de redes 105 17.1 Información general . . . 105

17.2 Contruir un gráfico . . . 106

17.3 Análisis gráfico . . . 107

18 Complementos de Python de QGIS Server 113 18.1 Server Filter Plugins architecture . . . 114

18.2 Raising exception from a plugin . . . 115

18.3 Escribiendo un complemento del servidor . . . 115

18.4 Complemento control de acceso . . . 119

19 hoja de referencia para PyQGIS 123 19.1 Interfaz de Usuario . . . 123

19.2 Configuración . . . 123

19.3 Barras de herramientas . . . 123

19.4 Menús . . . 124

19.5 Lienzo . . . 124

19.6 Capas . . . 124

19.7 Tabla de contenidos . . . 128

19.8 TOC avanzado . . . 128

(5)

iii

(6)
(7)

Introducción

Este documento pretende ser tanto un tutorial y una guía de referencia. Aunque no enumera todos los casos de uso posibles, debe proporcionar una buena visión general de la funcionalidad principal.

• Desarrollar scripts en la consola de Python

• Plugins Python

• Ejecutar código Python cuando QGIS se inicia.

– El fichero startup.py

– La variable de entorno PYQGIS_STARTUP

• Aplicaciones Python

– Usando PyQGIS en scripts individuales

– Usando PyQGIS en aplicaciones personalizadas – Ejecutar aplicaciones personalizadas

• Notas técnicas sobre PyQt y SIP

El soporte de Python se introdujo por primera vez en QGIS 0.9. Hay varias maneras de utilizar Python en QGIS Desktop (cubierto en las siguientes secciones):

• Emita comandos en la consola de Python dentro de QGIS

• Crear y usar plugins

• Ejecute automáticamente código Python cuando se inicie QGIS

• Crear aplicaciones personalizadas basadas en la API de QGIS

Los enlaces de Python también están disponibles para QGIS Server, incluidos los plugins de Python (veaComple- mentos de Python de QGIS Server) y los enlaces de Python que se pueden usar para incrustar QGIS Server en una aplicación de Python.

Esta es unacomplete QGIS APIde referencia que documenta las clases de la librería QGIS.The Pythonic QGIS API (pyqgis)es casi idéntica a la API de C++.

Un buen recurso para aprender a realizar tareas comunes es descargar complementos existentes desde elrepositorio de complementosy examinar su código.

1

(8)

1.1 Desarrollar scripts en la consola de Python

QGIS provee una consola Python integrada para scripting. Se puede abrir desde el menu: Complementos → Consola de Python

Figure 1.1: Consola Python de QGIS

La captura de pantalla anterior ilustra cómo obtener la capa seleccionada actualmente en la lista de capas, mostrar su ID y opcionalmente, si se trata de una capa vectorial, mostrar el recuento de entidades. Para la interacción con el entorno QGIS, hay una variable iface que es una instancia de la clase: QgisInterface <qgis.gui.QgisInterface>.

Esta interfaz permite el acceso al lienzo del mapa, menús, barras de herramientas y otras partes de la aplicación QGIS.

Para mayor comodidad del usuario, las siguientes instrucciones se ejecutan cuando se inicia la consola (en el futuro será posible establecer más comandos iniciales)

from qgis.core import * import qgis.utils

Para aquellos que utilizan la consola a menudo, puede ser útil establecer un acceso directo para activar la consola (dentro de Configuración → Atajos de teclado. . . )

1.2 Plugins Python

La funcionalidad de QGIS se puede ampliar utilizando complementos. Los complementos se pueden escribir en Python. La principal ventaja sobre los complementos de C++ es la simplicidad de la distribución (sin compilación para cada plataforma) y el desarrollo más fácil.

Muchos complementos que cubren diversas funciones se han escrito desde la introducción del soporte de Python.

El instalador de complemento permite a los usuarios buscar, actualizar y eliminar fácilmente complementos Python. Consulte la páginaComplementos de Pythonpara más información sobre complementos y desarrollo de complementos.

Crear plugins con Python es simple, veaDeveloping Python Pluginspara instrucciones detalladas.

Nota: Los plugins de Python están también disponibles para QGIS Server. VeaComplementos de Python de QGIS Serverpara más detalles.

(9)

1.3 Ejecutar código Python cuando QGIS se inicia.

Existen dos métodos distintos para ejecutar código Python cada vez que QGIS inicia.

1. Crear un script startup.py

2. Configurar la variable de entorno PYQGIS_STARTUP a un fichero Python existente

1.3.1 El fichero startup.py

Cada vez que se inicia QGIS, el directorio de inicio de Python del usuario

• Linux: .local/share/QGIS/QGIS3

• Windows: AppData\Roaming\QGIS\QGIS3

• macOS: Library/Application Support/QGIS/QGIS3

se busca un archivos llamado startup.py. Si ese archivo existe, lo ejecuta el intérprete de Python incorporado.

Nota: La ruta predeterminada depende de cada sistema operativo. Para encontrar la ruta que pueda funcionar en su caso, abra la consola de Python y ejecute QStandardPaths.

standardLocations(QStandardPaths.AppDataLocation) para ver el listado de directorios predeterminados.

1.3.2 La variable de entorno PYQGIS_STARTUP

Al configurar la variable de entorno PYQGIS_STARTUP con la ruta de un fichero Python existente, puede ejecutar código Python justo antes de que la inicialización de QGIS se haya completado.

Este código se ejecutará antes de que se complete la inicialización de QGIS. Este método es muy útil para la limpieza de sys.path, que puede tener rutas no deseables, o para aislar/cargar el entorno inicial sin necesidad de un entorno virtual, por ejemplo, homebrew o MacPorts se instala en Mac.

1.4 Aplicaciones Python

A menudo es útil crear scripts para automatizar procesos. Con PyQGIS, esto es perfectamente posible — importe el módulo qgis.core, inicialícelo y estará listo para el procesamiento.

O puede que desee crear una aplicación interactiva que utiliza la funcionalidad de los SIG — realizar mediciones, exportar un mapa en PDF . . . El módulo qgis.gui proporciona varios componentes de interfaz gráfica, sobre todo el widget de lienzo de mapa que se puede incorporar a la aplicación con soporte para zoom, paneo y/o cualquier otra herramienta de mapa personalizada.

Las aplicaciones personalizadas de PyQGIS o los scripts independientes deben configurarse para localizar los recursos QGIS, como la información de proyección y los proveedores para leer capas vectoriales y ráster. Los recursos de QGIS se inician añadiendo unas pocas líneas al principio de su aplicación o script. El código para inicializar QGIS para aplicaciones personalizadas y scripts independientes es similar. A continuación se propor- cionan ejemplos de cada uno de ellos.

Nota: No utilice qgis.py como nombre para su script. Python no podrá importar los enlaces, ya que el nombre del script será su sombra.

1.3. Ejecutar código Python cuando QGIS se inicia. 3

(10)

1.4.1 Usando PyQGIS en scripts individuales

Para iniciar un script independiente, inicialice los recursos QGIS al principio del script:

from qgis.core import *

# Supply path to qgis install location

QgsApplication.setPrefixPath("/path/to/qgis/installation", True)

# Create a reference to the QgsApplication. Setting the

# second argument to False disables the GUI.

qgs = QgsApplication([], False)

# Load providers qgs.initQgis()

# Write your code here to load some layers, use processing

# algorithms, etc.

# Finally, exitQgis() is called to remove the

# provider and layer registries from memory qgs.exitQgis()

Primero se importa el módulo qgis.core y configuramos el prefijo de ruta. El prefijo de ruta es la ubicación donde QGIS está instalado en su sistema. Se configura en el script llamando al métodosetPrefixPath. El segundo argumento desetPrefixPathse establece a True, especificando las rutas predeterminadas que se deben utilizar.

La ruta de instalación de QGIS varía según la plataforma; la forma más fácil de encontrarlo para su sistema es utilizar laDesarrollar scripts en la consola de Pythondesde dentro de QGIS y mirar la salida de la ejecución de QgsApplication.prefixPath().

Después de configurar la ruta del prefijo, guardamos una referencia a QgsApplication en la variable qgs.

El segundo argumento se establece en False, especificando que no planeamos usar la GUI ya que estamos escribiendo un script independiente. Con‘‘QgsApplication‘‘ configurado, cargamos los proveedores de datos QGIS y el registro de capas llamando al método qgs.initQgis(). Con QGIS inicializado, estamos listos para escribir el resto del script. Por último, terminamos llamando a qgs.exitQgis() para eliminar los proveedores de datos y el registro de capas de la memoria.

1.4.2 Usando PyQGIS en aplicaciones personalizadas

La única diferencia entreUsando PyQGIS en scripts individualesy una aplicación PyQGIS personalizada es el segundo argumento al crear instancias de QgsApplication. Pase True en lugar de False para indicar que se planea usar una GUI.

from qgis.core import *

# Supply the path to the qgis install location

QgsApplication.setPrefixPath("/path/to/qgis/installation", True)

# Create a reference to the QgsApplication.

# Setting the second argument to True enables the GUI. We need

# this since this is a custom application.

qgs = QgsApplication([], True)

# load providers qgs.initQgis()

# Write your code here to load some layers, use processing

(11)

# algorithms, etc.

# Finally, exitQgis() is called to remove the

# provider and layer registries from memory qgs.exitQgis()

Ahora puede trabajar con la API de QGIS - carga de capas y realizar algún procesamiento o encender una GUI con un lienzo de mapa. Las posibilidades son infinitas :-)

1.4.3 Ejecutar aplicaciones personalizadas

Necesita indicar a su sistema dónde buscar las bibliotecas QGIS y módulos de Python apropiados si no están en una ubicación conocida - de lo contrario Python se quejará:

>>> import qgis.core

ImportError: No module named qgis.core

Esto se puede solucionar estableciendo la variable de entorno PYTHONPATH . En los siguientes comandos,

<qgispath>deberá ser reemplazado con su ruta de instalación de QGIS actual:

• en Linux: export PYTHONPATH=/<qgispath>/share/qgis/python

• en Windows: set PYTHONPATH=c:\<qgispath>\python

• en macOS: export PYTHONPATH=/<qgispath>/Contents/Resources/python

Ahora, se conoce la ruta de acceso a los módulos PyQGIS, pero dependen de las bibliotecas qgis_core y qgis_gui(los módulos de Python solo sirven como contenedores). La ruta de acceso a estas bibliotecas puede ser desconocida para el sistema operativo, y luego obtendrá un error de importación de nuevo (el mensaje puede variar dependiendo del sistema):

>>> import qgis.core

ImportError: libqgis_core.so.3.2.0: cannot open shared object file:

No such file or directory

Para solucionar, agregar los directorios donde residen las bibliotecas QGIS a la ruta de búsqueda del en- lazador dinámico:

• en Linux: export LD_LIBRARY_PATH=/<qgispath>/lib

• en Windows: set PATH=C:\<qgispath>\bin;C:\<qgispath>\apps\<qgisrelease>\bin;

%PATH% donde <qgisrelease> debe ser reemplazado por el tipo de enlace apuntado (por ejemplo:

qgis-ltr, qgis, qgis-dev)

Estos comandos se pueden poner en un script de arranque que se encargará del inicio. Al implementar aplicaciones personalizadas con PyQGIS, normalmente hay dos posibilidades:

• requiere que el usuario instale QGIS antes de instalar la aplicación. El instalador de la aplicación debe buscar ubicaciones predeterminadas de las bibliotecas QGIS y permitir al usuario establecer la ruta si no se encuentra. Este enfoque tiene la ventaja de ser más sencillo, sin embargo, requiere que el usuario haga más pasos.

• paquete QGIS junto con su aplicación. Lanzar la aplicación puede ser más difícil y el paquete será más grande, pero el usuario se salvará de la carga de descargar e instalar piezas adicionales de software.

Los dos modelos de implementación pueden ser mixtos. Puede proporcionar aplicaciones independientes en Windows y macOS, pero para Linux dejar la instalación de SIG en manos del usuario y su administrador de paquetes.

1.4. Aplicaciones Python 5

(12)

1.5 Notas técnicas sobre PyQt y SIP

Se ha decidido por Python, ya que es uno de los lenguajes más favoritos para el scripting. Los enlaces PyQGIS en QGIS 3 dependen de SIP y PyQt5. La razón para usar SIP en lugar del ampliamente utilizado SWIG es que el código QGIS depende de las bibliotecas Qt. Los enlaces de Python para Qt (PyQt) se realizan utilizando SIP y esto permite la integración perfecta de PyQGIS con PyQt.

(13)

Cargar proyectos

Algunas veces se necesita cargar un proyecto existente desde un complemento o (más a menudo) al desarrollar una aplicación autónoma QGIS Python (vea :Aplicaciones Python).

Para cargar un proyecto en la aplicación QGIS actual, debe crear una instancia de la claseQgsProject. Esta es una clase singleton, por lo tanto se debe usar el métodoinstance()para realizarlo. Puede llamar su método read()y pasar la ruta para que el proyecto sea cargado:

# If you are not inside a QGIS console you first need to import

# qgis and PyQt classes you will use in this script as shown below:

from qgis.core import QgsProject

# Get the project instance project = QgsProject.instance()

# Print the current project file name (might be empty in case no projects have

˓→been loaded)

print(project.fileName())

'/home/user/projects/my_qgis_project.qgs'

# Load another project

project.read('/home/user/projects/my_other_qgis_project.qgs') print(project.fileName())

'/home/user/projects/my_other_qgis_project.qgs'

Si necesita hacer modificaciones a su proyecto (por ejemplo añadir o remover algunas capas) y guardar los cambios realizados, puede llamar el métodowrite()de su instancia de proyecto. El métodowrite()también acepta una ruta opcional para salvar el proyecto en una nueva localización:

# Save the project to the same project.write()

# ... or to a new file

project.write('/home/user/projects/my_new_qgis_project.qgs')

Las funcionesread()ywrite() retornan un valor booleano que puede utilizar para verificar si la operación fue exitosa.

Nota: Si está desarrollando una aplicación QGIS autónoma, para poder mantener la sincronización entre el proyecto cargado y el lienzo, debe instanciar una :class:”QgsLayerTreeMapCanvasBridge

<qgis.gui.QgsLayerTreeMapCanvasBridge>” al igual que en el ejemplo:

7

(14)

bridge = QgsLayerTreeMapCanvasBridge( \

QgsProject.instance().layerTreeRoot(), canvas)

# Now you can safely load your project and see it in the canvas project.read('/home/user/projects/my_other_qgis_project.qgs')

(15)

Cargar capas

Los fragmentos de códigos expuestos en esta página requieren las siguientes importaciones:

import os # This is is needed in the pyqgis console also from qgis.core import (

QgsVectorLayer )

• Capas Vectoriales

• Capas ráster

• Instancia QgsProject

Vamos a abrir algunas capas con datos. QGIS reconoce capas vectoriales y ráster. Además, están disponibles tipos de capas personalizadas, pero no se va a discutir de ellas aquí.

3.1 Capas Vectoriales

Para crear una instancia de capa vectorial, especifique el identificador de la fuente de datos y nombre de la capa, así como también el nombre del proveedor:

# get the path to the shapefile e.g. /home/project/data/ports.shp

path_to_ports_layer = os.path.join(QgsProject.instance().homePath(), "data", "ports

˓→", "ports.shp")

# The format is:

# vlayer = QgsVectorLayer(data_source, layer_name, provider_name) vlayer = QgsVectorLayer(path_to_ports_layer, "Ports layer", "ogr") if not vlayer.isValid():

print("Layer failed to load!")

El identificador de la fuente de datos es una cadena y se especifica a cada proveedor de datos vectoriales. El nombre de la capa se utiliza en el widget de la lista de capa. Es importante validar si la capa se ha cargado satisfactoriamente. Si no fue así, se devuelve una instancia de capa no válida.

9

(16)

Para una capa vectorial creada mediante un geopackage:

# get the path to a geopackage e.g. /home/project/data/data.gpkg

path_to_gpkg = os.path.join(QgsProject.instance().homePath(), "data", "data.gpkg")

# append the layername part

gpkg_places_layer = path_to_gpkg + "|layername=places"

# e.g. gpkg_places_layer = "/home/project/data/data.gpkg|layername=places"

vlayer = QgsVectorLayer(gpkg_places_layer, "Places layer", "ogr") if not vlayer.isValid():

print("Layer failed to load!")

La forma más rápida para abrir y visualizar una capa vectorial en QGIS es usar el métodoaddVectorLayer() perteneciente aQgisInterface:

vlayer = iface.addVectorLayer(path_to_ports_layer, "Ports layer", "ogr") if not vlayer:

print("Layer failed to load!")

Esto crea una nueva capa y la añade al actual proyecto QGIS (haciéndola aparecer en el listado de capas) en un solo paso. La función retorna la instancia de capa o None‘ si es que no puede cargarla.

La siguiente lista muestra cómo acceder a varias fuentes de datos utilizando los proveedores de datos vectoriales:

• Librería OGR ( Shapefile y muchos otros formatos) — la fuente de datos es la ruta hacia el archivo:

– Para Shapefile:

vlayer = QgsVectorLayer("/path/to/shapefile/file.shp", "layer_name_you_like

˓→", "ogr")

– Para dxf (tenga en cuenta las opciones internas en la fuente de datos uri):

uri = "/path/to/dxffile/file.dxf|layername=entities|geometrytype=Point"

vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr")

• Base de datos PostGIS - la fuente de datos es una cadena de texto con toda la información necesaria para crear una conexión con la base de datos PostgreSQL.

La claseQgsDataSourceUripuede generar esta cadena de texto para usted. Tenga en cuenta que QGIS debe compilarse con el soporte de Postgres, o de lo contrario, este proveedor no estará disponible:

uri = QgsDataSourceUri()

# set host name, port, database name, username and password uri.setConnection("localhost", "5432", "dbname", "johny", "xxx")

# set database schema, table name, geometry column and optionally

# subset (WHERE clause)

uri.setDataSource("public", "roads", "the_geom", "cityid = 2643")

vlayer = QgsVectorLayer(uri.uri(False), "layer name you like", "postgres")

Nota: El argumento False pasado a uri.uri(False) previene la expansión de los parámetros de con- figuración de la autenticación. En caso de que no esté utilizando ninguna configuración para autenticación, este argumento no hará ninguna diferencia.

• CSV u otros archivos de texto delimitados — para abrir un archivo con un punto y coma como delimitador, con el campo «x» para la coordenada X y el campo «y» para la coordenada Y, usaría algo como esto:

uri = "/some/path/file.csv?delimiter={}&xField={}&yField={}".format(";", "x",

˓→"y")

vlayer = QgsVectorLayer(uri, "layer name you like", "delimitedtext")

(17)

Nota: La cadena de proveedor está estructurada como una dirección URL, por lo que la ruta de acceso debe ir precedida de file://. También permite geometrías en formato WKT (texto bien conocido) como alternativa a los campos “”x”” y “”y”“, y permite especificar el sistema de referencia de coordenadas. Por ejemplo:

uri = "file:///some/path/file.csv?delimiter={}&crs=epsg:4723&wktField={}".

˓→format(";", "shape")

• Los archivos GPX — el proveedor de datos «gpx» lee los caminos, rutas y puntos de interés desde archivos GPX. Para abrir un archivo, el tipo (caminos/ruta/punto de interés) se debe especificar como parte de la url:

uri = "path/to/gpx/file.gpx?type=track"

vlayer = QgsVectorLayer(uri, "layer name you like", "gpx")

• La base de datos SpatiaLite — De forma similar a las bases de datos PostGIS, :class:”QgsDataSourceUri

<qgis.core.QgsDataSourceUri>” puede ser utilizado para la generación de identificador de origen de datos:

uri = QgsDataSourceUri()

uri.setDatabase('/home/martin/test-2.3.sqlite') schema = ''

table = 'Towns'

geom_column = 'Geometry'

uri.setDataSource(schema, table, geom_column) display_name = 'Towns'

vlayer = QgsVectorLayer(uri.uri(), display_name, 'spatialite')

• Las geometrias basadas en WKB de MySQL, a través de OGR — la fuente de datos es la cadena de conexión a la tabla:

uri = "MySQL:dbname,host=localhost,port=3306,user=root,

˓→password=xxx|layername=my_table"

vlayer = QgsVectorLayer( uri, "my table", "ogr" )

• Conexión WFS:. se define con un URI y utiliza el proveedor WFS:

uri = "http://localhost:8080/geoserver/wfs?srsname=EPSG:23030&typename=union&

˓→version=1.0.0&request=GetFeature&service=WFS", vlayer = QgsVectorLayer(uri, "my wfs layer", "WFS") La uri se puede crear utilizando la librería estándar urllib:

params = {

'service': 'WFS', 'version': '1.0.0', 'request': 'GetFeature', 'typename': 'union', 'srsname': "EPSG:23030"

}

uri = 'http://localhost:8080/geoserver/wfs?' + urllib.unquote(urllib.

˓→urlencode(params))

Nota: Puede cambiar el origen de datos de una capa existente llamando asetDataSource()en una instancia deQgsVectorLayer, como en el siguiente ejemplo:

# vlayer is a vector layer, uri is a QgsDataSourceUri instance vlayer.setDataSource(uri.uri(), "layer name you like", "postgres")

3.1. Capas Vectoriales 11

(18)

3.2 Capas ráster

Para acceder a un archivo raster, se utiliza la librería GDAL. Esta soporta un amplio rango de formatos de archivo.

En caso de que tenga problemas al abrir algún archivo, compruebe si es que su GDAL tiene soporte para el formato en particular (no todos los formatos están disponibles de forma predeterminada). Para cargar un raster desde un archivo, especifique el nombre del archivo y su nombre de visualización:

# get the path to a tif file e.g. /home/project/data/srtm.tif

path_to_tif = os.path.join(QgsProject.instance().homePath(), "data", "srtm.tif") rlayer = QgsRasterLayer(path_to_tif, "SRTM layer name")

if not rlayer.isValid():

print("Layer failed to load!") Para cargar una capa raster desde un geopackage:

# get the path to a geopackage e.g. /home/project/data/data.gpkg

path_to_gpkg = os.path.join(QgsProject.instance().homePath(), "data", "data.gpkg")

# gpkg_raster_layer = "GPKG:/home/project/data/data.gpkg:srtm"

gpkg_raster_layer = "GPKG:" + path_to_gpkg + ":srtm"

rlayer = QgsRasterLayer(gpkg_raster_layer, "layer name you like", "gdal") if not rlayer.isValid():

print("Layer failed to load!")

De manera similar a las capas vectoriales, las capas raster pueden ser cargadas utilizando la función addRaster- Layer de un objeto perteneciente aQgisInterface

iface.addRasterLayer("/path/to/raster/file.tif", "layer name you like")

Esto crea una nueva capa y la añade al proyecto actual (haciendo que aparezca en la lista) en un solo paso.

Las capas ráster también se pueden crear desde el servicio WCS:

layer_name = 'modis' uri = QgsDataSourceUri()

uri.setParam('url', 'http://demo.mapserver.org/cgi-bin/wcs') uri.setParam("identifier", layer_name)

rlayer = QgsRasterLayer(str(uri.encodedUri()), 'my wcs layer', 'wcs') Aquí está una descripción de los parámetros que el WCS URI puede contener:

El WCS URI se compone de pares calve=valor separadas por &. Es el mismo formato que la cadena de consulta en la URL, codificada de la misma manera. QgsDataSourceUridebe utilizarse para construir el URI para garantizar que los caracteres especiales se codifican correctamente.

• url (requerido) : URL del servidor WCS. No utilice la VERSION en el URL, porque cada versión del WCS está usando nombre de parámetro diferente para la versión de GetCapabilities vea la versión del parámetro.

• identifier (requerido) : Nombre de la Cobertura

• time (opcional) : posición de tiempo o período de tiempo (beginPosition/endPosition[/timeResolution])

• format (opcional) : Nombre de formato admitido. El valor predeterminado es el primer formato compatible con el nombre en tif o el primer formato compatible.

• crs (opcional): CRS en el formato AUTORIDAD:IDENTIFICADOR, p. ej. EPSG:4326. El valor predeter- minado es EPSG:4326, si es que es compatible, o si no el primer CRS compatible.

• nombre de usuario (opcional): Nombre de usuario para la autenticación básica.

• contraseña (opcional): Contraseña para la autenticación básica.

• IgnoreGetMapUrl (opcional, hack): si se especifica (establecido en 1), ignore la dirección URL de GetCov- erage anunciada por GetCapabilities. Puede ser necesario si un servidor no está configurado correctamente.

(19)

• InvertAxisOrientation (opcional, hack): si se especifica (establecido en 1), cambie el eje en la solicitud GetCoverage. Puede ser necesario para un CRS geográfico si un servidor está utilizando un orden de eje incorrecto.

• IgnoreAxisOrientation (opcional, hack): Si se especifica (establecido en 1), no invierta la orientación del eje de acuerdo con el estándar WCS para un CRS geográfico.

• cache (opcional): control de carga de caché, como se describe en QNetworkRequest::CacheLoadControl, pero la solicitud se reenvía como PreferCache si falló con AlwaysCache. Valores permitidos: AlwaysCache, PreferCache, PreferNetwork, AlwaysNetwork. El valor predeterminado es AlwaysCache.

Como alternativa se puede cargar una capa ráster desde un servidor WMS. Sin embargo actualmente no es posible acceder a las respuestas de GetCapabilities desde el API — se debe saber que capas desea:

urlWithParams = 'url=http://irs.gis-lab.info/?layers=landsat&styles=&format=image/

˓→jpeg&crs=EPSG:4326'

rlayer = QgsRasterLayer(urlWithParams, 'some layer name', 'wms') if not rlayer.isValid():

print("Layer failed to load!")

3.3 Instancia QgsProject

Si desea utilizar las capas abiertas para la representación, no olvide agregarlas a la instancia deQgsProject.

La instanciaQgsProjecttoma la posesión de las capas y más adelante, se puede acceder desde cualquier parte de la aplicación mediante su identificador único . Cuando la capa se elimina del proyecto, también se elimina.

Las capas pueden ser eliminadas por el usuario en la interfaz QGIS, o a través de Python usando el método removeMapLayer().

Añadir una capa al proyecto actual, se puede realizar, utilizando el métodoaddMapLayer(): QgsProject.instance().addMapLayer(rlayer)

Para agregar una capa en una posición absoluta:

# first add the layer without showing it

QgsProject.instance().addMapLayer(rlayer, False)

# obtain the layer tree of the top-level group in the project layerTree = iface.layerTreeCanvasBridge().rootGroup()

# the position is a number starting from 0, with -1 an alias for the end layerTree.insertChildNode(-1, QgsLayerTreeLayer(rlayer))

Si quiere remover una capa utilice el métodoremoveMapLayer():

# QgsProject.instance().removeMapLayer(layer_id) QgsProject.instance().removeMapLayer(rlayer.id())

En el código anterior, el identificador de la capa es pasado (puede obtenerlo llamando el método id()que pertenece a la capa), pero también puede hacerlo pasando el objeto capa en si mismo.

Para una lista de capas cargadas y sus identificadores, use el métodomapLayers(): QgsProject.instance().mapLayers()

3.3. Instancia QgsProject 13

(20)
(21)

Usar las capas ráster

Advertencia: |fuera de fecha|

• Detalles de la capa

• Renderizador

– Rásters de una sola banda – Rásters multibanda

• Valores de consulta

Los extractos de códigos en esta página, requieren las siguientes importaciones, si es que estás trabajando fuera de la consola pyqgis:

from qgis.core import ( QgsRasterLayer, QgsColorRampShader,

QgsSingleBandPseudoColorRenderer )

4.1 Detalles de la capa

Una capa ráster está compuesta por una o más bandas ráster — denominadas como raster de banda única o multibanda. Una banda representa una matriz de valores. Una imagen a color (p. ej. una fotografía aérea) es un ráster que está constituido por bandas roja, azul y verde. Los rásteres de banda única, representan generalmente variables continuas (p. ej. elevación) o variables discretas (p. ej. uso del suelo). En algunos casos, una capa ráster viene con una paleta y los valores ráster se refieren a los colores almacenados en la paleta.

El código a continuación, asume que rlayer es un objeto deQgsRasterLayer. rlayer = QgsProject.instance().mapLayersByName('srtm')[0]

# get the resolution of the raster in layer unit rlayer.width(), rlayer.height()

15

(22)

(919, 619)

# get the extent of the layer as QgsRectangle rlayer.extent()

<QgsRectangle: 20.06856808199999875 -34.27001076999999896, 20.83945284300000012 -

˓→33.75077500700000144>

# get the extent of the layer as Strings rlayer.extent().toString()

'20.0685680819999988,-34.2700107699999990 : 20.8394528430000001,-33.

˓→7507750070000014'

# get the raster type: 0 = GrayOrUndefined (single band), 1 = Palette (single

˓→band), 2 = Multiband rlayer.rasterType() 0

# get the total band count of the raster rlayer.bandCount()

1

# get all the available metadata as a QgsLayerMetadata object rlayer.metadata()

'<qgis._core.QgsLayerMetadata object at 0x13711d558>'

4.2 Renderizador

Cuando una capa ráster es cargada, recibe en base a su tipo, el valor del renderizador de forma predeterminada.

Esto puede ser modificado tanto en las propiedades de capa o mediante programación.

Para consultar el actual renderizador:

rlayer.renderer()

<qgis._core.QgsSingleBandGrayRenderer object at 0x7f471c1da8a0>

rlayer.renderer().type() 'singlebandgray'

Para configurar un renderizador, use el métodosetRendererde la clase QgsRasterLayer. Hay varias clases de renderizador (derivadas deQgsRasterRenderer):

• QgsMultiBandColorRenderer

• QgsPalettedRasterRenderer

• QgsSingleBandColorDataRenderer

• QgsSingleBandGrayRenderer

• QgsSingleBandPseudoColorRenderer

Las capas ráster de banda única pueden ser dibujadas tanto en colores grises (valor menor = negro, valor alto = blanco) o con un algoritmo pseudocolor que asigna colores a los valores. Rásters de banda única con una paleta puedes ser dibujados usando la paleta. Las capas multibanda generalmente se dibujan asignando las bandas a colores RGB. Otra posibilidad es usar una sola banda para dibujar.

4.2.1 Rásters de una sola banda

Supongamos que queremos renderizar una capa ráster de una sola banda con colores que van del verde al amarillo (correspondiente a los valores de píxel de 0 a 255). En la primera etapa prepararemos un objeto QgsRasterShadery configuraremos su función shader:

fcn = QgsColorRampShader()

fcn.setColorRampType(QgsColorRampShader.Interpolated)

lst = [ QgsColorRampShader.ColorRampItem(0, QColor(0,255,0)), QgsColorRampShader.ColorRampItem(255, QColor(255,255,0)) ]

(23)

fcn.setColorRampItemList(lst) shader = QgsRasterShader()

shader.setRasterShaderFunction(fcn)

El sombreador asigna los colores según lo especificado por su mapa de colores. El mapa de colores es proveído como una lista de valores de pixeles con colores asociados. Hay tres modos de interpolación:

• lineal (Interpolated): el color es linealmente interpolado desde las entradas en el mapa de colores, que están por encima y por debajo de el valor de pixel.

• discreto (Discrete): el color es tomado desde la entrada más cercana con igual o mayor valor en el mapa de colores.

• exacto (Exact): el color no es interpolado, solo los pixeles con un valor igual a las entradas del mapa de colores serán dibujados.

En el segundo paso asociaremos el sombreador con una capa ráster:

renderer = QgsSingleBandPseudoColorRenderer(rlayer.dataProvider(), 1, shader) rlayer.setRenderer(renderer)

El número 1 en el código anterior es el número de la banda (bandas ráster son indexadas de uno).

Finalmente debemos utilizar el métodotriggerRepaintpara ver los resultados:

rlayer.triggerRepaint()

4.2.2 Rásters multibanda

De forma predeterminada, QGIS asigna las tres primeras bandas a rojo, verde y azul para crear una imagen de color (este es el estilo de dibujo “”MultiBandColor”“). En algunos casos, es posible que desee omitir esta configuración.

El código siguiente intercambia la banda roja (1) y la banda verde (2):

rlayer_multi = QgsProject.instance().mapLayersByName('multiband')[0]

rlayer_multi.renderer().setGreenBand(1) rlayer_multi.renderer().setRedBand(2)

En caso de que sea necesaria solo una banda para la visualización del ráster, se puede elegir el dibujo de una banda única, ya sea niveles grises o pseudocolor.

Se tiene que usartriggerRepaintpara actualizar el mapa y ver el resultado:

rlayer_multi.triggerRepaint()

4.3 Valores de consulta

Los valores ráster se pueden consultar mediante el métodosamplede la claseQgsRasterDataProvider.

Debe especificar unQgsPointXYy el número de banda de la capa ráster que desea consultar. El método devuelve una tupla con el valor y “”True”” o “”False”” dependiendo de los resultados:

val, res = rlayer.dataProvider().sample(QgsPointXY(20.50, -34), 1)

Otra forma de consultar los valores ráster es usando el método identify, que retorna un objeto QgsRasterIdentifyResult.

ident = rlayer.dataProvider().identify(QgsPointXY(20.5, -34), QgsRaster.

˓→IdentifyFormatValue) if ident.isValid():

print(ident.results())

4.3. Valores de consulta 17

(24)

En este caso, el métodoresultsretorna un diccionario, que tiene el índice de la banda como clave y los valores de la banda como valor. Por ejemplo, algo como {1: 323.0}.

(25)

Usar capas vectoriales

• Recuperando información sobre atributos

• Iterando sobre la capa vectorial

• Seleccionando objetos espaciales – Accediendo a atributos

– Iterando sobre rasgos seleccionados – Iterando sobre un subconjunto de rasgos

• Modificación de capas vectoriales – Añadir Entidades

– Borrar Entidades

– Modificar los objetos espaciales

– Modificación de capas vectoriales con un búfer de edición – Agregando y Removiendo Campos

• Usar índice espacial

• Creación de capas vectoriales

– Desde una instancia deQgsVectorFileWriter – Directamente desde las funciones

– Desde una instancia deQgsVectorLayer

• Apariencia (Simbología) de capas vectoriales – Representador de Símbolo Único – Representador de símbolo categorizado – Graduated Symbol Renderer

– Trabajo con Símbolos

* Working with Symbol Layers

19

(26)

* Creating Custom Symbol Layer Types – Creating Custom Renderers

• Más Temas

Esta sección sumariza varias acciones que pueden ser realizadas con las capas vectoriales

La mayor parte del trabajo acá expuesto está basado en los métodos de la claseQgsVectorLayer.

5.1 Recuperando información sobre atributos

Puede recuperar información sobre los campos asociados a una capa vectorial llamando el métodofields() de un objeto de la claseQgsVectorLayer

# "layer" is a QgsVectorLayer instance for field in layer.fields():

print(field.name(), field.typeName())

5.2 Iterando sobre la capa vectorial

a iteración de las entidades de una capa vectorial es una de las tareas más comunes. A continuación se muestra un ejemplo del código básico simple para realizar esta tarea y mostrar cierta información sobre cada característica.

Se supone que la variable “”layer”” tiene un objetoQgsVectorLayer.

layer = iface.activeLayer() features = layer.getFeatures() for feature in features:

# retrieve every feature with its geometry and attributes print("Feature ID: ", feature.id())

# fetch geometry

# show some information about the feature geometry geom = feature.geometry()

geomSingleType = QgsWkbTypes.isSingleType(geom.wkbType()) if geom.type() == QgsWkbTypes.PointGeometry:

# the geometry type can be of single or multi type if geomSingleType:

x = geom.asPoint() print("Point: ", x) else:

x = geom.asMultiPoint() print("MultiPoint: ", x)

elif geom.type() == QgsWkbTypes.LineGeometry:

if geomSingleType:

x = geom.asPolyline()

print("Line: ", x, "length: ", geom.length()) else:

x = geom.asMultiPolyline()

print("MultiLine: ", x, "length: ", geom.length()) elif geom.type() == QgsWkbTypes.PolygonGeometry:

if geomSingleType:

x = geom.asPolygon()

print("Polygon: ", x, "Area: ", geom.area()) else:

x = geom.asMultiPolygon()

print("MultiPolygon: ", x, "Area: ", geom.area()) else:

print("Unknown or invalid geometry")

(27)

# fetch attributes

attrs = feature.attributes()

# attrs is a list. It contains all the attribute values of this feature print(attrs)

5.3 Seleccionando objetos espaciales

En el escritorio QGIS, las entidades se pueden seleccionar de diferentes maneras: el usuario puede hacer clic en una entidad, dibujar un rectángulo en el lienzo del mapa o utilizar un filtro de expresión. Las entidades selec- cionadas normalmente se resaltan en un color diferente (el valor predeterminado es el amarillo) para llamar la atención del usuario sobre la selección.

A veces puede ser útil seleccionar características mediante programación o cambiar el color predeterminado.

Para seleccionar todas las características, se puede utilizar el métodoselectAll()

# Get the active layer (must be a vector layer) layer = iface.activeLayer()

layer.selectAll()

Para seleccionar usando una expresión, utilice el métodoselectByExpression()

# Assumes that the active layer is points.shp file from the QGIS test suite

# (Class (string) and Heading (number) are attributes in points.shp) layer = iface.activeLayer()

layer.selectByExpression('"Class"=\'B52\' and "Heading" > 10 and "Heading" <70',

˓→QgsVectorLayer.SetSelection)

Para cambiar el color de selección puede utilizar el método setSelectionColor() deQgsMapCanvas como se muestra en el ejemplo siguiente:

iface.mapCanvas().setSelectionColor( QColor("red") )

Para agregar entidades a la lista de entidades seleccionada para una capa determinada, puede llamar aselect() pasándole la lista de identificadores de las entidades:

selected_fid = []

# Get the first feature id from the layer for feature in layer.getFeatures():

selected_fid.append(feature.id()) break

# Add these features to the selected list layer.select(selected_fid)

Para borrar la selección:

layer.removeSelection()

5.3.1 Accediendo a atributos

Los atributos pueden ser referidos por su nombre:

print(feature['name'])

Alternativamente, los atributos pueden ser referidos por índice. Esto es un poco más rápido que usar el nombre.

Por ejemplo, para obtener el primer atributo:

5.3. Seleccionando objetos espaciales 21

(28)

print(feature[0])

5.3.2 Iterando sobre rasgos seleccionados

Si solo necesita entidades seleccionadas, puede utilizar el métodoselectedFeatures()de la capa vectorial:

selection = layer.selectedFeatures() print(len(selection))

for feature in selection:

# do whatever you need with the feature

5.3.3 Iterando sobre un subconjunto de rasgos

Si desea iterar sobre un subconjunto determinado de entidades de una capa, como las que se encuentran en un área determinada, debe agregar un objetoQgsFeatureRequesta la llamada degetFeatures(). Este es un ejemplo:

areaOfInterest = QgsRectangle(450290,400520, 450750,400780) request = QgsFeatureRequest().setFilterRect(areaOfInterest) for feature in layer.getFeatures(request):

# do whatever you need with the feature

En aras de la velocidad, la intersección a menudo se realiza solo con el cuadro delimitador de la entidad. Sin embargo, hay una bandera ExactIntersect que se asegura de que solo se devolverán las entidades que se cruzan:

request = QgsFeatureRequest().setFilterRect(areaOfInterest).

˓→setFlags(QgsFeatureRequest.ExactIntersect)

ConsetLimit()puede limitar el número de entidades solicitadas. Este es un ejemplo:

request = QgsFeatureRequest() request.setLimit(2)

for feature in layer.getFeatures(request):

# loop through only 2 features

Si necesita un filtro basado en atributos en su lugar (o además) de uno espacial como se muestra en los ejemplos anteriores, puede crear un objetoQgsExpressiony pasarlo al constructorQgsFeatureRequest. Este es un ejemplo:

# The expression will filter the features where the field "location_name"

# contains the word "Lake" (case insensitive)

exp = QgsExpression('location_name ILIKE \'%Lake%\'') request = QgsFeatureRequest(exp)

Consulte Expresiones, Filtros y Calculando Valores para obtener detalles sobre la sintaxis admitida por QgsExpression.

La solicitud se puede utilizar para definir los datos recuperados para cada entidad, por lo que el iterador devuelve todas las entidades, pero devuelve datos parciales para cada una de ellas.

# Only return selected fields to increase the "speed" of the request request.setSubsetOfAttributes([0,2])

# More user friendly version

request.setSubsetOfAttributes(['name','id'],layer.fields())

(29)

# Don't return geometry objects to increase the "speed" of the request request.setFlags(QgsFeatureRequest.NoGeometry)

# Fetch only the feature with id 45 request.setFilterFid(45)

# The options may be chained

request.setFilterRect(areaOfInterest).setFlags(QgsFeatureRequest.NoGeometry).

˓→setFilterFid(45).setSubsetOfAttributes([0,2])

5.4 Modificación de capas vectoriales

La mayoría de los proveedores de datos vectoriales admiten la edición de datos de capa. A veces solo admiten un subconjunto de posibles acciones de edición. Utilice la funcióncapabilities()para averiguar qué conjunto de funcionalidad es compatible.

caps = layer.dataProvider().capabilities()

# Check if a particular capability is supported:

if caps & QgsVectorDataProvider.DeleteFeatures:

print('The layer supports DeleteFeatures')

Para obtener una lista de todas las capacidades disponibles, consulte la documentaciónAPI Documentation of QgsVectorDataProvider.

Para imprimir la descripción textual de las capacidades de las capas en una lista separada por comas, puede utilizar capabilitiesString()como en el ejemplo siguiente:

caps_string = layer.dataProvider().capabilitiesString()

# Print:

# 'Add Features, Delete Features, Change Attribute Values, Add Attributes,

# Delete Attributes, Rename Attributes, Fast Access to Features at ID,

# Presimplify Geometries, Presimplify Geometries with Validity Check,

# Transactions, Curved Geometries'

Mediante el uso de cualquiera de los métodos siguientes para la edición de capas vectoriales, los cambios se confirman directamente en el almacén de datos subyacente (un archivo, una base de datos, etc.). En caso de que desee realizar solo cambios temporales, vaya a la siguiente sección que explica cómo hacermodificaciones con la edición de cambios de búfer.

Nota: Si está trabajando dentro de QGIS (ya sea desde la consola o desde un complemento), podría ser necesario forzar un redibujo del lienzo del mapa para ver los cambios que ha realizado en la geometría, en el estilo o en los atributos:

# If caching is enabled, a simple canvas refresh might not be sufficient

# to trigger a redraw and you must clear the cached image for the layer if iface.mapCanvas().isCachingEnabled():

layer.triggerRepaint() else:

iface.mapCanvas().refresh()

5.4.1 Añadir Entidades

Cree algunas instancias deQgsFeaturey pase una lista de ellas al método del proveedoraddFeatures() Devolverá dos valores: resultado (verdadero/falso) y lista de características agregadas (su identificador lo establece el almacén de datos).

5.4. Modificación de capas vectoriales 23

(30)

Para configurar los atributos de la entidad, puede inicializar la entidad pasando un objetoQgsFields(puede obtenerlo del métodofields()de la capa vectorial) o llamar ainitAttributes()pasando el número de campos que desea agregar.

if caps & QgsVectorDataProvider.AddFeatures:

feat = QgsFeature(layer.fields()) feat.setAttributes([0, 'hello'])

# Or set a single attribute by key or by index:

feat.setAttribute('name', 'hello') feat.setAttribute(0, 'hello')

feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(123, 456))) (res, outFeats) = layer.dataProvider().addFeatures([feat])

5.4.2 Borrar Entidades

Para eliminar algunas entidades, solo tiene que proporcionar una lista de identificaciones de entidades.

if caps & QgsVectorDataProvider.DeleteFeatures:

res = layer.dataProvider().deleteFeatures([5, 10])

5.4.3 Modificar los objetos espaciales

Es posible cambiar la geometría de la entidad o cambiar algunos atributos. En el ejemplo siguiente se cambian primero los valores de los atributos con los índices 0 y 1 y, a continuación, se cambia la geometría de la entidad.

fid = 100 # ID of the feature we will modify

if caps & QgsVectorDataProvider.ChangeAttributeValues:

attrs = { 0 : "hello", 1 : 123 }

layer.dataProvider().changeAttributeValues({ fid : attrs }) if caps & QgsVectorDataProvider.ChangeGeometries:

geom = QgsGeometry.fromPointXY(QgsPointXY(111,222)) layer.dataProvider().changeGeometryValues({ fid : geom })

Truco: Favorecer la clase QgsVectorLayerEditUtils para ediciones de solo geometría

Si solo necesita cambiar geometrías, podría considerar el uso deQgsVectorLayerEditUtilsque propor- ciona algunos métodos útiles para editar geometrías (trasladar, insertar o mover vértices, etc.).

5.4.4 Modificación de capas vectoriales con un búfer de edición

Al editar vectores dentro de la aplicación QGIS, primero tiene que comenzar el modo de edición para una capa en particular, luego hacer algunas modificaciones y finalmente confirmar (o revertir) los cambios. Todos los cambios que realice no se escribirán hasta que los confirme — ellos permanecen en el búfer de edición en memoria de la capa. Es posible utilizar esta funcionalidad también mediante programación — es sólo otro método para la edición de capas vectoriales que complementa el uso directo de proveedores de datos. Utilice esta opción al proporcionar algunas herramientas GUI para la edición de capas vectoriales, ya que esto permitirá al usuario decidir si desea confirmar/revertir y permite el uso de deshacer/rehacer. Cuando se confirman los cambios, todos los cambios del búfer de edición se guardan en el proveedor de datos.

Los métodos son similares a los que hemos visto en el proveedor, pero se llaman en el objetoQgsVectorLayer en su lugar.

Para que estos métodos funcionen, la capa debe estar en modo de edición. Para iniciar el modo de edición, utilice el métodostartEditing()Para detener la edición, utilice los métodoscommitChanges()orollBack().

(31)

El primero confirmará todos los cambios en el origen de datos, mientras que el segundo los descartará y no modificará el origen de datos en absoluto.

Para averiguar si una capa está en modo de edición, utilice el métodoisEditable().

Aquí tiene algunos ejemplos que muestran cómo utilizar estos métodos de edición.

from qgis.PyQt.QtCore import QVariant

# add two features (QgsFeature instances) layer.addFeatures([feat1,feat2])

# delete a feature with specified ID layer.deleteFeature(fid)

# set new geometry (QgsGeometry instance) for a feature layer.changeGeometry(fid, geometry)

# update an attribute with given field index (int) to a given value layer.changeAttributeValue(fid, fieldIndex, value)

# add new field

layer.addAttribute(QgsField("mytext", QVariant.String))

# remove a field

layer.deleteAttribute(fieldIndex)

Para hacer que deshacer/rehacer trabaje correctamente, las llamadas mencionadas arriba tienen que ser envueltas en los comandos undo. (Si no le importa deshacer/rehacer y desea que los cambios se almacenen inmediatamente, entonces tendrá un trabajo más fácil poreditando con proveedor de datos.)

Así es cómo usted puede utilizar la funcionalidad de deshacer:

layer.beginEditCommand("Feature triangulation")

# ... call layer's editing methods ...

if problem_occurred:

layer.destroyEditCommand() return

# ... more editing ...

layer.endEditCommand()

El métodobeginEditCommand()creará un comando interno de «activo» y registrará los cambios posteriores en la capa vectorial. Con la llamada a el comandoendEditCommand()se inserta en la pila de deshacer y el usuario podrá deshacer/rehacerlo desde la GUI. En caso de que algo saliera mal al realizar los cambios, el método destroyEditCommand()quitará el comando y revertirá todos los cambios realizados mientras este comando estaba activo.

También puede utilizar la instrucción with edit(layer)- para encapsular la confirmación y la reversión en un bloque de código más semántico, como se muestra en el ejemplo siguiente:

with edit(layer):

feat = next(layer.getFeatures()) feat[0] = 5

layer.updateFeature(feat)

Esto llamará automáticamente acommitChanges()al final. Si ocurre alguna excepción, harárollBack()a todos los cambios. En caso de que se encuentre un problema dentro decommitChanges()(cuando el método devuelve False) se producirá una excepciónQgsEditError.

5.4. Modificación de capas vectoriales 25

(32)

5.4.5 Agregando y Removiendo Campos

Para agregar campos (atributos), usted necesita especificar una lista de definiciones de campo. Para la eliminación de campos sólo proporcione una lista de índices de campo.

from qgis.PyQt.QtCore import QVariant

if caps & QgsVectorDataProvider.AddAttributes:

res = layer.dataProvider().addAttributes(

[QgsField("mytext", QVariant.String), QgsField("myint", QVariant.Int)])

if caps & QgsVectorDataProvider.DeleteAttributes:

res = layer.dataProvider().deleteAttributes([0])

Después de agregar o quitar campos en el proveedor de datos, los campos de la capa deben actualizarse porque los cambios no se propagan automáticamente.

layer.updateFields()

Truco: Guarde directamente los cambios usando el comando basado en with

Usando with edit(layer): los cambios se confirmarán automáticamente llamando acommitChanges() al final. Si se produce alguna excepción, hará unrollBack()de todos los cambios. ConsulteModificación de capas vectoriales con un búfer de edición.

5.5 Usar índice espacial

Los índices espaciales pueden mejorar drásticamente el rendimiento del código si necesita realizar consultas fre- cuentes en una capa vectorial. Imagine, por ejemplo, que está escribiendo un algoritmo de interpolación, y que para una ubicación determinada necesita conocer los 10 puntos más cercanos de una capa de puntos, con el fin de utilizar esos puntos para calcular el valor interpolado. Sin un índice espacial, la única manera de que QGIS encuentre esos 10 puntos es calcular la distancia desde todos y cada uno de los puntos hasta la ubicación especi- ficada y luego comparar esas distancias. Esto puede ser una tarea que consume mucho tiempo, especialmente si necesita repetirse para varias ubicaciones. Si existe un índice espacial para la capa, la operación es mucho más efectiva.

Piense en una capa sin un índice espacial como una guía telefónica en la que los números de teléfono no se ordenan ni indexan. La única manera de encontrar el número de teléfono de una persona determinada es leer desde el principio hasta que lo encuentres.

Los índices espaciales no se crean de forma predeterminada para una capa vectorial QGIS, pero puede crearlos fácilmente. Esto es lo que tienes que hacer:

• crear índice espacial utilizando la claseQgsSpatialIndex():

index = QgsSpatialIndex()

• agregar entidades al índice — el índice toma el objetoQgsFeaturey lo agrega a la estructura de datos in- terna. Puede crear el objeto manualmente o usar uno de una llamada anterior al métodogetFeatures() del proveedor.

index.insertFeature(feat)

• alternativamente, puede cargar todas las entidades de una capa a la vez utilizando la carga masiva index = QgsSpatialIndex(layer.getFeatures())

(33)

• Una vez que el índice espacial se llena con algunos valores, puede realizar algunas consultas

# returns array of feature IDs of five nearest features nearest = index.nearestNeighbor(QgsPointXY(25.4, 12.7), 5)

# returns array of IDs of features which intersect the rectangle intersect = index.intersects(QgsRectangle(22.5, 15.3, 23.1, 17.2))

5.6 Creación de capas vectoriales

Hay varias maneras de generar un dataset de capa vectorial:

• la claseQgsVectorFileWriterclass: Una clase cómoda para escribir archivos vectoriales en el disco, utilizando una llamada estática awriteAsVectorFormat()que guarda toda la capa vectorial o crea una instancia de la clase y emite llamadas aaddFeature(). Esta clase admite todos los formatos vecto- riales que Soporta OGR (GeoPackage, Shapefile, GeoJSON, KML y otros).

• la claseQgsVectorLayer: crea una instancia de un proveedor de datos que interpreta la ruta de acceso proporcionada (url) del origen de datos para conectarse a los datos y tener acceso a ellos. Se puede utilizar para crear capas temporales basadas en memoria (memory) y conectarse a datasets OGR (ogr), bases de datos (postgres, spatialite, mysql, mssql) y más (wfs, gpx, delimitedtext. . . ).

5.6.1 Desde una instancia de QgsVectorFileWriter

# Write to a GeoPackage (default)

error = QgsVectorFileWriter.writeAsVectorFormat(layer,

"/path/to/folder/my_data",

"") if error[0] == QgsVectorFileWriter.NoError:

print("success!")

# Write to an ESRI Shapefile format dataset using UTF-8 text encoding error = QgsVectorFileWriter.writeAsVectorFormat(layer,

"/path/to/folder/my_esridata",

"UTF-8",

driverName="ESRI Shapefile") if error[0] == QgsVectorFileWriter.NoError:

print("success again!")

El tercer parámetro (obligatorio) especifica la codificación de texto de salida. Sólo algunos controladores necesitan esto para el funcionamiento correcto - Shapefile es uno de ellos (otros controladores ignorarán este parámetro).

Especificar la codificación correcta es importante si utiliza caracteres internacionales (no US-ASCII).

# Write to an ESRI GDB file

opts = QgsVectorFileWriter.SaveVectorOptions() opts.driverName = "FileGDB"

# if no geometry

opts.overrideGeometryType = QgsWkbTypes.NullGeometry

opts.actionOnExistingFile = QgsVectorFileWriter.ActionOnExistingFile.

˓→CreateOrOverwriteLayer

opts.layerName = 'my_new_layer_name'

error = QgsVectorFileWriter.writeAsVectorFormat(layer=vlayer, fileName=gdb_path, options=opts) if error[0] == QgsVectorFileWriter.NoError:

print("success!") else:

print(error)

5.6. Creación de capas vectoriales 27

(34)

También puede convertir campos para que sean compatibles con formatos diferentes usando FieldValueConverter. Por ejemplo, para convertir tipos de variable matriz (por ejemplo, en Post- gres) en un tipo texto, puede hacer lo siguiente:

LIST_FIELD_NAME = 'xxxx'

class ESRIValueConverter(QgsVectorFileWriter.FieldValueConverter):

def __init__(self, layer, list_field):

QgsVectorFileWriter.FieldValueConverter.__init__(self) self.layer = layer

self.list_field_idx = self.layer.fields().indexFromName(list_field)

def convert(self, fieldIdxInLayer, value):

if fieldIdxInLayer == self.list_field_idx:

return QgsListFieldFormatter().representValue(layer=vlayer,

fieldIndex=self.list_field_idx, config={},

cache=None, value=value) else:

return value

def fieldDefinition(self, field):

idx = self.layer.fields().indexFromName(field.name()) if idx == self.list_field_idx:

return QgsField(LIST_FIELD_NAME, QVariant.String) else:

return self.layer.fields()[idx]

converter = ESRIValueConverter(vlayer, LIST_FIELD_NAME)

#opts is a QgsVectorFileWriter.SaveVectorOptions as above opts.fieldValueConverter = converter

También se puede especificar un CRS de destino — si se pasa una instancia válida de QgsCoordinateReferenceSystemcomo cuarto parámetro, la capa se transforma a ese CRS.

Para los nombres de controlador válidos, llame al métodosupportedFiltersAndFormatso consulte los

“formatos admitidos por OGR‘_ — debe pasar el valor en la columna «Código» como el nombre del controlador.

Opcionalmente, puede establecer si desea exportar solo las entidades seleccionadas, pasar más opciones específi- cas del controlador para la creación o indicar al escritor que no cree atributos. . . Hay una serie de otros parámetros (opcionales); consulte la documentación deQgsVectorFileWriterpara más detalles.

5.6.2 Directamente desde las funciones

from qgis.PyQt.QtCore import QVariant

# define fields for feature attributes. A QgsFields object is needed fields = QgsFields()

fields.append(QgsField("first", QVariant.Int)) fields.append(QgsField("second", QVariant.String))

""" create an instance of vector file writer, which will create the vector file.

Arguments:

1. path to new file (will fail if exists already) 2. encoding of the attributes

3. field map

4. geometry type - from WKBTYPE enum 5. layer's spatial reference (instance of

QgsCoordinateReferenceSystem) - optional 6. driver name for the output file """

(35)

writer = QgsVectorFileWriter("my_shapes.shp", "UTF-8", fields, QgsWkbTypes.Point,

˓→driverName="ESRI Shapefile")

if writer.hasError() != QgsVectorFileWriter.NoError:

print("Error when creating shapefile: ", w.errorMessage())

# add a feature fet = QgsFeature()

fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10))) fet.setAttributes([1, "text"])

writer.addFeature(fet)

# delete the writer to flush features to disk del writer

5.6.3 Desde una instancia de QgsVectorLayer

Entre todos los proveedores de datos admitidos por la clase QgsVectorLayer, vamos a centrarnos en las capas basadas en memoria. Proveedor de memoria está destinado a ser utilizado principalmente por plugins o desarrolladores de aplicaciones de 3as partes. No almacena datos en el disco, lo que permite a los desarrolladores utilizarlos como un backend rápido para algunas capas temporales.

El proveedor admite los campos string, int y double.

El proveedor de memoria también admite la indexación espacial, que se habilita llamando a la función createSpatialIndex() del proveedor. Una vez creado el índice espacial, podrá recorrer iterando sobre las entidades dentro de regiones más pequeñas más rápido (ya que no es necesario atravesar todas las entidades, solo las del rectángulo especificado)..

Un proveedor de memoria se crea pasando "memory" como la cadena del proveedor al constructor QgsVectorLayer.

El constructor también toma un URI que define el tipo de geometría de la capa, uno de: "Point",

"LineString", "Polygon", "MultiPoint", "MultiLineString", "MultiPolygon" o "None".

El URI también puede especificar el sistema de referencia de coordenadas, los campos y la indexación del provee- dor de memoria en el URI. La sintaxis es:

crs=definición Especifica el sistema de referencia de coordenadas, donde la definition puede ser cualquiera de las formas aceptadas porQgsCoordinateReferenceSystem.createFromString

index=yes Especifica que el proveedor utilizará un índice espacial

campo Especifica un atributo de la capa. El atributo tiene un nombre y, opcionalmente, un tipo (entero, doble o cadena), longitud y precisión. Puede haber múltiples definiciones de campo

El siguiente ejemplo de una URI incorpora todas estas opciones

"Point?crs=epsg:4326&field=id:integer&field=name:string(20)&index=yes"

El siguiente código de ejemplo ilustra como crear y rellenar un proveedor de memoria from qgis.PyQt.QtCore import QVariant

# create layer

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

# add fields

pr.addAttributes([QgsField("name", QVariant.String), QgsField("age", QVariant.Int),

5.6. Creación de capas vectoriales 29

(36)

QgsField("size", QVariant.Double)])

vl.updateFields() # tell the vector layer to fetch changes from the provider

# add a feature fet = QgsFeature()

fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10,10))) fet.setAttributes(["Johny", 2, 0.3])

pr.addFeatures([fet])

# update layer's extent when new features have been added

# because change of extent in provider is not propagated to the layer vl.updateExtents()

Finalmente, vamos a comprobar si todo salió bien

# show some stats

print("fields:", len(pr.fields())) print("features:", pr.featureCount()) e = vl.extent()

print("extent:", e.xMinimum(), e.yMinimum(), e.xMaximum(), e.yMaximum())

# iterate over features features = vl.getFeatures() for fet in features:

print("F:", fet.id(), fet.attributes(), fet.geometry().asPoint())

5.7 Apariencia (Simbología) de capas vectoriales

Cuando una capa vectorial se representa, la apariencia de los datos se indica por renderer y símbolos asociados a la capa. Los símbolos son clases que se encargan del dibujo de la representación visual de las entidades, mientras que los renderizadores determinan qué símbolo se utilizará para una entidad determinada.

El renderizador para una capa determinada se puede obtener como se muestra a continuación:

renderer = layer.renderer()

And with that reference, let us explore it a bit print("Type:", renderer.type())

There are several known renderer types available in the QGIS core library:

Tipo Clase Descripción

singleSymbol QgsSingleSymbolRenderer Renders all features with the same symbol catego-

rizedSymbol

QgsCategorizedSymbolRendererRenders features using a different symbol for each cat- egory

graduatedSym- bol

QgsGraduatedSymbolRendererRenders features using a different symbol for each range of values

There might be also some custom renderer types, so never make an assumption there are just these types. You can query the application’sQgsRendererRegistryto find out currently available renderers:

print(QgsApplication.rendererRegistry().renderersList())

# Print:

(37)

['nullSymbol', 'singleSymbol', 'categorizedSymbol', 'graduatedSymbol', 'RuleRenderer', 'pointDisplacement', 'pointCluster',

'invertedPolygonRenderer', 'heatmapRenderer',

'25dRenderer']

It is possible to obtain a dump of a renderer contents in text form — can be useful for debugging print(renderer.dump())

5.7.1 Representador de Símbolo Único

You can get the symbol used for rendering by callingsymbol()method and change it withsetSymbol() method (note for C++ devs: the renderer takes ownership of the symbol.)

You can change the symbol used by a particular vector layer by calling setSymbol()passing an instance of the appropriate symbol instance. Symbols for point, line and polygon layers can be created by calling the createSimple()function of the corresponding classesQgsMarkerSymbol,QgsLineSymboland QgsFillSymbol.

The dictionary passed tocreateSimple()sets the style properties of the symbol.

For example you can replace the symbol used by a particular point layer by callingsetSymbol()passing an instance of aQgsMarkerSymbol, as in the following code example:

symbol = QgsMarkerSymbol.createSimple({'name': 'square', 'color': 'red'}) layer.renderer().setSymbol(symbol)

# show the change layer.triggerRepaint()

nameindicates the shape of the marker, and can be any of the following:

• circle

• cuadrado

• cross

• rectangle

• Diamante

• pentagon

• triángulo

• equilateral_triangle

• star

• regular_star

• arrow

• filled_arrowhead

• x

To get the full list of properties for the first symbol layer of a symbol instance you can follow the example code:

5.7. Apariencia (Simbología) de capas vectoriales 31

Riferimenti

Documenti correlati

e da occasioni di supervisione, oltre 40 operatori sono stati formati alla funzione di ascolto, di pre- venzione e de-escalation della conflittualità; alla gestione di incontri

Relative to our previous public release (DR10), DR12 adds one million new spectra of galaxies and quasars from the Baryon Oscillation Spectroscopic Survey (BOSS) over an additional

Figure 8 is the main result of this work: for the first time we have performed a NLO+NLL calculation of supersymmetric particle pair production at hadron colliders accounting for

Con respecto a la elección de los conventos mendicantes como espacios para la celebración de reuniones concejiles, debemos advertir de que dicha tendencia ha sido documentada

Ovarian suppression with the use of LHRHa during chemotherapy is an attractive option to preserve gonadal function and fertility given the wide availability of such agents and

Analisi termo-energetica della struttura opaca di involucro realizzata con parete multistrato leggera, calcolo della prestazione energetica globale, analisi tecnico-economica

ocurre en un diccionario jurídico, en el que los lexicógrafos no pueden —por razo- nes de espacio— añadir demasiado contexto en sus entradas, en el caso de Rebecca Jowers, los