0% encontró este documento útil (0 votos)
60 vistas178 páginas

QGIS 3.40 PyQGISDeveloperCookbook Es

El 'PyQGIS 3.40 Developer Cookbook' es una guía para desarrolladores que cubre la creación de scripts y plugins en QGIS utilizando Python. Incluye secciones sobre la carga de proyectos y capas, así como el manejo de geometría y la personalización de la apariencia de las capas. Este documento es esencial para aquellos que buscan profundizar en el desarrollo de aplicaciones geoespaciales con QGIS.

Cargado por

re_a_c_tor
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
60 vistas178 páginas

QGIS 3.40 PyQGISDeveloperCookbook Es

El 'PyQGIS 3.40 Developer Cookbook' es una guía para desarrolladores que cubre la creación de scripts y plugins en QGIS utilizando Python. Incluye secciones sobre la carga de proyectos y capas, así como el manejo de geometría y la personalización de la apariencia de las capas. Este documento es esencial para aquellos que buscan profundizar en el desarrollo de aplicaciones geoespaciales con QGIS.

Cargado por

re_a_c_tor
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

PyQGIS 3.

40 developer cookbook

QGIS Project

28 de junio de 2025
Índice general

1 Introducción 3
1.1 Desarrollar scripts en la consola de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Plugins Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2.1 Complementos de procesamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3 Ejecutar código Python cuando QGIS se inicia. . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.1 El fichero [Link] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.2 La variable de entorno PYQGIS_STARTUP . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.3 El parámetro --code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.3.4 Argumentos adicionales para Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4 Aplicaciones Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4.1 Usando PyQGIS en scripts individuales . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.4.2 Usando PyQGIS en aplicaciones personalizadas . . . . . . . . . . . . . . . . . . . . . . 7
1.4.3 Ejecutar aplicaciones personalizadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.5 Notas técnicas sobre PyQt y SIP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

2 Cargar proyectos 9
2.1 Resolver rutas erróneas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.2 Uso de banderas para acelerar las cosas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

3 Cargar capas 13
3.1 Capas Vectoriales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Capas ráster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3 Instancia QgsProject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

4 Accediendo a la Tabla de Contenidos (TOC) 19


4.1 La clase QgsProject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.2 Clase QgsLayerTreeGroup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

5 Usar las capas ráster 23


5.1 Detalles de la capa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2 Renderizador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
5.2.1 Rásters de una sola banda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2.2 Rásters multibanda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.3 Valores de consulta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.4 Edición de datos ráster . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

6 Usar capas vectoriales 27


6.1 Recuperando información sobre atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6.2 Iterando sobre la capa vectorial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6.3 Seleccionando objetos espaciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.3.1 Accediendo a atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

i
6.3.2 Iterando sobre rasgos seleccionados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.3.3 Iterando sobre un subconjunto de rasgos . . . . . . . . . . . . . . . . . . . . . . . . . . 31
6.4 Modificación de capas vectoriales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.4.1 Añadir Entidades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
6.4.2 Borrar Entidades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.4.3 Modificar los objetos espaciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.4.4 Modificación de capas vectoriales con un búfer de edición . . . . . . . . . . . . . . . . . 33
6.4.5 Agregando y Removiendo Campos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.5 Usar índice espacial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.6 La clase QgsVectorLayerUtils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.7 Creación de capas vectoriales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.7.1 Desde una instancia de QgsVectorFileWriter . . . . . . . . . . . . . . . . . . . . 37
6.7.2 Directamente desde las funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.7.3 Desde una instancia de QgsVectorLayer . . . . . . . . . . . . . . . . . . . . . . . . 39
6.8 Apariencia (Simbología) de capas vectoriales . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.8.1 Representador de Símbolo Único . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.8.2 Representador de símbolo categorizado . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.8.3 Renderizador de símbolo graduado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
6.8.4 Trabajo con Símbolos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
6.8.5 Crear Renderizados personalizados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.9 Más Temas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

7 Manejo de Geometría 51
7.1 Construcción de Geometría . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.2 Acceso a Geometría . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.3 Geometría predicados y Operaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

8 Soporte de Proyecciones 57
8.1 Sistemas de coordenadas de referencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.2 Transformación SRC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

9 Usando el Lienzo de Mapa 61


9.1 Lienzo de mapa insertado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
9.2 Bandas elásticas y marcadores de vértices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
9.3 Utilizar las herramientas del mapa con el lienzo . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
9.3.1 Selecciona una entidad usando QgsMapToolIdentifyFeature . . . . . . . . . . . . . . . . 65
9.3.2 Añadir temas al menú contextual del lienzo del mapa . . . . . . . . . . . . . . . . . . . . 65
9.4 Escribir herramientas de mapa personalizados . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.5 Escribir elementos de lienzo de mapa personalizado . . . . . . . . . . . . . . . . . . . . . . . . . 67

10 Representación del Mapa e Impresión 69


10.1 Representación Simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.2 Representando capas con diferente SRC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
10.3 Salida usando diseño de impresión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
10.3.1 Comprobación de la validez del diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
10.3.2 Exportando la composición . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
10.3.3 Exportar un atlas de diseño . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74

11 Expresiones, Filtros y Calculando Valores 75


11.1 Análisis de expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
11.2 Evaluar expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
11.2.1 Expresiones Basicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
11.2.2 Expresiones con caracteristicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
11.2.3 Flitrando una capa con expresiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
11.3 Manejando errores de expresión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

12 Configuración de lectura y almacenamiento 81

13 Comunicarse con el usuario 85

ii
13.1 Mostrando mensajes. La clase QgsMessageBar . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
13.2 Mostrando el progreso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
13.3 Registro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.3.1 QgsMessageLog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
13.3.2 El python construído en el módulo de registro . . . . . . . . . . . . . . . . . . . . . . . . 90

14 Infraestructura de autenticación 91
14.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
14.2 Glosario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
14.3 QgsAuthManager el punto de entrada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
14.3.1 Inicie el administrador y configure la contraseña maestra . . . . . . . . . . . . . . . . . . 93
14.3.2 Complete authdb con una nueva entrada de configuración de autenticación . . . . . . . . . 93
14.3.3 Borrar una entrada de authdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
14.3.4 Deje la expansión authcfg a QgsAuthManager . . . . . . . . . . . . . . . . . . . . . . . 95
14.4 Adpatar complementos para usar Infraestructura de Autenticación . . . . . . . . . . . . . . . . . . 96
14.5 Autenticación IGUs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
14.5.1 IGU para seleccionar credenciales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
14.5.2 IGU Editor Autenticación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
14.5.3 IGU de Editor de Autoridades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98

15 Tareas - haciendo trabajo duro en segundo plano 99


15.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
15.2 Ejemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
15.2.1 Extendiendo QgsTask . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
15.2.2 Tarea desde función . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
15.2.3 Tarea de un algoritmo de procesamiento . . . . . . . . . . . . . . . . . . . . . . . . . . 104

16 Desarrollando Plugins Python 107


16.1 Estructurar Complementos de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
16.1.1 Cómo empezar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
16.1.2 Escribir el código del complemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
16.1.3 Documentación de complementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
16.1.4 Traducción de complementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
16.1.5 Compartir su complemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
16.1.6 Consejos y Trucos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
16.2 Fragmentos de código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
16.2.1 Cómo llamar a un método por un atajo de teclado . . . . . . . . . . . . . . . . . . . . . 117
16.2.2 Cómo reutilizar los iconos de QGIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
16.2.3 Interfaz para complemento en el cuadro de diálogo de opciones . . . . . . . . . . . . . . 117
16.2.4 Incrustar widgets personalizados para capas en el árbol de capas . . . . . . . . . . . . . . 119
16.3 Configuración IDE para escribir y depurar complementos . . . . . . . . . . . . . . . . . . . . . . 120
16.3.1 Complementos útiles para escribir complementos de Python . . . . . . . . . . . . . . . . 120
16.3.2 Una nota sobre la configuración de su IDE en Linux y Windows . . . . . . . . . . . . . . 120
16.3.3 Depuración con Pyscripter IDE (Windows) . . . . . . . . . . . . . . . . . . . . . . . . . 120
16.3.4 Depurar con Eclipse y PyDev . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
16.3.5 Depurar con PyCharm en Ubuntu con un QGIS compilado . . . . . . . . . . . . . . . . . 125
16.3.6 Depurar usando PDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
16.4 Lanzamiento de su complemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
16.4.1 Metadatos y nombres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
16.4.2 Código y ayuda . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
16.4.3 Repositorio oficial de complementos de Python . . . . . . . . . . . . . . . . . . . . . . . 128

17 Escribir nuevos complementos de procesamiento 131


17.1 Creando desde cero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
17.2 Actuializar un complemento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131

18 Utilizar complemento Capas 135


18.1 Subclassing QgsPluginLayer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135

iii
19 Biblioteca de análisis de redes 137
19.1 Información general . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
19.2 Contruir un gráfico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
19.3 Análisis gráfico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
19.3.1 Encontrar la ruta más corta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
19.3.2 Áreas de disponibilidad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144

20 Servidor QGIS y Python 147


20.1 Introducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
20.2 Conceptos básicos de la API del servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
20.3 Independiente o incrustado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
20.4 Complementos del servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
20.4.1 Complementos de filtro de servidor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
20.4.2 Servicios personalizados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
20.4.3 APIs personalizadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

21 hoja de referencia para PyQGIS 161


21.1 Interfaz de Usuario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
21.2 Configuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
21.3 Barras de herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
21.4 Menús . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
21.5 Lienzo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
21.6 Capas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
21.7 Tabla de contenidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
21.8 TOC avanzado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
21.9 Algoritmos de procesamiento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
21.10 Decoradores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
21.11 Compositor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
21.12 Fuentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172

iv
PyQGIS 3.40 developer cookbook

Índice general 1
PyQGIS 3.40 developer cookbook

2 Índice general
CAPÍTULO 1

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.
Se otorga permiso para copiar, distribuir y/o modificar este documento bajo los términos de la Licencia de
Documentación Libre GNU, Versión 1.3 o cualquier versión posterior publicada por la Free Software Foundation;
sin secciones invariantes, sin textos de portada y sin textos de contraportada.
Se incluye una copia de la licencia en la sección gnu_fdl.
Esta licencia también se aplica a todos los fragmentos de código de este documento.
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 algoritmos de procesamiento
• Crear funciones para expresiones en 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 (vea Servidor
QGIS y Python) y los enlaces de Python que se pueden usar para incrustar QGIS Server en una aplicación de Python.
Hay una referencia API completa de QGIS C++ que documenta las clases de las librerías de QGIS. The Pythonic
QGIS API (pyqgis) es casi idéntica a la API de C++.
Otro buen recurso para aprender a realizar tareas comunes es descargar complementos existentes desde el repositorio
de complementos y examine su código.

3
PyQGIS 3.40 developer cookbook

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

Figura 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 <[Link]>. 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 [Link] import *


import [Link]

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ágina Complementos de Python para más información sobre complementos y desarrollo de
complementos.
Crear plugins con Python es simple, vea Desarrollando Plugins Python para instrucciones detalladas.

Nota: Los plugins de Python están también disponibles para QGIS Server. Vea Servidor QGIS y Python para más
detalles.

4 Capítulo 1. Introducción
PyQGIS 3.40 developer cookbook

1.2.1 Complementos de procesamiento

Los complementos de procesamiento se pueden utilizar para procesar datos. Son más fáciles de desarrollar, más
específicos y más livianos que los complementos de Python. Escribir nuevos complementos de procesamiento explica
cuándo es adecuado el uso de algoritmos de Processing y cómo desarrollarlos.

1.3 Ejecutar código Python cuando QGIS se inicia.

Existen diferentes métodos para ejecutar código Python cada vez que se inicia QGIS.
1. Crear un script [Link]
2. Configurar la variable de entorno PYQGIS_STARTUP a un fichero Python existente
3. Especificación de un script de inicio mediante el parámetro --code init_qgis.py.

1.3.1 El fichero [Link]

Cada vez que se inicia QGIS, se busca en el directorio de Python del usuario y en una lista de rutas del sistema un
fichero llamado [Link]. Si ese archivo existe, es ejecutado por el intérprete de Python incrustado.
La ruta en el directorio personal del usuario suele encontrarse en:
• Linux: .local/share/QGIS/QGIS3
• Windows: AppData\Roaming\QGIS\QGIS3
• macOS: Library/Application Support/QGIS/QGIS3
Las rutas predeterminada del sistema dependen del sistema operativo. Para encontrar las rutas que funcionan para
usted, abra la consola de Python y ejecute [Link](QStandardPaths.
AppDataLocation) para ver la lista de directorios por defecto.
El script [Link] se ejecuta inmediatamente después de inicializar python en QGIS, al inicio de la aplicación.

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 [Link], 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.3.3 El parámetro --code

Puede proporcionar código personalizado para ejecutar como parámetro de inicio a QGIS. Para ello, cree un archivo
python, por ejemplo qgis_init.py, para ejecutar e iniciar QGIS desde la línea de comandos utilizando qgis
--code qgis_init.py.
El código proporcionado a través de --code se ejecuta al final de la fase de inicialización de QGIS, después de que
se hayan cargado los componentes de la aplicación.

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


PyQGIS 3.40 developer cookbook

1.3.4 Argumentos adicionales para Python

Para proporcionar argumentos adicionales para tu script --code o para otro código python que se ejecute, puedes
usar el argumento --py-args. Cualquier argumento que venga después de --py-args y antes de -- arg (si está
presente) será pasado a Python pero ignorado por la propia aplicación QGIS.
En el siguiente ejemplo, [Link] estará disponible a través de [Link] en Python pero no será cargado
por QGIS. Mientras que [Link] será cargado por QGIS pero no está presente en [Link].

qgis --code qgis_init.py --py-args [Link] -- [Link]

Si quiere acceder a todos los parámetros de la línea de comandos desde Python, puedes utilizar
[Link]().

[Link]().arguments()

1.4 Aplicaciones Python

A menudo es útil crear scripts para automatizar procesos. Con PyQGIS, esto es perfectamente posible — importe el
módulo [Link], Inicialícelo y estará listo para el procesamiento.
O tal vez desee crear una aplicación interactiva que utilice la funcionalidad GIS — realizar mediciones, exportar un
mapa como PDF, … El módulo [Link] proporciona varios componentes GUI, en particular el widget de lienzo del
mapa que se puede incorporar a la aplicación con soporte para hacer 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 proporcionan ejemplos de
cada uno de ellos.

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

1.4.1 Usando PyQGIS en scripts individuales

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

1 from [Link] import *


2

3 # Supply path to qgis install location


4 [Link]("/path/to/qgis/installation", True)
5

6 # Create a reference to the QgsApplication. Setting the


7 # second argument to False disables the GUI.
8 qgs = QgsApplication([], False)
9

10 # Load providers
11 [Link]()
12

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


14 # algorithms, etc.
15

16 # Finally, exitQgis() is called to remove the


17 # provider and layer registries from memory
18 [Link]()

6 Capítulo 1. Introducción
PyQGIS 3.40 developer cookbook

Primero importa el módulo [Link] y configura el prefijo de ruta. El prefijo de ruta es la ubicación donde
está instalado QGIS en su sistema. Se configura en el script llamando al método setPrefixPath(). El
segundo argumento de setPrefixPath() es establecido a True, especificando que se utilizarán las rutas
predeterminadas.
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 usar
Desarrollar scripts en la consola de Python desde dentro de QGIS y ver el resultado de ejecutar:

[Link]()

Una vez configurada la ruta del prefijo, guardamos una referencia a QgsApplication en la variable qgs. El
segundo argumento está establecido como False, especificando que no planeamos usar la GUI ya que estamos
escribiendo un script independiente. Con QgsApplication configurado, cargamos los proveedores de datos de
QGIS y el registro de capas llamando al método initQgis().

[Link]()

Con QGIS inicializado, estamos listos para escribir el resto del script. Finalmente, terminamos llamando a
exitQgis() para eliminar los proveedores de datos y el registro de capas de la memoria.

[Link]()

1.4.2 Usando PyQGIS en aplicaciones personalizadas

La única diferencia entre Usando PyQGIS en scripts individuales y una aplicación PyQGIS personalizada es el segundo
argumento al crear una instancia del QgsApplication. Pase True en lugar de False para indicar que planeamos
utilizar una IGU.

1 from [Link] import *


2

3 # Supply the path to the qgis install location


4 [Link]("/path/to/qgis/installation", True)
5

6 # Create a reference to the QgsApplication.


7 # Setting the second argument to True enables the GUI. We need
8 # this since this is a custom application.
9

10 qgs = QgsApplication([], True)


11

12 # load providers
13 [Link]()
14

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


16 # algorithms, etc.
17

18 # Finally, exitQgis() is called to remove the


19 # provider and layer registries from memory
20 [Link]()

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. Aplicaciones Python 7


PyQGIS 3.40 developer cookbook

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 [Link]


ImportError: No module named [Link]

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 [Link]


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
enlazador 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.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.

8 Capítulo 1. Introducción
CAPÍTULO 2

Cargar proyectos

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 Qgis,
3 QgsProject,
4 QgsPathResolver
5 )
6

7 from [Link] import (


8 QgsLayerTreeMapCanvasBridge,
9 )

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 clase QgsProject. Esta es una
clase singleton, por lo tanto se debe usar el método instance() para realizarlo. Puede llamar su método read()
y pasar la ruta para que el proyecto sea cargado:

1 # If you are not inside a QGIS console you first need to import
2 # qgis and PyQt classes you will use in this script as shown below:
3 from [Link] import QgsProject
4 # Get the project instance
5 project = [Link]()
6 # Print the current project file name (might be empty in case no projects have␣
,→been loaded)

7 # print([Link]())
8

9 # Load another project


10 [Link]('testdata/01_project.qgs')
11 print([Link]())

testdata/01_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étodo write() de su instancia de proyecto. El método write() también acepta una

9
PyQGIS 3.40 developer cookbook

ruta opcional para salvar el proyecto en una nueva localización:

# Save the project to the same


[Link]()
# ... or to a new file
[Link]('testdata/my_new_qgis_project.qgs')

Las funciones read() y write() 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
<[Link]>” al igual que en el ejemplo:

bridge = QgsLayerTreeMapCanvasBridge( \
[Link]().layerTreeRoot(), canvas)
# Now you can safely load your project and see it in the canvas
[Link]('testdata/my_new_qgis_project.qgs')

2.1 Resolver rutas erróneas

Puede suceder que las capas cargadas en el proyecto se muevan a otra ubicación. Cuando el proyecto se vuelve a
cargar, todas las rutas de las capas se rompen. La clase QgsPathResolver le ayuda a reescribir la ruta de las
capas dentro del proyecto.
Su método setPathPreprocessor() permite configurar una función de preprocesador de ruta personalizada
para manipular rutas y fuentes de datos antes de resolverlas en referencias de archivos o fuentes de capas.
La función del procesador debe aceptar un único argumento de cadena (que represente la ruta del archivo original o
la fuente de datos) y devolver una versión procesada de esta ruta. La función de preprocesador de ruta se llama antes
de cualquier controlador de capa defectuoso. Si se configuran varios preprocesadores, se llamarán en secuencia según
el orden en que se configuraron originalmente.
Algunos casos de uso:
1. reemplazar ruta desactualizada:

def my_processor(path):
return [Link]('c:/Users/ClintBarton/Documents/Projects', 'x:/
,→Projects/')

[Link](my_processor)

2. reemplace una dirección host de base de datos con una nueva:

def my_processor(path):
return [Link]('host=[Link]', 'host=[Link]')

[Link](my_processor)

3. reemplazar credenciales de base de datos almacenada con unas nuevas:

1 def my_processor(path):
2 path= [Link]("user='gis_team'", "user='team_awesome'")
3 path = [Link]("password='cats'", "password='g7as!m*'")
4 return path
5

6 [Link](my_processor)

10 Capítulo 2. Cargar proyectos


PyQGIS 3.40 developer cookbook

Del mismo modo, un método setPathWriter() está disponible para una función de escritor de ruta.
Un ejemplo para reemplazar la ruta con una variable:

def my_processor(path):
return [Link]('c:/Users/ClintBarton/Documents/Projects', '$projectdir$')

[Link](my_processor)

Ambos métodos devuelven un id que se puede usar para eliminar el preprocesador o escritor que agregaron. Consulte
removePathPreprocessor() y removePathWriter().

2.2 Uso de banderas para acelerar las cosas

En algunos casos en los que puede que no necesite utilizar un proyecto completamente funcional, pero sólo desea
acceder a él por una razón específica, las banderas pueden ser útiles. Una lista completa de banderas está disponible
en ProjectReadFlag. Se pueden añadir varias banderas juntas.
Por ejemplo, si no nos importan las capas y los datos reales y simplemente queremos acceder a un proyecto (por
ejemplo, para el diseño o la configuración de la vista 3D), podemos utilizar la bandera DontResolveLayers
para omitir el paso de validación de datos y evitar que aparezca el diálogo de capa incorrecta. Se puede hacer lo
siguiente:

readflags = [Link]()
readflags |= [Link]
project = [Link]()
[Link]('C:/Users/ClintBarton/Documents/Projects/[Link]',␣
,→readflags)

Para añadir más banderas se debe utilizar el operador Bitwise OR de python (|).

2.2. Uso de banderas para acelerar las cosas 11


PyQGIS 3.40 developer cookbook

12 Capítulo 2. Cargar proyectos


CAPÍTULO 3

Cargar capas

Consejo: Los fragmentos de código en esta página necesitan las siguientes importaciones:
import os # This is is needed in the pyqgis console also
from [Link] import (
QgsVectorLayer
)

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 y añadir una instancia de capa vectorial al proyecto, especifique el identificador de fuente de datos de la
capa. El identificador de fuente de datos es una cadena y es específico de cada proveedor de datos vectoriales. Se
utiliza un nombre de capa opcional para identificar la capa en el panel Capas. Es importante comprobar si la capa se
ha cargado correctamente. Si no es así, se devuelve una instancia de capa no válida.
Para una capa vectorial creada mediante un geopackage:
1 # get the path to a geopackage
2 path_to_gpkg = "testdata/data/[Link]"
3 # append the layername part
4 gpkg_airports_layer = path_to_gpkg + "|layername=airports"
5 vlayer = QgsVectorLayer(gpkg_airports_layer, "Airports layer", "ogr")
6 if not [Link]():
7 print("Layer failed to load!")
8 else:
9 [Link]().addMapLayer(vlayer)

La forma más rápida de abrir y mostrar una capa vectorial en QGIS es el método addVectorLayer() de la clase
QgisInterface:
vlayer = [Link](gpkg_airports_layer, "Airports layer", "ogr")
if not vlayer:
print("Layer failed to load!")

13
PyQGIS 3.40 developer cookbook

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:
• El proveedor ogr de la biblioteca GDAL soporta una amplia variedad de formatos, también llamados drivers en
el lenguaje GDAL. Algunos ejemplos son ESRI Shapefile, Geopackage, Flatgeobuf, Geojson, … Para formatos
de un solo archivo, la ruta del archivo suele ser suficiente como uri. Para geopackages o dxf, un sufijo separado
por una tubería permite especificar la capa a cargar.
– para Shapefile de ESRI:

uri = "testdata/[Link]"
vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr")
[Link]().addMapLayer(vlayer)

– para Geopackage (tenga en cuenta las opciones internas en la uri de la fuente de datos):

uri = "testdata/data/[Link]|layername=airports"
vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr")
[Link]().addMapLayer(vlayer)

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

uri = "testdata/[Link]|layername=entities|geometrytype=Polygon"
vlayer = QgsVectorLayer(uri, "layer_name_you_like", "ogr")
[Link]().addMapLayer(vlayer)

• 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 clase QgsDataSourceUri puede 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:

1 uri = QgsDataSourceUri()
2 # set host name, port, database name, username and password
3 [Link]("localhost", "5432", "dbname", "johny", "xxx")
4 # set database schema, table name, geometry column and optionally
5 # subset (WHERE clause)
6 [Link]("public", "roads", "the_geom", "cityid = 2643", "primary_key_
,→field")

8 vlayer = QgsVectorLayer([Link](False), "layer name you like", "postgres")

Nota: El argumento False pasado a [Link](False) previene la expansión de los parámetros de


configuració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 = "[Link]
,→format([Link](), ";", "x", "y")

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


[Link]().addMapLayer(vlayer)

Nota: La cadena de proveedor está estructurada como una dirección URL, por lo que la ruta de acceso debe ir
precedida de [Link] 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:

14 Capítulo 3. Cargar capas


PyQGIS 3.40 developer cookbook

uri = "[Link]
,→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 = "testdata/[Link]?type=track"
vlayer = QgsVectorLayer(uri, "layer name you like", "gpx")
[Link]().addMapLayer(vlayer)

• La base de datos SpatiaLite — De forma similar a las bases de datos PostGIS, :class:”QgsDataSourceUri
<[Link]>” puede ser utilizado para la generación de identificador de origen de datos:

1 uri = QgsDataSourceUri()
2 [Link]('/home/martin/[Link]')
3 schema = ''
4 table = 'Towns'
5 geom_column = 'Geometry'
6 [Link](schema, table, geom_column)
7

8 display_name = 'Towns'
9 vlayer = QgsVectorLayer([Link](), display_name, 'spatialite')
10 [Link]().addMapLayer(vlayer)

• Geometrías basadas en MySQL WKB, a través de GDAL — 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" )


[Link]().addMapLayer(vlayer)

• Conexión WFS: La conexión se define con un URL y usando el proveedor `` WFS “”:

uri = "[Link]
,→request=GetFeature&typename=ms:cities"

vlayer = QgsVectorLayer(uri, "my wfs layer", "WFS")

La uri se puede crear utilizando la librería estándar urllib:

1 import urllib
2

3 params = {
4 'service': 'WFS',
5 'version': '2.0.0',
6 'request': 'GetFeature',
7 'typename': 'ms:cities',
8 'srsname': "EPSG:4326"
9 }
10 uri2 = '[Link] + [Link](urllib.
,→[Link](params))

Nota: Puede cambiar la fuente de datos de una capa existente llamando a setDataSource() en una instancia
de QgsVectorLayer, como se muestra a continuación ejemplo:

1 uri = "[Link]
,→request=GetFeature&typename=ms:cities"

2 provider_options = [Link]()
3 # Use project's transform context
(continúe en la próxima página)

3.1. Capas Vectoriales 15


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


4 provider_options.transformContext = [Link]().transformContext()
5 [Link](uri, "layer name you like", "WFS", provider_options)
6

7 del(vlayer)

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:

1 # get the path to a tif file e.g. /home/project/data/[Link]


2 path_to_tif = "qgis-projects/python_cookbook/data/[Link]"
3 rlayer = QgsRasterLayer(path_to_tif, "SRTM layer name")
4 if not [Link]():
5 print("Layer failed to load!")

Para cargar una capa raster desde un geopackage:

1 # get the path to a geopackage e.g. /home/project/data/[Link]


2 path_to_gpkg = [Link]([Link](), "testdata", "[Link]")
3 # gpkg_raster_layer = "GPKG:/home/project/data/[Link]:srtm"
4 gpkg_raster_layer = "GPKG:" + path_to_gpkg + ":srtm"
5

6 rlayer = QgsRasterLayer(gpkg_raster_layer, "layer name you like", "gdal")


7

8 if not [Link]():
9 print("Layer failed to load!")

De manera similar a las capas vectoriales, las capas raster pueden ser cargadas utilizando la función addRasterLayer
de un objeto perteneciente a QgisInterface

[Link](path_to_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.
Para cargar un ráster PostGIS:
Los rásteres PostGIS, similares a los vectores PostGIS, se pueden agregar a un proyecto mediante una cadena URI.
Es eficaz mantener un diccionario de cadenas reutilizable para los parámetros de conexión de la base de datos.
Esto facilita la edición del diccionario para la conexión correspondiente. Luego, el diccionario se codifica en un
URI utilizando el objeto de metadatos del proveedor “postgresraster”. Después de eso, el ráster se puede agregar al
proyecto.

1 uri_config = {
2 # database parameters
3 'dbname':'gis_db', # The PostgreSQL database to connect to.
4 'host':'localhost', # The host IP address or localhost.
5 'port':'5432', # The port to connect on.
6 'sslmode':[Link], # SslAllow, SslPrefer, SslRequire,␣
,→SslVerifyCa, SslVerifyFull

7 # user and password are not needed if stored in the authcfg or service
8 'authcfg':'QconfigId', # The QGIS athentication database ID holding␣
,→connection details.

9 'service': None, # The PostgreSQL service to be used for connection to␣


,→the database.

(continúe en la próxima página)

16 Capítulo 3. Cargar capas


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


10 'username':None, # The PostgreSQL user name.
11 'password':None, # The PostgreSQL password for the user.
12 # table and raster column details
13 'schema':'public', # The database schema that the table is located in.
14 'table':'my_rasters', # The database table to be loaded.
15 'geometrycolumn':'rast',# raster column in PostGIS table
16 'sql':None, # An SQL WHERE clause. It should be placed at the end␣
,→of the string.

17 'key':None, # A key column from the table.


18 'srid':None, # A string designating the SRID of the coordinate␣
,→reference system.

19 'estimatedmetadata':'False', # A boolean value telling if the metadata is␣


,→estimated.

20 'type':None, # A WKT string designating the WKB Type.


21 'selectatid':None, # Set to True to disable selection by feature ID.
22 'options':None, # other PostgreSQL connection options not in this list.
23 'enableTime': None,
24 'temporalDefaultTime': None,
25 'temporalFieldIndex': None,
26 'mode':'2', # GDAL 'mode' parameter, 2 unions raster tiles, 1 adds␣
,→tiles separately (may require user input)

27 }
28 # remove any NULL parameters
29 uri_config = {key:val for key, val in uri_config.items() if val is not None}
30 # get the metadata for the raster provider and configure the URI
31 md = [Link]().providerMetadata('postgresraster')
32 uri = QgsDataSourceUri([Link](uri_config))
33

34 # the raster can then be loaded into the project


35 rlayer = [Link]([Link](False), "raster layer name", "postgresraster
,→")

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

layer_name = 'modis'
url = "[Link]
rlayer = QgsRasterLayer(uri, '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. QgsDataSourceUri debe 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
predeterminado 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
GetCoverage anunciada por GetCapabilities. Puede ser necesario si un servidor no está configurado
correctamente.

3.2. Capas ráster 17


PyQGIS 3.40 developer cookbook

• 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 = "crs=EPSG:4326&format=image/png&layers=continents&styles&
,→url=[Link]

rlayer = QgsRasterLayer(urlWithParams, 'some layer name', 'wms')


if not [Link]():
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 de QgsProject.
La instancia QgsProject toma 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étodo addMapLayer() :

[Link]().addMapLayer(rlayer)

Para agregar una capa en una posición absoluta:

1 # first add the layer without showing it


2 [Link]().addMapLayer(rlayer, False)
3 # obtain the layer tree of the top-level group in the project
4 layerTree = [Link]().rootGroup()
5 # the position is a number starting from 0, with -1 an alias for the end
6 [Link](-1, QgsLayerTreeLayer(rlayer))

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

# [Link]().removeMapLayer(layer_id)
[Link]().removeMapLayer([Link]())

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étodo mapLayers() :

[Link]().mapLayers()

18 Capítulo 3. Cargar capas


CAPÍTULO 4

Accediendo a la Tabla de Contenidos (TOC)

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:
from [Link] import (
QgsProject,
QgsVectorLayer,
)

Puede usar diferentes clases para acceder a todas las capas cargadas en la TOC y usarlas para obtener información:
• QgsProject
• QgsLayerTreeGroup

4.1 La clase QgsProject

Puede usar la clase QgsProject para recuperar información sobre la TOC y todas las capas cargadas.
Debe crear una instance de QgsProject y usar sus métodos para obtener las capas cargadas.
El método principal es mapLayers(). Devolverá un diccionario con las capas cargadas:
layers = [Link]().mapLayers()
print(layers)

{'countries_89ae1b0f_f41b_4f42_bca4_caf55ddbe4b6': <QgsVectorLayer: 'countries'␣


,→(ogr)>}

Las claves del diccionario son las ids únicas de capa mientras que los valores son los objetos relacionados.
Ahora es sencillo obtener cualquier otra información sobre las capas:
1 # list of layer names using list comprehension
2 l = [[Link]() for layer in [Link]().mapLayers().values()]
3 # dictionary with key = layer name and value = layer object
4 layers_list = {}
(continúe en la próxima página)

19
PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


5 for l in [Link]().mapLayers().values():
6 layers_list[[Link]()] = l
7

8 print(layers_list)

{'countries': <QgsVectorLayer: 'countries' (ogr)>}

Puede además consultar la TOC usando el nombre de la capa:


country_layer = [Link]().mapLayersByName("countries")[0]

Nota: Se devuelve una lista con todas las capas coincidentes, por lo que indexamos con [0] para obtener la primera
capa con este nombre.

4.2 Clase QgsLayerTreeGroup

La capa árbol es una estructura clásica de árbol construida con nodos. Hay actualmente dos tipos de nodos: nodos de
grupo (QgsLayerTreeGroup) y nodos de capa (QgsLayerTreeLayer).

Nota: for more information you can read these blog posts of Martin Dobias: Part 1 Part 2 Part 3

Se puede acceder fácilmente al árbol de capas del proyecto con el método layerTreeRoot() de la clase
QgsProject:
root = [Link]().layerTreeRoot()

root es un nodo de grupo y tiene hijos:


[Link]()

Se devuelve una lista de hijos directos. Se debe acceder a los hijos del subgrupo desde su propio padre directo.
Podemos recuperar uno de los hijos:
child0 = [Link]()[0]
print(child0)

<QgsLayerTreeLayer: countries>

Las capas también se pueden recuperar usando su (única) id:


ids = [Link]()
# access the first layer of the ids list
[Link](ids[0])

Y los grupos también se pueden buscar usando sus nombres:


[Link]('Group Name')

QgsLayerTreeGroup tiene muchos otros métodos útiles que se pueden utilizar para obtener más información
sobre el TOC:
# list of all the checked layers in the TOC
checked_layers = [Link]()
print(checked_layers)

20 Capítulo 4. Accediendo a la Tabla de Contenidos (TOC)


PyQGIS 3.40 developer cookbook

[<QgsVectorLayer: 'countries' (ogr)>]

Ahora agreguemos algunas capas al árbol de capas del proyecto. Hay dos formas de hacerlo:
1. Adición explícita usando las funciones addLayer() o insertLayer():
1 # create a temporary layer
2 layer1 = QgsVectorLayer("path_to_layer", "Layer 1", "memory")
3 # add the layer to the legend, last position
4 [Link](layer1)
5 # add the layer at given position
6 [Link](5, layer1)

2. Adición implícita: dado que el árbol de capas del proyecto está conectado al registro de capas, basta con
agregar una capa al registro de capas del mapa:
[Link]().addMapLayer(layer1)

Puede conmutar entre QgsVectorLayer y QgsLayerTreeLayer fácilmente:


node_layer = [Link](country_layer.id())
print("Layer node:", node_layer)
print("Map layer:", node_layer.layer())

Layer node: <QgsLayerTreeLayer: countries>


Map layer: <QgsVectorLayer: 'countries' (ogr)>

Los grupos pueden ser añadidos con el método addGroup(). En el siguiente ejemplo, el primero agregará un grupo
al final de la tabla de contenido, mientras que para el segundo puede agregar otro grupo dentro de uno existente:
node_group1 = [Link]('Simple Group')
# add a sub-group to Simple Group
node_subgroup1 = node_group1.addGroup("I'm a sub group")

Para mover nodos y grupos hay muchos métodos útiles.


Mover un nodo existente se hace en tres pasos:
1. Clonando el nodo existente
2. moviendo el nodo clonado a la posición deseada
3. borrando el nodo original
1 # clone the group
2 cloned_group1 = node_group1.clone()
3 # move the node (along with sub-groups and layers) to the top
4 [Link](0, cloned_group1)
5 # remove the original node
6 [Link](node_group1)

Es un poco mas complicado mover una capa por la leyenda:


1 # get a QgsVectorLayer
2 vl = [Link]().mapLayersByName("countries")[0]
3 # create a QgsLayerTreeLayer object from vl by its id
4 myvl = [Link]([Link]())
5 # clone the myvl QgsLayerTreeLayer object
6 myvlclone = [Link]()
7 # get the parent. If None (layer is not in group) returns ''
8 parent = [Link]()
9 # move the cloned layer to the top (0)
10 [Link](0, myvlclone)
(continúe en la próxima página)

4.2. Clase QgsLayerTreeGroup 21


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


11 # remove the original myvl
12 [Link](myvl)

o moverla a un grupo existente:

1 # get a QgsVectorLayer
2 vl = [Link]().mapLayersByName("countries")[0]
3 # create a QgsLayerTreeLayer object from vl by its id
4 myvl = [Link]([Link]())
5 # clone the myvl QgsLayerTreeLayer object
6 myvlclone = [Link]()
7 # create a new group
8 group1 = [Link]("Group1")
9 # get the parent. If None (layer is not in group) returns ''
10 parent = [Link]()
11 # move the cloned layer to the top (0)
12 [Link](0, myvlclone)
13 # remove the QgsLayerTreeLayer from its parent
14 [Link](myvl)

Algunos otros métodos que se pueden utilizar para modificar los grupos y capas:

1 node_group1 = [Link]("Group1")
2 # change the name of the group
3 node_group1.setName("Group X")
4 node_layer2 = [Link](country_layer.id())
5 # change the name of the layer
6 node_layer2.setName("Layer X")
7 # change the visibility of a layer
8 node_group1.setItemVisibilityChecked(True)
9 node_layer2.setItemVisibilityChecked(False)
10 # expand/collapse the group view
11 node_group1.setExpanded(True)
12 node_group1.setExpanded(False)

22 Capítulo 4. Accediendo a la Tabla de Contenidos (TOC)


CAPÍTULO 5

Usar las capas ráster

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsRasterLayer,
3 QgsProject,
4 QgsPointXY,
5 QgsRaster,
6 QgsRasterShader,
7 QgsColorRampShader,
8 QgsSingleBandPseudoColorRenderer,
9 QgsSingleBandColorDataRenderer,
10 QgsSingleBandGrayRenderer,
11 )
12

13 from [Link] import (


14 QColor,
15 )

5.1 Detalles de la capa

Una capa ráster está compuesta por una o más bandas ráster — denominadas como raster monobanda 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 de QgsRasterLayer .

rlayer = [Link]().mapLayersByName('srtm')[0]
# get the resolution of the raster in layer unit
print([Link](), [Link]())

23
PyQGIS 3.40 developer cookbook

919 619

# get the extent of the layer as QgsRectangle


print([Link]())

<QgsRectangle: 20.06856808199999875 -34.27001076999999896, 20.83945284300000012 -


,→33.75077500700000144>

# get the extent of the layer as Strings


print([Link]().toString())

20.0685680819999988,-34.2700107699999990 : 20.8394528430000001,-33.7507750070000014

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


,→band), 2 = Multiband

print([Link]())

# get the total band count of the raster


print([Link]())

# get the first band name of the raster


print([Link](1))

Band 1: Height

# get all the available metadata as a QgsLayerMetadata object


print([Link]())

<qgis._core.QgsLayerMetadata object at 0x13711d558>

5.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:
print([Link]())

<qgis._core.QgsSingleBandGrayRenderer object at 0x7f471c1da8a0>

print([Link]().type())

singlebandgray

Para establecer un renderizador, use el método setRenderer() de QgsRasterLayer. Hay una serie de clases
de renderizado (derivadas de QgsRasterRenderer):
• QgsHillshadeRenderer
• QgsMultiBandColorRenderer

24 Capítulo 5. Usar las capas ráster


PyQGIS 3.40 developer cookbook

• QgsPalettedRasterRenderer
• QgsRasterContourRenderer
• 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.

5.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 QgsRasterShader
y configuraremos su función shader:

1 fcn = QgsColorRampShader()
2 [Link]([Link])
3 lst = [ [Link](0, QColor(0,255,0)),
4 [Link](255, QColor(255,255,0)) ]
5 [Link](lst)
6 shader = QgsRasterShader()
7 [Link](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([Link](), 1, shader)


[Link](renderer)

El número 1 en el código anterior es el número de la banda (bandas ráster son indexadas de uno).
Finálmente tenemos que usar el método triggerRepaint() para ver los resultados:

[Link]()

5.2. Renderizador 25
PyQGIS 3.40 developer cookbook

5.2.2 Rásters multibanda

De forma predeterminada, QGIS asigna las tres primeras bandas a rojo, verde y azul para crear una imagen en color
(este es el estilo de dibujo MultiBandColor). En algunos casos, es posible que desee anular esta configuración.
El siguiente código intercambia la banda roja (1) y la banda verde (2):

rlayer_multi = [Link]().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.
Tenemos que usar triggerRepaint() para actualizar el mapa y ver el resultado:

rlayer_multi.triggerRepaint()

5.3 Valores de consulta

Los valores rster ´pueden ser consultados usando el método sample() de la clase QgsRasterDataProvider
. Tienes que especificar una QgsPointXY y el número de banda de la capa ráster que quiera consultar. El método
devuelve una tupla con el valor y True o False dependiendo del resultado:

val, res = [Link]().sample(QgsPointXY(20.50, -34), 1)

Otro método para consultar valores ráster es usar el método identify() que devuelve un objeto
QgsRasterIdentifyResult.

ident = [Link]().identify(QgsPointXY(20.5, -34), QgsRaster.


,→IdentifyFormatValue)

if [Link]():
print([Link]())

{1: 323.0}

En este caso, el método results() devuelve un diccionario, con el índice de banda como clave, y valores de banda
como valores. Por ejemplo, algo como {1: 323.0}

5.4 Edición de datos ráster

Puede crear una capa ráster utilizando la clase QgsRasterBlock. Por ejemplo, para crear un bloque ráster de 2x2
con un byte por píxel:

block = QgsRasterBlock([Link], 2, 2)
[Link](b'\xaa\xbb\xcc\xdd')

Los píxeles de trama se pueden sobrescribir gracias al método writeBlock(). Para sobrescribir datos ráster
existentes en la posición 0,0 por el bloque 2x2:

provider = [Link]()
[Link](True)
[Link](block, 1, 0, 0)
[Link](False)

26 Capítulo 5. Usar las capas ráster


CAPÍTULO 6

Usar capas vectoriales

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsApplication,
3 QgsDataSourceUri,
4 QgsCategorizedSymbolRenderer,
5 QgsClassificationRange,
6 QgsPointXY,
7 QgsProject,
8 QgsExpression,
9 QgsField,
10 QgsFields,
11 QgsFeature,
12 QgsFeatureRequest,
13 QgsFeatureRenderer,
14 QgsGeometry,
15 QgsGraduatedSymbolRenderer,
16 QgsMarkerSymbol,
17 QgsMessageLog,
18 QgsRectangle,
19 QgsRendererCategory,
20 QgsRendererRange,
21 QgsSymbol,
22 QgsVectorDataProvider,
23 QgsVectorLayer,
24 QgsVectorFileWriter,
25 QgsWkbTypes,
26 QgsSpatialIndex,
27 QgsVectorLayerUtils
28 )
29

30 from [Link] import edit


31

32 from [Link] import (


33 QColor,
34 )

27
PyQGIS 3.40 developer cookbook

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 clase QgsVectorLayer.

6.1 Recuperando información sobre atributos

Puede recuperar información sobre los campos asociados a una capa vectorial llamando el método fields() de
un objeto de la clase QgsVectorLayer

vlayer = QgsVectorLayer("testdata/data/[Link]|layername=airports", "Airports␣


,→layer", "ogr")

for field in [Link]():


print([Link](), [Link]())

1 fid Integer64
2 id Integer64
3 scalerank Integer64
4 featurecla String
5 type String
6 name String
7 abbrev String
8 location String
9 gps_code String
10 iata_code String
11 wikipedia String
12 natlscale Real

Los métodos displayField() y mapTipTemplate() proporcionan información sobre el campo y la plantilla


utilizados en la pestaña maptips.
Cuando carga una capa vectorial, un campo es siempre escogido por QGIS como el Nombre de
Visualización, mientras que el Aviso Mapa HTML está vacío de forma predeterminada. Con estos métodos
puede fácilmente conseguir ambos:

vlayer = QgsVectorLayer("testdata/data/[Link]|layername=airports", "Airports␣


,→layer", "ogr")

print([Link]())

name

Nota: Si cambia el Nombre de Visualización de un campo a una expresión, tiene que usar
displayExpression() en vez de displayField().

6.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 objeto QgsVectorLayer.

1 # "layer" is a QgsVectorLayer instance


2 layer = [Link]()
3 features = [Link]()
4

5 for feature in features:


6 # retrieve every feature with its geometry and attributes
(continúe en la próxima página)

28 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


7 print("Feature ID: ", [Link]())
8 # fetch geometry
9 # show some information about the feature geometry
10 geom = [Link]()
11 geomSingleType = [Link]([Link]())
12 if [Link]() == [Link]:
13 # the geometry type can be of single or multi type
14 if geomSingleType:
15 x = [Link]()
16 print("Point: ", x)
17 else:
18 x = [Link]()
19 print("MultiPoint: ", x)
20 elif [Link]() == [Link]:
21 if geomSingleType:
22 x = [Link]()
23 print("Line: ", x, "length: ", [Link]())
24 else:
25 x = [Link]()
26 print("MultiLine: ", x, "length: ", [Link]())
27 elif [Link]() == [Link]:
28 if geomSingleType:
29 x = [Link]()
30 print("Polygon: ", x, "Area: ", [Link]())
31 else:
32 x = [Link]()
33 print("MultiPolygon: ", x, "Area: ", [Link]())
34 else:
35 print("Unknown or invalid geometry")
36 # fetch attributes
37 attrs = [Link]()
38 # attrs is a list. It contains all the attribute values of this feature
39 print(attrs)
40 # for this test only print the first feature
41 break

Feature ID: 1
Point: <QgsPointXY: POINT(7 45)>
[1, 'First feature']

6.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 seleccionadas
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étodo selectAll()
# Get the active layer (must be a vector layer)
layer = [Link]()
[Link]()

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


# Assumes that the active layer is [Link] file from the QGIS test suite
# (Class (string) and Heading (number) are attributes in [Link])
(continúe en la próxima página)

6.3. Seleccionando objetos espaciales 29


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


layer = [Link]()
[Link]('"Class"=\'B52\' and "Heading" > 10 and "Heading" <70',␣
,→[Link])

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

[Link]().setSelectionColor( QColor("red") )

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

1 selected_fid = []
2

3 # Get the first feature id from the layer


4 feature = next([Link]())
5 if feature:
6 selected_fid.append([Link]())
7

8 # Add that features to the selected list


9 [Link](selected_fid)

Para borrar la selección:

[Link]()

6.3.1 Accediendo a atributos

Los atributos pueden ser referidos por su nombre:

print(feature['name'])

First feature

Alternativamente, se puede hacer referencia a los atributos por índice. Esto es un poco más rápido que usar el nombre.
Por ejemplo, para obtener el segundo atributo:

print(feature[1])

First feature

6.3.2 Iterando sobre rasgos seleccionados

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

selection = [Link]()
for feature in selection:
# do whatever you need with the feature
pass

30 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

6.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 objeto QgsFeatureRequest a la llamada de getFeatures(). Este es
un ejemplo:

1 areaOfInterest = QgsRectangle(450290,400520, 450750,400780)


2

3 request = QgsFeatureRequest().setFilterRect(areaOfInterest)
4

5 for feature in [Link](request):


6 # do whatever you need with the feature
7 pass

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([Link])

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

request = QgsFeatureRequest()
[Link](2)
for feature in [Link](request):
print(feature)

<qgis._core.QgsFeature object at 0x7f9b78590948>


<qgis._core.QgsFeature object at 0x7faef5881670>

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 objeto QgsExpression y pasarlo al constructor QgsFeatureRequest. 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.

1 # Only return selected fields to increase the "speed" of the request


2 [Link]([0,2])
3

4 # More user friendly version


5 [Link](['name','id'],[Link]())
6

7 # Don't return geometry objects to increase the "speed" of the request


8 [Link]([Link])
9

10 # Fetch only the feature with id 45


11 [Link](45)
12

13 # The options may be chained


14 [Link](areaOfInterest).setFlags([Link]).
,→setFilterFid(45).setSubsetOfAttributes([0,2])

6.3. Seleccionando objetos espaciales 31


PyQGIS 3.40 developer cookbook

6.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ón capabilities() para averiguar qué conjunto de
funcionalidad es compatible.

caps = [Link]().capabilities()
# Check if a particular capability is supported:
if caps & [Link]:
print('The layer supports DeleteFeatures')

The layer supports DeleteFeatures

Para obtener una lista de todas las capacidades disponibles, consulte la documentación API 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:

1 caps_string = [Link]().capabilitiesString()
2 # Print:
3 # 'Add Features, Delete Features, Change Attribute Values, Add Attributes,
4 # Delete Attributes, Rename Attributes, Fast Access to Features at ID,
5 # Presimplify Geometries, Presimplify Geometries with Validity Check,
6 # 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 hacer modificaciones 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:

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


2 # to trigger a redraw and you must clear the cached image for the layer
3 if [Link]().isCachingEnabled():
4 [Link]()
5 else:
6 [Link]().refresh()

6.4.1 Añadir Entidades

Crea algunas instancias QgsFeature y pasa una lista de ellas al método QgsVectorDataProvider
addFeatures(). Devolverá dos valores: resultado (True o False) y lista de objetos espaciales añadidos (su
ID lo establece el almacén de datos).
Para configurar los atributos de la entidad, puede inicializar la entidad pasando un objeto QgsFields (puede
obtenerlo del método fields() de la capa vectorial) o llamar a initAttributes() pasando el número de
campos que desea agregar.

1 if caps & [Link]:


2 feat = QgsFeature([Link]())
3 [Link]([0, 'hello'])
4 # Or set a single attribute by key or by index:
5 [Link]('name', 'hello')
(continúe en la próxima página)

32 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


6 [Link](0, 'hello')
7 [Link]([Link](QgsPointXY(123, 456)))
8 (res, outFeats) = [Link]().addFeatures([feat])

6.4.2 Borrar Entidades

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

if caps & [Link]:


res = [Link]().deleteFeatures([5, 10])

6.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.

1 fid = 100 # ID of the feature we will modify


2

3 if caps & [Link]:


4 attrs = { 0 : "hello", 1 : 123 }
5 [Link]().changeAttributeValues({ fid : attrs })
6

7 if caps & [Link]:


8 geom = [Link](QgsPointXY(111,222))
9 [Link]().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 de QgsVectorLayerEditUtils que proporciona
algunos métodos útiles para editar geometrías (trasladar, insertar o mover vértices, etc.).

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

Al editar vectores dentro de la aplicación QGIS, primero debe iniciar el modo de edición para una capa en particular,
luego hacer algunas modificaciones y finalmente confirmar (o deshacer) los cambios. Todos los cambios que realiza
no se escriben hasta que los confirma; permanecen en el búfer de edición en memoria de la capa. Es posible utilizar
esta funcionalidad también de forma programática, es solo otro método para la edición de capas vectoriales que
complementa el uso directo de los proveedores de datos. Use esta opción cuando proporcione algunas herramientas
GUI para la edición de capas vectoriales, ya que esto permitirá al usuario decidir si confirmar / deshacer 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 objeto QgsVectorLayer
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étodo startEditing() Para detener la edición, utilice los métodos commitChanges() o rollBack().
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étodo isEditable().
Aquí tiene algunos ejemplos que muestran cómo utilizar estos métodos de edición.

6.4. Modificación de capas vectoriales 33


PyQGIS 3.40 developer cookbook

1 from [Link] import QMetaType


2

3 feat1 = feat2 = QgsFeature([Link]())


4 fid = 99
5 [Link](fid)
6

7 # add two features (QgsFeature instances)


8 [Link]([feat1,feat2])
9 # delete a feature with specified ID
10 [Link](fid)
11

12 # set new geometry (QgsGeometry instance) for a feature


13 geometry = [Link]("POINT(7 45)")
14 [Link](fid, geometry)
15 # update an attribute with given field index (int) to a given value
16 fieldIndex =1
17 value ='My new name'
18 [Link](fid, fieldIndex, value)
19

20 # add new field


21 [Link](QgsField("mytext", [Link]))
22 # remove a field
23 [Link](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 por editando con proveedor de datos.)
Así es cómo usted puede utilizar la funcionalidad de deshacer:

1 [Link]("Feature triangulation")
2

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


4

5 if problem_occurred:
6 [Link]()
7 # ... tell the user that there was a problem
8 # and return
9

10 # ... more editing ...


11

12 [Link]()

El método beginEditCommand() creará un comando interno de «activo» y registrará los cambios posteriores
en la capa vectorial. Con la llamada a el comando endEditCommand() 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([Link]())
feat[0] = 5
[Link](feat)

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

34 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

6.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.

1 from [Link] import QMetaType


2

3 if caps & [Link]:


4 res = [Link]().addAttributes(
5 [QgsField("mytext", [Link]),
6 QgsField("myint", [Link])])
7

8 if caps & [Link]:


9 res = [Link]().deleteAttributes([0])

1 # Alternate methods for removing fields


2 # first create temporary fields to be removed (f1-3)
3 [Link]().addAttributes([QgsField("f1", [Link]),
4 QgsField("f2", [Link]),
5 QgsField("f3", [Link])])
6 [Link]()
7 count=[Link]().count() # count of layer fields
8 ind_list=list((count-3, count-2)) # create list
9

10 # remove a single field with an index


11 [Link]().deleteAttributes([count-1])
12

13 # remove multiple fields with a list of indices


14 [Link]().deleteAttributes(ind_list)

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.

[Link]()

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


Usando with edit(layer): los cambios serán automàticamente enviados a commitChanges() al final. si
ocurre alguna excepción, serán rollBack() todos los cambios. Ver Modificación de capas vectoriales con un búfer
de edición.

6.5 Usar índice espacial

Los índices espaciales pueden mejorar drásticamente el rendimiento del código si necesita realizar consultas frecuentes
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 especificada 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:

6.5. Usar índice espacial 35


PyQGIS 3.40 developer cookbook

• crear índice espacial usando la clase QgsSpatialIndex:

index = QgsSpatialIndex()

• agregar entidades al índice — el índice toma el objeto QgsFeature y lo agrega a la estructura de datos
interna. Puede crear el objeto manualmente o usar uno de una llamada anterior al método getFeatures()
del proveedor.

[Link](feat)

• alternativamente, puede cargar todas las entidades de una capa a la vez utilizando la carga masiva

index = QgsSpatialIndex([Link]())

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

1 # returns array of feature IDs of five nearest features


2 nearest = [Link](QgsPointXY(25.4, 12.7), 5)
3

4 # returns array of IDs of features which intersect the rectangle


5 intersect = [Link](QgsRectangle(22.5, 15.3, 23.1, 17.2))

También puede usar el índice espacial QgsSpatialIndexKDBush. Este índice es similar al estándar
QgsSpatialIndex pero:
• soporta solo entidades de único punto
• es estática (no se pueden agregar entidades adicionales al índice después de la construcción)
• es ¡mas rápida!
• permite la recuperación directa de los puntos de la entidad original, sin requerir solicitudes de entidades
adicionales
• admite búsquedas verdaderas basadas en la distancia, es decir, devuelve todos los puntos dentro de un radio
desde un punto de búsqueda

6.6 La clase QgsVectorLayerUtils

La clase QgsVectorLayerUtils contiene algunos métodos muy útiles que puede utilizar con capas vectoriales.
Por ejemplo el método createFeature() prepara una QgsFeature para ser agregada a una capa vectorial
manteniendo todas las eventuales restricciones y valores predeterminados de cada campo:

vlayer = QgsVectorLayer("testdata/data/[Link]|layername=airports", "Airports␣


,→layer", "ogr")

feat = [Link](vlayer)

El método getValues() le permite obtener rápidamente los valores de un campo o expresión:

1 vlayer = QgsVectorLayer("testdata/data/[Link]|layername=airports", "Airports␣


,→layer", "ogr")

2 # select only the first feature to make the output shorter


3 [Link]([1])
4 val = [Link](vlayer, "NAME", selectedOnly=True)
5 print(val)

(['Sahnewal'], True)

36 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

6.7 Creación de capas vectoriales

Hay varias maneras de generar un dataset de capa vectorial:


• la clase QgsVectorFileWriter: Una clase práctica para escribir archivos vectoriales en disco, utilizando
una llamada estática a writeAsVectorFormatV3() que guarda toda la capa vectorial o creando una
instancia de la clase y emitiendo llamadas a la clase heredada addFeature(). Esta clase soporta todos los
formatos vectoriales que soporta GDAL (GeoPackage, archivo Shape, GeoJSON, KML y otros).
• la clase QgsVectorLayer: crea una instancia de un proveedor de datos que interpreta la ruta seleccionada
(url) de la fuente de datos para conectar y acceder a los datos. Se puede usar para crear capas temporales,
basadas en la memoria (memoria) y conectar a conjunto de datos vectoriales GDAL (ogr), bases de datos
(postgres, spatialite, mysql, mssql) y más (wfs, gpx, delimitedtext…).

6.7.1 Desde una instancia de QgsVectorFileWriter

1 # SaveVectorOptions contains many settings for the writer process


2 save_options = [Link]()
3 transform_context = [Link]().transformContext()
4 # Write to a GeoPackage (default)
5 error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
6 "testdata/my_new_file.gpkg",
7 transform_context,
8 save_options)
9 if error[0] == [Link]:
10 print("success!")
11 else:
12 print(error)

1 # Write to an ESRI Shapefile format dataset using UTF-8 text encoding


2 save_options = [Link]()
3 save_options.driverName = "ESRI Shapefile"
4 save_options.fileEncoding = "UTF-8"
5 transform_context = [Link]().transformContext()
6 error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
7 "testdata/my_new_shapefile",
8 transform_context,
9 save_options)
10 if error[0] == [Link]:
11 print("success again!")
12 else:
13 print(error)

1 # Write to an ESRI GDB file


2 save_options = [Link]()
3 save_options.driverName = "FileGDB"
4 # if no geometry
5 save_options.overrideGeometryType = [Link]
6 save_options.actionOnExistingFile = [Link]
7 save_options.layerName = 'my_new_layer_name'
8 transform_context = [Link]().transformContext()
9 gdb_path = "testdata/my_example.gdb"
10 error = QgsVectorFileWriter.writeAsVectorFormatV3(layer,
11 gdb_path,
12 transform_context,
13 save_options)
14 if error[0] == [Link]:
15 print("success!")
16 else:
17 print(error)

6.7. Creación de capas vectoriales 37


PyQGIS 3.40 developer cookbook

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 Postgres)
en un tipo texto, puede hacer lo siguiente:

1 LIST_FIELD_NAME = 'xxxx'
2

3 class ESRIValueConverter([Link]):
4

5 def __init__(self, layer, list_field):


6 [Link].__init__(self)
7 [Link] = layer
8 self.list_field_idx = [Link]().indexFromName(list_field)
9

10 def convert(self, fieldIdxInLayer, value):


11 if fieldIdxInLayer == self.list_field_idx:
12 return QgsListFieldFormatter().representValue(layer=vlayer,
13 fieldIndex=self.list_field_idx,
14 config={},
15 cache=None,
16 value=value)
17 else:
18 return value
19

20 def fieldDefinition(self, field):


21 idx = [Link]().indexFromName([Link]())
22 if idx == self.list_field_idx:
23 return QgsField(LIST_FIELD_NAME, [Link])
24 else:
25 return [Link]()[idx]
26

27 converter = ESRIValueConverter(vlayer, LIST_FIELD_NAME)


28 opts = [Link]()
29 [Link] = converter

También se puede especificar un CRS de destino — si se pasa una instancia válida de


QgsCoordinateReferenceSystem como cuarto parámetro, la capa se transforma a ese CRS.
Para obtener nombres de controladores válidos, llame al método supportedFiltersAndFormats() o
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íficas
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 de QgsVectorFileWriter para más detalles.

6.7.2 Directamente desde las funciones

1 from [Link] import QMetaType


2

3 # define fields for feature attributes. A QgsFields object is needed


4 fields = QgsFields()
5 [Link](QgsField("first", [Link]))
6 [Link](QgsField("second", [Link]))
7

8 """ create an instance of vector file writer, which will create the vector file.
9 Arguments:
10 1. path to new file (will fail if exists already)
11 2. field map
12 3. geometry type - from WKBTYPE enum
13 4. layer's spatial reference (instance of
14 QgsCoordinateReferenceSystem)
(continúe en la próxima página)

38 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


15 5. coordinate transform context
16 6. save options (driver name for the output file, encoding etc.)
17 """
18

19 crs = [Link]().crs()
20 transform_context = [Link]().transformContext()
21 save_options = [Link]()
22 save_options.driverName = "ESRI Shapefile"
23 save_options.fileEncoding = "UTF-8"
24

25 writer = [Link](
26 "testdata/my_new_shapefile.shp",
27 fields,
28 [Link],
29 crs,
30 transform_context,
31 save_options
32 )
33

34 if [Link]() != [Link]:
35 print("Error when creating shapefile: ", [Link]())
36

37 # add a feature
38 fet = QgsFeature()
39

40 [Link]([Link](QgsPointXY(10,10)))
41 [Link]([1, "text"])
42 [Link](fet)
43

44 # delete the writer to flush features to disk


45 del writer

6.7.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 proveedor
de memoria en el URI. La sintaxis es:
crs=definition
Especifica el sistema de referencia de coordenadas, donde la definición puede ser cualquiera de las formas
aceptadas por [Link]()
index=yes
Especifica que el proveedor utilizará un índice espacial

6.7. Creación de capas vectoriales 39


PyQGIS 3.40 developer cookbook

field=name:type(length,precision)
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


1 from [Link] import QMetaType
2

3 # create layer
4 vl = QgsVectorLayer("Point", "temporary_points", "memory")
5 pr = [Link]()
6

7 # add fields
8 [Link]([QgsField("name", [Link]),
9 QgsField("age", [Link]),
10 QgsField("size", [Link])])
11 [Link]() # tell the vector layer to fetch changes from the provider
12

13 # add a feature
14 fet = QgsFeature()
15 [Link]([Link](QgsPointXY(10,10)))
16 [Link](["Johnny", 2, 0.3])
17 [Link]([fet])
18

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


20 # because change of extent in provider is not propagated to the layer
21 [Link]()

Finalmente, vamos a comprobar si todo salió bien


1 # show some stats
2 print("fields:", len([Link]()))
3 print("features:", [Link]())
4 e = [Link]()
5 print("extent:", [Link](), [Link](), [Link](), [Link]())
6

7 # iterate over features


8 features = [Link]()
9 for fet in features:
10 print("F:", [Link](), [Link](), [Link]().asPoint())

fields: 3
features: 1
extent: 10.0 10.0 10.0 10.0
F: 1 ['Johnny', 2, 0.3] <QgsPointXY: POINT(10 10)>

6.8 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 = [Link]()

Y con esa referencia, vamos a explorar un poco

40 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

print("Type:", [Link]())

Type: singleSymbol

Hay varios tipos de renderizadores conocidos disponibles en la biblioteca principal de QGIS:

Tipo Clase Descripción


singleSymbol QgsSingleSymbolRendererRepresenta todas las entidades con el mismo símbolo
categorizedSymbol
QgsCategorizedSymbolRenderer
Representa entidades utilizando un símbolo diferente para
cada categoría
graduatedSymbolQgsGraduatedSymbolRenderer
Representa entidades utilizando un símbolo diferente para
cada rango de valores

También puede haber algunos tipos de presentadores personalizados, por lo que nunca haga una suposición de que
solo hay estos tipos. Puede consultar el QgsRendererRegistry de la aplicación para encontrar los presentadores
disponibles actualmente:

print([Link]().renderersList())

['nullSymbol', 'singleSymbol', 'categorizedSymbol', 'graduatedSymbol',


,→'RuleRenderer', 'pointDisplacement', 'pointCluster', 'mergedFeatureRenderer',

,→'invertedPolygonRenderer', 'heatmapRenderer', '25dRenderer', 'embeddedSymbol']

Es posible obtener un volcado del contenido de presentador en forma de texto — puede ser útil para la depuración

[Link]()

SINGLE: MARKER SYMBOL (1 layers) color 190,207,80,255

6.8.1 Representador de Símbolo Único

Puede obtener el símbolo utilizado para la representación llamando al método symbol() y cambiarlo con el
método :meth:`setSymbol() <[Link]>`(nota para desarrolladores de C++:
el renderizado toma posesión del símbolo.)
Puede cambiar el símbolo utilizado por una capa vectorial determinada llamando a setSymbol() pasando
una instancia de la instancia de símbolo apropiada. Los símbolos para las capas de point, line y polygon pueden
ser creadas llamando a la función createSimple() de las clases correspondientes QgsMarkerSymbol,
QgsLineSymbol y QgsFillSymbol.
El diccionario pasado a createSimple() establece las propiedades de estilo del símbolo.
Por ejemplo, puede reemplazar el símbolo utilizado por una capa point particular llamando a setSymbol()
pasando una instancia de QgsMarkerSymbol, como en el siguiente ejemplo de código:

symbol = [Link]({'name': 'square', 'color': 'red'})


[Link]().setSymbol(symbol)
# show the change
[Link]()

name indica la forma del marcador, y puede ser cualquiera de los siguientes:
• circle
• square
• cross
• rectangle

6.8. Apariencia (Simbología) de capas vectoriales 41


PyQGIS 3.40 developer cookbook

• diamond
• pentagon
• triangle
• equilateral_triangle
• star
• regular_star
• arrow
• filled_arrowhead
• x
Para obtener la lista completa de propiedades de la primera capa de símbolos de una instancia de símbolo, puede
seguir el código de ejemplo:

print([Link]().symbol().symbolLayers()[0].properties())

{'angle': '0', 'cap_style': 'square', 'color': '255,0,0,255,rgb:1,0,0,1',


,→'horizontal_anchor_point': '1', 'joinstyle': 'bevel', 'name': 'square', 'offset

,→': '0,0', 'offset_map_unit_scale': '3x:0,0,0,0,0,0', 'offset_unit': 'MM',

,→'outline_color': '35,35,35,255,rgb:0.13725490196078433,0.13725490196078433,0.

,→13725490196078433,1', 'outline_style': 'solid', 'outline_width': '0', 'outline_

,→width_map_unit_scale': '3x:0,0,0,0,0,0', 'outline_width_unit': 'MM', 'scale_

,→method': 'diameter', 'size': '2', 'size_map_unit_scale': '3x:0,0,0,0,0,0', 'size_

,→unit': 'MM', 'vertical_anchor_point': '1'}

Esto puede ser útil si desea modificar algunas propiedades:

1 # You can alter a single property...


2 [Link]().symbol().symbolLayer(0).setSize(3)
3 # ... but not all properties are accessible from methods,
4 # you can also replace the symbol completely:
5 props = [Link]().symbol().symbolLayer(0).properties()
6 props['color'] = 'yellow'
7 props['name'] = 'square'
8 [Link]().setSymbol([Link](props))
9 # show the changes
10 [Link]()

6.8.2 Representador de símbolo categorizado

Al utilizar un representador categorizado, puede consultar y establecer el atributo que se utiliza para la clasificación:
utilice los métodos classAttribute() y setClassAttribute().
Para obtener una lista de categorías

1 categorized_renderer = QgsCategorizedSymbolRenderer()
2 # Add a few categories
3 cat1 = QgsRendererCategory('1', QgsMarkerSymbol(), 'category 1')
4 cat2 = QgsRendererCategory('2', QgsMarkerSymbol(), 'category 2')
5 categorized_renderer.addCategory(cat1)
6 categorized_renderer.addCategory(cat2)
7

8 for cat in categorized_renderer.categories():


9 print("{}: {} :: {}".format([Link](), [Link](), [Link]()))

1: category 1 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>


2: category 2 :: <qgis._core.QgsMarkerSymbol object at 0x7f378ffcd9d8>

42 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

Donde value() es el valor utilizado para la discriminación entre categorías, label() es el texto utilizado para la
descripción de la categoría y el método symbol() devuelve el símbolo asignado.
El renderizador suele almacenar también el símbolo original y la rampa de color que se utilizaron para la clasificación:
métodos sourceColorRamp() y sourceSymbol().

6.8.3 Renderizador de símbolo graduado

Este representador es muy similar al representador de símbolos categorizados descrito anteriormente, pero en lugar
de un valor de atributo por clase trabaja con rangos de valores y, por lo tanto, solo se puede utilizar con atributos
numéricos.
Para obtener más información sobre los rangos utilizados en el renderizador

1 graduated_renderer = QgsGraduatedSymbolRenderer()
2 # Add a few categories
3 graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class 0-
,→100', 0, 100), QgsMarkerSymbol()))

4 graduated_renderer.addClassRange(QgsRendererRange(QgsClassificationRange('class␣
,→101-200', 101, 200), QgsMarkerSymbol()))

6 for ran in graduated_renderer.ranges():


7 print("{} - {}: {} {}".format(
8 [Link](),
9 [Link](),
10 [Link](),
11 [Link]()
12 ))

0.0 - 100.0: class 0-100 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>


101.0 - 200.0: class 101-200 <qgis._core.QgsMarkerSymbol object at 0x7f8bad281b88>

puedes volver a usar los métodos classAttribute() (para encontrar el nombre del atributo de clasificación),
sourceSymbol() y sourceColorRamp() . Adicionalmente está el método mode() que determina como
son creados los rangos: usando intervalos iguales, cuanties o algún otro método.
Si desea crear su propio renderizador de símbolos graduados, puede hacerlo como se ilustra en el siguiente fragmento
de ejemplo (que crea una sencilla disposición de dos clases)

1 from [Link] import QtGui


2

3 myVectorLayer = QgsVectorLayer("testdata/data/[Link]|layername=airports",
,→"Airports layer", "ogr")

4 myTargetField = 'scalerank'
5 myRangeList = []
6 myOpacity = 1
7 # Make our first symbol and range...
8 myMin = 0.0
9 myMax = 50.0
10 myLabel = 'Group 1'
11 myColour = [Link]('#ffee00')
12 mySymbol1 = [Link]([Link]())
13 [Link](myColour)
14 [Link](myOpacity)
15 myRange1 = QgsRendererRange(myMin, myMax, mySymbol1, myLabel)
16 [Link](myRange1)
17 #now make another symbol and range...
18 myMin = 50.1
19 myMax = 100
20 myLabel = 'Group 2'
21 myColour = [Link]('#00eeff')
(continúe en la próxima página)

6.8. Apariencia (Simbología) de capas vectoriales 43


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


22 mySymbol2 = [Link](
23 [Link]())
24 [Link](myColour)
25 [Link](myOpacity)
26 myRange2 = QgsRendererRange(myMin, myMax, mySymbol2, myLabel)
27 [Link](myRange2)
28 myRenderer = QgsGraduatedSymbolRenderer('', myRangeList)
29 myClassificationMethod = [Link]().method(
,→"EqualInterval")

30 [Link](myClassificationMethod)
31 [Link](myTargetField)
32

33 [Link](myRenderer)

6.8.4 Trabajo con Símbolos

Para la representación de símbolos, hay esta clase base QgsSymbol con tres clases derivadas:
• QgsMarkerSymbol — para entidades de punto
• QgsLineSymbol — para entidades de línea
• QgsFillSymbol — para entidades de polígono
Cada símbolo consta de una o más capas de símbolos (clases derivadas de QgsSymbolLayer). Las capas de
símbolos hacen la representación real, la propia clase de símbolo sirve sólo como un contenedor para las capas de
símbolo.
Teniendo una instancia de un símbolo (por ejemplo, de un renderizador), es posible explorarlo: el método type()
dice si es un marcador, línea o símbolo de relleno . Hay un método dump() que devuelve una breve descripción del
símbolo. Para obtener una lista de capas de símbolos:

marker_symbol = QgsMarkerSymbol()
for i in range(marker_symbol.symbolLayerCount()):
lyr = marker_symbol.symbolLayer(i)
print("{}: {}".format(i, [Link]()))

0: SimpleMarker

Para averiguar el color del símbolo use el método color() y setColor() para cmabiar su color. Con los símbolos
de marcador, además, puede consultar el tamaño y la rotación del símbolo con los métodos size() y angle() .
Para símbolos lineales el método width() devuelve la anchura de la línea.
De forma predeterminada el tamaño y ancho están en milímetros, los ángulos en grados.

Trabajando con capas de símbolos

Como se dijo antes, las capas de símbolo (subclases de QgsSymbolLayer) determinar la apariencia de las
entidades. Hay varias clases de capas de símbolos básicas para uso general. Es posible implementar nuevos tipos de
capas de símbolos y así personalizar arbitrariamente cómo se renderizarán las entidades. El método layerType()
identifica de forma única la clase de capa de símbolo — las básicas y predeterminadas son los tipos de capas de
símbolo `` SimpleMarker “”, `` SimpleLine “” y `` SimpleFill “”.
identifica de forma única la clase de capa de símbolo — las básicas y predeterminadas son los tipos de capas de
símbolo `` SimpleMarker “”, `` SimpleLine “” y `` SimpleFill “”.

1 from [Link] import QgsSymbolLayerRegistry


2 myRegistry = [Link]()
3 myMetadata = [Link]("SimpleFill")
(continúe en la próxima página)

44 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


4 for item in [Link]([Link]):
5 print(item)

1 AnimatedMarker
2 EllipseMarker
3 FilledMarker
4 FontMarker
5 GeometryGenerator
6 MaskMarker
7 RasterMarker
8 SimpleMarker
9 SvgMarker
10 VectorField

La clase QgsSymbolLayerRegistry gestiona una base de datos de todos los tipos de capas de símbolos
disponibles.
Para acceder a los datos de la capa de símbolos, use su método properties() que devuelve un diccionario de
propiedades clave-valor que determina la apariencia. Cada tipo de capa de símbolo tiene un conjunto específico
de propiedades que utiliza. Además, existen los métodos genéricos color(), size(), angle() y width(),
con sus contrapartes setter. Por supuesto, el tamaño y el ángulo solo están disponibles para las capas de símbolo de
marcador y el ancho para las capas de símbolo de línea.

Crear tipos de capas de símbolos personalizados

Imagine que le gustaría personalizar la forma en que se procesan los datos. Puede crear su propia clase de capa de
símbolo que dibujará las entidades exactamente como lo desee. Aquí hay un ejemplo de un marcador que dibuja
círculos rojos con un radio especificado

1 from [Link] import QgsMarkerSymbolLayer


2 from [Link] import QColor
3

4 class FooSymbolLayer(QgsMarkerSymbolLayer):
5

6 def __init__(self, radius=4.0):


7 QgsMarkerSymbolLayer.__init__(self)
8 [Link] = radius
9 [Link] = QColor(255,0,0)
10

11 def layerType(self):
12 return "FooMarker"
13

14 def properties(self):
15 return { "radius" : str([Link]) }
16

17 def startRender(self, context):


18 pass
19

20 def stopRender(self, context):


21 pass
22

23 def renderPoint(self, point, context):


24 # Rendering depends on whether the symbol is selected (QGIS >= 1.5)
25 color = [Link]() if [Link]() else [Link]
26 p = [Link]().painter()
27 [Link](color)
28 [Link](point, [Link], [Link])
29

30 def clone(self):
31 return FooSymbolLayer([Link])

6.8. Apariencia (Simbología) de capas vectoriales 45


PyQGIS 3.40 developer cookbook

El layerType() el método determina el nombre de la capa de símbolo; tiene que ser único entre todas las capas
de símbolos. El método properties() es usada para la persistencia de sus atributos. El método clone() debe
devolver una copia de la capa de símbolo con todos los atributos exactamente iguales. Finalmente, existen métodos
de renderizado: startRender() se llama antes de renderizar la primera entidad, stopRender() cuando el
renderizado está terminado, y renderPoint() es llamado para hacer el renderizado. Las coordenadas de los
puntos ya están transformadas a las coordenadas de salida.
Para polilíneas y polígonos, la única diferencia estaría en el método de representación: que usaría
renderPolyline () que recibe una lista de líneas, mientras que :meth:`renderPolygon()
<[Link]> `recibe una lista de puntos en el anillo exterior como primer
parámetro y una lista de anillos interiores (o Ninguno) como segundo parámetro.
Por lo general, es conveniente agregar una GUI para configurar los atributos del tipo de capa de símbolo para permitir
a los usuarios personalizar la apariencia: en el caso de nuestro ejemplo anterior, podemos permitir que el usuario
establezca el radio del círculo. El siguiente código implementa dicho widget

1 from [Link] import QgsSymbolLayerWidget


2

3 class FooSymbolLayerWidget(QgsSymbolLayerWidget):
4 def __init__(self, parent=None):
5 QgsSymbolLayerWidget.__init__(self, parent)
6

7 [Link] = None
8

9 # setup a simple UI
10 [Link] = QLabel("Radius:")
11 [Link] = QDoubleSpinBox()
12 [Link] = QHBoxLayout()
13 [Link]([Link])
14 [Link]([Link])
15 [Link]([Link])
16 [Link]([Link], SIGNAL("valueChanged(double)"), \
17 [Link])
18

19 def setSymbolLayer(self, layer):


20 if [Link]() != "FooMarker":
21 return
22 [Link] = layer
23 [Link]([Link])
24

25 def symbolLayer(self):
26 return [Link]
27

28 def radiusChanged(self, value):


29 [Link] = value
30 [Link](SIGNAL("changed()"))

Este widget se puede incrustar en el cuadro de diálogo de propiedades del símbolo. Cuando se selecciona el tipo de
capa de símbolo en el cuadro de diálogo de propiedades de símbolo, crea una instancia de la capa de símbolo y una
instancia del widget de capa de símbolo. Luego llama al método setSymbolLayer() para asignar la capa de
símbolo al widget. En ese método, el widget debería actualizar la interfaz de usuario para reflejar los atributos de la
capa de símbolo. El método symbolLayer() se usa para recuperar la capa de símbolo nuevamente mediante el
diálogo de propiedades para usarla para el símbolo.
En cada cambio de atributos, el widget debe emitir la señal changed() para permitir que el diálogo de propiedades
actualice la vista previa del símbolo.
Ahora solo nos falta el pegamento final: hacer que QGIS esté al tanto de estas nuevas clases. Esto se hace agregando
la capa de símbolo al registro. También es posible utilizar la capa de símbolo sin agregarla al registro, pero algunas
funciones no funcionarán: p. Ej. carga de archivos de proyecto con capas de símbolo personalizadas o incapacidad
para editar los atributos de la capa en la GUI.
Tendremos que crear metadatos para la capa de símbolo.

46 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

1 from [Link] import QgsSymbol, QgsSymbolLayerAbstractMetadata,␣


,→QgsSymbolLayerRegistry

3 class FooSymbolLayerMetadata(QgsSymbolLayerAbstractMetadata):
4

5 def __init__(self):
6 super().__init__("FooMarker", "My new Foo marker", [Link])
7

8 def createSymbolLayer(self, props):


9 radius = float(props["radius"]) if "radius" in props else 4.0
10 return FooSymbolLayer(radius)
11

12 fslmetadata = FooSymbolLayerMetadata()

[Link]().addSymbolLayerType(fslmetadata)

Debe pasar el tipo de capa (el mismo que devuelve la capa) y el tipo de símbolo (marcador / línea /
relleno) al constructor de la clase principal. El método createSymbolLayer() se encarga de crear una
instancia de la capa de símbolo con los atributos especificados en el diccionario props. Y esta el método
createSymbolLayerWidget() que devuelve el widget de configuración para este tipo de capa de símbolo.
El último pase es adicionar esta capa símbolo al registro — y estamos listos.

6.8.5 Crear Renderizados personalizados

Puede ser útil crear una nueva implementación de renderizador si desea personalizar las reglas sobre cómo seleccionar
símbolos para renderizar características. Algunos casos de uso en los que desearía hacerlo: el símbolo se determina a
partir de una combinación de campos, el tamaño de los símbolos cambia según la escala actual, etc.
El siguiente código muestra un renderizador personalizado simple que crea dos símbolos de marcador y elige
aleatoriamente uno de ellos para cada objeto.

1 import random
2 from [Link] import QgsWkbTypes, QgsSymbol, QgsFeatureRenderer
3

5 class RandomRenderer(QgsFeatureRenderer):
6 def __init__(self, syms=None):
7 super().__init__("RandomRenderer")
8 [Link] = syms if syms else [
9 [Link]([Link]([Link])),
10 [Link]([Link]([Link]))
11 ]
12

13 def symbolForFeature(self, feature, context):


14 return [Link]([Link])
15

16 def startRender(self, context, fields):


17 super().startRender(context, fields)
18 for s in [Link]:
19 [Link](context, fields)
20

21 def stopRender(self, context):


22 super().stopRender(context)
23 for s in [Link]:
24 [Link](context)
25

26 def usedAttributes(self, context):


27 return []
28

(continúe en la próxima página)

6.8. Apariencia (Simbología) de capas vectoriales 47


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


29 def clone(self):
30 return RandomRenderer([Link])

El constructor de la clase padre QgsFeatureRenderer necesita un nombre de renderizador (que tiene que ser
único entre los renderizadores). El método symbolForFeature() es el que decide qué símbolo se utilizará para
una entidad en particular. startRender() y stopRender() se encargan de la inicialización/finalización de la
representación de símbolos. El método usedAttributes() puede devolver una lista de nombres de campo que el
renderizador espera que esté presente. Finalmente, el método clone() debería devolver una copia del renderizador.
Al igual que con las capas de símbolos, es posible adjuntar una GUI para la configuración del renderizador. Tiene
que derivarse de QgsRendererWidget. El siguiente código de muestra crea un botón que permite al usuario
establecer el primer símbolo
1 from [Link] import QgsRendererWidget, QgsColorButton
2

4 class RandomRendererWidget(QgsRendererWidget):
5 def __init__(self, layer, style, renderer):
6 super().__init__(layer, style)
7 if renderer is None or [Link]() != "RandomRenderer":
8 self.r = RandomRenderer()
9 else:
10 self.r = renderer
11 # setup UI
12 self.btn1 = QgsColorButton()
13 [Link]([Link][0].color())
14 [Link] = QVBoxLayout()
15 [Link](self.btn1)
16 [Link]([Link])
17 [Link](self.setColor1)
18

19 def setColor1(self):
20 color = [Link]()
21 if not [Link](): return
22 [Link][0].setColor(color)
23

24 def renderer(self):
25 return self.r

El constructor recibe instancias de la capa activa (QgsVectorLayer), el estilo global (QgsStyle) y el


renderizador actual. Si no hay renderizador o el renderizador tiene un tipo diferente, será reemplazado por nuestro
nuevo renderizador, de lo contrario usaremos el renderizador actual (que ya tiene el tipo que necesitamos). El
contenido del widget debe actualizarse para mostrar el estado actual del renderizador. Cuando se acepta el cuadro
de diálogo del renderizador, se llama al método del widget : meth:renderer() <[Link]>
para obtener el renderizador actual — se asignará a la capa.
El último bit que falta son los metadatos del renderizador y el registro en el registro; de lo contrario, la carga de
capas con el renderizador no funcionará y el usuario no podrá seleccionarlo de la lista de renderizadores. Terminemos
nuestro ejemplo de RandomRenderer
1 from [Link] import (
2 QgsRendererAbstractMetadata,
3 QgsRendererRegistry,
4 QgsApplication
5 )
6

7 class RandomRendererMetadata(QgsRendererAbstractMetadata):
8

9 def __init__(self):
10 super().__init__("RandomRenderer", "Random renderer")
11

(continúe en la próxima página)

48 Capítulo 6. Usar capas vectoriales


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


12 def createRenderer(self, element):
13 return RandomRenderer()
14

15 def createRendererWidget(self, layer, style, renderer):


16 return RandomRendererWidget(layer, style, renderer)
17

18 rrmetadata = RandomRendererMetadata()

[Link]().addRenderer(rrmetadata)

Del mismo modo que con las capas de símbolo, el constructor de metadatos abstracto espera el nombre del
renderizador, el nombre visible para los usuarios y, opcionalmente, el nombre del icono del renderizador. El
método createRenderer() pasa una instancia QDomElement que puede usarse para restaurar el estado del
renderizador desde el árbol DOM. El método createRendererWidget() crea el widget de configuración. No
tiene que estar presente o puede devolver Ninguno si el renderizador no viene con GUI.
Para asociar un icono con el renderizador, puede asignarlo en el constructor QgsRendererAbstractMetadata
como tercer argumento (opcional) — el constructor de la clase base en la función RandomRendererMetadata
__init__() se convierte en

QgsRendererAbstractMetadata.__init__(self,
"RandomRenderer",
"Random renderer",
QIcon(QPixmap("[Link]", "png")))

El icono también se puede asociar en cualquier momento posterior mediante el método setIcon() de la clase de
metadatos. El icono se puede cargar desde un archivo (como se muestra arriba) o se puede cargar desde un recurso
Qt (PyQt5 incluye el compilador .qrc para Pitón).

6.9 Más Temas

PENDIENTE:
• crear/modificar símbolos
• trabajandocon estilo (QgsStyle)
• trabajando con rampas de color (QgsColorRamp)
• explorar la capa de símbolo y los registros de renderizado

6.9. Más Temas 49


PyQGIS 3.40 developer cookbook

50 Capítulo 6. Usar capas vectoriales


CAPÍTULO 7

Manejo de Geometría

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsGeometry,
3 QgsGeometryCollection,
4 QgsPoint,
5 QgsPointXY,
6 QgsWkbTypes,
7 QgsProject,
8 QgsFeatureRequest,
9 QgsVectorLayer,
10 QgsDistanceArea,
11 QgsUnitTypes,
12 QgsCoordinateTransform,
13 QgsCoordinateReferenceSystem
14 )

Los puntos, las cadenas de líneas y los polígonos que representan una característica espacial se conocen comúnmente
como geometrías. En QGIS están representados con la clase QgsGeometry.
A veces una geometría es realmente una colección simple (partes simples) geométricas. Tal geometría se llama
geometría de múltiples partes. Si contiene un tipo de geometría simple, lo llamamos un punto múltiple, lineas múltiples
o polígonos múltiples. Por ejemplo, un país consiste en múltiples islas que se pueden representar como un polígono
múltiple.
Las coordenadas de las geometrías pueden estar en cualquier sistema de referencia de coordenadas (SRC). Cuando
extrae características de una capa, las geometrías asociadas tendrán sus coordenadas en el SRC de la capa.
Descripción y especificaciones de todas las posibles geometrías de construcción y las relaciones están disponibles en
el OGC Simple Feature Access Standards para detalles avanzados.

51
PyQGIS 3.40 developer cookbook

7.1 Construcción de Geometría

PyQGIS proporciona varias opciones para crear una geometría:


• desde coordenadas

1 gPnt = [Link](QgsPointXY(1,1))
2 print(gPnt)
3 gLine = [Link]([QgsPoint(1, 1), QgsPoint(2, 2)])
4 print(gLine)
5 gPolygon = [Link]([[QgsPointXY(1, 1),
6 QgsPointXY(2, 2), QgsPointXY(2, 1)]])
7 print(gPolygon)

Las coordenadas son dadas usando la clase QgsPoint o la clase QgsPointXY. La diferencia entre estas
clases es que soporten QgsPoint dimensione M y Z.
Una polilínea (cadena lineal) es representada por una lista de puntos.
Un polígono está representado por una lista de anillos lineales (es decir, cadenas de líneas cerradas). El primer
anillo es el anillo exterior (límite), los anillos subsiguientes opcionales son agujeros en el polígono. Tenga en
cuenta que, a diferencia de algunos programas, QGIS cerrará el anillo por usted, por lo que no es necesario
duplicar el primer punto como el último.
Las geometrías multi-parte van un nivel más allá: multi-punto es una lista de puntos, multi-linea es una lista de
polilíneas y multi-polígono es una lista de polígonos.
• desde well-known text (WKT)

geom = [Link]("POINT(3 4)")


print(geom)

• desde well-known binary (WKB)

1 g = QgsGeometry()
2 wkb = [Link]("010100000000000000000045400000000000001440")
3 [Link](wkb)
4

5 # print WKT representation of the geometry


6 print([Link]())

7.2 Acceso a Geometría

Primero, debe averiguar el tipo de geometría. El método wkbType() es el que se va a utilizar. Devuelve un valor
de la enumeración [Link].

1 print([Link]())
2 # output: 1
3 print([Link]())
4 # output: 2
5 print([Link]())
6 # output: 3

Como alternativa, se puede utilizar el método type() que devuelve un valor de la enumeración QgsWkbTypes.
GeometryType.

print([Link]())
# output: 1

Puede usar la función displayString() para obtener un tipo de geometría legible por humanos.

52 Capítulo 7. Manejo de Geometría


PyQGIS 3.40 developer cookbook

1 print([Link]([Link]()))
2 # output: 'Point'
3 print([Link]([Link]()))
4 # output: 'LineString'
5 print([Link]([Link]()))
6 # output: 'Polygon'

También hay una función de ayuda isMultipart() para saber si una geometría es multiparte o no.
Para extraer información de una geometría, existen funciones de acceso para cada tipo de vector. A continuación, se
muestra un ejemplo sobre cómo utilizar estos accesos:

1 print([Link]())
2 # output: <QgsPointXY: POINT(1 1)>
3 print([Link]())
4 # output: [<QgsPointXY: POINT(1 1)>, <QgsPointXY: POINT(2 2)>]
5 print([Link]())
6 # output: [[<QgsPointXY: POINT(1 1)>, <QgsPointXY: POINT(2 2)>, <QgsPointXY:␣
,→POINT(2 1)>, <QgsPointXY: POINT(1 1)>]]

Nota: Las tuplas (x, y) no son tuplas reales, son objetos QgsPoint, los valores son accesibles con los métodos x()
y y().

Para geometrías multiparte, existen funciones de acceso similares: asMultiPoint(), asMultiPolyline()


y asMultiPolygon().
Es posible iterar sobre todas las partes de una geometría, independientemente del tipo de geometría. [Link].

geom = [Link]( 'MultiPoint( 0 0, 1 1, 2 2)' )


for part in [Link]():
print([Link]())

Point (0 0)
Point (1 1)
Point (2 2)

geom = [Link]( 'LineString( 0 0, 10 10 )' )


for part in [Link]():
print([Link]())

LineString (0 0, 10 10)

gc = QgsGeometryCollection()
[Link]('GeometryCollection( Point(1 2), Point(11 12), LineString(33 34, 44 45))
,→')

print(gc[1].asWkt())

Point (11 12)

También es posible modificar cada parte de la geometría usando el método [Link]().

1 geom = [Link]( 'MultiPoint( 0 0, 1 1, 2 2)' )


2 for part in [Link]():
3 [Link](QgsCoordinateTransform(
4 QgsCoordinateReferenceSystem("EPSG:4326"),
5 QgsCoordinateReferenceSystem("EPSG:3111"),
6 [Link]())
7 )
(continúe en la próxima página)

7.2. Acceso a Geometría 53


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


8

9 print([Link]())

MultiPoint ((-10334726.79314758814871311 -5360105.10101194866001606),(-10462133.


,→82917747274041176 -5217484.34365733992308378),(-10589398.51346861757338047 -

,→5072020.35880533326417208))

7.3 Geometría predicados y Operaciones

QGIS utiliza la biblioteca GEOS para operaciones de geometría avanzadas como predicados de geometría
(contains(), intersects(), …) y hacer operaciones (combine(), difference(), …). También puede
calcular propiedades geométricas de geometrías, como área (en el caso de polígonos) o longitudes (para polígonos y
líneas).
Veamos un ejemplo que combina iterar sobre las entidades en una capa determinada y realizar algunos cálculos
geométricos basados en sus geometrías. El siguiente código calculará e imprimirá el área y el perímetro de cada país
en la capa de países dentro de nuestro proyecto tutorial QGIS.
El siguiente código asume que layer es un obleto QgsVectorLayer que tiene el tipo de entidad Polígono.

1 # let's access the 'countries' layer


2 layer = [Link]().mapLayersByName('countries')[0]
3

4 # let's filter for countries that begin with Z, then get their features
5 query = '"name" LIKE \'Z%\''
6 features = [Link](QgsFeatureRequest().setFilterExpression(query))
7

8 # now loop through the features, perform geometry computation and print the results
9 for f in features:
10 geom = [Link]()
11 name = [Link]('NAME')
12 print(name)
13 print('Area: ', [Link]())
14 print('Perimeter: ', [Link]())

1 Zambia
2 Area: 62.82279065343119
3 Perimeter: 50.65232014052552
4 Zimbabwe
5 Area: 33.41113559136517
6 Perimeter: 26.608288555013935

Ahora ha calculado e impreso las áreas y perímetros de las geometrías. Sin embargo, puede notar rápidamente que
los valores son extraños. Esto se debe a que las áreas y los perímetros no tienen en cuenta el CRS cuando se calculan
con los métodos area() y length() desde la clase QgsGeometry. Para un cálculo de área y distancia más
potente, la clase QgsDistanceArea se puede utilizar, que puede realizar cálculos basados en elipsoides:
El siguiente código asume que layer es un obleto QgsVectorLayer que tiene el tipo de entidad Polígono.

1 d = QgsDistanceArea()
2 [Link]('WGS84')
3

4 layer = [Link]().mapLayersByName('countries')[0]
5

6 # let's filter for countries that begin with Z, then get their features
7 query = '"name" LIKE \'Z%\''
8 features = [Link](QgsFeatureRequest().setFilterExpression(query))
9

(continúe en la próxima página)

54 Capítulo 7. Manejo de Geometría


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


10 for f in features:
11 geom = [Link]()
12 name = [Link]('NAME')
13 print(name)
14 print("Perimeter (m):", [Link](geom))
15 print("Area (m2):", [Link](geom))
16

17 # let's calculate and print the area again, but this time in square kilometers
18 print("Area (km2):", [Link]([Link](geom), QgsUnitTypes.
,→AreaSquareKilometers))

1 Zambia
2 Perimeter (m): 5539361.250294601
3 Area (m2): 751989035032.9031
4 Area (km2): 751989.0350329031
5 Zimbabwe
6 Perimeter (m): 2865021.3325076113
7 Area (m2): 389267821381.6008
8 Area (km2): 389267.8213816008

Alternativamente, puede querer saber la distancia entre dos puntos.

1 d = QgsDistanceArea()
2 [Link]('WGS84')
3

4 # Let's create two points.


5 # Santa claus is a workaholic and needs a summer break,
6 # lets see how far is Tenerife from his home
7 santa = QgsPointXY(25.847899, 66.543456)
8 tenerife = QgsPointXY(-16.5735, 28.0443)
9

10 print("Distance in meters: ", [Link](santa, tenerife))

Puede encontrar muchos ejemplos de algoritmos que se incluyen en QGIS y utilizan estos métodos para analizar y
transformar los datos vectoriales. Aquí hay algunos enlaces al código de algunos de ellos.
• Distancia y área usando QgsDistanceArea class: Distance matrix algorithm
• Lines to polygons algorithm

7.3. Geometría predicados y Operaciones 55


PyQGIS 3.40 developer cookbook

56 Capítulo 7. Manejo de Geometría


CAPÍTULO 8

Soporte de Proyecciones

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsCoordinateReferenceSystem,
3 QgsCoordinateTransform,
4 QgsProject,
5 QgsPointXY,
6 )

8.1 Sistemas de coordenadas de referencia

Sistemas de Coordenadas de Referencia (SRC) son encapsulados por la clase


QgsCoordinateReferenceSystem. Las instancias de esta clase se pueden crear de varias formas diferentes:
• especificar SRC por su ID

# EPSG 4326 is allocated for WGS84


crs = QgsCoordinateReferenceSystem("EPSG:4326")
print([Link]())

True

QGIS admite diferentes identificadores de SRC con los siguientes formatos:


– EPSG:<code> — ID asignada por la organización EPSG - manejada con createFromOgcWms()
– POSTGIS:<srid>— ID usada en bases de datos PostGIS - manejada con createFromSrid()
– INTERNAL:<srsid> — ID usada en la base de datos QGIS - manejada con createFromSrsId()
– PROJ:<proj> - manejada con createFromProj()
– WKT:<wkt> - manejada con createFromWkt()
Si no se especifica ningún prefijo, se asume la definición de WKT.

57
PyQGIS 3.40 developer cookbook

• especificar SRC por su well-known text (WKT)

1 wkt = 'GEOGCS["WGS84", DATUM["WGS84", SPHEROID["WGS84", 6378137.0, 298.


,→257223563]],' \

2 'PRIMEM["Greenwich", 0.0], UNIT["degree",0.017453292519943295],' \


3 'AXIS["Longitude",EAST], AXIS["Latitude",NORTH]]'
4 crs = QgsCoordinateReferenceSystem(wkt)
5 print([Link]())

True

• cree un SRC no válido y luego use una de las funciones crear* para inicializarlo. En el siguiente ejemplo
usamos una cadena Proj para inicializar la proyección.

crs = QgsCoordinateReferenceSystem()
[Link]("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
print([Link]())

True

Es aconsejable comprobar si la creación (es decir, la búsqueda en la base de datos) del SRC se ha realizado
correctamente: isValid() debe devolver True.
Tenga en cuenta que para la inicialización de sistemas de referencia espacial, QGIS necesita buscar los valores
apropiados en su base de datos interna [Link]. Por lo tanto, en caso de que cree una aplicación independiente,
debe configurar las rutas correctamente con [Link](), de lo contrario, no podrá
encontrar la base de datos. Si está ejecutando los comandos desde la consola de QGIS Python o desarrollando un
complemento, no le importa: todo ya está configurado para usted.
Acceso a la información del sistema de referencia espacial:

1 crs = QgsCoordinateReferenceSystem("EPSG:4326")
2

3 print("QGIS CRS ID:", [Link]())


4 print("PostGIS SRID:", [Link]())
5 print("Description:", [Link]())
6 print("Projection Acronym:", [Link]())
7 print("Ellipsoid Acronym:", [Link]())
8 print("Proj String:", [Link]())
9 # check whether it's geographic or projected coordinate system
10 print("Is geographic:", [Link]())
11 # check type of map units in this CRS (values defined in QGis::units enum)
12 print("Map units:", [Link]())

Salida:

1 QGIS CRS ID: 3452


2 PostGIS SRID: 4326
3 Description: WGS 84
4 Projection Acronym: longlat
5 Ellipsoid Acronym: EPSG:7030
6 Proj String: +proj=longlat +datum=WGS84 +no_defs
7 Is geographic: True
8 Map units: 6

58 Capítulo 8. Soporte de Proyecciones


PyQGIS 3.40 developer cookbook

8.2 Transformación SRC

Puede realizar la transformación entre diferentes sistemas de referencia espacial utilizando la clase
QgsCoordinateTransform. La forma más fácil de usarlo es crear un SRC de origen y destino y construir una
instancia QgsCoordinateTransform con ellos y el proyecto actual. Luego simplemente llame repetidamente
transform() function para hacer la transformación. De forma predeterminada, realiza una transformación hacia
adelante, pero también es capaz de realizar una transformación inversa.

1 crsSrc = QgsCoordinateReferenceSystem("EPSG:4326") # WGS 84


2 crsDest = QgsCoordinateReferenceSystem("EPSG:32633") # WGS 84 / UTM zone 33N
3 transformContext = [Link]().transformContext()
4 xform = QgsCoordinateTransform(crsSrc, crsDest, transformContext)
5

6 # forward transformation: src -> dest


7 pt1 = [Link](QgsPointXY(18,5))
8 print("Transformed point:", pt1)
9

10 # inverse transformation: dest -> src


11 pt2 = [Link](pt1, [Link])
12 print("Transformed back:", pt2)

Salida:

Transformed point: <QgsPointXY: POINT(832713.79873844375833869 553423.


,→98688333143945783)>

Transformed back: <QgsPointXY: POINT(18 4.99999999999999911)>

8.2. Transformación SRC 59


PyQGIS 3.40 developer cookbook

60 Capítulo 8. Soporte de Proyecciones


CAPÍTULO 9

Usando el Lienzo de Mapa

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QColor,
3 )
4

5 from [Link] import Qt, QRectF


6

7 from [Link] import QMenu


8

9 from [Link] import (


10 QgsVectorLayer,
11 QgsPoint,
12 QgsPointXY,
13 QgsProject,
14 QgsGeometry,
15 QgsMapRendererJob,
16 QgsWkbTypes,
17 )
18

19 from [Link] import (


20 QgsMapCanvas,
21 QgsVertexMarker,
22 QgsMapCanvasItem,
23 QgsMapMouseEvent,
24 QgsRubberBand,
25 )

El widget del lienzo del mapa es probablemente el widget más importante dentro de QGIS porque muestra el mapa
integrado de capas de mapas superpuestos y permite la interacción con el mapa y las capas. El lienzo muestra siempre
una parte del mapa definido por el alcance del lienzo actual. La interacción se realiza mediante el uso de herramientas
de mapa: hay herramientas para desplazamiento, zum, la identificación de las capas, de medida, para editar vectores
y otros. Al igual que en otros programas de gráficos, siempre hay una herramienta activa y el usuario puede cambiar
entre las herramientas disponibles.
El lienzo del mapa está implementado con la clase QgsMapCanvas en el módulo [Link] . La implementación

61
PyQGIS 3.40 developer cookbook

se basa en el marco Qt Graphics View. Este marco generalmente proporciona una superficie y una vista donde
se colocan elementos gráficos personalizados y el usuario puede interactuar con ellos. Asumiremos que está lo
suficientemente familiarizado con Qt para comprender los conceptos de escena, vista y elementos gráficos. Si no
es así, lea la descripción general del marco. <[Link]
Cada vez que el mapa se ha desplazado, ampliado / reducido (o alguna otra acción que desencadena una actualización),
el mapa se representa nuevamente dentro de la extensión actual. Las capas se representan en una imagen (utilizando la
clase QgsMapRendererJob) y esa imagen se muestra en el lienzo. La clase QgsMapCanvas También controla
la actualización del mapa representado. Además de este elemento que actúa como fondo, puede haber más elementos
de lienzo de mapas.
Los elementos típicos del lienzo del mapa son bandas elásticas (utilizadas para medir, editar vectores, etc.) o
marcadores de vértice. Los elementos del lienzo generalmente se usan para dar retroalimentación visual a las
herramientas de mapa, por ejemplo, al crear un nuevo polígono, la herramienta de mapa crea un elemento de lienzo
con banda elástica que muestra la forma actual del polígono. Todos los elementos del lienzo del mapa son subclases
de QgsMapCanvasItem que agrega más funcionalidad a los objetos básicos QGraphicsItem.
Para resumir, la arquitectura del lienzo de mapa consiste en tres conceptos:
• lienzo de mapa — para la visualización del mapa
• Los elementos de lienzo de mapa — los elementos adicionales que se pueden desplegar en un lienzo de mapa
• herramientas de mapa — para interactuar con el lienzo del mapa

9.1 Lienzo de mapa insertado

Map Canvas es un widget como cualquier otro widget de Qt, por lo que usarlo es tan simple como crearlo y mostrarlo.

canvas = QgsMapCanvas()
[Link]()

Esto produce una ventana independiente con el lienzo de mapa. Puede también ser incrustado en un widget existente
o ventana. Al utilizar archivo ui y Qt Designer, coloque un QWidget sobre el formulario y promuévalo a una nueva
clase: establezca QgsMapCanvas como nombre de clase y [Link] como archivo de encabezado. La utilidad
pyuic5 se hará cargo de ella. Esta es una forma conveniente de incrustar el lienzo. La otra posibilidad es escribir
manualmente el código para construir el lienzo del mapa y otros widgets (como hijos de una ventana principal o
diálogo) y crea un diseño.
Por defecto, el lienzo de mapa tiene un fondo negro y no utiliza anti-aliasing. Para establecer el fondo blanco y habilitar
el anti-aliasing para suavisar la presentación

[Link]([Link])
[Link](True)

(En caso de que se esté preguntando, Qt viene del modulo [Link] y [Link] es uno de lo que predefine
las instancias QColor.)
Ahora es el momento de agregar algunas capas del mapa. Primero abriremos una capa y la agregaremos al proyecto
actual. Luego estableceremos la extensión del lienzo y la lista de capas para el lienzo.

1 vlayer = QgsVectorLayer("testdata/data/[Link]|layername=airports", "Airports␣


,→layer", "ogr")

2 if not [Link]():
3 print("Layer failed to load!")
4

5 # add layer to the registry


6 [Link]().addMapLayer(vlayer)
7

8 # set extent to the extent of our layer


9 [Link]([Link]())
(continúe en la próxima página)

62 Capítulo 9. Usando el Lienzo de Mapa


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


10

11 # set the map canvas layer set


12 [Link]([vlayer])

Después de ejecutar estos comandos, el lienzo debe mostrar la capa que se ha cargado.

9.2 Bandas elásticas y marcadores de vértices

Para mostrar algunos datos adicionales en la parte superior del mapa en el lienzo, utilice los elementos del lienzo
de mapa. Es posible crear clases de elementos del lienzo personalizada (cubiertas más abajo), sin embargo, hay dos
clases de elementos de lienzo útiles para mayor comodidad QgsRubberBand para dibujar polilíneas o polígonos, y
QgsVertexMarker para dibujar puntos. Ambos trabajan con coordenadas de mapa, por lo que la figura se mueve/
se escala de forma automática cuando el lienzo está siendo desplazado o haciendo zum.
Para mostrar una polilínea:

r = QgsRubberBand(canvas, [Link]) # line


points = [QgsPoint(-100, 45), QgsPoint(10, 60), QgsPoint(120, 45)]
[Link]([Link](points), None)

Para mostrar un polígono

r = QgsRubberBand(canvas, [Link]) # polygon


points = [[QgsPointXY(-100, 35), QgsPointXY(10, 50), QgsPointXY(120, 35)]]
[Link]([Link](points), None)

Tenga en cuenta que los puntos de polígonos no es una lista simple: de hecho, es una lista de anillos que contienen
lista de anillos del polígono: el primer anillo es el borde exterior, anillos adicionales (opcional) corresponden a los
agujeros en el polígono.
Las bandas elásticas permiten algún tipo de personalizacion, es decir, para cambiar su color o ancho de línea

[Link](QColor(0, 0, 255))
[Link](3)

Los elementos del lienzo están vinculados a la escena del lienzo. Para ocultarlos temporalmente (y mostrarlos
nuevamente), use el combo hide() and show(). Para eliminar completamente el elemento, debe eliminarlo de la
escena del lienzo.

[Link]().removeItem(r)

(en C++ es posible simplemente eliminar el elemento, sin embargo en Python del r sería simplemente suprimir la
referencia y el objeto aún existirá ya que es propiedad del lienzo)
La banda de goma también se puede usar para dibujar puntos, pero la clase QgsVertexMarker Es más adecuada
para esto (QgsRubberBand solo dibujaría un rectángulo alrededor del punto deseado).
Puede usar el marcador de vértices así:

m = QgsVertexMarker(canvas)
[Link](QgsPointXY(10,40))

Esto dibujará una cruz roja en la posición [10,45]. Es posible personalizar el tipo de icono, tamaño, color y ancho del
lápiz.

[Link](QColor(0, 255, 0))


[Link](5)
[Link](QgsVertexMarker.ICON_BOX) # or ICON_CROSS, ICON_X
[Link](3)

9.2. Bandas elásticas y marcadores de vértices 63


PyQGIS 3.40 developer cookbook

Para ocultar temporalmente los marcadores de vértice y eliminarlos del lienzo, utilice los mismos métodos que para
las gomas elásticas.

9.3 Utilizar las herramientas del mapa con el lienzo

El siguiente ejemplo construye una ventana que contiene un lienzo de mapa y herramientas de mapa básicas para
la panorámica y el zoom del mapa. Las acciones se crean para la activación de cada herramienta: la panorámica se
realiza con QgsMapToolPan, acercando/alejando con un par de instancias QgsMapToolZoom. Las acciones se
configuran como verificables y luego se asignan a las herramientas para permitir el manejo automático del estado
verificado / no verificado de las acciones: cuando una herramienta de mapa se activa, su acción se marca como
seleccionada y la acción de la herramienta de mapa anterior se deselecciona. Las herramientas de mapa se activan
usando setMapTool() method.
1 from [Link] import *
2 from [Link] import QAction, QMainWindow
3 from [Link] import Qt
4

5 class MyWnd(QMainWindow):
6 def __init__(self, layer):
7 QMainWindow.__init__(self)
8

9 [Link] = QgsMapCanvas()
10 [Link]([Link])
11

12 [Link]([Link]())
13 [Link]([layer])
14

15 [Link]([Link])
16

17 [Link] = QAction("Zoom in", self)


18 [Link] = QAction("Zoom out", self)
19 [Link] = QAction("Pan", self)
20

21 [Link](True)
22 [Link](True)
23 [Link](True)
24

25 [Link]([Link])
26 [Link]([Link])
27 [Link]([Link])
28

29 [Link] = [Link]("Canvas actions")


30 [Link]([Link])
31 [Link]([Link])
32 [Link]([Link])
33

34 # create the map tools


35 [Link] = QgsMapToolPan([Link])
36 [Link]([Link])
37 [Link] = QgsMapToolZoom([Link], False) # false = in
38 [Link]([Link])
39 [Link] = QgsMapToolZoom([Link], True) # true = out
40 [Link]([Link])
41

42 [Link]()
43

44 def zoomIn(self):
45 [Link]([Link])
46

47 def zoomOut(self):
(continúe en la próxima página)

64 Capítulo 9. Usando el Lienzo de Mapa


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


48 [Link]([Link])
49

50 def pan(self):
51 [Link]([Link])

Puede probar el código anterior en el editor de la consola de Python. Para invocar la ventana del lienzo, agregue las
siguientes líneas para crear una instancia de la clase ``MyWnd””. Representarán la capa seleccionada actualmente en
el lienzo recién creado

w = MyWnd([Link]())
[Link]()

9.3.1 Selecciona una entidad usando QgsMapToolIdentifyFeature

Puedes usar la herramienta del mapa QgsMapToolIdentifyFeature para pedirle al usuario que seleccione
una entidad que se enviará a una función de devolución de llamada.

1 def callback(feature):
2 """Code called when the feature is selected by the user"""
3 print("You clicked on feature {}".format([Link]()))
4

5 canvas = [Link]()
6 feature_identifier = QgsMapToolIdentifyFeature(canvas)
7

8 # indicates the layer on which the selection will be done


9 feature_identifier.setLayer(vlayer)
10

11 # use the callback as a slot triggered when the user identifies a feature
12 feature_identifier.[Link](callback)
13

14 # activation of the map tool


15 [Link](feature_identifier)

9.3.2 Añadir temas al menú contextual del lienzo del mapa

La interacción con el lienzo del mapa se puede hacer también por medio de entradas que usted puede hacer en su
menú contextual usando la señal contextMenuAboutToShow.
El siguiente código añade la acción Mi menú ► Mi Acción cerca de las entradas predeterminadas cuando hace pulsación
derecha sobre el lienzo del mapa.

1 # a slot to populate the context menu


2 def populateContextMenu(menu: QMenu, event: QgsMapMouseEvent):
3 subMenu = [Link]('My Menu')
4 action = [Link]('My Action')
5 [Link](lambda *args:
6 print(f'Action triggered at {event.x()},{event.y()}'))
7

8 [Link](populateContextMenu)
9 [Link]()

9.3. Utilizar las herramientas del mapa con el lienzo 65


PyQGIS 3.40 developer cookbook

9.4 Escribir herramientas de mapa personalizados

Puede escribir sus herramientas personalizadas, para implementar un comportamiento personalizado a las acciones
realizadas por los usuarios en el lienzo.
Las herramientas de mapa deben heredar de QgsMapTool, clase o cualquier clase derivada, y seleccionada como
herramientas activas en el lienzo utilizando el método setMapTool() como ya hemos visto.
Aquí esta un ejemplo de una herramienta de mapa para definir una extensión rectangular haciendo clic y arrastrando
en el lienzo. Cuando se define el rectángulo, imprime su limite de coordenadas en la consola. Utiliza los elementos
de la banda elástica descrita antes para mostrar el rectángulo seleccionado ya que se esta definiendo.

1 class RectangleMapTool(QgsMapToolEmitPoint):
2 def __init__(self, canvas):
3 [Link] = canvas
4 QgsMapToolEmitPoint.__init__(self, [Link])
5 [Link] = QgsRubberBand([Link], [Link])
6 [Link]([Link])
7 [Link](1)
8 [Link]()
9

10 def reset(self):
11 [Link] = [Link] = None
12 [Link] = False
13 [Link]([Link])
14

15 def canvasPressEvent(self, e):


16 [Link] = [Link]([Link]())
17 [Link] = [Link]
18 [Link] = True
19 [Link]([Link], [Link])
20

21 def canvasReleaseEvent(self, e):


22 [Link] = False
23 r = [Link]()
24 if r is not None:
25 print("Rectangle:", [Link](),
26 [Link](), [Link](), [Link]()
27 )
28

29 def canvasMoveEvent(self, e):


30 if not [Link]:
31 return
32

33 [Link] = [Link]([Link]())
34 [Link]([Link], [Link])
35

36 def showRect(self, startPoint, endPoint):


37 [Link]([Link])
38 if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y():
39 return
40

41 point1 = QgsPointXY(startPoint.x(), startPoint.y())


42 point2 = QgsPointXY(startPoint.x(), endPoint.y())
43 point3 = QgsPointXY(endPoint.x(), endPoint.y())
44 point4 = QgsPointXY(endPoint.x(), startPoint.y())
45

46 [Link](point1, False)
47 [Link](point2, False)
48 [Link](point3, False)
49 [Link](point4, True) # true to update canvas
50 [Link]()
(continúe en la próxima página)

66 Capítulo 9. Usando el Lienzo de Mapa


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


51

52 def rectangle(self):
53 if [Link] is None or [Link] is None:
54 return None
55 elif ([Link].x() == [Link].x() or \
56 [Link].y() == [Link].y()):
57 return None
58

59 return QgsRectangle([Link], [Link])


60

61 def deactivate(self):
62 [Link](self)
63 [Link]()

9.5 Escribir elementos de lienzo de mapa personalizado

Aquí hay un ejemplo de un elemento de lienzo personalizado que dibuja un círculo:

1 class CircleCanvasItem(QgsMapCanvasItem):
2 def __init__(self, canvas):
3 super().__init__(canvas)
4 [Link] = QgsPoint(0, 0)
5 [Link] = 100
6

7 def setCenter(self, center):


8 [Link] = center
9

10 def center(self):
11 return [Link]
12

13 def setSize(self, size):


14 [Link] = size
15

16 def size(self):
17 return [Link]
18

19 def boundingRect(self):
20 return QRectF([Link].x() - [Link]/2,
21 [Link].y() - [Link]/2,
22 [Link].x() + [Link]/2,
23 [Link].y() + [Link]/2)
24

25 def paint(self, painter, option, widget):


26 path = QPainterPath()
27 [Link]([Link].x(), [Link].y());
28 [Link]([Link](), 0.0, 360.0)
29 [Link](path, QColor("red"))
30

31

32 # Using the custom item:


33 item = CircleCanvasItem([Link]())
34 [Link](QgsPointXY(200,200))
35 [Link](80)

9.5. Escribir elementos de lienzo de mapa personalizado 67


PyQGIS 3.40 developer cookbook

68 Capítulo 9. Usando el Lienzo de Mapa


CAPÍTULO 10

Representación del Mapa e Impresión

Consejo: Los fragmentos de código en esta página necesitan las siguientes importaciones:

1 import os
2

3 from [Link] import (


4 QgsGeometry,
5 QgsMapSettings,
6 QgsPrintLayout,
7 QgsMapSettings,
8 QgsMapRendererParallelJob,
9 QgsLayoutItemLabel,
10 QgsLayoutItemLegend,
11 QgsLayoutItemMap,
12 QgsLayoutItemPolygon,
13 QgsLayoutItemScaleBar,
14 QgsLayoutExporter,
15 QgsLayoutItem,
16 QgsLayoutPoint,
17 QgsLayoutSize,
18 QgsUnitTypes,
19 QgsProject,
20 QgsFillSymbol,
21 QgsAbstractValidityCheck,
22 check,
23 )
24

25 from [Link] import (


26 QPolygonF,
27 QColor,
28 )
29

30 from [Link] import (


31 QPointF,
32 QRectF,
33 QSize,
34 )

69
PyQGIS 3.40 developer cookbook

Por lo general, hay dos enfoques cuando los datos de entrada deben representarse como un mapa: hacerlo de
manera rápida usando QgsMapRendererJob o producir una salida más ajustada componiendo el mapa con la clase
QgsLayout.

10.1 Representación Simple

La renderización se realiza creando un objeto QgsMapSettings para definir la configuración de renderizado,


y luego construir una clase QgsMapRendererJob con esos ajustes. Este último se utiliza para crear la imagen
resultante.
Aquí hay un ejemplo:

1 image_location = [Link]([Link]().homePath(), "[Link]")


2

3 vlayer = [Link]()
4 settings = QgsMapSettings()
5 [Link]([vlayer])
6 [Link](QColor(255, 255, 255))
7 [Link](QSize(800, 600))
8 [Link]([Link]())
9

10 render = QgsMapRendererParallelJob(settings)
11

12 def finished():
13 img = [Link]()
14 # save the image; e.g. [Link]("/Users/myuser/[Link]","png")
15 [Link](image_location, "png")
16

17 [Link](finished)
18

19 # Start the rendering


20 [Link]()
21

22 # The following loop is not normally required, we


23 # are using it here because this is a standalone example.
24 from [Link] import QEventLoop
25 loop = QEventLoop()
26 [Link]([Link])
27 loop.exec_()

10.2 Representando capas con diferente SRC

Si tiene más de una capa y tienen un SRC diferente, el simple ejemplo anterior probablemente no funcionará: para
obtener los valores correctos de los cálculos de extensión, debe establecer explícitamente el SRC de destino

layers = [[Link]()]
settings = QgsMapSettings()
[Link](layers)
[Link](layers[0].crs())

70 Capítulo 10. Representación del Mapa e Impresión


PyQGIS 3.40 developer cookbook

10.3 Salida usando diseño de impresión

El diseño de impresión es una herramienta muy útil si desea realizar una salida más sofisticada que la simple
representación mostrada anteriormente. Es posible crear diseños de mapas complejos compuestos por vistas de mapas,
etiquetas, leyendas, tablas y otros elementos que suelen estar presentes en los mapas en papel. Los diseños pueden
exportarse a PDF, SVG, imágenes rasterizadas o imprimirse directamente en una impresora.
El diseño consta de varias clases. Todos pertenecen a la biblioteca principal. La aplicación QGIS tiene una GUI
conveniente para la ubicación de los elementos, aunque no está disponible en la biblioteca de la GUI. Si no está
familiarizado con Qt Graphics View framework, entonces le recomendamos que consulte la documentación ahora,
porque el diseño se basa en ella.
La clase central del diseño es la clase QgsLayout, que deriva de la clase de Qt QGraphicsScene . Creemos una
instancia de ello:

project = [Link]()
layout = QgsPrintLayout(project)
[Link]()

Esto inicializa el diseño con algunas configuraciones predeterminadas, específicamente agregando una página A4
vacía al diseño. Puede crear diseños sin llamar al método initializeDefaults(), pero deberá encargarse de
agregar páginas al diseño usted mismo.
El código anterior crea un diseño «temporal» que no es visible en la GUI. Puede ser útil [Link]. agregue rápidamente
algunos elementos y exporte sin modificar el proyecto en sí ni exponer estos cambios al usuario. Si desea que el diseño
se guarde/restaure junto con el proyecto y esté disponible en el administrador de diseño, agregue:

[Link]("MyLayout")
[Link]().addLayout(layout)

Ahora podemos agregar varios elementos (mapa, etiqueta, …) al diseño. Todos estos objetos están representados por
clases que heredan de la clase base QgsLayoutItem.
Aquí hay una descripción de algunos de los elementos de diseño principales que se pueden agregar a un diseño.
• mapa — Aquí creamos un mapa de un tamaño personalizado y renderizamos el lienzo del mapa actual.

1 map = QgsLayoutItemMap(layout)
2 # Set map item position and size (by default, it is a 0 width/0 height item␣
,→placed at 0,0)

3 [Link](QgsLayoutPoint(5,5, [Link]))
4 [Link](QgsLayoutSize(200,200, [Link]))
5 # Provide an extent to render
6 [Link]([Link]().extent())
7 [Link](map)

• etiqueta — permite mostrar etiquetas. Es posible modificar su letra, color, alineación y margen.

label = QgsLayoutItemLabel(layout)
[Link]("Hello world")
[Link]()
[Link](label)

• legend

legend = QgsLayoutItemLegend(layout)
[Link](map) # map is an instance of QgsLayoutItemMap
[Link](legend)

• barra de escala

10.3. Salida usando diseño de impresión 71


PyQGIS 3.40 developer cookbook

1 item = QgsLayoutItemScaleBar(layout)
2 [Link]('Numeric') # optionally modify the style
3 [Link](map) # map is an instance of QgsLayoutItemMap
4 [Link]()
5 [Link](item)

• forma basada en nodos

1 polygon = QPolygonF()
2 [Link](QPointF(0.0, 0.0))
3 [Link](QPointF(100.0, 0.0))
4 [Link](QPointF(200.0, 100.0))
5 [Link](QPointF(100.0, 200.0))
6

7 polygonItem = QgsLayoutItemPolygon(polygon, layout)


8 [Link](polygonItem)
9

10 props = {}
11 props["color"] = "green"
12 props["style"] = "solid"
13 props["style_border"] = "solid"
14 props["color_border"] = "black"
15 props["width_border"] = "10.0"
16 props["joinstyle"] = "miter"
17

18 symbol = [Link](props)
19 [Link](symbol)

Una vez que un elemento es añadido a la composiciónm puede ser movida y redimensionadas:

[Link](QgsLayoutPoint(1.4, 1.8, [Link]))


[Link](QgsLayoutSize(2.8, 2.2, [Link]))

Un cuadro es dibujado alrededor de cada elemento por defecto. Puede borrarlo como sigue:

# for a composer label


[Link](False)

Además de crear los elementos de diseño a mano, QGIS tiene soporte para plantillas de diseño que son esencialmente
composiciones con todos sus elementos guardados en un archivo .qpt (con sintaxis XML).
Una vez que la composición está lista (los elementos de diseño se han creado y agregado a la composición), podemos
proceder a producir una salida rasterizada y/o vectorial.

10.3.1 Comprobación de la validez del diseño

Un diseño está formado por un conjunto de elementos interconectados y puede ocurrir que estas conexiones se
rompan durante las modificaciones (una leyenda conectada a un mapa eliminado, un elemento de imagen al que
le falta el archivo fuente,…) o puede que desee aplicar restricciones personalizadas a los elementos del diseño. La
QgsAbstractValidityCheck te ayuda a conseguirlo.
Una comprobación básica tiene este aspecto:

@[Link](type=[Link])
def my_layout_check(context, feedback):
results = ...
return results

Aquí hay una comprobación que lanza una advertencia cada vez que un elemento de mapa de diseño se establece en
la proyección mercator web:

72 Capítulo 10. Representación del Mapa e Impresión


PyQGIS 3.40 developer cookbook

1 @[Link](type=[Link])
2 def layout_map_crs_choice_check(context, feedback):
3 layout = [Link]
4 results = []
5 for i in [Link]():
6 if isinstance(i, QgsLayoutItemMap) and [Link]().authid() == 'EPSG:3857':
7 res = QgsValidityCheckResult()
8 [Link] = [Link]
9 [Link] = 'Map projection is misleading'
10 [Link] = 'The projection for the map item {} is set to <i>
,→Web Mercator (EPSG:3857)</i> which misrepresents areas and shapes. Consider␣

,→using an appropriate local projection instead.'.format([Link]())

11 [Link](res)
12

13 return results

Y aquí hay un ejemplo más complejo, que lanza una advertencia si cualquier elemento de mapa de diseño se establece
en un SRC que sólo es válido fuera de la extensión mostrada en ese elemento de mapa:

1 @[Link](type=[Link])
2 def layout_map_crs_area_check(context, feedback):
3 layout = [Link]
4 results = []
5 for i in [Link]():
6 if isinstance(i, QgsLayoutItemMap):
7 bounds = [Link]().bounds()
8 ct = QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'),␣
,→[Link](), [Link]())

9 bounds_crs = [Link](bounds)
10

11 if not bounds_crs.contains([Link]()):
12 res = QgsValidityCheckResult()
13 [Link] = [Link]
14 [Link] = 'Map projection is incorrect'
15 [Link] = 'The projection for the map item {} is␣
,→set to \'{}\', which is not valid for the area displayed within the map.'.

,→format([Link](), [Link]().authid())

16 [Link](res)
17

18 return results

10.3.2 Exportando la composición

Para exportar una composición, la clase QgsLayoutExporter debe ser usada.

1 base_path = [Link]([Link]().homePath())
2 pdf_path = [Link](base_path, "[Link]")
3

4 exporter = QgsLayoutExporter(layout)
5 [Link](pdf_path, [Link]())

Utilice exportToSvg() o exportToImage() en caso de que desee exportar respectivamente a un archivo


SVG o de imagen en lugar de a un archivo PDF.

10.3. Salida usando diseño de impresión 73


PyQGIS 3.40 developer cookbook

10.3.3 Exportar un atlas de diseño

Si desea exportar todas las páginas de un diseño que tiene la opción de atlas configurada y habilitada, debe usar el
método atlas() en el exportador (QgsLayoutExporter) con pequeños ajustes. En el siguiente ejemplo, las
páginas se exportan a imágenes PNG:

[Link]([Link](), base_path, 'png', QgsLayoutExporter.


,→ImageExportSettings())

Observe que las salidas se guardarán en la carpeta de ruta base, utilizando la expresión de nombre de archivo de salida
configurada en atlas.

74 Capítulo 10. Representación del Mapa e Impresión


CAPÍTULO 11

Expresiones, Filtros y Calculando Valores

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 edit,
3 QgsExpression,
4 QgsExpressionContext,
5 QgsFeature,
6 QgsFeatureRequest,
7 QgsField,
8 QgsFields,
9 QgsVectorLayer,
10 QgsPointXY,
11 QgsGeometry,
12 QgsProject,
13 QgsExpressionContextUtils
14 )

QGIS tiene cierto soporte para analizar expresiones similares a SQL. Solo se admite un pequeño subconjunto de
sintaxis SQL. Las expresiones se pueden evaluar como predicados booleanos (devolviendo True o False) o como
funciones (devolviendo un valor escalar). Consulte vector_expressions en el Manual del usuario para obtener una lista
completa de las funciones disponibles.
Se le da apoyo a tres tipos:
• numero - números enteros y números con decimales, e.j. 123, 3.14
• cadena - se tiene que encerrar en comas individuales: 'hola mundo'
• columna de referencia - cuando se evalúa, la referencia se substituye con el valor actual del campo. Los nombres
no se escapan.
Los siguientes operadores están disponibles:
• operadores aritméticos: «+». «-», «/», ^
• paréntesis: para hacer cumplir la precedencia del operador: (1 + 1) * 3
• unario mas y menos: -12, +5

75
PyQGIS 3.40 developer cookbook

• funciones matemáticas: sqrt, sin, cos, tan, asin, acos, atan


• funciones de conversión: to_int, to_real, to_string, to_date
• funciones geométricas: $area, $length
• funciones de manejo de geometría: $x, $y, $geometry, num_geometries, centroid
Se apoya las siguientes predicciones:
• comparación: =, !=, >, >=, <, <=
• patrones iguales: LIKE (using % and _), ~ (expresión regular)
• lógica predicado: AND, OR, NOT
• revisión de valores NULO: IS NULL, IS NOT NULL
Ejemplos de predicado:
• 1 + 2 = 3
• sin(angulo) > 0
• “Hello” LIKE “He%”`
• (x > 10 AND y > 10) OR z = 0
Ejemplo de escala de expresiones:
• 2 ^ 10
• sqrt(val)
• $length + 1

11.1 Análisis de expresiones

El siguiente ejemplo muestra cómo verificar si una expresión dada se puede analizar correctamente:

1 exp = QgsExpression('1 + 1 = 2')


2 assert(not [Link]())
3

4 exp = QgsExpression('1 + 1 = ')


5 assert([Link]())
6

7 assert([Link]() == '\nsyntax error, unexpected end of file')

11.2 Evaluar expresiones

Las expresiones se pueden usar en diferentes contextos, por ejemplo, para filtrar entidades o para calcular nuevos
valores de campo. En cualquier caso, la expresión tiene que ser evaluada. Eso significa que su valor se calcula
realizando los pasos computacionales especificados, que pueden variar desde expresiones aritméticas simples hasta
expresiones agregadas.

76 Capítulo 11. Expresiones, Filtros y Calculando Valores


PyQGIS 3.40 developer cookbook

11.2.1 Expresiones Basicas

Esta expresión básica evalúa una operación aritmética simple:

exp = QgsExpression('2 * 3')


print(exp)
print([Link]())

<QgsExpression: '2 * 3'>


6

La expresión también se puede utilizar para comparar, evaluando 1 (True) o 0 (False)

exp = QgsExpression('1 + 1 = 2')


[Link]()
# 1

11.2.2 Expresiones con caracteristicas

Para evaluar una expresión sobre una entidad, se debe crear un objeto :clase:`QgsExpressionContext
<[Link]>` y pasarlo a la función de evaluación para permitir que la expresión acceda a
los valores de campo de la entidad.
El siguiente ejemplo muestra cómo crear una entidad con un campo llamado «Columna» y cómo agregar esta entidad
al contexto de expresión.

1 fields = QgsFields()
2 field = QgsField('Column')
3 [Link](field)
4 feature = QgsFeature()
5 [Link](fields)
6 [Link](0, 99)
7

8 exp = QgsExpression('"Column"')
9 context = QgsExpressionContext()
10 [Link](feature)
11 [Link](context)
12 # 99

El siguiente es un ejemplo más completo de cómo usar expresiones en el contexto de una capa vectorial, para calcular
nuevos valores de campo:

1 from [Link] import QMetaType


2

3 # create a vector layer


4 vl = QgsVectorLayer("Point", "Companies", "memory")
5 pr = [Link]()
6 [Link]([QgsField("Name", [Link]),
7 QgsField("Employees", [Link]),
8 QgsField("Revenue", [Link]),
9 QgsField("Rev. per employee", [Link]),
10 QgsField("Sum", [Link]),
11 QgsField("Fun", [Link])])
12 [Link]()
13

14 # add data to the first three fields


15 my_data = [
16 {'x': 0, 'y': 0, 'name': 'ABC', 'emp': 10, 'rev': 100.1},
17 {'x': 1, 'y': 1, 'name': 'DEF', 'emp': 2, 'rev': 50.5},
18 {'x': 5, 'y': 5, 'name': 'GHI', 'emp': 100, 'rev': 725.9}]
(continúe en la próxima página)

11.2. Evaluar expresiones 77


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


19

20 for rec in my_data:


21 f = QgsFeature()
22 pt = QgsPointXY(rec['x'], rec['y'])
23 [Link]([Link](pt))
24 [Link]([rec['name'], rec['emp'], rec['rev']])
25 [Link](f)
26

27 [Link]()
28 [Link]().addMapLayer(vl)
29

30 # The first expression computes the revenue per employee.


31 # The second one computes the sum of all revenue values in the layer.
32 # The final third expression doesn’t really make sense but illustrates
33 # the fact that we can use a wide range of expression functions, such
34 # as area and buffer in our expressions:
35 expression1 = QgsExpression('"Revenue"/"Employees"')
36 expression2 = QgsExpression('sum("Revenue")')
37 expression3 = QgsExpression('area(buffer($geometry,"Employees"))')
38

39 # [Link]() is a convenience
40 # function that adds the global, project, and layer scopes all at once.
41 # Alternatively, those scopes can also be added manually. In any case,
42 # it is important to always go from “most generic” to “most specific”
43 # scope, i.e. from global to project to layer
44 context = QgsExpressionContext()
45 [Link]([Link](vl))
46

47 with edit(vl):
48 for f in [Link]():
49 [Link](f)
50 f['Rev. per employee'] = [Link](context)
51 f['Sum'] = [Link](context)
52 f['Fun'] = [Link](context)
53 [Link](f)
54

55 print(f['Sum'])

876.5

11.2.3 Flitrando una capa con expresiones

El siguiente ejemplo se puede utilizar para filtra capas y regresar cualquier característica que empata con el predicado.

1 layer = QgsVectorLayer("Point?field=Test:integer",
2 "addfeat", "memory")
3

4 [Link]()
5

6 for i in range(10):
7 feature = QgsFeature()
8 [Link]([i])
9 assert([Link](feature))
10 [Link]()
11

12 expression = 'Test >= 3'


13 request = QgsFeatureRequest().setFilterExpression(expression)
14

15 matches = 0
(continúe en la próxima página)

78 Capítulo 11. Expresiones, Filtros y Calculando Valores


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


16 for f in [Link](request):
17 matches += 1
18

19 print(matches)

11.3 Manejando errores de expresión

Los errores relacionados con la expresión pueden ocurrir durante el análisis o la evaluación de expresiones:

1 exp = QgsExpression("1 + 1 = 2")


2 if [Link]():
3 raise Exception([Link]())
4

5 value = [Link]()
6 if [Link]():
7 raise ValueError([Link]())

11.3. Manejando errores de expresión 79


PyQGIS 3.40 developer cookbook

80 Capítulo 11. Expresiones, Filtros y Calculando Valores


CAPÍTULO 12

Configuración de lectura y almacenamiento

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsProject,
3 QgsSettings,
4 QgsVectorLayer
5 )

Muchas veces es útil para un complemento guardar algunas variables para que el usuario no tenga que introducir o
seleccionar de nuevo la próxima vez que el complemento se ejecute.
Estas variables se pueden guardar y recuperar con ayuda de Qt y QGIS API. Para cada variable, se debe escoger
una clave que será utilizada para acceder a la variable — para el color favorito del usuario podría utilizarse la clave
«favourite_color» o cualquier otra cadena que tenga sentido. Es recomendable dar un poco de estructura al nombrar
las claves.
Podemos diferenciar entre varios tipos de configuraciones:
• global settings — están vinculados al usuario en una máquina en particular. QGIS almacena muchas
configuraciones globales, por ejemplo, el tamaño de la ventana principal o la tolerancia de ajuste
predeterminada. La configuración se maneja usando la clase QgsSettings, por ejemplo, a través de
setValue() y :meth:`value() < [Link]>`métodos.
Aquí puede ver un ejemmplo de como se usan estos métodos.

1 def store():
2 s = QgsSettings()
3 [Link]("myplugin/mytext", "hello world")
4 [Link]("myplugin/myint", 10)
5 [Link]("myplugin/myreal", 3.14)
6

7 def read():
8 s = QgsSettings()
9 mytext = [Link]("myplugin/mytext", "default text")
10 myint = [Link]("myplugin/myint", 123)
11 myreal = [Link]("myplugin/myreal", 2.71)
(continúe en la próxima página)

81
PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


12 nonexistent = [Link]("myplugin/nonexistent", None)
13 print(mytext)
14 print(myint)
15 print(myreal)
16 print(nonexistent)

El segundo parámetro del método value() es opcional y especifica el valor predeterminado que se devuelve
si no hay un valor anterior establecido para el nombre de configuración pasado.
Para conocer un método para preconfigurar los valores predeterminados de las configuraciones globales a través
del archivo qgis_global_settings.ini, consulte deploying_organization para obtener más detalles.
• project settings — varían entre diferentes proyectos y, por lo tanto, están conectados con un archivo de
proyecto. El color de fondo del lienzo del mapa o el sistema de referencia de coordenadas de destino (CRS) son
ejemplos: el fondo blanco y WGS84 pueden ser adecuados para un proyecto, mientras que el fondo amarillo y
la proyección UTM son mejores para otro.
A continuación se muestra un ejemplo de uso.

1 proj = [Link]()
2

3 # store values
4 [Link]("myplugin", "mytext", "hello world")
5 [Link]("myplugin", "myint", 10)
6 [Link]("myplugin", "mydouble", 0.01)
7 [Link]("myplugin", "mybool", True)
8

9 # read values (returns a tuple with the value, and a status boolean
10 # which communicates whether the value retrieved could be converted to
11 # its type, in these cases a string, an integer, a double and a boolean
12 # respectively)
13

14 mytext, type_conversion_ok = [Link]("myplugin",


15 "mytext",
16 "default text")
17 myint, type_conversion_ok = [Link]("myplugin",
18 "myint",
19 123)
20 mydouble, type_conversion_ok = [Link]("myplugin",
21 "mydouble",
22 123)
23 mybool, type_conversion_ok = [Link]("myplugin",
24 "mybool",
25 123)

Como puede ver, el método writeEntry() es usado para muchos tipos de datos (entero, cadena, lista),
pero existen varios métodos para volver a leer el valor de ajuste, y se debe seleccionar el correspondiente para
cada tipo de datos.
• map layer settings — esta configuración está relacionada con una instancia particular de una capa de mapa
con un proyecto. No están conectados con la fuente de datos subyacente de una capa, por lo que si crea dos
instancias de capa de mapa de un archivo de forma, no compartirán la configuración. La configuración se
almacena dentro del archivo del proyecto, por lo que si el usuario abre el proyecto nuevamente, la configuración
relacionada con la capa volverá a estar allí. El valor para una configuración dada se recupera usando el método
customProperty(), y se puede establecer usando el método setCustomProperty() uno.

1 vlayer = QgsVectorLayer()
2 # save a value
3 [Link]("mytext", "hello world")
4

5 # read the value again (returning "default text" if not found)


6 mytext = [Link]("mytext", "default text")

82 Capítulo 12. Configuración de lectura y almacenamiento


PyQGIS 3.40 developer cookbook

83
PyQGIS 3.40 developer cookbook

84 Capítulo 12. Configuración de lectura y almacenamiento


CAPÍTULO 13

Comunicarse con el usuario

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:
1 from [Link] import (
2 QgsMessageLog,
3 QgsGeometry,
4 )
5

6 from [Link] import (


7 QgsMessageBar,
8 )
9

10 from [Link] import (


11 QSizePolicy,
12 QPushButton,
13 QDialog,
14 QGridLayout,
15 QDialogButtonBox,
16 )

Esta sección muestra algunos métodos y elementos que deberían utilizarse para comunicarse con el usuario, con el
objetivo de mantener la consistencia en la Interfaz del Usuario.

13.1 Mostrando mensajes. La clase QgsMessageBar

Utilizar las bandejas de mensajes puede ser una mala idea desde el punto de vista de la experiencia de un usuario.
Para mostrar una pequeña línea de información o mensajes de advertencia/error, la barrar de mensajes de QGIS suele
ser una mejor opción.
Utilizar la referencia a la interfaz objeto de QGIS, puede mostrar un mensaje en la barra de mensajes con el siguiente
código
from [Link] import Qgis
[Link]().pushMessage("Error", "I'm sorry Dave, I'm afraid I can't do that
,→", level=[Link])

85
PyQGIS 3.40 developer cookbook

Messages(2): Error : I'm sorry Dave, I'm afraid I can't do that

Figura 13.1: Barra de Mensajes de QGIS

Se puede establecer una duración para mostrarlo en un tiempo limitado

[Link]().pushMessage("Ooops", "The plugin is not working as it should",␣


,→level=[Link], duration=3)

Messages(2): Ooops : The plugin is not working as it should

Figura 13.2: Barra de Mensajes de QGIS con temporizador

Los ejemplos anteriores muestran una barra de error, pero el parámetro level se puede usar para crear mensajes
de advertencia o mensajes de información, utilizando la enumeración [Link]. Puede usar hasta 4
niveles diferentes:
0. Información
1. Advertencia
2. Critica
3. Éxito

Figura 13.3: Barra de Mensajes de QGIS (información)

Se puede añadir complementos a la barra de mensajes, como por ejemplo un botón para mostrar más información

1 def showError():
2 pass
3

4 widget = [Link]().createMessage("Missing Layers", "Show Me")


5 button = QPushButton(widget)
6 [Link]("Show Me")
7 [Link](showError)
8 [Link]().addWidget(button)
9 [Link]().pushWidget(widget, [Link])

86 Capítulo 13. Comunicarse con el usuario


PyQGIS 3.40 developer cookbook

Messages(1): Missing Layers : Show Me

Figura 13.4: Barra de Mensajes de QGIS con un botón

Incluso puedes utilizar una barra de mensajes en tu propio cuadro de diálogo para no tener que mostrar la bandeja de
mensajes o si no tiene sentido mostrarla en la pantalla principal de QGIS.

1 class MyDialog(QDialog):
2 def __init__(self):
3 QDialog.__init__(self)
4 [Link] = QgsMessageBar()
5 [Link]( [Link], [Link] )
6 [Link](QGridLayout())
7 [Link]().setContentsMargins(0, 0, 0, 0)
8 [Link] = QDialogButtonBox([Link])
9 [Link]([Link])
10 [Link]().addWidget([Link], 0, 0, 2, 1)
11 [Link]().addWidget([Link], 0, 0, 1, 1)
12 def run(self):
13 [Link]("Hello", "World", level=[Link])
14

15 myDlg = MyDialog()
16 [Link]()

13.1. Mostrando mensajes. La clase QgsMessageBar 87


PyQGIS 3.40 developer cookbook

Figura 13.5: Barra de Mensajes de QGIS con un cuadro de diálogo personalizado

13.2 Mostrando el progreso

Las barras de progreso también pueden ponerse en la barra de Mensajes de QGIS, ya que, como hemos visto, admite
complementos. Este es un ejemplo que puedes probar en la consola.

1 import time
2 from [Link] import QProgressBar
3 from [Link] import *
4 progressMessageBar = [Link]().createMessage("Doing something boring...")
5 progress = QProgressBar()
6 [Link](10)
7 [Link]([Link]|[Link])
8 [Link]().addWidget(progress)
9 [Link]().pushWidget(progressMessageBar, [Link])
10

11 for i in range(10):
12 [Link](1)
13 [Link](i + 1)
14

15 [Link]().clearWidgets()

88 Capítulo 13. Comunicarse con el usuario


PyQGIS 3.40 developer cookbook

Messages(0): Doing something boring...

Además, puede usar el constructor en la barra de estado para comunicar progreso, como en el siguiente ejemplo:

1 vlayer = [Link]()
2

3 count = [Link]()
4 features = [Link]()
5

6 for i, feature in enumerate(features):


7 # do something time-consuming here
8 print('.') # printing should give enough time to present the progress
9

10 percent = i / float(count) * 100


11 # [Link]().statusBar().showMessage("Processed {} %".
,→format(int(percent)))

12 [Link]().showMessage("Processed {} %".format(int(percent)))
13

14 [Link]().clearMessage()

13.3 Registro

Hay tres tipos diferentes de registro disponible en QGIS para registrar y guardar toda la información sobre la ejecución
de su código. Cada uno tiene una ubicación de salida específica. Por favor considere el uso de la forma correcta de
registro para su propósito:
• QgsMessageLog es para que los mensajes comuniquen problemas al usuario. La salida del QgsMessageLog
es mostrada en el Panel de Mensajes de Registro.
• El python construido en el módilo registro es para depuración en el nivel de la API Python QGIS (PyQGIS).
Es recomendado para desarrolladores de script Python que necesitan depurar su código python, e.g. ids o
geometría de objeto espacial
• QgsLogger es para mensajes para depuración / desarrolladores internos QGIS (i.e. usted sospecha que algo
es gatillado por algún código dañado). Los mensajes sólo están visibles con versiones desarrollador de QGIS.
Ejemplos para los diferentes tipos de registro son mostrados en las siguientes secciones abajo.

Advertencia: El uso de la declaración print Python no es segura en ningún código que sea multihilos y
ralentiza extremadamente el algoritmo. Esto incluye funciones de expresión, representadores, capas de
símbolo y algoritmos Procesos (entre otros). En estos casos usted siempre debería usar en vez el módulo python
registro o clases seguras de hilo (QgsLogger o QgsMessageLog).

13.3.1 QgsMessageLog

# You can optionally pass a 'tag' and a 'level' parameters


[Link]("Your plugin code has been executed correctly", 'MyPlugin
,→', level=[Link])

[Link]("Your plugin code might have some problems", level=Qgis.


,→Warning)

[Link]("Your plugin code has crashed!", level=[Link])

MyPlugin(0): Your plugin code has been executed correctly


(1): Your plugin code might have some problems
(2): Your plugin code has crashed!

13.3. Registro 89
PyQGIS 3.40 developer cookbook

Nota: Puede ver la salida de la QgsMessageLog en el log_message_panel

13.3.2 El python construído en el módulo de registro

1 import logging
2 formatter = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
3 logfilename=r'c:\temp\[Link]'
4 [Link](filename=logfilename, level=[Link], format=formatter)
5 [Link]("This logging info text goes into the file")
6 [Link]("This logging debug text goes into the file as well")

El método basicConfig configura la definición básica del registro. En el código de arriba el nombre de archivo, nivel
de registro y el formato son definidos. El nombre de archivo se refiere a donde escribir el archivo de registro, el nivel
de registro define qué niveles imprimir y el formato define el formato en el que cada mensaje es impreso.

2020-10-08 [Link],998 - root - INFO - This logging text goes into the file
2020-10-08 [Link],998 - root - DEBUG - This logging debug text goes into the␣
,→file as well

Si quiere borrar el archivo de registro cada vez que ejecuta su script usted puede hacer algo como:

if [Link](logfilename):
with open(logfilename, 'w') as file:
pass

Mayores recursos sobre cómo usar la instalación de registro python están disponibles en:
• [Link]
• [Link]
• [Link]

Advertencia: Por favor tome nota que sin registrar a un archivo al definir el nombre de archivo, el registro podría
darse en multihilos lo que ralentiza fuertemente la salida.

90 Capítulo 13. Comunicarse con el usuario


CAPÍTULO 14

Infraestructura de autenticación

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsApplication,
3 QgsRasterLayer,
4 QgsAuthMethodConfig,
5 QgsDataSourceUri,
6 QgsPkiBundle,
7 QgsMessageLog,
8 )
9

10 from [Link] import (


11 QgsAuthAuthoritiesEditor,
12 QgsAuthConfigEditor,
13 QgsAuthConfigSelect,
14 QgsAuthSettingsWidget,
15 )
16

17 from [Link] import (


18 QWidget,
19 QTabWidget,
20 )
21

22 from [Link] import QSslCertificate

91
PyQGIS 3.40 developer cookbook

14.1 Introducción

La referencia de Usuario de la infraestructura de Autenticación puede ser leída en el Manual del Usuario en el párrafo
authentication_overview.
En este capítulo se describen las mejores prácticas para usar el sistema de autenticación desde una perspectiva de
desarrollador.
El sistema de autenticación es ampliamente utilizado en QGIS Desktop por los proveedores de datos siempre que se
requieren credenciales para acceder a un recurso en particular, por ejemplo, cuando una capa establece una conexión
a una base de datos de Postgres.
También hay algunos widgets en la biblioteca de interfaz gráfica de usuario de QGIS que los desarrolladores de
complementos pueden usar para integrar fácilmente la infraestructura de autenticación en su código:
• QgsAuthConfigEditor
• QgsAuthConfigSelect
• QgsAuthSettingsWidget
Se puede leer una buena referencia de código desde la infraestructura de autenticación tests code.

Advertencia: Debido a las restricciones de seguridad que se tuvieron en cuenta durante el diseño de la
infraestructura de autenticación, solo un subconjunto seleccionado de los métodos internos están expuestos a
Python.

14.2 Glosario

Aquí hay algunas definiciones de los objetos más comunes tratados en este capítulo.
Contraseña maestra
Contraseña para permitir el acceso y descifrar las credenciales almacenadas en la base de datos de autenticación
de QGIS
BBDD de Autenticación
Un Master Password encriptado sqlite db [Link] donde Authentication Configuration son
almacenados. [Link]. usuario/contraseña, certificados personales y claves, Autoridades de certificación
Autenticación BD
Authentication Database
Configuración de Autenticación
Un conjunto de datos de autenticación según Authentication Method. [Link]. El método de Autenticación básica
almacena el par de usuario/contraseña.
Configuración de autenticación
Authentication Configuration
Método de autenticación
Un método específico utilizado para autenticarse. Cada método tiene su propio protocolo utilizado para obtener
el nivel autenticado. Cada método se implementa como una biblioteca compartida cargada dinámicamente
durante el inicio de la infraestructura de autenticación de QGIS.

92 Capítulo 14. Infraestructura de autenticación


PyQGIS 3.40 developer cookbook

14.3 QgsAuthManager el punto de entrada

El QgsAuthManager singleton es el punto de entrada para usar las credenciales almacenadas en el QGIS encriptado
BBDD Autenticación, es decir, el archivo [Link] en la carpeta activa perfil de usuario.
Esta clase se encarga de la interacción del usuario: solicitando establecer una contraseña maestra o utilizándola de
forma transparente para acceder a la información almacenada cifrada.

14.3.1 Inicie el administrador y configure la contraseña maestra

El siguiente fragmento ofrece un ejemplo para establecer una contraseña maestra para abrir el acceso a la configuración
de autenticación. Los comentarios de código son importantes para comprender el fragmento.

1 authMgr = [Link]()
2

3 # check if QgsAuthManager has already been initialized... a side effect


4 # of the [Link]() is that AuthDbPath is set.
5 # [Link]() is executed during QGIS application init and hence
6 # you do not normally need to call it directly.
7 if [Link]():
8 # already initialized => we are inside a QGIS app.
9 if [Link]():
10 msg = 'Authentication master password not recognized'
11 assert [Link]("your master password"), msg
12 else:
13 msg = 'Master password could not be set'
14 # The verify parameter checks if the hash of the password was
15 # already saved in the authentication db
16 assert [Link]("your master password",
17 verify=True), msg
18 else:
19 # outside qgis, e.g. in a testing environment => setup env var before
20 # db init
21 [Link]['QGIS_AUTH_DB_DIR_PATH'] = "/path/where/located/[Link]"
22 msg = 'Master password could not be set'
23 assert [Link]("your master password", True), msg
24 [Link]("/path/where/located/[Link]")

14.3.2 Complete authdb con una nueva entrada de configuración de


autenticación

Cualquier credencial almacenado es una instancia Authentication Configuration de la clase


QgsAuthMethodConfig se accede usando una cadena única como la siguiente:

authcfg = 'fm1s770'

esa cadena se genera automáticamente al crear una entrada utilizando la API o GUI de QGIS, pero podría ser útil
establecerla manualmente en un valor conocido en caso de que la configuración deba compartirse (con diferentes
credenciales) entre varios usuarios dentro de una organización.
QgsAuthMethodConfig es la clase base para cualquier Método de autenticación. Cualquier método de
autenticación establece un mapa hash de configuración donde se almacenará la información de autenticación. A
continuación, un fragmento útil para almacenar las credenciales de ruta PKI para un usuario hipotético de Alice:

1 authMgr = [Link]()
2 # set alice PKI data
3 config = QgsAuthMethodConfig()
4 [Link]("alice")
(continúe en la próxima página)

14.3. QgsAuthManager el punto de entrada 93


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


5 [Link]("PKI-Paths")
6 [Link]("[Link]
7 [Link]("certpath", "path/to/[Link]" )
8 [Link]("keypath", "path/to/[Link]" )
9 # check if method parameters are correctly set
10 assert [Link]()
11

12 # register alice data in authdb returning the ``authcfg`` of the stored


13 # configuration
14 [Link](config)
15 newAuthCfgId = [Link]()
16 assert newAuthCfgId

Métodos de autenticación disponibles

Authentication Method las bibliotecas se cargan dinámicamente durante el inicio del administrador de autenticación.
Los métodos de autenticación disponibles son:
1. Basic Autenticación de usuario y contraseña
2. EsriToken Autenticación basada en token ESRI
3. Identity-Cert Autenticación del certificado de identidad
4. OAuth2 autenticación OAuth2
5. PKI-Paths Autenticación de rutas PKI
6. PKI-PKCS#12 PKI PKCS#12 Autenticación

Populate Authorities

1 authMgr = [Link]()
2 # add authorities
3 cacerts = [Link]( "/path/to/ca_chains.pem" )
4 assert cacerts is not None
5 # store CA
6 [Link](cacerts)
7 # and rebuild CA caches
8 [Link]()
9 [Link]()

Administrar paquetes de PKI con QgsPkiBundle

Una clase de conveniencia para empaquetar paquetes PKI compuestos en cadenas SslCert, SslKey y CA es la clase
QgsPkiBundle. A continuación, un fragmento para protegerse con contraseña:

1 # add alice cert in case of key with pwd


2 caBundlesList = [] # List of CA bundles
3 bundle = [Link]( "/path/to/[Link]",
4 "/path/to/alice-key_w-[Link]",
5 "unlock_pwd",
6 caBundlesList )
7 assert bundle is not None
8 # You can check bundle validity by calling:
9 # [Link]()

Referirse a documentación de la clase QgsPkiBundle para extraer cert/clave/CAs del paquete.

94 Capítulo 14. Infraestructura de autenticación


PyQGIS 3.40 developer cookbook

14.3.3 Borrar una entrada de authdb

Podemos borrar una entrada de Authentication Database usando su identificador authcfg con el siguiente
fragmento:

authMgr = [Link]()
[Link]( "authCfg_Id_to_remove" )

14.3.4 Deje la expansión authcfg a QgsAuthManager

La mejor manera de utilizar una Configuración de Autenticación almacenada en BBDD de Autenticación es


refiriéndola con el identificador único authcfg. Expandir significa convertirlo de un identificador a un conjunto
completo de credenciales. La mejor práctica para usar el Authentication Configs almacenado, es dejarlo administrado
automáticamente por el administrador de Autenticación. El uso común de una configuración almacenada es conectarse
a un servicio habilitado para autenticación como WMS o WFS oa una conexión de base de datos.

Nota: Tenga en cuenta que no todos los proveedores de datos de QGIS están integrados con la infraestructura de
autenticación. Cada método de autenticación, derivado de la clase base QgsAuthMethod y soporta un conjunto
diferente de Proveedores. Por ejemplo el método certIdentity() soporta la siguiente lista de proveedores:

authM = [Link]()
print([Link]("Identity-Cert").supportedDataProviders())

Salida de muestra:

['ows', 'wfs', 'wcs', 'wms', 'postgres']

Por ejemplo, para acceder a un servicio WMS usando credenciales almacenadas identificadas con authcfg =
'fm1s770', solo tenemos que usar el authcfg en la URL de la fuente de datos como en el siguiente fragmento:

1 authCfg = 'fm1s770'
2 quri = QgsDataSourceUri()
3 [Link]("layers", 'usa:states')
4 [Link]("styles", '')
5 [Link]("format", 'image/png')
6 [Link]("crs", 'EPSG:4326')
7 [Link]("dpiMode", '7')
8 [Link]("featureCount", '10')
9 [Link]("authcfg", authCfg) # <---- here my authCfg url parameter
10 [Link]("contextualWMSLegend", '0')
11 [Link]("url", '[Link]
12 rlayer = QgsRasterLayer(str([Link](), "utf-8"), 'states', 'wms')

En mayúsculas, el proveedor wms se encargará de expandir el parámetro URI authcfg con credencial justo antes
de configurar la conexión HTTP.

Advertencia: El desarrollador tendría que dejar la expansión ʻauthcfg` a QgsAuthManager, de esta manera
se asegurará de que la expansión no se haga demasiado pronto.

Por lo general, una cadena URI, construida usando la clase QgsDataSourceURI , se utiliza para configurar una
fuente de datos de la siguiente manera:

authCfg = 'fm1s770'
quri = QgsDataSourceUri("my WMS uri here")
[Link]("authcfg", authCfg)
rlayer = QgsRasterLayer( [Link](False), 'states', 'wms')

14.3. QgsAuthManager el punto de entrada 95


PyQGIS 3.40 developer cookbook

Nota: El parámetro False es importante para evitar la expansión completa de URI del id authcfg presente en
el URI.

Ejemplos PKI con otros proveedores de datos

Otro ejemplo se puede leer directamente en las pruebas de QGIS en sentido ascendente como en
test_authmanager_pki_ows o test_authmanager_pki_postgres.

14.4 Adpatar complementos para usar Infraestructura de


Autenticación

Muchos complementos de terceros están utilizando httplib2 u otras bibliotecas de red de Python para administrar las
conexiones HTTP en lugar de integrarse con QgsNetworkAccessManager y su integración relacionada con la
infraestructura de autenticación.
Para facilitar esta integración se ha creado una función auxiliar de Python llamada NetworkAccessManager.
Su código se puede encontrar aquí.
Esta clase auxiliar se puede utilizar como en el siguiente fragmento:

1 http = NetworkAccessManager(authid="my_authCfg", exception_class=My_


,→FailedRequestError)

2 try:
3 response, content = [Link]( "my_rest_url" )
4 except My_FailedRequestError, e:
5 # Handle exception
6 pass

14.5 Autenticación IGUs

En este párrafo se enumeran las IGU disponibles útiles para integrar la infraestructura de autenticación en interfaces
personalizadas.

14.5.1 IGU para seleccionar credenciales

Si es necesario seleccionar un Authentication Configuration del conjunto almacenado en la BBDD Autenticación está
disponible en la clase IGU QgsAuthConfigSelect.

y se puede utilizar como en el siguiente fragmento:

96 Capítulo 14. Infraestructura de autenticación


PyQGIS 3.40 developer cookbook

1 # create the instance of the QgsAuthConfigSelect GUI hierarchically linked to


2 # the widget referred with `parent`
3 parent = QWidget() # Your GUI parent widget
4 gui = QgsAuthConfigSelect( parent, "postgres" )
5 # add the above created gui in a new tab of the interface where the
6 # GUI has to be integrated
7 tabGui = QTabWidget()
8 [Link]( 1, gui, "Configurations" )

El ejemplo anterior está tomado de la fuente QGIS code. El segundo parámetro del constructor de GUI se refiere
al tipo de proveedor de datos. El parámetro se utiliza para restringir el Método de autenticación compatible con el
proveedor especificado.

14.5.2 IGU Editor Autenticación

La GUI completa utilizada para administrar credenciales, autoridades y para acceder a las utilidades de autenticación
es administrada por la clase QgsAuthEditorWidgets.

y se puede utilizar como en el siguiente fragmento:

1 # create the instance of the QgsAuthEditorWidgets GUI hierarchically linked to


2 # the widget referred with `parent`
3 parent = QWidget() # Your GUI parent widget
4 gui = QgsAuthConfigSelect( parent )
5 [Link]()

Se puede encontrar un ejemplo integrado en el test.

14.5. Autenticación IGUs 97


PyQGIS 3.40 developer cookbook

14.5.3 IGU de Editor de Autoridades

Una GUI utilizada para administrar solo las autoridades es administrada por la clase
QgsAuthAuthoritiesEditor.

y se puede utilizar como en el siguiente fragmento:

1 # create the instance of the QgsAuthAuthoritiesEditor GUI hierarchically


2 # linked to the widget referred with `parent`
3 parent = QWidget() # Your GUI parent widget
4 gui = QgsAuthAuthoritiesEditor( parent )
5 [Link]()

98 Capítulo 14. Infraestructura de autenticación


CAPÍTULO 15

Tareas - haciendo trabajo duro en segundo plano

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:
1 from [Link] import (
2 Qgis,
3 QgsApplication,
4 QgsMessageLog,
5 QgsProcessingAlgRunnerTask,
6 QgsProcessingContext,
7 QgsProcessingFeedback,
8 QgsProject,
9 QgsTask,
10 QgsTaskManager,
11 )

15.1 Introducción

El procesamiento en segundo plano utilizando subprocesos es una forma de mantener una interfaz de usuario receptiva
cuando se está realizando un procesamiento pesado. Las tareas se pueden utilizar para realizar subprocesos en QGIS.
Una tarea (QgsTask) es un contenedor para el código que se realizará en segundo plano, y el administrador de tareas
(QgsTaskManager) se usa para controlas la ejecución de las tareas. Estas clases simplifican el procesamiento en
segundo plano en QGIS al proporcionar mecanismos de señalización, informes de progreso y acceso al estado de los
procesos en segundo plano. Las tareas se pueden agrupar mediante subtareas.
El administrador de tareas global (encontrado con [Link]()) es usado
normalmente. Esto significa que sus tareas pueden no ser las únicas tareas controladas por el administrador de tareas.
Hay varias vías para crear una tarea QGIS:
• Crea tu propia tarea extendiendo QgsTask
class SpecialisedTask(QgsTask):
pass

• Crear una tarea desde una función

99
PyQGIS 3.40 developer cookbook

1 def heavyFunction():
2 # Some CPU intensive processing ...
3 pass
4

5 def workdone():
6 # ... do something useful with the results
7 pass
8

9 task = [Link]('heavy function', heavyFunction,


10 on_finished=workdone)

• Crear una tarea desde un algoritmo de procesamiento

1 params = dict()
2 context = QgsProcessingContext()
3 [Link]([Link]())
4 feedback = QgsProcessingFeedback()
5

6 buffer_alg = [Link]().processingRegistry().algorithmById(
,→'native:buffer')

7 task = QgsProcessingAlgRunnerTask(buffer_alg, params, context,


8 feedback)

Advertencia: Cualquier tarea en segundo plano (independientemente de cómo se cree) NUNCA debe usar ningún
QObject que viva en el hilo principal, como acceder a QgsVectorLayer, QgsProject o realizar cualquier operación
basada en GUI como crear nuevos widgets o interactuar con widgets existentes. Solo se debe acceder o modificar
los widgets de Qt desde el hilo principal. Los datos que se utilizan en una tarea se deben copiar antes de iniciar la
tarea. Intentar utilizarlos desde subprocesos en segundo plano provocará bloqueos.
Además asegúrese siempre de que context y feedback viven al menos tanto tiempo como las tareas que
los utilizan. QGIS se bloqueará si, al finalizar una tarea, QgsTaskManager falla al acceder al context y feedback
contra los que se programó la tarea.

Nota: Es un patrón común llamar setProject() poco después de llamar a QgsProcessingContext. Esto
permite que la tarea, así como su función de devolución de llamada, utilicen la mayor parte de la configuración de
todo el proyecto. Esto es especialmente valioso cuando se trabaja con capas espaciales en la función callback.

Las dependencias entre tareas se pueden describir utilizando la función addSubTask() de QgsTask. Cuando
se establece una dependencia, el administrador de tareas determinará automáticamente cómo se ejecutarán estas
dependencias. Siempre que sea posible, las dependencias se ejecutarán en paralelo para satisfacerlas lo más rápido
posible. Si se cancela una tarea de la que depende otra tarea, la tarea dependiente también se cancelará. Las
dependencias circulares pueden hacer posibles los interbloqueos, así que tenga cuidado.
Si una tarea depende de que haya una capa disponible, esto se puede indicar usando la función
setDependentLayers() de QgsTask. Si una capa de la que depende una tarea no está disponible, la tarea se
cancelará.
Una vez que se ha creado la tarea, se puede programar su ejecución utilizando la función addTask() del
administrador de tareas. Agregar una tarea al administrador transfiere automáticamente la propiedad de esa tarea al
administrador, y el administrador limpiará y eliminará las tareas después de que se hayan ejecutado. La programación
de las tareas está influenciada por la prioridad de la tarea, que se establece en addTask().
El estado de las tareas puede ser monitorizado usando señales y funciones QgsTask y QgsTaskManager.

100 Capítulo 15. Tareas - haciendo trabajo duro en segundo plano


PyQGIS 3.40 developer cookbook

15.2 Ejemplos

15.2.1 Extendiendo QgsTask

En este ejemplo RandomIntegerSumTask se extiende QgsTask y generará 100 enteros aleatorios entre 0 y 500
durante un período de tiempo específico. Si el número aleatorio es 42, la tarea se cancela y se genera una excepción.
Se generan y agregan varias instancias de RandomIntegerSumTask (con subtareas) al administrador de tareas,
lo que demuestra dos tipos de dependencias.

1 import random
2 from time import sleep
3

4 from [Link] import (


5 QgsApplication, QgsTask, QgsMessageLog, Qgis
6 )
7

8 MESSAGE_CATEGORY = 'RandomIntegerSumTask'
9

10 class RandomIntegerSumTask(QgsTask):
11 """This shows how to subclass QgsTask"""
12

13 def __init__(self, description, duration):


14 super().__init__(description, [Link])
15 [Link] = duration
16 [Link] = 0
17 [Link] = 0
18 [Link] = None
19

20 def run(self):
21 """Here you implement your heavy lifting.
22 Should periodically test for isCanceled() to gracefully
23 abort.
24 This method MUST return True or False.
25 Raising exceptions will crash QGIS, so we handle them
26 internally and raise them in [Link]
27 """
28 [Link]('Started task "{}"'.format(
29 [Link]()),
30 MESSAGE_CATEGORY, [Link])
31 wait_time = [Link] / 100
32 for i in range(100):
33 sleep(wait_time)
34 # use setProgress to report progress
35 [Link](i)
36 arandominteger = [Link](0, 500)
37 [Link] += arandominteger
38 [Link] += 1
39 # check isCanceled() to handle cancellation
40 if [Link]():
41 return False
42 # simulate exceptions to show how to abort task
43 if arandominteger == 42:
44 # DO NOT raise Exception('bad value!')
45 # this would crash QGIS
46 [Link] = Exception('bad value!')
47 return False
48 return True
49

50 def finished(self, result):


51 """
52 This function is automatically called when the task has
(continúe en la próxima página)

15.2. Ejemplos 101


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


53 completed (successfully or not).
54 You implement finished() to do whatever follow-up stuff
55 should happen after the task is complete.
56 finished is always called from the main thread, so it's safe
57 to do GUI operations and raise Python exceptions here.
58 result is the return value from [Link].
59 """
60 if result:
61 [Link](
62 'RandomTask "{name}" completed\n' \
63 'RandomTotal: {total} (with {iterations} '\
64 'iterations)'.format(
65 name=[Link](),
66 total=[Link],
67 iterations=[Link]),
68 MESSAGE_CATEGORY, [Link])
69 else:
70 if [Link] is None:
71 [Link](
72 'RandomTask "{name}" not successful but without '\
73 'exception (probably the task was manually '\
74 'canceled by the user)'.format(
75 name=[Link]()),
76 MESSAGE_CATEGORY, [Link])
77 else:
78 [Link](
79 'RandomTask "{name}" Exception: {exception}'.format(
80 name=[Link](),
81 exception=[Link]),
82 MESSAGE_CATEGORY, [Link])
83 raise [Link]
84

85 def cancel(self):
86 [Link](
87 'RandomTask "{name}" was canceled'.format(
88 name=[Link]()),
89 MESSAGE_CATEGORY, [Link])
90 super().cancel()
91

92

93 longtask = RandomIntegerSumTask('waste cpu long', 20)


94 shorttask = RandomIntegerSumTask('waste cpu short', 10)
95 minitask = RandomIntegerSumTask('waste cpu mini', 5)
96 shortsubtask = RandomIntegerSumTask('waste cpu subtask short', 5)
97 longsubtask = RandomIntegerSumTask('waste cpu subtask long', 10)
98 shortestsubtask = RandomIntegerSumTask('waste cpu subtask shortest', 4)
99

100 # Add a subtask (shortsubtask) to shorttask that must run after


101 # minitask and longtask has finished
102 [Link](shortsubtask, [minitask, longtask])
103 # Add a subtask (longsubtask) to longtask that must be run
104 # before the parent task
105 [Link](longsubtask, [], [Link])
106 # Add a subtask (shortestsubtask) to longtask
107 [Link](shortestsubtask)
108

109 [Link]().addTask(longtask)
110 [Link]().addTask(shorttask)
111 [Link]().addTask(minitask)

102 Capítulo 15. Tareas - haciendo trabajo duro en segundo plano


PyQGIS 3.40 developer cookbook

1 RandomIntegerSumTask(0): Started task "waste cpu subtask shortest"


2 RandomIntegerSumTask(0): Started task "waste cpu short"
3 RandomIntegerSumTask(0): Started task "waste cpu mini"
4 RandomIntegerSumTask(0): Started task "waste cpu subtask long"
5 RandomIntegerSumTask(3): Task "waste cpu subtask shortest" completed
6 RandomTotal: 25452 (with 100 iterations)
7 RandomIntegerSumTask(3): Task "waste cpu mini" completed
8 RandomTotal: 23810 (with 100 iterations)
9 RandomIntegerSumTask(3): Task "waste cpu subtask long" completed
10 RandomTotal: 26308 (with 100 iterations)
11 RandomIntegerSumTask(0): Started task "waste cpu long"
12 RandomIntegerSumTask(3): Task "waste cpu long" completed
13 RandomTotal: 22534 (with 100 iterations)

15.2.2 Tarea desde función

Cree una tarea desde una función (doSomething en este ejemplo). El primer parámetro de la función contendrá
el QgsTask para la función. Un importante parámetro(llamado) es on_finished, que especifica una función
que se llamará cuando la tarea se haya completado. La función doSomething en este ejemplo tiene un parámetro
adicional llamado wait_time.
1 import random
2 from time import sleep
3

4 MESSAGE_CATEGORY = 'TaskFromFunction'
5

6 def doSomething(task, wait_time):


7 """
8 Raises an exception to abort the task.
9 Returns a result if success.
10 The result will be passed, together with the exception (None in
11 the case of success), to the on_finished method.
12 If there is an exception, there will be no result.
13 """
14 [Link]('Started task {}'.format([Link]()),
15 MESSAGE_CATEGORY, [Link])
16 wait_time = wait_time / 100
17 total = 0
18 iterations = 0
19 for i in range(100):
20 sleep(wait_time)
21 # use [Link] to report progress
22 [Link](i)
23 arandominteger = [Link](0, 500)
24 total += arandominteger
25 iterations += 1
26 # check [Link]() to handle cancellation
27 if [Link]():
28 stopped(task)
29 return None
30 # raise an exception to abort the task
31 if arandominteger == 42:
32 raise Exception('bad value!')
33 return {'total': total, 'iterations': iterations,
34 'task': [Link]()}
35

36 def stopped(task):
37 [Link](
38 'Task "{name}" was canceled'.format(
39 name=[Link]()),
(continúe en la próxima página)

15.2. Ejemplos 103


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


40 MESSAGE_CATEGORY, [Link])
41

42 def completed(exception, result=None):


43 """This is called when doSomething is finished.
44 Exception is not None if doSomething raises an exception.
45 result is the return value of doSomething."""
46 if exception is None:
47 if result is None:
48 [Link](
49 'Completed with no exception and no result '\
50 '(probably manually canceled by the user)',
51 MESSAGE_CATEGORY, [Link])
52 else:
53 [Link](
54 'Task {name} completed\n'
55 'Total: {total} ( with {iterations} '
56 'iterations)'.format(
57 name=result['task'],
58 total=result['total'],
59 iterations=result['iterations']),
60 MESSAGE_CATEGORY, [Link])
61 else:
62 [Link]("Exception: {}".format(exception),
63 MESSAGE_CATEGORY, [Link])
64 raise exception
65

66 # Create a few tasks


67 task1 = [Link]('Waste cpu 1', doSomething,
68 on_finished=completed, wait_time=4)
69 task2 = [Link]('Waste cpu 2', doSomething,
70 on_finished=completed, wait_time=3)
71 [Link]().addTask(task1)
72 [Link]().addTask(task2)

1 RandomIntegerSumTask(0): Started task "waste cpu subtask short"


2 RandomTaskFromFunction(0): Started task Waste cpu 1
3 RandomTaskFromFunction(0): Started task Waste cpu 2
4 RandomTaskFromFunction(0): Task Waste cpu 2 completed
5 RandomTotal: 23263 ( with 100 iterations)
6 RandomTaskFromFunction(0): Task Waste cpu 1 completed
7 RandomTotal: 25044 ( with 100 iterations)

15.2.3 Tarea de un algoritmo de procesamiento

Crear una tarea que use el algoritmo qgis:randompointsinextent para generar 50000 puntos aleatorios dentro de una
extensión específica. El resultado se agrega al proyecto de manera segura.

1 from functools import partial


2 from [Link] import (QgsTaskManager, QgsMessageLog,
3 QgsProcessingAlgRunnerTask, QgsApplication,
4 QgsProcessingContext, QgsProcessingFeedback,
5 QgsProject)
6

7 MESSAGE_CATEGORY = 'AlgRunnerTask'
8

9 def task_finished(context, successful, results):


10 if not successful:
11 [Link]('Task finished unsucessfully',
12 MESSAGE_CATEGORY, [Link])
(continúe en la próxima página)

104 Capítulo 15. Tareas - haciendo trabajo duro en segundo plano


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


13 output_layer = [Link](results['OUTPUT'])
14 # because getMapLayer doesn't transfer ownership, the layer will
15 # be deleted when context goes out of scope and you'll get a
16 # crash.
17 # takeMapLayer transfers ownership so it's then safe to add it
18 # to the project and give the project ownership.
19 if output_layer and output_layer.isValid():
20 [Link]().addMapLayer(
21 [Link](output_layer.id()))
22

23 alg = [Link]().algorithmById(
24 'qgis:randompointsinextent')
25 # `context` and `feedback` need to
26 # live for as least as long as `task`,
27 # otherwise the program will crash.
28 # Initializing them globally is a sure way
29 # of avoiding this unfortunate situation.
30 context = QgsProcessingContext()
31 feedback = QgsProcessingFeedback()
32 params = {
33 'EXTENT': '0.0,10.0,40,50 [EPSG:4326]',
34 'MIN_DISTANCE': 0.0,
35 'POINTS_NUMBER': 50000,
36 'TARGET_CRS': 'EPSG:4326',
37 'OUTPUT': 'memory:My random points'
38 }
39 task = QgsProcessingAlgRunnerTask(alg, params, context, feedback)
40 [Link](partial(task_finished, context))
41 [Link]().addTask(task)

Vea también: [Link]

15.2. Ejemplos 105


PyQGIS 3.40 developer cookbook

106 Capítulo 15. Tareas - haciendo trabajo duro en segundo plano


CAPÍTULO 16

Desarrollando Plugins Python

16.1 Estructurar Complementos de Python

Los pasos principales para crear un complemento son:


1. Idea: Tenga una idea de lo que quiere hacer con tu nuevo complemento QGIS.
2. Configuración: Crea los archivos para tu complemento. Dependiendo del tipo de complemento, algunos son
obligatorios y otros opcionales.
3. Desarrollar: Escribir el código en los archivos correspondientes
4. Documentar: Escribir la documentación del complemento
5. Opcionalmente: * Traducir*: Traduce su complemento en diferentes idiomas
6. Test: Recarga tu complemento para comprobar si todo está bien
7. Publish: Publique su complemento en el repositorio de QGIS o cree su propio repositorio como un «arsenal»
de «armas GIS» personales.

16.1.1 Cómo empezar

Antes de empezar a escribir un nuevo complemento, eche un vistazo al Repositorio oficial de complementos de Python.
El código fuente de los complementos existentes puede ayudarle a aprender más sobre programación. También puedes
encontrar que ya existe un complemento similar y puede ser capaz de extenderlo o al menos basarte en él para
desarrollar el tuyo propio.

107
PyQGIS 3.40 developer cookbook

Configurar la estructura de archivos del complemento

Para empezar con un nuevo complemento, necesitamos configurar los archivos necesarios del complemento.
Existen dos recursos de plantillas de complementos que pueden ayudarle a empezar:
• Para fines educativos o siempre que se desee un enfoque minimalista, la plantilla minimal plugin template
proporciona los archivos básicos (esqueleto) necesarios para crear un complemento válido de QGIS Python.
• Para una plantilla de complemento más completa, el Plugin Builder puede crear plantillas para múltiples tipos
de complementos diferentes, incluyendo características como localización (traducción) y pruebas.
Un directorio de complementos típico incluye los siguientes archivos:
• [Link] - requerido - Contiene información general, versión, nombre y algunos otros metadatos
utilizados por el sitio web de complementos y la infraestructura de complementos.
• __init__.py - requerido - El punto de inicio del complemento. Tiene que tener el método
classFactory() y puede tener cualquier otro código de inicialización.
• [Link] - código núcleo - El código principal de trabajo del complemento. Contiene toda la
información sobre las acciones del complemento y el código principal.
• [Link] - para complementos con IGU personalizada - La IGU creada por Qt Designer.
• [Link] - GUI compilado - La traducción del [Link] descrito anteriormente a Python.
• [Link] - opcional - Un documento .xml creado por Qt Designer. Contiene rutas relativas a los
recursos utilizados en los formularios GUI.
• [Link] - recursos compilados, opcional - La traducción del archivo .qrc descrito anteriormente a
Python.
• LICENSE - required if plugin is to be published or updated in the QGIS Plugins Directory, otherwise optional.
File should be a plain text file with no file extension in the filename.

Advertencia: Si planea subir el complemento al Repositorio oficial de complementos de Python debe comprobar
que su complemento sigue algunas reglas adicionales, requeridas para el complemento Validación.

16.1.2 Escribir el código del complemento

La siguiente sección muestra qué contenido debe añadirse en cada uno de los archivos introducidos anteriormente.

[Link]

En primer lugar, el Gestor de Complementos necesita recuperar cierta información básica sobre el complemento,
como su nombre, descripción, etc. Esta información se almacena en [Link].

Nota: Todos los metadatos deben estar en codificación UTF-8.

108 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

Nombre Necesario
Notas
de
metadatos
Nombre Verdadero
una cadena corta que contiene el nombre del complemento
qgisMinimumVersion
Verdadero
notación con puntos de la versión mínima de QGIS
qgisMaximumVersion
Falso notación con puntos de la versión máxima de QGIS
description Verdaderotexto breve que describe el complemento, no se permite HTML
about Verdadero
texto más largo que describe el complemento en detalles, no se permite HTML
version Verdadero
cadena corta con la notación punteada de la versión
author Verdadero
nombre del autor
email Verdadero
correo electrónico del autor, que solo se muestra en el sitio web para los usuarios que han
iniciado sesión, pero que es visible en el Administrador de complementos después de instalar
el complemento
changelog Falso cadena, puede ser de varias líneas, no se permite HTML
experimental Falso bandera booleana, True o False - True si esta versión es experimental
deprecated Falso bandera booleana, True o False, se aplica a todo el complemento y no solo a la versión
cargada
etiquetas Falso lista separada por comas, los espacios son permitidos dentro de etiquetas individuales
homepage Falso una URL válida que apunta a la página de inicio de su complemento
repository Verdadero
una URL válida al repositorio de código fuente
tracker Falso Una URL válida a los tickets y reportes de errores
icon Falso un nombre de archivo o una ruta relativa (relativa a la carpeta base del paquete comprimido
del complemento) de una imagen compatible con la web (PNG, JPEG)
category Falso una de las siguientes opciones: Raster, Vector, Base de datos, Malla y Web.
plugin_dependencies
Falso Lista separada por comas de otros complementos a instalar, utiliza los nombres de los
complementos procedentes del campo de nombre de sus metadatos
server Falso bandera booleana, True o False, determina si el complemento tiene una interfaz de
servidor
hasProcessingProvider
Falso bandera booleana, True o False, determina si el complemento proporciona algoritmos
de procesamiento

De forma predeterminada, los complementos se colocan en el menú Complementos (veremos en la siguiente sección
cómo añadir una entrada de menú para tu complemento) pero también pueden colocarse en los menús Raster, Vector,
Base de datos, Malla y Web.
Existe una entrada de metadatos de «categoría» correspondiente para especificar eso, por lo que el complemento se
puede clasificar en consecuencia. Esta entrada de metadatos se utiliza como sugerencia para los usuarios y les dice
dónde (en qué menú) se puede encontrar el complemento. Los valores permitidos para «categoría» son: Vectorial,
Ráster, Base de datos o Web. Por ejemplo, si su complemento estará disponible en el menú Ráster, agréguelo a
[Link]
category=Raster

Nota: Si qgisMaximumVersion está vacío, se establecerá automáticamente en la versión principal más .99 cuando se
cargue en el Repositorio oficial de complementos de Python.

Un ejemplo para este [Link]


; the next section is mandatory

[general]
name=HelloWorld
email=me@[Link]
author=Just Me
qgisMinimumVersion=3.0
description=This is an example plugin for greeting the world.
(continúe en la próxima página)

16.1. Estructurar Complementos de Python 109


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


Multiline is allowed:
lines starting with spaces belong to the same
field, in this case to the "description" field.
HTML formatting is not allowed.
about=This paragraph can contain a detailed description
of the plugin. Multiline is allowed, HTML is not.
version=version 1.2
tracker=[Link]
repository=[Link]
; end of mandatory metadata

; start of optional metadata


category=Raster
changelog=The changelog lists the plugin versions
and their changes as in the example below:
1.0 - First stable release
0.9 - All features implemented
0.8 - First testing release

; Tags are in comma separated value format, spaces are allowed within the
; tag name.
; Tags should be in English language. Please also check for existing tags and
; synonyms before creating a new one.
tags=wkt,raster,hello world

; these metadata can be empty, they will eventually become mandatory.


homepage=[Link]
icon=[Link]

; experimental flag (applies to the single version)


experimental=True

; deprecated flag (applies to the whole plugin and not only to the uploaded␣
,→version)

deprecated=False

; if empty, it will be automatically set to major version + .99


qgisMaximumVersion=3.99

; Since QGIS 3.8, a comma separated list of plugins to be installed


; (or upgraded) can be specified.
; The example below will try to install (or upgrade) "MyOtherPlugin" version 1.12
; and any version of "YetAnotherPlugin".
; Both "MyOtherPlugin" and "YetAnotherPlugin" names come from their own metadata's
; name field
plugin_dependencies=MyOtherPlugin==1.12,YetAnotherPlugin

__init__.py

Este archivo es requerido por el sistema de importación de Python. Además, QGIS requiere que este archivo contenga
una función classFactory(), que se llama cuando el complemento se carga en QGIS. Recibe una referencia a
la instancia de: class: QgisInterface <[Link]> y debe devolver un objeto de la clase de su complemento
desde [Link] — en nuestro caso se llama TestPlugin (ver más abajo). Así es como debería verse
__init __. Py
def classFactory(iface):
from .mainPlugin import TestPlugin
return TestPlugin(iface)

# any other initialisation needed

110 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

[Link]

Aquí es donde ocurre la magia y así es como se ve la magia: (por ejemplo [Link])

from [Link] import *


from [Link] import *

# initialize Qt resources from file [Link]


from . import resources

class TestPlugin:

def __init__(self, iface):


# save reference to the QGIS interface
[Link] = iface

def initGui(self):
# create action that will start plugin configuration
[Link] = QAction(QIcon("testplug:[Link]"),
"Test plugin",
[Link]())
[Link]("testAction")
[Link]("Configuration for test plugin")
[Link]("This is status tip")
[Link]([Link])

# add toolbar button and menu item


[Link]([Link])
[Link]("&Test plugins", [Link])

# connect to signal renderComplete which is emitted when canvas


# rendering is done
[Link]().[Link]([Link])

def unload(self):
# remove the plugin menu item and icon
[Link]("&Test plugins", [Link])
[Link]([Link])

# disconnect form signal of the canvas


[Link]().[Link]([Link])

def run(self):
# create and show a configuration dialog or something similar
print("TestPlugin: run called!")

def renderTest(self, painter):


# use painter for drawing to map canvas
print("TestPlugin: renderTest called!")

Las únicas funciones de complemento que deben existir en el archivo fuente del complemento principal (por ejemplo
[Link]) son:
• __init__ que da acceso a la interfaz QGIS
• initGui() llamado cuando se carga el complemento
• unload() llamado cuando se descarga el complemento
En el ejemplo anterior, se usó addPluginToMenu(). Esto agregará la acción de menú correspondiente al menú
Complementos. Existen métodos alternativos para agregar la acción a un menú diferente. Aquí hay una lista de esos
métodos:
• addPluginToRasterMenu()

16.1. Estructurar Complementos de Python 111


PyQGIS 3.40 developer cookbook

• addPluginToVectorMenu()
• addPluginToDatabaseMenu()
• addPluginToWebMenu()
Todos tienen la misma sintaxis que el método addPluginToMenu().
Se recomienda agregar su menú de complementos a uno de esos métodos predefinidos para mantener la coherencia
en la forma en que se organizan las entradas de los complementos. Sin embargo, puede agregar su grupo de menú
personalizado directamente a la barra de menú, como lo demuestra el siguiente ejemplo:

def initGui(self):
[Link] = QMenu([Link]())
[Link]("testMenu")
[Link]("MyMenu")

[Link] = QAction(QIcon("testplug:[Link]"),
"Test plugin",
[Link]())
[Link]("testAction")
[Link]("Configuration for test plugin")
[Link]("This is status tip")
[Link]([Link])
[Link]([Link])

menuBar = [Link]().menuBar()
[Link]([Link]().menuAction(),
[Link])

def unload(self):
[Link]()

No olvide establecer QAction y QMenu objectName con un nombre específico para su complemento para que
pueda personalizarse.
Aunque las acciones de ayuda y acerca de también se pueden añadir a su menú personalizado, un lugar conveniente
para hacerlas disponibles es en el menú principal de QGIS Ayuda ► Complementos. Esto se hace usando el método
pluginHelpMenu().

def initGui(self):

self.help_action = QAction(
QIcon("testplug:[Link]"),
[Link]("Test Plugin..."),
[Link]()
)
# Add the action to the Help menu
[Link]().addAction(self.help_action)

self.help_action.[Link](self.show_help)

@staticmethod
def show_help():
""" Open the online help. """
[Link](QUrl('[Link]

def unload(self):

[Link]().removeAction(self.help_action)
del self.help_action

Cuando trabaje en un complemento real, es aconsejable escribir el complemento en otro directorio (de trabajo) y crear
un archivo MAKE que generará UI + archivos de recursos e instalará el complemento en su instalación de QGIS.

112 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

16.1.3 Documentación de complementos

La documentación del complemento se puede escribir como archivos de ayuda HTML. El módulo [Link]
proporciona una función, showPluginHelp() que abrirá el navegador de archivos de ayuda, de la misma manera
que otras ayudas de QGIS.
La función showPluginHelp() busca archivos de ayuda en el mismo directorio que el módulo de llamada.
Buscará, a su vez, index-ll_cc.html, [Link], [Link], index-en_us.html `y
:file:`[Link], mostrando el que encuentre primero. Aquí ll_cc es la configuración regional de QGIS.
Esto permite que se incluyan múltiples traducciones de la documentación con el complemento.
La función showPluginHelp() también puede tomar parámetros packageName, que identifica un complemento
específico para el que se mostrará la ayuda, nombre de archivo, que puede reemplazar» índice «en los nombres de
los archivos que se buscan, y sección, que es el nombre de una etiqueta de anclaje html en el documento en el que se
colocará el navegador.

16.1.4 Traducción de complementos

Con unos pocos pasos, puede configurar el entorno para la localización del complemento de modo que, según la
configuración regional de su computadora, el complemento se cargue en diferentes idiomas.

Requisitos de Software

The easiest way to create and manage all the translation files is to install Qt Linguist. In a Debian-based GNU/Linux
environment you can install it typing:

sudo apt install qttools5-dev-tools

Archivos y directorio

Cuando cree el complemento, encontrará la carpeta i18n dentro del directorio principal del complemento.
Todos los archivos de traducción deben estar dentro de este directorio.

archivo .pro

Primero debe crear un archivo .pro, que es un archivo proyecto que puede ser administrado por Qt Linguist.
En este archivo .pro debe especificar todos los archivos y formularios que desea traducir. Este archivo se utiliza para
configurar los archivos de localización y las variables. Un posible archivo de proyecto, que coincide con la estructura
de nuestro complemento de ejemplo:

FORMS = ../[Link]
SOURCES = ../your_plugin.py
TRANSLATIONS = your_plugin_it.ts

Su complemento puede seguir una estructura más compleja y puede estar distribuido en varios archivos. Si este es el
caso, tenga en cuenta que pylupdate5, el programa que usamos para leer el archivo .pro y actualizar la cadena
traducible, no expande los caracteres comodín, por lo que debe colocar cada archivo explícitamente en el archivo
.pro. Su archivo de proyecto podría verse así:

FORMS = ../ui/[Link] ../ui/[Link] \


../ui/main_dialog.ui
SOURCES = ../your_plugin.py ../[Link] \
../[Link]

16.1. Estructurar Complementos de Python 113


PyQGIS 3.40 developer cookbook

Además, el archivo your_plugin.py es el archivo que llama a todos los menús y submenús de su complemento
en la barra de herramientas de QGIS y desea traducirlos todos.
Finalmente, con la variable TRANSLATIONS puede especificar los idiomas de traducción que desee.

Advertencia: Asegúrese de nombrar el archivo ts como your_plugin_ + language + .ts, de lo


contrario, la carga del idioma fallará. Utilice el atajo de 2 letras para el idioma (it para italiano, de a alemán,
etc.)

archivo .ts

Una vez que haya creado el .pro, estará listo para generar los archivos .ts para el(los) idioma(s) de su complemento.
Abra una terminal, vaya al directorio your_plugin/i18n y escriba:

pylupdate5 your_plugin.pro

debería ver el archivo(s) your_plugin_language.ts.


Abra el archivo .ts con Qt Linguist y comience a traducir.

archivo .qm

Cuando termine de traducir su complemento (si algunas cadenas no se completan, se utilizará el idioma de origen
para esas cadenas), debe crear el archivo .qm (el archivo .ts compilado que se utilizará por QGIS).
Simplemente abra un cd de terminal en el directorio your_plugin/i18n y escriba:

lrelease your_plugin.ts

ahora, en el directorio i18n verá el archivo(s) your_plugin.qm.

Traducir usando Makefile

Alternativamente, puede usar el archivo MAKE para extraer mensajes del código Python y los cuadros de diálogo
Qt, si creó su complemento con Plugin Builder. Al comienzo del Makefile hay una variable LOCALES:

LOCALES = en

Agregue la abreviatura del idioma a esta variable, por ejemplo, para el idioma húngaro:

LOCALES = en hu

Ahora puede generar o actualizar el archivo [Link] (y el [Link] también) desde las fuentes mediante:

make transup

Después de esto, ha actualizado el archivo .ts para todos los idiomas configurados en la variable LOCALES. Utilice
Qt Linguist para traducir los mensajes del programa. Al finalizar la traducción, el transcompile puede crear los
archivos .qm:

make transcompile

Tienes que distribuir archivos .ts” con tu complemento.

114 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

Carga el complemento

Para ver la traducción de su complemento, abra QGIS, cambie el idioma (Configuración -> Opciones -> General) y
reinicie QGIS.
Debería ver su complemento en el idioma correcto.

Advertencia: Si cambia algo en su complemento (nuevas IU, nuevo menú, etc.), debe generar nuevamente la
versión de actualización de los archivos .ts y .qm, así que vuelva a ejecutar el comando de arriba.

16.1.5 Compartir su complemento

QGIS aloja cientos de complementos en el repositorio de complementos. ¡Considere compartir el suyo! Ampliará las
posibilidades de QGIS y la gente podrá aprender de su código. Todos los complementos alojados se pueden encontrar
e instalar desde QGIS con el Administrador de complementos.
La información y los requisitos están aquí: [Link].

16.1.6 Consejos y Trucos

Recargador de Complemento

Durante el desarrollo de su complemento, con frecuencia deberá volver a cargarlo en QGIS para realizar pruebas.
Esto es muy fácil con el complemento Recargador de complementos. Puedes encontrarlo con el Administrador de
Complementos.

Automatice el empaquetado, la publicación y la traducción con qgis-plugin-ci

qgis-plugin-ci provides a command line interface to perform automated packaging and deployment for QGIS plugins
on your computer, or using continuous integration like GitHub workflows or Gitlab-CI as well as Transifex for
translation.
Permite liberar, traducir, publicar o generar un archivo XML de repositorio de complementos a través de CLI o en
acciones CI.

Acceder a complementos

Puede acceder a todas las clases de complementos instalados desde QGIS utilizando Python, que puede ser útil para
fines de depuración.

my_plugin = [Link]['My Plugin']

Registro de Mensajes

Los complementos tienen su propia pestaña dentro de log_message_panel.

16.1. Estructurar Complementos de Python 115


PyQGIS 3.40 developer cookbook

Archivo de Recursos

Algunos complementos utilizan archivos de recursos, por ejemplo [Link] que definen recursos para la
interfaz gráfica de usuario, como iconos:

<RCC>
<qresource prefix="/plugins/testplug" >
<file>[Link]</file>
</qresource>
</RCC>

Es bueno usar un prefijo que no colisione con otros complementos o partes de QGIS, de lo contrario, podría obtener
recursos que no deseaba. Ahora solo necesita generar un archivo Python que contendrá los recursos. Se hace con el
comando pyrcc5:

pyrcc5 -o [Link] [Link]

Nota: En entornos Windows, intentar ejecutar pyrcc5 desde el símbolo del sistema o Powershell probablemente
resultará en el error» Windows no puede acceder al dispositivo, ruta o archivo especificado […] «. La solución más
fácil es probablemente utilizar OSGeo4W Shell, pero si se siente cómodo modificando la variable de entorno PATH
o especificando la ruta al ejecutable de forma explícita, debería poder encontrarla en <Your QGIS Install
Directory>\bin\[Link].

16.2 Fragmentos de código

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsProject,
3 QgsApplication,
4 QgsMapLayer,
5 )
6

7 from [Link] import (


8 QgsGui,
9 QgsOptionsWidgetFactory,
10 QgsOptionsPageWidget,
11 QgsLayerTreeEmbeddedWidgetProvider,
12 QgsLayerTreeEmbeddedWidgetRegistry,
13 )
14

15 from [Link] import Qt


16 from [Link] import (
17 QMessageBox,
18 QAction,
19 QHBoxLayout,
20 QComboBox,
21 )
22 from [Link] import QIcon

Esta sección cuenta con fragmentos de código para facilitar el desarrollo de complementos.

116 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

16.2.1 Cómo llamar a un método por un atajo de teclado

En el complemento añadir a la initGui()

self.key_action = QAction("Test Plugin", [Link]())


[Link](self.key_action, "Ctrl+I") # action triggered␣
,→by Ctrl+I

[Link]("&Test plugins", self.key_action)


self.key_action.[Link](self.key_action_triggered)

Para añadir unload()

[Link](self.key_action)

El método que se llama cuando se presiona CTRL+I

def key_action_triggered(self):
[Link]([Link](),"Ok", "You pressed Ctrl+I")

También es posible permitir a los usuarios personalizar los atajos de teclado para las acciones proporcionadas. Esto
se hace añadiendo:

1 # in the initGui() function


2 [Link]().registerAction(self.key_action)
3

4 # and in the unload() function


5 [Link]().unregisterAction(self.key_action)

16.2.2 Cómo reutilizar los iconos de QGIS

Debido a que son bien conocidos y transmiten un mensaje claro a los usuarios, es posible que a veces desee reutilizar
los iconos de QGIS en su plugin en lugar de dibujar y establecer uno nuevo. Utilice el método getThemeIcon().

Por ejemplo, para reutilizar el icono [Link] disponible en el repositorio de código de QGIS:

1 # e.g. somewhere in the initGui


2 self.file_open_action = QAction(
3 [Link]("/[Link]"),
4 [Link]("Select a File..."),
5 [Link]()
6 )
7 [Link]("MyPlugin", self.file_open_action)

iconPath() es otro método para llamar a los iconos de QGIS. Encuentre ejemplos de llamadas a iconos temáticos
en Imágenes incrustadas de QGIS - Cheatsheet.

16.2.3 Interfaz para complemento en el cuadro de diálogo de opciones

Puede agregar una pestaña de opciones de complementos personalizados a Configuración -> Opciones. Esto es
preferible a agregar una entrada de menú principal específica para las opciones de su complemento, ya que mantiene
todas las configuraciones de la aplicación QGIS y las configuraciones del complemento en un solo lugar que es fácil
de descubrir y navegar por los usuarios.
El siguiente fragmento solo agregará una nueva pestaña en blanco para la configuración del complemento, lista para
que la complete con todas las opciones y configuraciones específicas de su complemento. Puede dividir las siguientes
clases en diferentes archivos. En este ejemplo, estamos agregando dos clases al archivo principal [Link].

16.2. Fragmentos de código 117


PyQGIS 3.40 developer cookbook

1 class MyPluginOptionsFactory(QgsOptionsWidgetFactory):
2

3 def __init__(self):
4 super().__init__()
5

6 def icon(self):
7 return QIcon('icons/my_plugin_icon.svg')
8

9 def createWidget(self, parent):


10 return ConfigOptionsPage(parent)
11

12

13 class ConfigOptionsPage(QgsOptionsPageWidget):
14

15 def __init__(self, parent):


16 super().__init__(parent)
17 layout = QHBoxLayout()
18 [Link](0, 0, 0, 0)
19 [Link](layout)

Finalmente estamos agregando las importaciones y modificando la función __init__:

1 from [Link] import QHBoxLayout


2 from [Link] import QgsOptionsWidgetFactory, QgsOptionsPageWidget
3

5 class MyPlugin:
6 """QGIS Plugin Implementation."""
7

8 def __init__(self, iface):


9 """Constructor.
10

11 :param iface: An interface instance that will be passed to this class


12 which provides the hook by which you can manipulate the QGIS
13 application at run time.
14 :type iface: QgsInterface
15 """
16 # Save reference to the QGIS interface
17 [Link] = iface
18

19

20 def initGui(self):
21 self.options_factory = MyPluginOptionsFactory()
22 self.options_factory.setTitle([Link]('My Plugin'))
23 [Link](self.options_factory)
24

25 def unload(self):
26 [Link](self.options_factory)

Truco: Añadir pestañas personalizadas al diálogo de propiedades de capa


Puede aplicar una lógica similar para agregar la opción personalizada del complemento al cuadro de
diálogo de propiedades de la capa usando las clases QgsMapLayerConfigWidgetFactory y
QgsMapLayerConfigWidget.

118 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

16.2.4 Incrustar widgets personalizados para capas en el árbol de capas

Además de los elementos habituales de simbología de capas que se muestran al lado o debajo de la entrada de la
capa en el panel Capas, puede añadir sus propios widgets, permitiendo un acceso rápido a algunas acciones que se
utilizan a menudo con una capa (configuración de filtrado, selección, estilo, actualización de una capa con un widget
de botón, creación de un deslizador de tiempo basado en la capa o simplemente mostrar información adicional de la
capa en una etiqueta, o …). Estos llamados Widgets incrustados en el árbol de capas están disponibles a través de
la pestaña Legend de las propiedades de cada capa.
El siguiente fragmento de código crea un desplegable en la leyenda que muestra los estilos de capa disponibles para
la capa, permitiendo cambiar rápidamente entre los diferentes estilos de capa.

1 class LayerStyleComboBox(QComboBox):
2 def __init__(self, layer):
3 QComboBox.__init__(self)
4 [Link] = layer
5 for style_name in [Link]().styles():
6 [Link](style_name)
7

8 idx = [Link]([Link]().currentStyle())
9 if idx != -1:
10 [Link](idx)
11

12 [Link](self.on_current_changed)
13

14 def on_current_changed(self, index):


15 [Link]().setCurrentStyle([Link](index))
16

17 class LayerStyleWidgetProvider(QgsLayerTreeEmbeddedWidgetProvider):
18 def __init__(self):
19 QgsLayerTreeEmbeddedWidgetProvider.__init__(self)
20

21 def id(self):
22 return "style"
23

24 def name(self):
25 return "Layer style chooser"
26

27 def createWidget(self, layer, widgetIndex):


28 return LayerStyleComboBox(layer)
29

30 def supportsLayer(self, layer):


31 return True # any layer is fine
32

33 provider = LayerStyleWidgetProvider()
34 [Link]().addProvider(provider)

A continuación, desde la pestaña de propiedades Leyenda de una capa determinada, arrastre el Selector de
estilo de capa de Widgets disponibles a Widgets utilizados para habilitar el widget en el árbol de capas. Los
widgets incrustados SIEMPRE se muestran en la parte superior de sus subelementos de nodo de capa asociados.
Si quiere utilizar los widgets desde, por ejemplo, un complemento, puede añadirlos así:

1 layer = [Link]()
2 counter = int([Link]("embeddedWidgets/count", 0))
3 [Link]("embeddedWidgets/count", counter+1)
4 [Link]("embeddedWidgets/{}/id".format(counter), "style")
5 view = [Link]()
6 [Link]().refreshLayerLegend([Link]())
7 [Link]().setExpanded(True)

16.2. Fragmentos de código 119


PyQGIS 3.40 developer cookbook

16.3 Configuración IDE para escribir y depurar complementos

Aunque cada programador tiene su editor de texto/IDE preferido, aquí hay algunas recomendaciones para configurar
IDE populares para escribir y depurar complementos de QGIS Python.

16.3.1 Complementos útiles para escribir complementos de Python

Algunos complementos son convenientes al escribir complementos de Python. Desde Complementos ► Administrar
e instalar complementos…, instala:
• Plugin reloader: Esto le permitirá recargar un complemento y realizar nuevos cambios sin reiniciar QGIS.
• First Aid: Esto agregará una consola de Python y un depurador local para inspeccionar las variables cuando se
genere una excepción desde un complemento.

Advertencia: A pesar de nuestros constantes esfuerzos, es posible que la información más allá de esta línea no
esté actualizada para QGIS 3.

16.3.2 Una nota sobre la configuración de su IDE en Linux y Windows

On Linux, Todo lo que normalmente se debe hacer es agregar las ubicaciones de la biblioteca QGIS a la variable de
entorno PYTHONPATH del usuario. En la mayoría de las distribuciones, esto se puede hacer editando ~/.bashrc
or ~/.bash-profile con la siguiente línea (probado en OpenSUSE Tumbleweed):
export PYTHONPATH="$PYTHONPATH:/usr/share/qgis/python/plugins:/usr/share/qgis/
,→python"

Guarde el archivo e implemente la configuración del entorno mediante el siguiente comando de shell:
source ~/.bashrc

On Windows, debe asegurarse de tener la misma configuración de entorno y utilizar las mismas bibliotecas e
intérprete que QGIS. La forma más rápida de hacerlo es modificar el archivo por lotes de inicio de QGIS.
Si utilizó el instalador de OSGeo4W, puede encontrarlo en la carpeta bin de su instalación de OSGeo4W. Busca
algo como C:\OSGeo4W\bin\[Link].

16.3.3 Depuración con Pyscripter IDE (Windows)

Para usar Pyscripter IDE, esto es lo que tienes que hacer:


1. Haz una copia de [Link] y renómbrela [Link].
2. Ábrelo en un editor. Y elimine la última línea, la que inicia QGIS.
3. Agregue una línea que apunte a su ejecutable de Pyscripter y agregue el argumento de línea de comando que
establece la versión de Python que se utilizará
4. También agregue el argumento que apunta a la carpeta donde Pyscripter puede encontrar la dll de Python
utilizada por QGIS, puede encontrar esto en la carpeta bin de su instalación de OSGeoW
@echo off
SET OSGEO4W_ROOT=C:\OSGeo4W
call "%OSGEO4W_ROOT%"\bin\o4w_env.bat
call "%OSGEO4W_ROOT%"\bin\[Link]
@echo off
path %PATH%;%GISBASE%\bin
Start C:\pyscripter\[Link] --python25 --pythondllpath=C:\OSGeo4W\bin

120 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

5. Ahora, cuando haga doble clic en este archivo por lotes, se iniciará Pyscripter, con la ruta correcta.
Más popular que Pyscripter, Eclipse es una opción común entre los desarrolladores. En la siguiente sección,
explicaremos cómo configurarlo para desarrollar y probar complementos.

16.3.4 Depurar con Eclipse y PyDev

Instalación

Para utilizar Eclipse, asegúrese de haber instalado lo siguiente


• Eclipse
• Aptana Studio 3 Plugin or PyDev
• QGIS 3.x
• Es posible que también desee instalar ** Remote Debug **, un complemento de QGIS. Por el momento,
todavía es experimental, habilite Complementos experimentales en Complementos ► Administrar e instalar
complementos… ► Opciones de antemano.
Para preparar su entorno para usar Eclipse en Windows, también debe crear un archivo por lotes y usarlo para iniciar
Eclipse:
1. Localice la carpeta donde qgis_core.dll reside. Normalmente este es C:\OSGeo4W\apps\qgis\
bin, pero si compiló su propia aplicación QGIS, esto está en su carpeta de compilación en output/bin/
RelWithDebInfo
2. Localice su ejecutable [Link].
3. Cree el siguiente script y utilícelo para iniciar eclipse al desarrollar complementos de QGIS.

call "C:\OSGeo4W\bin\o4w_env.bat"
set PATH=%PATH%;C:\path\to\your\qgis_core.dll\parent\folder
start /B C:\path\to\your\[Link]

Configurando Eclipse

1. En Eclipse, cree un nuevo proyecto. Puede seleccionar * Proyecto general * y vincular sus fuentes reales más
adelante, por lo que realmente no importa dónde coloque este proyecto.

16.3. Configuración IDE para escribir y depurar complementos 121


PyQGIS 3.40 developer cookbook

Figura 16.1: Proyecto Eclipse

2. Haz clic derecho en tu nuevo proyecto y elige Nueva ► Carpeta.


3. Click en Acanzado y elige Enlace a ubicación alternativa (carpeta vinculada). En caso de que ya tenga fuentes
que desee depurar, elija estas. En caso de que no lo haga, cree una carpeta como ya se explicó.
Ahora en la vista Explorador de proyecto, su árbol de fuentes aparece y puede comenzar a trabajar con el código. Ya
tiene resaltado de sintaxis y todas las otras potentes herramientas IDE disponibles.

122 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

Configurar el depurador

Para que el depurador funcione:


1. Cambiar a la perspectiva de depuración en Eclipse (Ventana ► Abrir Perspectiva ► Otra ► Depurar).
2. inicie el servidor de depuración PyDev eligiendo PyDev ► Iniciar servidor de depuración.
3. Eclipse ahora está esperando una conexión de QGIS a su servidor de depuración y cuando QGIS se conecte al
servidor de depuración, le permitirá controlar los scripts de Python. Eso es exactamente para lo que instalamos
el complemento Depuración remota. Así que inicie QGIS en caso de que aún no lo haya hecho y haga clic en
el símbolo de error.
Ahora puede establecer un punto de interrupción y tan pronto como el código lo golpee, la ejecución se detendrá
y podrá inspeccionar el estado actual de su complemento. (El punto de interrupción es el punto verde en la imagen
de abajo, establezca uno haciendo doble clic en el espacio en blanco a la izquierda de la línea donde desea que se
establezca el punto de interrupción).

Figura 16.2: Breakpoint

Una cosa muy interesante que puede utilizar ahora es la consola de depuración. Asegúrese de que la ejecución esté
detenida en un punto de interrupción antes de continuar.
1. Abra la vista de la consola (Ventana ► Mostrar vista). Mostrará la consola Debug Server que no es muy
interesante. Pero hay un botón Abrir consola que le permite cambiar a una consola PyDev Debug más
interesante.
2. Haga clic en la flecha junto al: guilabel: botón «Abrir consola» y seleccione * Consola PyDev *. Se abre una
ventana para preguntarle qué consola desea iniciar.
3. Elija * PyDev Debug Console *. En caso de que esté atenuado y le indique que inicie el depurador y seleccione
el marco válido, asegúrese de que tiene el depurador remoto adjunto y se encuentra actualmente en un punto
de interrupción.

Figura 16.3: Consola de depuración de PyDev

Ahora tiene una consola interactiva que le permite probar cualquier comando desde el contexto actual. Puedes
manipular variables o hacer llamadas a API o lo que quieras.

16.3. Configuración IDE para escribir y depurar complementos 123


PyQGIS 3.40 developer cookbook

Truco: Un poco molesto es que cada vez que ingresa un comando, la consola vuelve al servidor de depuración. Para
detener este comportamiento, puede hacer clic en el botón * Fijar consola * cuando esté en la página del servidor de
depuración y debe recordar esta decisión al menos para la sesión de depuración actual.

Haciendo que eclipse entienda la API

Una característica muy útil es que Eclipse conozca realmente la API de QGIS. Esto le permite verificar su código en
busca de errores tipográficos. Pero no solo esto, también permite que Eclipse lo ayude con el autocompletado desde
las importaciones hasta las llamadas a la API.
Para hacer esto, Eclipse analiza los archivos de la biblioteca de QGIS y obtiene toda la información. Lo único que
tienes que hacer es decirle a Eclipse dónde encontrar las bibliotecas.
1. Click Ventana ► Preferencias ► PyDev ► Intérprete ► Python.
Verá su intérprete de Python configurado en la parte superior de la ventana (en este momento python2.7 para
QGIS) y algunas pestañas en la parte inferior. Las pestañas más interesantes para nosotros son * Bibliotecas *
y * Forced Builtins *.

Figura 16.4: Consola de depuración de PyDev

2. Primero abra la pestaña Bibliotecas.


3. Agregue una nueva carpeta y elija la carpeta de Python de su instalación de QGIS. Si no sabe dónde está esta
carpeta (no es la carpeta de complementos):
1. Abrir QGIS
2. Inicia una consola de python

124 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

3. Introduce qgis
4. y presione Entrar. Le mostrará qué módulo QGIS utiliza y su ruta.
5. Quite el /qgis/__init__.pyc final de esta ruta y obtendrá la ruta que está buscando.
4. También debe agregar su carpeta de complementos aquí (está en python/complementos debajo de la
carpeta user profile).
5. Luego salte a la pestaña * Forced Builtins *, haga clic en * New … * e ingrese `` qgis “”. Esto hará que Eclipse
analice la API de QGIS. Probablemente también desee que Eclipse conozca la API de PyQt. Por lo tanto,
también agregue PyQt como incorporado forzado. Eso probablemente ya debería estar presente en la pestaña
de bibliotecas.
6. Click en Aceptar y ya estas listo.

Nota: Cada vez que cambia la API de QGIS (por ejemplo, si está compilando el maestro QGIS y el archivo SIP
cambió), debe volver a esta página y simplemente hacer clic en Aplicar. Esto permitirá que Eclipse vuelva a analizar
todas las bibliotecas.

16.3.5 Depurar con PyCharm en Ubuntu con un QGIS compilado

PyCharm es un IDE para Python desarrollado por JetBrains. Hay una versión gratuita llamada Community Edition y
una de pago llamada Professional. Puede descargar PyCharm en el sitio web: [Link]
download
Suponemos que ha compilado QGIS en Ubuntu con el directorio de compilación proporcionado ~/dev/qgis/
build/master. No es obligatorio tener un QGIS autocompilado, pero solo esto ha sido probado. Los caminos
deben adaptarse.
1. En PyCharm, en su: guilabel: Propiedades del proyecto, Intérprete del proyecto, vamos a crear un entorno virtual
Python llamado `` QGIS``.
2. Haga clic en el engranaje pequeño y luego Añadir.
3. Selecciona Virtualenv environment.
4. Seleccione una ubicación genérica para todos sus proyectos de Python, como ~/dev/qgis/venv porque
usaremos este intérprete de Python para todos nuestros complementos.
5. Elija un intérprete base de Python 3 disponible en su sistema y marque las siguientes dos opciones Inherit global
site-packages y Poner a disposición de todos los proyectos.

16.3. Configuración IDE para escribir y depurar complementos 125


PyQGIS 3.40 developer cookbook

1. Click en Aceptar, regrese al pequeño engranaje y click en Mostrar todo.


2. En la nueva ventana, seleccione su nuevo intérprete `` QGIS “” y haga clic en el último icono del menú vertical
Mostrar rutas para el intérprete seleccionado.
3. Finalmente, agregue la siguiente ruta absoluta a la lista ~/dev/qgis/build/master/output/
python.

1. Reinicie PyCharm y podrá comenzar a usar este nuevo entorno virtual de Python para todos sus complementos.
PyCharm conocerá la API de QGIS y también la API de PyQt si usa Qt proporcionado por QGIS como from
[Link] import QDir. El autocompletado debería funcionar y PyCharm puede inspeccionar su
código.
En la versión profesional de PyCharm, la depuración remota funciona bien. Para la edición Community, la depuración
remota no está disponible. Solo puede tener acceso a un depurador local, lo que significa que el código debe ejecutarse
dentro de PyCharm (como script o unittest), no en QGIS. Para el código Python que se ejecuta en QGIS, puede usar
el complemento First Aid mencionado anteriormente.

126 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

16.3.6 Depurar usando PDB

Si no usa un IDE como Eclipse o PyCharm, puede depurar usando PDB, siguiendo estos pasos.
1. Primero agregue este código en el lugar donde le gustaría depurar

# Use pdb for debugging


import pdb
# also import pyqtRemoveInputHook
from [Link] import pyqtRemoveInputHook
# These lines allow you to set a breakpoint in the app
pyqtRemoveInputHook()
pdb.set_trace()

2. Luego ejecute QGIS desde la línea de comando.


En Linux haga:

$ ./Qgis

En macOS haga:

$ /Applications/[Link]/Contents/MacOS/Qgis

3. ¡Y cuando la aplicación llegue a su punto de interrupción, puede escribir en la consola!


PENDIENTE:
Agregar información de prueba

16.4 Lanzamiento de su complemento

Una vez que su complemento esté listo y crea que el complemento podría ser útil para algunas personas, no dude
en cargarlo en Repositorio oficial de complementos de Python. En esa página también puede encontrar pautas de
empaquetado sobre cómo preparar el complemento para que funcione bien con el instalador del complemento. O en
caso de que desee configurar su propio repositorio de complementos, cree un archivo XML simple que enumere los
complementos y sus metadatos.
Preste especial atención a las siguientes sugerencias:

16.4.1 Metadatos y nombres

• evite usar un nombre demasiado similar a los complementos existentes


• Si su complemento tiene una funcionalidad similar a un complemento existente, explique las diferencias en el
campo Acerca de, para que el usuario sepa cuál usar sin la necesidad de instalarlo y probarlo.
• evitar repetir «complemento» en el nombre del propio complemento
• use el campo de descripción en los metadatos para una descripción de 1 línea, el campo Acerca de para obtener
instrucciones más detalladas
• incluir un depósito de código, un rastreador de errores y una página de inicio; esto mejorará enormemente la
posibilidad de colaboración y se puede hacer muy fácilmente con una de las infraestructuras web disponibles
(GitHub, GitLab, Bitbucket, etc.)
• elija las etiquetas con cuidado: evite las que no son informativas (por ejemplo, vector) y prefiera las que ya
utilizan otros (consulte el sitio web del complemento)
• agregue un icono adecuado, no deje el predeterminado; consulte la interfaz de QGIS para obtener una sugerencia
del estilo que se utilizará

16.4. Lanzamiento de su complemento 127


PyQGIS 3.40 developer cookbook

16.4.2 Código y ayuda

• no incluya el archivo generado (ui_*.py, resources_rc.py, archivos de ayuda generados …) y cosas inútiles (por
ejemplo, .gitignore) en el repositorio
• agregue el complemento al menú apropiado (Vector, Raster, Web, Database)
• cuando sea apropiado (complementos que realizan análisis), considere agregar el complemento como un
subplugin del marco de procesamiento: esto permitirá a los usuarios ejecutarlo en lotes, integrarlo en flujos
de trabajo más complejos y lo liberará de la carga de diseñar una interfaz
• incluya al menos documentación mínima y, si es útil para probar y comprender, datos de muestra.

16.4.3 Repositorio oficial de complementos de Python

Puede encontrar el repositorio de complementos de Python oficial en [Link]


Para utilizar el repositorio oficial, debe obtener un ID de OSGEO en el portal web OSGEO.
Una vez que haya cargado su complemento, un miembro del personal lo aprobará y se le notificará.
PENDIENTE:
Insertar un enlace al documento de gobernanza

Permisos

Estas reglas se han implementado en el repositorio oficial de complementos:


• cada usuario registrado puede agregar un nuevo complemento
• staff los usuarios pueden aprobar o rechazar todas las versiones del complemento
• los usuarios que tienen el permiso especial plugins.can_approve obtienen las versiones que cargan
automáticamente aprobadas
• los usuarios que tienen el permiso especial plugins.can_approve pueden aprobar versiones cargadas por otros
siempre que estén en la lista de plugins propietarios
• un complemento en particular puede ser eliminado y editado solo por personal usuarios y propietarios de
complementos
• si un usuario sin el permiso plugins.can_approve carga una nueva versión, la versión del complemento no se
aprueba automáticamente.

Gestión de confianza

Los miembros del personal pueden otorgar confianza a los creadores de complementos seleccionados que configuran
el permiso plugins.can_approve a través de la aplicación frontal.
La vista de detalles del complemento ofrece enlaces directos para otorgar confianza al creador del complemento o los
propietarios del complemento.

128 Capítulo 16. Desarrollando Plugins Python


PyQGIS 3.40 developer cookbook

Validación

Los metadatos del complemento se importan y validan automáticamente desde el paquete comprimido cuando se
carga el complemento.
Aquí hay algunas reglas de validación que debe conocer cuando desee cargar un complemento en el repositorio oficial:
1. el nombre de la carpeta principal que contiene su complemento debe contener solo caracteres ASCII (A-Z y
a-z), dígitos y los caracteres de subrayado (_) y menos (-), además no puede comenzar con un dígito
2. [Link] es requerido
3. todos los metadatos requeridos enumerados en tabla de metadatos deben estar presentes
4. el campo de metadatos versión debe ser único
5. debe incluirse un archivo de licencia, guardado como LICENSE sin extensión (es decir, no [Link]
por ejemplo)

Estructura de complementos

Siguiendo las reglas de validación, el paquete comprimido (.zip) de tu complemento debe tener una estructura
específica para ser validado como un complemento funcional. Como el complemento se descomprimirá dentro de la
carpeta de complementos del usuario, debe tener su propio directorio dentro del archivo .zip para no interferir con
otros complementos. Los archivos obligatorios son: [Link], __init__.py y LICENSE. Pero estaría
bien tener un README y por supuesto un icono para representar el complemento. A continuación se muestra un
ejemplo de cómo podría ser un [Link].

[Link]
pluginfolder/
|-- i18n
| |-- translation_file_de.ts
|-- img
| |-- [Link]
| |-- [Link]
|-- __init__.py
|-- LICENSE
|-- Makefile
|-- [Link]
|-- more_code.py
|-- main_code.py
|-- README
|-- ui_Qt_user_interface_file.ui

Es posible crear complementos en el lenguaje de programación Python. En comparación con los complementos
clásicos escritos en C++, estos deberían ser más fáciles de escribir, comprender, mantener y distribuir debido a la
naturaleza dinámica del lenguaje Python.
Los complementos de Python se enumeran junto con los complementos de C++ en el administrador de complementos
de QGIS. Se buscan en ~/(UserProfile)/python/plugins and these paths:
• UNIX/Mac: (qgis_prefix)/share/qgis/python/plugins
• Windows: (qgis_prefix)/python/plugins
Para definiciones de ~ y (UserProfile) vea core_and_external_plugins.

Nota: Al configurar QGIS_PLUGINPATH en una ruta de directorio existente, puede agregar esta ruta a la lista de
rutas en las que se buscan complementos.

16.4. Lanzamiento de su complemento 129


PyQGIS 3.40 developer cookbook

130 Capítulo 16. Desarrollando Plugins Python


CAPÍTULO 17

Escribir nuevos complementos de procesamiento

Dependiendo del tipo de complemento que vaya a desarrollar, podría ser una mejor opción agregar su funcionalidad
como un algoritmo de procesamiento (o un conjunto de ellos). Eso proporcionaría una mejor integración dentro de
QGIS, funcionalidad adicional (ya que se puede ejecutar en los componentes de Processing, como el modelador o la
interfaz de procesamiento por lotes), y un tiempo de desarrollo más rápido (ya que Processing tomará una gran parte
del trabajo).
Para distribuir esos algoritmos, debe crear un nuevo complemento que los agregue a Caja de Herramientas de
Procesos. El complemento debe contener un proveedor de algoritmos, que debe registrarse cuando se crea una
instancia del complemento.

17.1 Creando desde cero

Para crear un complemento desde cero que contenga un proveedor de algoritmos, puede seguir estos pasos utilizando
el Generador de complementos:
1. Instala el complemento Plugin Builder
2. Crea un nuevo complemento, usando el Plugin Builder. En el cuadro de diálogo del Plugin Builder, selecciona
«Processing provider».
3. El complemento creado contiene un proveedor con un solo algoritmo. Tanto el archivo del proveedor como
el archivo del algoritmo están completamente comentados y contienen información sobre cómo modificar el
proveedor y agregar algoritmos adicionales. Consúltelos para obtener más información.

17.2 Actuializar un complemento

Si quiere añadir su complemento existente a Procesos, necesitará añadir algo de código.


1. En su archivo [Link], necesitará añadir una variable:

hasProcessingProvider=yes

2. En el archivo Python donde tu complemento está instalado con el método initGui, necesitas adaptar algunas
líneas como esta:

131
PyQGIS 3.40 developer cookbook

1 from [Link] import QgsApplication


2 from .processing_provider.provider import Provider
3

4 class YourPluginName:
5

6 def __init__(self):
7 [Link] = None
8

9 def initProcessing(self):
10 [Link] = Provider()
11 [Link]().addProvider([Link])
12

13 def initGui(self):
14 [Link]()
15

16 def unload(self):
17 [Link]().removeProvider([Link])

3. Puedes crear una carpeta processing_provider con tres archivos en ella:


• __init__.py sin nada en él. Esto es necesario para crear un paquete Python válido.
• [Link] que creará el proveedor de procesamiento y expondrá sus algoritmos.

1 from [Link] import QgsProcessingProvider


2 from [Link] import QIcon
3

4 from .example_processing_algorithm import ExampleProcessingAlgorithm


5

7 class Provider(QgsProcessingProvider):
8

9 """ The provider of our plugin. """


10

11 def loadAlgorithms(self):
12 """ Load each algorithm into the current provider. """
13 [Link](ExampleProcessingAlgorithm())
14 # add additional algorithms here
15 # [Link](MyOtherAlgorithm())
16

17 def id(self) -> str:


18 """The ID of your plugin, used for identifying the provider.
19

20 This string should be a unique, short, character only string,


21 eg "qgis" or "gdal". This string should not be localised.
22 """
23 return 'yourplugin'
24

25 def name(self) -> str:


26 """The human friendly name of your plugin in Processing.
27

28 This string should be as short as possible (e.g. "Lastools", not


29 "Lastools version 1.0.1 64-bit") and localised.
30 """
31 return [Link]('Your plugin')
32

33 def icon(self) -> QIcon:


34 """Should return a QIcon which is used for your provider inside
35 the Processing toolbox.
36 """
37 return [Link](self)

• example_processing_algorithm.py el cuál contiene el archivo de ejemplo de algoritmo.

132 Capítulo 17. Escribir nuevos complementos de procesamiento


PyQGIS 3.40 developer cookbook

Copiar/pegar el contenido de la fuente archivo de plantilla de script y actualizalo de acuerdo a tus


necesidades.
Debería tener un árbol similar a este :

1 └── your_plugin_root_folder
2 ├── __init__.py
3 ├── LICENSE
4 ├── [Link]
5 └── processing_provider
6 ├── example_processing_algorithm.py
7 ├── __init__.py
8 └── [Link]

1. Ahora puede volver a cargar su complemento en QGIS y debería ver su script de ejemplo en la caja de
herramientas de procesamiento y el modelador.

17.2. Actuializar un complemento 133


PyQGIS 3.40 developer cookbook

134 Capítulo 17. Escribir nuevos complementos de procesamiento


CAPÍTULO 18

Utilizar complemento Capas

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

1 from [Link] import (


2 QgsPluginLayer,
3 QgsPluginLayerType,
4 QgsMapLayerRenderer,
5 QgsApplication,
6 QgsProject,
7 )
8

9 from [Link] import QImage

Si su complemento utiliza sus propios métodos para representar una capa de mapa, escribir su propio tipo de capa
basándose en QgsPluginLayer podría ser la mejor manera de implementarlo.

18.1 Subclassing QgsPluginLayer

A continuación se muestra un ejemplo de una implementación mínima de QgsPluginLayer. Se basa en el código


original del complemento de ejemplo Marca de agua.
El renderizador personalizado es la parte del implemento que define el dibujo real en el canvas.

1 class WatermarkLayerRenderer(QgsMapLayerRenderer):
2

3 def __init__(self, layerId, rendererContext):


4 super().__init__(layerId, rendererContext)
5

6 def render(self):
7 image = QImage("/usr/share/icons/hicolor/128x128/apps/[Link]")
8 painter = [Link]().painter()
9 [Link]()
10 [Link](10, 10, image)
11 [Link]()
(continúe en la próxima página)

135
PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


12 return True
13

14 class WatermarkPluginLayer(QgsPluginLayer):
15

16 LAYER_TYPE="watermark"
17

18 def __init__(self):
19 super().__init__(WatermarkPluginLayer.LAYER_TYPE, "Watermark plugin layer")
20 [Link](True)
21

22 def createMapRenderer(self, rendererContext):


23 return WatermarkLayerRenderer([Link](), rendererContext)
24

25 def setTransformContext(self, ct):


26 pass
27

28 # Methods for reading and writing specific information to the project file can
29 # also be added:
30

31 def readXml(self, node, context):


32 pass
33

34 def writeXml(self, node, doc, context):


35 pass

La capa de complemento se puede agregar al proyecto y al lienzo como cualquier otra capa de mapa:

plugin_layer = WatermarkPluginLayer()
[Link]().addMapLayer(plugin_layer)

Al cargar un proyecto que contiene dicha capa, se necesita una clase de fábrica:

1 class WatermarkPluginLayerType(QgsPluginLayerType):
2

3 def __init__(self):
4 super().__init__(WatermarkPluginLayer.LAYER_TYPE)
5

6 def createLayer(self):
7 return WatermarkPluginLayer()
8

9 # You can also add GUI code for displaying custom information
10 # in the layer properties
11 def showLayerProperties(self, layer):
12 pass
13

14

15 # Keep a reference to the instance in Python so it won't


16 # be garbage collected
17 plt = WatermarkPluginLayerType()
18

19 assert [Link]().addPluginLayerType(plt)

136 Capítulo 18. Utilizar complemento Capas


CAPÍTULO 19

Biblioteca de análisis de redes

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:

from [Link] import (


QgsVectorLayer,
QgsPointXY,
)

La biblioteca de análisis de red se puede utilizar para:


• crear un gráfico matemático a partir de datos geográficos (capas vectoriales de polilínea)
• implementar métodos básicos de la teoría de grafos (actualmente solo el algoritmo de Dijkstra)
La librería de análisis de redes fue creada por funciones básicas de exportación del complemento núcleo RoadGraph
y ahora se puede utilizar los metodos en complementos o directamente de la consola Python.

19.1 Información general

Brevemente, un caso de uso típico se puede describir como:


1. Crear gráfica de geodatos (normalmente de capa vectorial de polilíneas)
2. ejecutar análisis gráfico
3. utilizar resultados de análisis (por ejemplo, visualizarlos)

137
PyQGIS 3.40 developer cookbook

19.2 Contruir un gráfico

Lo primero que hay que hacer — es preparar la entrada de datos, que es convertir una capa vectorial en un gráfico.
Todas las acciones adicionales utilizarán esta gráfica, no la capa.
Como fuente podemos utilizar una capa vectorial de polilínea. Los nodos de las polilíneas se convierten en vértices
del gráfico, y los segmentos de la polilínea son bordes de gráfico. Si varios nodos tienen la misma coordenada entonces
ellos tienen el mimso vértice gráfico. Por lo que dos líneas que tienen un nodo en común se conectaran entre si.
Además durante la creación del gráfico se puede «arreglar» («atar») a la capa vectorial de entrada cualquier número
de puntos adicionales. Para cada punto adicional se encontrará una coincidencia — el vértice gráfico más cercano o
el borde gráfico más cercano. En el último caso el borde será dividido y un nuevo vértice se añadirá.
Los atributos de la capa vectorial y la longitud de un borde se puede utilizar como las propiedades de un borde.
La conversión de una capa vectorial al gráfico se realiza mediante el patrón de programación Constructor. Un gráfico
se construye utilizando el llamado Director. Solo hay un Director por ahora: QgsVectorLayerDirector. El
director establece la configuración básica que se utilizará para construir un gráfico a partir de una capa vectorial de
línea, utilizada por el constructor para crear el gráfico. Actualmente, como en el caso del director, solo existe un
constructor: QgsGraphBuilder, que crea objetos QgsGraph. Es posible que desee implementar sus propios
constructores que crearán un gráfico compatible con bibliotecas como BGL o NetworkX.
Para calcular las propiedades del borde, se usó el patrón de programación estrategia. Por ahora
solo estrategia QgsNetworkDistanceStrategy (que tiene en cuenta la longitud de la ruta) y
QgsNetworkSpeedStrategy (que también considera la velocidad) están disponibles. Puede implementar su
propia estrategia que utilizará todos los parámetros necesarios. Por ejemplo, el complemento RoadGraph utiliza una
estrategia que calcula el tiempo de viaje utilizando la longitud del borde y el valor de velocidad de los atributos.
Es tiempo de sumergirse en el proceso.
En primer lugar, para utilizar esta biblioteca debemos importar el módulo de análisis

from [Link] import *

Después algunos ejemplos para crear un director

1 # don't use information about road direction from layer attributes,


2 # all roads are treated as two-way
3 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣
,→[Link])

5 # use field with index 5 as source of information about road direction.


6 # one-way roads with direct direction have attribute value "yes",
7 # one-way roads with reverse direction have the value "1", and accordingly
8 # bidirectional roads have "no". By default roads are treated as two-way.
9 # This scheme can be used with OpenStreetMap data
10 director = QgsVectorLayerDirector(vectorLayer, 5, 'yes', '1', 'no',␣
,→[Link])

Para construir un director, debemos pasar una capa vectorial que se utilizará como fuente para la estructura del
gráfico y la información sobre el movimiento permitido en cada segmento de la carretera (movimiento unidireccional
o bidireccional, dirección directa o inversa). La llamada se ve así

1 director = QgsVectorLayerDirector(vectorLayer,
2 directionFieldId,
3 directDirectionValue,
4 reverseDirectionValue,
5 bothDirectionValue,
6 defaultDirection)

Y aquí esta la lista completa de lo que significan estos parámetros:


• vectorLayer — capa vectorial usada para construir la gráfica

138 Capítulo 19. Biblioteca de análisis de redes


PyQGIS 3.40 developer cookbook

• directionFieldId — índice de la tabla de atributos de campo, donde se almacena información acerca


de dirección de carreteras. Si -1, entonces no utilice esta información en absoluto. Un entero.
• directDirectionValue — el valor del campo de carreteras con dirección directa (mover desde la primer
punto de línea a la última). Un texto.
• reverseDirectionValue — valor del campo de carreteras con dirección inversa (mover del último
punto de línea al primero). Un texto.
• bothDirectionValue — valor de campo para carreteras bidireccionales (para cada carretera podemos
mover del primer punto al último y del último al primero). Un texto.
• defaultDirection — dirección de la carretera predeterminada. Este valor se usará para aquellas
carreteras donde el campo directionFieldId no está configurado o tiene algún valor diferente de
cualquiera de los tres valores especificados anteriormente. Los posibles valores son:
– [Link] — dirección de un sentido
– [Link] — Sentido único reversible
– [Link] — Bi-direccional
Es necesario entonces crear una estrategia para calcular propiedades de borde
1 # The index of the field that contains information about the edge speed
2 attributeId = 1
3 # Default speed value
4 defaultValue = 50
5 # Conversion from speed to metric units ('1' means no conversion)
6 toMetricFactor = 1
7 strategy = QgsNetworkSpeedStrategy(attributeId, defaultValue, toMetricFactor)

Y decirle al director sobre esta estrategia


director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '', 3)
[Link](strategy)

Ahora podemos usar el constructor, que creará el gráfico. La clase QgsGraphBuilder constructor toma varios
argumentos:
• crs — sistema de referencia de coordenadas a utilizar. Argumento obligatorio.
• otfEnabled — usar reproyección «al vuelo» o no. Por defecto True (usa OTF).
• topologyTolerance — tolerancia topológica. Por defecto es 0.
• ellipsoidID — elipsoide a usar. Por defecto «WGS84».
# only CRS is set, all other values are defaults
builder = QgsGraphBuilder([Link]())

También podemos definir varios puntos, que se utilizarán en el análisis. Por ejemplo
startPoint = QgsPointXY(1179720.1871, 5419067.3507)
endPoint = QgsPointXY(1180616.0205, 5419745.7839)

Ahora todo está en su lugar para que podamos construir el gráfico y «atar» a estos puntos
tiedPoints = [Link](builder, [startPoint, endPoint])

Construir el grafo puede tomar tiempo (que depende del número de elementos y tamaño de una capa). tiedPoints
es una lista con coordenadas de puntos «tied». Cuando la operación de construcción se finalizo podemos obtener la
gráfica y utilizarlo para el análisis
graph = [Link]()

Con el siguiente código podemos obtener el índice del vértice de nuestros puntos

19.2. Contruir un gráfico 139


PyQGIS 3.40 developer cookbook

startId = [Link](tiedPoints[0])
endId = [Link](tiedPoints[1])

19.3 Análisis gráfico

El análisis de redes es utilizado para encontrar respuestas a dos preguntas: que vértices estan conectados y cómo
encontrar la ruta más corta. Para resolver estos problemas la librería de análisis de redes proporciona el algoritmo
Dijkstra.
El algoritmo Dijkstra encuentra la ruta más corta de uno de los vértices del grafo a todos los otros y los valores de los
parámetros de optimización, El resultado puede ser representado como un árbol de la ruta más corta.
El árbol de ruta más corto es un gráfico ponderado dirigido (o más precisamente un árbol) con las siguientes
propiedades:
• sólo un vértice no tiene bordes entrantes — la raíz del árbol
• todos los otros vértices sólo tienen un borde entrante
• Si el vértice B es accesible desde el vértice A, entonces el camino de A a B es la única ruta disponible y es
optima (más corta) en este grafo
Para obtener la ruta del árbol más corta, use los métodos shortestTree() y dijkstra() de la clase
QgsGraphAnalyzer . Es recomendable usar el método dijkstra() porque funciona más rápido y usa la
memoria de manera más eficiente.
El método shortestTree() es útil cuando desea caminar alrededor del árbol del camino más corto. Siempre
crea un nuevo objeto gráfico (QgsGraph) y acepta tres variables:
• source — gráfica entrante
• startVertexIdx — índice del punto en el árbol (la raíz del árbol)
• criterionNum — número de propiedad de borde a usar (comenzando desde 0).

tree = [Link](graph, startId, 0)

El método dijkstra() tiene los mismos argumentos, pero devuelve dos matrices. En el primer elemento de matriz,
n contiene el índice del borde entrante o -1 si no hay bordes entrantes. En el segundo elemento de matriz, n contiene
la distancia desde la raíz del árbol al vértice` n` o DOUBLE_MAX si el vértice n es inalcanzable desde la raíz.

(tree, cost) = [Link](graph, startId, 0)

Aquí hay un código muy simple para mostrar el árbol de ruta más corto usando el gráfico creado con el método
shortestTree() (seleccione la capa de cadena de líneas en el panel Capas y reemplace las coordenadas por las
suyas).

Advertencia: Use este código solo como ejemplo, crea muchos objetos QgsRubberBand y puede ser lento en
conjuntos de datos extensos.

1 from [Link] import *


2 from [Link] import *
3 from [Link] import *
4 from [Link] import *
5 from [Link] import *
6

7 vectorLayer = QgsVectorLayer('testdata/[Link]|layername=network_lines',
,→'lines')

8 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣


(continúe en la próxima página)

140 Capítulo 19. Biblioteca de análisis de redes


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


,→[Link])
9 strategy = QgsNetworkDistanceStrategy()
10 [Link](strategy)
11 builder = QgsGraphBuilder([Link]())
12

13 pStart = QgsPointXY(1179661.925139,5419188.074362)
14 tiedPoint = [Link](builder, [pStart])
15 pStart = tiedPoint[0]
16

17 graph = [Link]()
18

19 idStart = [Link](pStart)
20

21 tree = [Link](graph, idStart, 0)


22

23 i = 0
24 while (i < [Link]()):
25 rb = QgsRubberBand([Link]())
26 [Link] ([Link])
27 [Link] ([Link]([Link](i).fromVertex()).point())
28 [Link] ([Link]([Link](i).toVertex()).point())
29 i = i + 1

Lo mismo pero usando el método dijkstra()

1 from [Link] import *


2 from [Link] import *
3 from [Link] import *
4 from [Link] import *
5 from [Link] import *
6

7 vectorLayer = QgsVectorLayer('testdata/[Link]|layername=network_lines',
,→'lines')

9 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣


,→[Link])

10 strategy = QgsNetworkDistanceStrategy()
11 [Link](strategy)
12 builder = QgsGraphBuilder([Link]())
13

14 pStart = QgsPointXY(1179661.925139,5419188.074362)
15 tiedPoint = [Link](builder, [pStart])
16 pStart = tiedPoint[0]
17

18 graph = [Link]()
19

20 idStart = [Link](pStart)
21

22 (tree, costs) = [Link](graph, idStart, 0)


23

24 for edgeId in tree:


25 if edgeId == -1:
26 continue
27 rb = QgsRubberBand([Link]())
28 [Link] ([Link])
29 [Link] ([Link]([Link](edgeId).fromVertex()).point())
30 [Link] ([Link]([Link](edgeId).toVertex()).point())

19.3. Análisis gráfico 141


PyQGIS 3.40 developer cookbook

19.3.1 Encontrar la ruta más corta

Para encontrar la ruta óptima entre dos puntos, se utiliza el siguiente enfoque. Ambos puntos (inicio A y final B)
están «vinculados» al gráfico cuando se construye. Luego, usando el método shortestTree () o dijkstra()
construimos el árbol de ruta más corto con la raiz en el punto inicial A. En el mismo árbol también encontramos el
punto final B y comenzamos a caminar a través del árbol desde el punto B al punto A. Todo el algoritmo se puede
escribir como:

1 assign T = B
2 while T != B
3 add point T to path
4 get incoming edge for point T
5 look for point TT, that is start point of this edge
6 assign T = TT
7 add point A to path

En este punto tenemos la ruta, en el formulario de la lista invertida de vértices (los vértices están listados en orden
invertida del punto final al punto inicial) que serán visitados durante el viaje por este camino.
Aquí está el código de muestra para Consola de Pyhton QGIS (es posible que deba cargar y seleccionar
una capa de cadena de líneas en TOC y reemplazar las coordenadas en el código por las suyas) que usa el
método:meth:shortestTree() <[Link]>

1 from [Link] import *


2 from [Link] import *
3 from [Link] import *
4

5 from [Link] import *


6 from [Link] import *
7

8 vectorLayer = QgsVectorLayer('testdata/[Link]|layername=network_lines',
,→'lines')

9 builder = QgsGraphBuilder([Link]())
10 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣
,→[Link])

11 strategy = QgsNetworkDistanceStrategy()
12 [Link](strategy)
13

14 startPoint = QgsPointXY(1179661.925139,5419188.074362)
15 endPoint = QgsPointXY(1180942.970617,5420040.097560)
16

17 tiedPoints = [Link](builder, [startPoint, endPoint])


18 tStart, tStop = tiedPoints
19

20 graph = [Link]()
21 idxStart = [Link](tStart)
22

23 tree = [Link](graph, idxStart, 0)


24

25 idxStart = [Link](tStart)
26 idxEnd = [Link](tStop)
27

28 if idxEnd == -1:
29 raise Exception('No route!')
30

31 # Add last point


32 route = [[Link](idxEnd).point()]
33

34 # Iterate the graph


35 while idxEnd != idxStart:
36 edgeIds = [Link](idxEnd).incomingEdges()
37 if len(edgeIds) == 0:
(continúe en la próxima página)

142 Capítulo 19. Biblioteca de análisis de redes


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


38 break
39 edge = [Link](edgeIds[0])
40 [Link](0, [Link]([Link]()).point())
41 idxEnd = [Link]()
42

43 # Display
44 rb = QgsRubberBand([Link]())
45 [Link]([Link])
46

47 # This may require coordinate transformation if project's CRS


48 # is different than layer's CRS
49 for p in route:
50 [Link](p)

Y aquí está la misma muestra pero usando el método dijkstra()

1 from [Link] import *


2 from [Link] import *
3 from [Link] import *
4

5 from [Link] import *


6 from [Link] import *
7

8 vectorLayer = QgsVectorLayer('testdata/[Link]|layername=network_lines',
,→'lines')

9 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣


,→[Link])

10 strategy = QgsNetworkDistanceStrategy()
11 [Link](strategy)
12

13 builder = QgsGraphBuilder([Link]())
14

15 startPoint = QgsPointXY(1179661.925139,5419188.074362)
16 endPoint = QgsPointXY(1180942.970617,5420040.097560)
17

18 tiedPoints = [Link](builder, [startPoint, endPoint])


19 tStart, tStop = tiedPoints
20

21 graph = [Link]()
22 idxStart = [Link](tStart)
23 idxEnd = [Link](tStop)
24

25 (tree, costs) = [Link](graph, idxStart, 0)


26

27 if tree[idxEnd] == -1:
28 raise Exception('No route!')
29

30 # Total cost
31 cost = costs[idxEnd]
32

33 # Add last point


34 route = [[Link](idxEnd).point()]
35

36 # Iterate the graph


37 while idxEnd != idxStart:
38 idxEnd = [Link](tree[idxEnd]).fromVertex()
39 [Link](0, [Link](idxEnd).point())
40

41 # Display
42 rb = QgsRubberBand([Link]())
43 [Link]([Link])
(continúe en la próxima página)

19.3. Análisis gráfico 143


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


44

45 # This may require coordinate transformation if project's CRS


46 # is different than layer's CRS
47 for p in route:
48 [Link](p)

19.3.2 Áreas de disponibilidad

El área de la disponibilidad para el vértice A es el subconjunto de vértices del grafo que son accesibles desde el vértice
A y el costo de los caminos de la A a estos vértices son no es mayor que cierto valor.
Más claramente esto se puede demostrar con el siguiente ejemplo: «Hay una estación de bomberos ¿Qué partes de
la ciudad puede un camión de bomberos alcanzar en 5 minutos? 10 minutos? 15 minutos?». Las respuestas a estas
preguntas son las zonas de la estación de bomberos de la disponibilidad.
Para encontrar las áreas de disponibilidad podemos usar el método dijkstra() de la clase
QgsGraphAnalyzer. Es suficiente comparar los elementos de la matriz de costos con un valor predefinido. Si el
costo [i] es menor o igual a un valor predefinido, entonces el vértice i está dentro del área de disponibilidad, de lo
contrario, está fuera.
Un problema más difícil es conseguir los límites de la zona de disponibilidad. El borde inferior es el conjunto de
vértices que son todavía accesibles, y el borde superior es el conjunto de vértices que no son accesibles. De hecho
esto es simple: es la frontera disponibilidad basado en los bordes del árbol de ruta más corta para los que el vértice
origen del contorno es más accesible y el vértice destino del borde no lo es.
Aquí tiene un ejemplo

1 director = QgsVectorLayerDirector(vectorLayer, -1, '', '', '',␣


,→[Link])

2 strategy = QgsNetworkDistanceStrategy()
3 [Link](strategy)
4 builder = QgsGraphBuilder([Link]())
5

7 pStart = QgsPointXY(1179661.925139, 5419188.074362)


8 delta = [Link]().getCoordinateTransform().mapUnitsPerPixel() * 1
9

10 rb = QgsRubberBand([Link]())
11 [Link]([Link])
12 [Link](QgsPointXY(pStart.x() - delta, pStart.y() - delta))
13 [Link](QgsPointXY(pStart.x() + delta, pStart.y() - delta))
14 [Link](QgsPointXY(pStart.x() + delta, pStart.y() + delta))
15 [Link](QgsPointXY(pStart.x() - delta, pStart.y() + delta))
16

17 tiedPoints = [Link](builder, [pStart])


18 graph = [Link]()
19 tStart = tiedPoints[0]
20

21 idStart = [Link](tStart)
22

23 (tree, cost) = [Link](graph, idStart, 0)


24

25 upperBound = []
26 r = 1500.0
27 i = 0
28 [Link]()
29

30 while i < len(cost):


31 if cost[i] > r and tree[i] != -1:
32 outVertexId = [Link](tree [i]).toVertex()
(continúe en la próxima página)

144 Capítulo 19. Biblioteca de análisis de redes


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


33 if cost[outVertexId] < r:
34 [Link](i)
35 i = i + 1
36

37 for i in upperBound:
38 centerPoint = [Link](i).point()
39 rb = QgsRubberBand([Link]())
40 [Link]([Link])
41 [Link](QgsPointXY(centerPoint.x() - delta, centerPoint.y() - delta))
42 [Link](QgsPointXY(centerPoint.x() + delta, centerPoint.y() - delta))
43 [Link](QgsPointXY(centerPoint.x() + delta, centerPoint.y() + delta))
44 [Link](QgsPointXY(centerPoint.x() - delta, centerPoint.y() + delta))

19.3. Análisis gráfico 145


PyQGIS 3.40 developer cookbook

146 Capítulo 19. Biblioteca de análisis de redes


CAPÍTULO 20

Servidor QGIS y Python

20.1 Introducción

Para obtener más información sobre QGIS Server, lea QGIS-Server-manual.


QGIS Server es tres cosas diferentes:
1. Biblioteca de QGIS Server: una biblioteca que proporciona una API para crear servicios web OGC
2. QGIS Server FCGI: una aplicación binaria FCGI qgis_mapserv.fcgi que junto con un servidor web
implementa un conjunto de servicios OGC (WMS, WFS, WCS etc.) y APIs OGC (WFS3/OAPIF)
3. QGIS Development Server: una aplicación binaria de servidor de desarrollo qgis_mapserver que
implementa un conjunto de servicios OGC (WMS, WFS, WCS, etc.) y API de OGC (WFS3 / OAPIF)
Este capítulo del libro de cocina se centra en el primer tema y, al explicar el uso de la API de QGIS Server, muestra
cómo es posible utilizar Python para ampliar, mejorar o personalizar el comportamiento del servidor o cómo utilizar
la API de QGIS Server para incrustar el servidor QGIS en otra aplicación.
Hay algunas formas diferentes en las que puede alterar el comportamiento de QGIS Server o ampliar sus capacidades
para ofrecer nuevos servicios personalizados o API, estos son los principales escenarios a los que puede enfrentarse:
• EMBEDDING → Utilice la API de QGIS Server desde otra aplicación de Python
• STANDALONE → Ejecutar QGIS Server como servicio autónomo WSGI/HTTP
• FILTERS → Mejorar/personalizar QGIS Server con complementos de filtro
• SERVICES → Añadir un nuevo SERVICE
• OGC APIs → Añadir una nueva OGC API
Las aplicaciones integradas e independientes requieren el uso de la API de Python de QGIS Server directamente desde
otro script o aplicación de Python. Las opciones restantes son más adecuadas para cuando desee agregar funciones
personalizadas a una aplicación binaria estándar de QGIS Server (FCGI o servidor de desarrollo): en este caso, deberá
escribir un complemento de Python para la aplicación del servidor y registrar sus filtros personalizados, servicios o
API.

147
PyQGIS 3.40 developer cookbook

20.2 Conceptos básicos de la API del servidor

Las clases fundamentales involucradas en una aplicación típica de QGIS Server son:
• QgsServer la instancia del servidor (normalmente una sola instancia durante toda la vida de la aplicación)
• QgsServerRequest el objeto de la solicitud (normalmente recreado en cada solicitud)
• [Link](request, response) procesa la solicitud y completa la respuesta
El flujo de trabajo del servidor de desarrollo o FCGI de QGIS Server se puede resumir de la siguiente manera:

1 initialize the QgsApplication


2 create the QgsServer
3 the main server loop waits forever for client requests:
4 for each incoming request:
5 create a QgsServerRequest request
6 create a QgsServerResponse response
7 call [Link](request, response)
8 filter plugins may be executed
9 send the output to the client

Dentro del métodod [Link](request, response) las devoluciones de llamada de


los complementos de filtro se llaman y QgsServerRequest y QgsServerResponse están disponibles para
los complementos a través de la clase QgsServerInterface

Advertencia: Las clases de servidor de QGIS no son seguras para subprocesos, siempre debe usar un modelo o
contenedores de multiprocesamiento cuando cree aplicaciones escalables basadas en la API de QGIS Server.

20.3 Independiente o incrustado

Para aplicaciones de servidor independientes o incrustaciones, deberá usar las clases de servidor mencionadas
anteriormente directamente, envolviéndolas en una implementación de servidor web que gestiona todas las
interacciones del protocolo HTTP con el cliente.
A continuación, se muestra un ejemplo mínimo del uso de la API de QGIS Server (sin la parte HTTP):

1 from [Link] import QgsApplication


2 from [Link] import *
3 app = QgsApplication([], False)
4

5 # Create the server instance, it may be a single one that


6 # is reused on multiple requests
7 server = QgsServer()
8

9 # Create the request by specifying the full URL and an optional body
10 # (for example for POST requests)
11 request = QgsBufferServerRequest(
12 '[Link] +
13 '&SERVICE=WMS&REQUEST=GetCapabilities')
14

15 # Create a response objects


16 response = QgsBufferServerResponse()
17

18 # Handle the request


19 [Link](request, response)
20

21 print([Link]())
22 print([Link]().data().decode('utf8'))
(continúe en la próxima página)

148 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


23

24 [Link]()

A continuación se muestra un ejemplo completo de aplicación independiente desarrollada para las pruebas de
integraciones continuas en el repositorio de código fuente de QGIS, que muestra un amplio conjunto de diferentes
filtros de complementos y esquemas de autenticación (no significa para la producción, ya que se desarrollaron sólo
para fines de prueba, pero sigue siendo interesante para el aprendizaje): qgis_wrapped_server.py

20.4 Complementos del servidor

Los complementos de Python del servidor se cargan una vez cuando se inicia la aplicación QGIS Server y se pueden
usar para registrar filtros, servicios o API.
La estructura de un complemento de servidor es muy similar a su contraparte de escritorio, un objeto
QgsServerInterface está disponible para los complementos y los complementos pueden registrar uno o más
filtros personalizados, servicios o API en el registro correspondiente mediante uno de los métodos expuestos por la
interfaz del servidor.

20.4.1 Complementos de filtro de servidor

Los filtros vienen en tres sabores diferentes y se pueden instanciar subclasificando una de las clases a continuación y
llamando al método correspondiente de QgsServerInterface:

Tipo de filtro Clase Base Registro de QgsServerInterface


I/O QgsServerFilter registerFilter()
Control de acceso QgsAccessControlFilter registerAccessControl()
Cache QgsServerCacheFilter registerServerCache()

Filtros de E/S

Los filtros de E/S pueden modificar la entrada y salida del servidor (la solicitud y la respuesta) de los servicios
centrales (WMS, WFS, etc.) permitiendo realizar cualquier tipo de manipulación del flujo de trabajo de los servicios.
Es posible, por ejemplo, restringir el acceso a las capas seleccionadas, inyectar una hoja de estilo XSL a la respuesta
XML, agregar una marca de agua a una imagen WMS generada, etc.
A partir de este punto, encontrará útil un vistazo rápido a server plugins API docs.
Cada filtro debe implementar al menos una de las tres devoluciones de llamada:
• onRequestReady()
• onResponseComplete()
• onSendResponse()
Todos los filtros tienen acceso al objeto de solicitud/respuesta (QgsRequestHandler) y puede manipular todas
sus propiedades (entrada/salida) y generar excepciones (aunque de una manera bastante particular como veremos a
continuación).
Todos estos métodos devuelven un valor booleano que indica si la llamada debe propagarse a los filtros siguientes.
Si uno de estos métodos devuelve False entonces la cadena se detiene, de lo contrario la llamada se propagará al
siguiente filtro.
Aquí está el pseudocódigo que muestra cómo el servidor maneja una solicitud típica y cuándo se llaman las
devoluciones de llamada del filtro:

20.4. Complementos del servidor 149


PyQGIS 3.40 developer cookbook

1 for each incoming request:


2 create GET/POST request handler
3 pass request to an instance of QgsServerInterface
4 call onRequestReady filters
5

6 if there is not a response:


7 if SERVICE is WMS/WFS/WCS:
8 create WMS/WFS/WCS service
9 call service’s executeRequest
10 possibly call onSendResponse for each chunk of bytes
11 sent to the client by a streaming services (WFS)
12 call onResponseComplete
13 request handler sends the response to the client

Los siguientes párrafos describen las devoluciones de llamada disponibles en detalle.

onRequestReady

Esto se llama cuando la solicitud está lista: la URL entrante y los datos se han analizado y antes de ingresar al
conmutador de servicios centrales (WMS, WFS, etc.), este es el punto donde puede manipular la entrada y realizar
acciones como:
• autenticación/autorización
• redirije
• añadir/borrar ciertos parámetros (nombres de tipos, por ejemplo)
• plantear excepciones
Incluso podría sustituir un servicio central por completo cambiando el parámetro SERVICE y, por lo tanto, omitiendo
el servicio central por completo (aunque esto no tiene mucho sentido).

onSendResponse

Esta llamada se realiza siempre que cualquier salida parcial se descarga desde el buffer de respuesta (es decir, a FCGI
stdout si se utiliza el servidor fcgi) y desde allí, al cliente. Esto ocurre cuando se transmite un contenido enorme
(como WFS GetFeature). En este caso onSendResponse() puede ser llamado varias veces.
Tenga en cuenta que si la respuesta no se transmite, entonces onSendResponse() no se llamará en absoluto.
En todos los casos, el último (o único) trozo se enviará al cliente tras una llamada a onResponseComplete().
Devolver False prevendrá la descarga de datos al cliente. Esto es deseable cuando un complemento quiere recoger
todos los trozos de una respuesta y examinar o cambiar la respuesta en onResponseComplete().

onResponseComplete

Se llama una vez cuando los servicios centrales (si se han alcanzado) terminan su proceso y la petición está lista para
ser enviada al cliente. Como se ha comentado anteriormente, este método se llamará antes de que el último (o único)
trozo de datos se envíe al cliente. Para servicios de streaming, multiples llamadas a onSendResponse() pueden
haber sido llamadas.
onResponseComplete() es el lugar ideal para proporcionar la implementación de nuevos servicios (WPS o
servicios personalizados) y para realizar la manipulación directa de la salida procedente de los servicios centrales
(por ejemplo para añadir una marca de agua sobre una imagen WMS).
Tenga en cuenta que devolver False evitará que los siguientes complementos ejecuten
onResponseComplete() pero, en cualquier caso, evitará que se envíe la respuesta al cliente.

150 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

Generación de excepciones de un complemento

Aún queda trabajo por hacer en este tema: la implementación actual puede distinguir entre excepciones manejadas y
no manejadas estableciendo una propiedad QgsRequestHandler a una instancia de QgsMapServiceException,
de esta manera el código principal de C ++ puede detectar excepciones de Python controladas e ignorar las excepciones
no controladas (o mejor: registrarlas).
Este enfoque básicamente funciona, pero no es muy «pitónico»: un mejor enfoque sería generar excepciones del
código de Python y verlas burbujear en el bucle C ++ para que se manejen allí.

Escribiendo un complemento del servidor

Un complemento de servidor es un complemento estándar de QGIS Python como se describe en Desarrollando Plugins
Python, que solo proporciona una interfaz adicional (o alternativa): un complemento de escritorio QGIS típico tiene
acceso a la aplicación QGIS a través de: class:` QgisInterface <qgis. [Link]> , un complemento de servidor
solo tiene acceso a :class:`QgsServerInterface <[Link]> cuando se ejecuta dentro del contexto
de la aplicación QGIS Server.
Para que QGIS Server sepa que un complemento tiene una interfaz de servidor, se necesita una entrada de metadatos
especial (en [Link]):

server=True

Importante: QGIS Server solo cargará y ejecutará los complementos que tengan el conjunto de metadatos
server=True.

El complemento de ejemplo qgis3-server-vagrant discutido aquí (con muchos más) está disponible en github, algunos
complementos de servidor también están publicados en el repositorio oficial de complementos QGIS.

Archivos de complementos

Aquí está la estructura de directorios de nuestro complemento de servidor de ejemplo.

1 PYTHON_PLUGINS_PATH/
2 HelloServer/
3 __init__.py --> *required*
4 [Link] --> *required*
5 [Link] --> *required*

__init__.py

Este archivo es requerido por el sistema de importación de Python. Además, QGIS Server requiere que este archivo
contenga una función serverClassFactory(), que se llama cuando el complemento se carga en QGIS Server
cuando se inicia el servidor. Recibe una referencia a la instancia de QgsServerInterface y debe devolver la
instancia de la clase de su complemento. Así es como se ve el complemento de ejemplo __init __. Py:

def serverClassFactory(serverIface):
from .HelloServer import HelloServerServer
return HelloServerServer(serverIface)

20.4. Complementos del servidor 151


PyQGIS 3.40 developer cookbook

[Link]

Aquí es donde ocurre la magia y así es como se ve la magia: (por ejemplo [Link])
Un complemento de servidor generalmente consiste en una o más devoluciones de llamada empaquetadas en instancias
de QgsServerFilter.
Cada QgsServerFilter implementa una o más de las siguientes devoluciones de llamada:
• onRequestReady()
• onResponseComplete()
• onSendResponse()
El siguiente ejemplo implementa un filtro mínimo que imprime HelloServer! En caso de que el parámetro SERVICE
sea igual a «HELLO»:

1 class HelloFilter(QgsServerFilter):
2

3 def __init__(self, serverIface):


4 super().__init__(serverIface)
5

6 def onRequestReady(self) -> bool:


7 [Link]("[Link]")
8 return True
9

10 def onSendResponse(self) -> bool:


11 [Link]("[Link]")
12 return True
13

14 def onResponseComplete(self) -> bool:


15 [Link]("[Link]")
16 request = [Link]().requestHandler()
17 params = [Link]()
18 if [Link]('SERVICE', '').upper() == 'HELLO':
19 [Link]()
20 [Link]('Content-type', 'text/plain')
21 # Note that the content is of type "bytes"
22 [Link](b'HelloServer!')
23 return True

Los filtros deben registrarse en serverIface como en el siguiente ejemplo:

class HelloServerServer:
def __init__(self, serverIface):
[Link](HelloFilter(serverIface), 100)

El segundo parámetro del método registerFilter() establece una prioridad que define el orden de las
devoluciones de llamada con el mismo nombre (la prioridad más baja se invoca primero).
Al utilizar las tres devoluciones de llamada, los complementos pueden manipular la entrada y / o la salida
del servidor de muchas formas diferentes. En todo momento, la instancia del complemento tiene acceso a
QgsRequestHandler a través de QgsServerInterface. La clase QgsRequestHandler tiene muchos
métodos que se pueden usar para modificar los parámetros de entrada antes de ingresar al procesamiento central del
servidor (usando requestReady()) o después de la solicitud ha sido procesado por los servicios centrales (usando
sendResponse()).
Los siguientes ejemplos cubren algunos casos comunes de uso:

152 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

Modificando la entrada

El complemento de ejemplo contiene un ejemplo de prueba que cambia los parámetros de entrada provenientes de
la cadena de consulta, en este ejemplo se inyecta un nuevo parámetro en el (ya analizado) parameterMap, este
parámetro es visible luego por los servicios centrales (WMS, etc.) , al final del procesamiento de los servicios centrales,
verificamos que el parámetro todavía esté allí:

1 class ParamsFilter(QgsServerFilter):
2

3 def __init__(self, serverIface):


4 super(ParamsFilter, self).__init__(serverIface)
5

6 def onRequestReady(self) -> bool:


7 request = [Link]().requestHandler()
8 params = [Link]( )
9 [Link]('TEST_NEW_PARAM', 'ParamsFilter')
10 return True
11

12 def onResponseComplete(self) -> bool:


13 request = [Link]().requestHandler()
14 params = [Link]( )
15 if [Link]('TEST_NEW_PARAM') == 'ParamsFilter':
16 [Link]("SUCCESS - [Link]")
17 else:
18 [Link]("FAIL - [Link]")
19 return True

Esto es un extracto de lo que puede ver en el archivo de log:

1 src/core/[Link]: 45: (logMessage) [0ms] 2014-12-12T[Link] plugin[0]␣


,→HelloServerServer - loading filter ParamsFilter
2 src/core/[Link]: 45: (logMessage) [1ms] 2014-12-12T[Link] Server[0]␣
,→Server plugin HelloServer loaded!

3 src/core/[Link]: 45: (logMessage) [0ms] 2014-12-12T[Link] Server[0]␣


,→Server python plugins loaded

4 src/mapserver/[Link]: 547: (requestStringToParameterMap) [1ms]␣


,→inserting pair SERVICE // HELLO into the parameter map

5 src/mapserver/[Link]: 42: (onRequestReady) [0ms] QgsServerFilter␣


,→plugin default onRequestReady called

6 src/core/[Link]: 45: (logMessage) [0ms] 2014-12-12T[Link] plugin[0]␣


,→SUCCESS - [Link]

En la línea resaltada, la cadena «SUCCESS» indica que el complemento pasó la prueba.


La misma técnica se puede aprovechar para usar un servicio personalizado en lugar de uno central: por ejemplo,
podría omitir una solicitud SERVICE WFS o cualquier otra solicitud principal simplemente cambiando el parámetro
SERVICE a algo diferente y se omitirá el servicio principal. Luego, puede inyectar sus resultados personalizados en
la salida y enviarlos al cliente (esto se explica a continuación).

Truco: Si realmente desea implementar un servicio personalizado, se recomienda crear una subclase QgsService
y registre su servicio en registerFilter() llamando a su método registerService(service)

20.4. Complementos del servidor 153


PyQGIS 3.40 developer cookbook

Modificar o reemplazar la salida

El ejemplo del filtro de marca de agua muestra cómo reemplazar la salida de WMS con una nueva imagen obtenida
agregando una imagen de marca de agua en la parte superior de la imagen de WMS generada por el servicio principal
de WMS:

1 from [Link] import *


2 from [Link] import *
3 from [Link] import *
4

5 class WatermarkFilter(QgsServerFilter):
6

7 def __init__(self, serverIface):


8 super().__init__(serverIface)
9

10 def onResponseComplete(self) -> bool:


11 request = [Link]().requestHandler()
12 params = [Link]( )
13 # Do some checks
14 if ([Link]('SERVICE').upper() == 'WMS' \
15 and [Link]('REQUEST').upper() == 'GETMAP' \
16 and not [Link]() ):
17 [Link]("[Link]: image␣
,→ready %s" % [Link]("FORMAT"))

18 # Get the image


19 img = QImage()
20 [Link]([Link]())
21 # Adds the watermark
22 watermark = QImage([Link]([Link](__file__), 'media/
,→[Link]'))

23 p = QPainter(img)
24 [Link](QRect( 20, 20, 40, 40), watermark)
25 [Link]()
26 ba = QByteArray()
27 buffer = QBuffer(ba)
28 [Link]([Link])
29 [Link](buffer, "PNG" if "png" in [Link]("FORMAT") else
,→"JPG")

30 # Set the body


31 [Link]()
32 [Link](ba)
33 return True

En este ejemplo, el valor del parámetro SERVICE se verifica y si la solicitud entrante es un WMS GETMAP y no
se han establecido excepciones por un complemento ejecutado previamente o por el servicio central (WMS en este
caso), la imagen generada por WMS se recupera del búfer de salida y se agrega la imagen de marca de agua. El último
paso es borrar el búfer de salida y reemplazarlo con la imagen recién generada. Tenga en cuenta que, en una situación
del mundo real, también deberíamos comprobar el tipo de imagen solicitada en lugar de admitir solo PNG o JPG.

Filtros de control de acceso

Los filtros de control de acceso brindan al desarrollador un control detallado sobre las capas, características y atributos
a los que se puede acceder; las siguientes devoluciones de llamada se pueden implementar en un filtro de control de
acceso:
• layerFilterExpression(layer)
• layerFilterSubsetString(layer)
• layerPermissions(layer)
• authorizedLayerAttributes(layer, attributes)

154 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

• allowToEdit(layer, feature)
• cacheKey()

Archivos de complementos

Aquí está la estructura de directorios de nuestro complemento de ejemplo:


1 PYTHON_PLUGINS_PATH/
2 MyAccessControl/
3 __init__.py --> *required*
4 [Link] --> *required*
5 [Link] --> *required*

__init__.py

Este archivo es requerido por el sistema de importación de Python. Como para todos los complementos del servidor
QGIS, este archivo contiene una función serverClassFactory (), que se llama cuando el complemento se
carga en el servidor QGIS al inicio. Recibe una referencia a una instancia de QgsServerInterface y debe
devolver una instancia de la clase de su complemento. Así es como el complemento de ejemplo __init__.py
aparece:
def serverClassFactory(serverIface):
from [Link] import AccessControlServer
return AccessControlServer(serverIface)

[Link]

1 class AccessControlFilter(QgsAccessControlFilter):
2

3 def __init__(self, server_iface):


4 super().__init__(server_iface)
5

6 def layerFilterExpression(self, layer):


7 """ Return an additional expression filter """
8 return super().layerFilterExpression(layer)
9

10 def layerFilterSubsetString(self, layer):


11 """ Return an additional subset string (typically SQL) filter """
12 return super().layerFilterSubsetString(layer)
13

14 def layerPermissions(self, layer):


15 """ Return the layer rights """
16 return super().layerPermissions(layer)
17

18 def authorizedLayerAttributes(self, layer, attributes):


19 """ Return the authorised layer attributes """
20 return super().authorizedLayerAttributes(layer, attributes)
21

22 def allowToEdit(self, layer, feature):


23 """ Are we authorised to modify the following geometry """
24 return super().allowToEdit(layer, feature)
25

26 def cacheKey(self):
27 return super().cacheKey()
28

29 class AccessControlServer:
(continúe en la próxima página)

20.4. Complementos del servidor 155


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


30

31 def __init__(self, serverIface):


32 """ Register AccessControlFilter """
33 [Link](AccessControlFilter(serverIface), 100)

Este ejemplo otorga acceso total para todos.


Es rol del complemento saber quién ha ingresado.
En todos esos métodos tenemos el argumento layer on para poder personalizar la restricción por capa.

layerFilterExpression

Permite añadir una expresión para limitar los resultados.


Por ejemplo, para limitar a características donde el atributo role es igual a user.

def layerFilterExpression(self, layer):


return "$role = 'user'"

layerFilterSubsetString

Igual que el anterior pero usa el SubsetString (ejecutado en la base de datos)


Por ejemplo, para limitar a características donde el atributo role es igual a user.

def layerFilterSubsetString(self, layer):


return "role = 'user'"

layerPermissions

Limitar el acceso a la capa.


Devuelve un objeto de tipo LayerPermissions(), el cuál tiene las propiedades:
• canRead para verlo en GetCapabilities y tiene acceso de lectura.
• canInsert para poder insertar una nueva característica.
• canUpdate para ser capaz de actualizar una característica.
• canDelete para ser capaz de borrar una característica.
Por ejemplo, para limitar todo al acceso de sólo lectura:

1 def layerPermissions(self, layer):


2 rights = [Link]()
3 [Link] = True
4 [Link] = [Link] = [Link] = False
5 return rights

156 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

authorizedLayerAttributes

Usado para limitar la visibilidad de un subconjunto específico de atributo.


El atributo del argumento devuelve el conjunto actual de atributos visibles.
Por ejemplo, para ocultar el atributo role:
def authorizedLayerAttributes(self, layer, attributes):
return [a for a in attributes if a != "role"]

allowToEdit

Esto es usado para limitar la edición de un subconjunto de objetos espaciales.


Se utiliza en el protocolo WFS-Transaction.
Por ejemplo, para poder editar sólo el objeto espacial que tiene el atributo role con el valor user:
def allowToEdit(self, layer, feature):
return [Link]('role') == 'user'

cacheKey

QGIS Server mantiene una caché de las capacidades entonces para tener una caché por rol puedes retornar el rol en
este método. O devolver None para desactivar completamente la caché.

20.4.2 Servicios personalizados

En QGIS Server, los servicios centrales como WMS, WFS y WCS se implementan como subclases de QgsService.
Para implementar un nuevo servicio que se ejecutará cuando el parámetro de cadena de consulta SERVICE
coincida con el nombre del servicio, puedes implementar tu propio QgsService y registrar tu servicio en el
serviceRegistry() llamando a su registerService(service).
Este es un ejemplo de un servicio personalizado llamado CUSTOM:
1 from [Link] import QgsService
2 from [Link] import QgsMessageLog
3

4 class CustomServiceService(QgsService):
5

6 def __init__(self):
7 QgsService.__init__(self)
8

9 def name(self):
10 return "CUSTOM"
11

12 def version(self):
13 return "1.0.0"
14

15 def executeRequest(self, request, response, project):


16 [Link](200)
17 [Link]('Custom service executeRequest')
18 [Link]("Custom service executeRequest")
19

20

21 class CustomService():
22

(continúe en la próxima página)

20.4. Complementos del servidor 157


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


23 def __init__(self, serverIface):
24 [Link]().registerService(CustomServiceService())

20.4.3 APIs personalizadas

En QGIS Server, las API principales de OGC como OAPIF (también conocido como WFS3) se implementan
como colecciones de QgsServerOgcApiHandler subclases que están registradas en una instancia de
QgsServerOgcApi).
Para implementar una nueva API que se ejecute cuando la ruta url coincida con una determinada URL, puede
implementar sus propias instancias QgsServerOgcApiHandler, añadirlas a una QgsServerOgcApi y
registrar la API en el serviceRegistry() llamando a su registerApi(api).
A continuación, se muestra un ejemplo de una API personalizada que se ejecutará cuando la URL contenga /
customapi:
1 import json
2 import os
3

4 from [Link] import QBuffer, QIODevice, QTextStream, QRegularExpression


5 from [Link] import (
6 QgsServiceRegistry,
7 QgsService,
8 QgsServerFilter,
9 QgsServerOgcApi,
10 QgsServerQueryStringParameter,
11 QgsServerOgcApiHandler,
12 )
13

14 from [Link] import (


15 QgsMessageLog,
16 QgsJsonExporter,
17 QgsCircle,
18 QgsFeature,
19 QgsPoint,
20 QgsGeometry,
21 )
22

23

24 class CustomApiHandler(QgsServerOgcApiHandler):
25

26 def __init__(self):
27 super(CustomApiHandler, self).__init__()
28 [Link]([[Link], [Link]])
29

30 def path(self):
31 return QRegularExpression("/customapi")
32

33 def operationId(self):
34 return "CustomApiXYCircle"
35

36 def summary(self):
37 return "Creates a circle around a point"
38

39 def description(self):
40 return "Creates a circle around a point"
41

42 def linkTitle(self):
43 return "Custom Api XY Circle"
44

(continúe en la próxima página)

158 Capítulo 20. Servidor QGIS y Python


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


45 def linkType(self):
46 return [Link]
47

48 def handleRequest(self, context):


49 """Simple Circle"""
50

51 values = [Link](context)
52 x = values['x']
53 y = values['y']
54 r = values['r']
55 f = QgsFeature()
56 [Link]([x, y, r])
57 [Link](QgsCircle(QgsPoint(x, y), r).toCircularString())
58 exporter = QgsJsonExporter()
59 [Link]([Link]([Link](f)), context)
60

61 def templatePath(self, context):


62 # The template path is used to serve HTML content
63 return [Link]([Link](__file__), '[Link]')
64

65 def parameters(self, context):


66 return [QgsServerQueryStringParameter('x', True,␣
,→[Link], 'X coordinate'),

67 QgsServerQueryStringParameter(
68 'y', True, [Link], 'Y␣
,→coordinate'),

69 QgsServerQueryStringParameter('r', True,␣
,→[Link], 'radius')]

70

71

72 class CustomApi():
73

74 def __init__(self, serverIface):


75 api = QgsServerOgcApi(serverIface, '/customapi',
76 'custom api', 'a custom api', '1.1')
77 handler = CustomApiHandler()
78 [Link](handler)
79 [Link]().registerApi(api)

20.4. Complementos del servidor 159


PyQGIS 3.40 developer cookbook

160 Capítulo 20. Servidor QGIS y Python


CAPÍTULO 21

hoja de referencia para PyQGIS

Consejo: Los fragmentos de código en esta página necesitan las siguientes adiciones si está fuera de la consola de
pyqgis:
1 from [Link] import (
2 QRectF,
3 )
4

5 from [Link] import (


6 Qgis,
7 QgsProject,
8 QgsLayerTreeModel,
9 )
10

11 from [Link] import (


12 QgsLayerTreeView,
13 )

21.1 Interfaz de Usuario

Cambiar apariencia
1 from [Link] import QApplication
2

3 app = [Link]()
4 [Link](".QWidget {color: blue; background-color: yellow;}")
5 # You can even read the stylesheet from a file
6 with open("testdata/[Link]") as qss_file_content:
7 [Link](qss_file_content.read())

Cambiar icono y título


1 from [Link] import QIcon
2

3 icon = QIcon("/path/to/logo/[Link]")
(continúe en la próxima página)

161
PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


4 [Link]().setWindowIcon(icon)
5 [Link]().setWindowTitle("My QGIS")

21.2 Configuración

Obtenga la lista de QgsSettings

1 from [Link] import QgsSettings


2

3 qs = QgsSettings()
4

5 for k in sorted([Link]()):
6 print (k)

21.3 Barras de herramientas

Eliminar barra de herramientas

1 toolbar = [Link]()
2 parent = [Link]()
3 [Link](toolbar)
4

5 # and add again


6 [Link](toolbar)

Eliminar acciones de un barra de herramientas

actions = [Link]().actions()
[Link]().clear()
[Link]().addAction(actions[4])
[Link]().addAction(actions[3])

21.4 Menús

Eliminar menú

1 # for example Help Menu


2 menu = [Link]()
3 menubar = [Link]()
4 [Link]([Link]())
5

6 # and add again


7 [Link]([Link]())

162 Capítulo 21. hoja de referencia para PyQGIS


PyQGIS 3.40 developer cookbook

21.5 Lienzo

Acceder al lienzo

canvas = [Link]()

Cambiar color de lienzo

from [Link] import Qt

[Link]().setCanvasColor([Link])
[Link]().refresh()

Intervalo de actualización del mapa

from [Link] import QgsSettings


# Set milliseconds (150 milliseconds)
QgsSettings().setValue("/qgis/map_update_interval", 150)

21.6 Capas

Añadir capa vectorial

layer = [Link]("testdata/data/[Link]|layername=airports",
,→"Airports layer", "ogr")

if not layer or not [Link]():


print("Layer failed to load!")

Obtener capa activa

layer = [Link]()

Listar todas las capas

from [Link] import QgsProject

[Link]().mapLayers().values()

Obtener el nombre de las capas

1 from [Link] import QgsVectorLayer


2 layer = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like", "memory")
3 [Link]().addMapLayer(layer)
4

5 layers_names = []
6 for layer in [Link]().mapLayers().values():
7 layers_names.append([Link]())
8

9 print("layers TOC = {}".format(layers_names))

layers TOC = ['layer name you like']

De otra manera

layers_names = [[Link]() for layer in [Link]().mapLayers().


,→values()]

print("layers TOC = {}".format(layers_names))

21.5. Lienzo 163


PyQGIS 3.40 developer cookbook

layers TOC = ['layer name you like']

Encuentra una capa por el nombre

from [Link] import QgsProject

layer = [Link]().mapLayersByName("layer name you like")[0]


print([Link]())

layer name you like

Establecer capa activa

from [Link] import QgsProject

layer = [Link]().mapLayersByName("layer name you like")[0]


[Link](layer)

Intervalo para actualizar capa

1 from [Link] import QgsProject


2

3 layer = [Link]().mapLayersByName("layer name you like")[0]


4 # Set seconds (5 seconds)
5 [Link](5000)
6 # Enable data reloading
7 [Link]([Link])

Mostrar métodos

dir(layer)

Agregar nueva objeto espacial con un formulario

1 from [Link] import QgsFeature, QgsGeometry


2

3 feat = QgsFeature()
4 geom = QgsGeometry()
5 [Link](geom)
6 [Link]([Link]())
7

8 [Link](layer, feat, False)

Agregar nueva objeto espacial sin un formulario

1 from [Link] import QgsGeometry, QgsPointXY, QgsFeature


2

3 pr = [Link]()
4 feat = QgsFeature()
5 [Link]([Link](QgsPointXY(10,10)))
6 [Link]([feat])

Obtener los objetos espaciales

for f in [Link]():
print (f)

<qgis._core.QgsFeature object at 0x7f45cc64b678>

Obtener los objetos espaciales seleccionados

164 Capítulo 21. hoja de referencia para PyQGIS


PyQGIS 3.40 developer cookbook

for f in [Link]():
print (f)

Obtener los Ids de los objetos espaciales seleccionados


selected_ids = [Link]()
print(selected_ids)

Crear una capa en memoria a partir de los Ids seleccionados


from [Link] import QgsFeatureRequest

memory_layer = [Link](QgsFeatureRequest().setFilterFids(layer.
,→selectedFeatureIds()))

[Link]().addMapLayer(memory_layer)

Obtener geometría
# Point layer
for f in [Link]():
geom = [Link]()
print ('%f, %f' % ([Link]().y(), [Link]().x()))

10.000000, 10.000000

Mover geometría
1 from [Link] import QgsFeature, QgsGeometry
2 poly = QgsFeature()
3 geom = [Link]("POINT(7 45)")
4 [Link](1, 1)
5 [Link](geom)
6 print([Link]())

<QgsGeometry: Point (8 46)>

Establecer SRC
from [Link] import QgsProject, QgsCoordinateReferenceSystem

for layer in [Link]().mapLayers().values():


[Link](QgsCoordinateReferenceSystem('EPSG:4326'))

Ver SRC
1 from [Link] import QgsProject
2

3 for layer in [Link]().mapLayers().values():


4 crs = [Link]().authid()
5 [Link]('{} ({})'.format([Link](), crs))

Ocultar columna
1 from [Link] import QgsEditorWidgetSetup
2

3 def fieldVisibility (layer,fname):


4 setup = QgsEditorWidgetSetup('Hidden', {})
5 for i, column in enumerate([Link]()):
6 if [Link]()==fname:
7 [Link](idx, setup)
8 break
(continúe en la próxima página)

21.6. Capas 165


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


9 else:
10 continue

Capa desde WKT

1 from [Link] import QgsVectorLayer, QgsFeature, QgsGeometry, QgsProject


2

3 layer = QgsVectorLayer('Polygon?crs=epsg:4326', 'Mississippi', 'memory')


4 pr = [Link]()
5 poly = QgsFeature()
6 geom = [Link]("POLYGON ((-88.82 34.99,-88.09 34.89,-88.39 30.34,-89.
,→57 30.18,-89.73 31,-91.63 30.99,-90.87 32.37,-91.23 33.44,-90.93 34.23,-90.30 34.

,→99,-88.82 34.99))")

7 [Link](geom)
8 [Link]([poly])
9 [Link]()
10 [Link]().addMapLayers([layer])

** Cargue todas las capas vectoriales de GeoPackage **

1 from [Link] import QgsDataProvider


2

3 fileName = "testdata/[Link]"
4 layer = QgsVectorLayer(fileName, "test", "ogr")
5 subLayers = [Link]().subLayers()
6

7 for subLayer in subLayers:


8 name = [Link](QgsDataProvider.SUBLAYER_SEPARATOR)[1]
9 uri = "%s|layername=%s" % (fileName, name,)
10 # Create layer
11 sub_vlayer = QgsVectorLayer(uri, name, 'ogr')
12 # Add layer to map
13 [Link]().addMapLayer(sub_vlayer)

Cargar capa de mosaico (XYZ-Layer)

1 from [Link] import QgsRasterLayer, QgsProject


2

3 def loadXYZ(url, name):


4 rasterLyr = QgsRasterLayer("type=xyz&url=" + url, name, "wms")
5 [Link]().addMapLayer(rasterLyr)
6

7 urlWithParams = '[Link]
,→zmax=19&zmin=0&crs=EPSG3857'

8 loadXYZ(urlWithParams, 'OpenStreetMap')

Eliminar todas las capas

[Link]().removeAllMapLayers()

Eliminar todos

[Link]().clear()

166 Capítulo 21. hoja de referencia para PyQGIS


PyQGIS 3.40 developer cookbook

21.7 Tabla de contenidos

Accede a las capas activadas

[Link]().layers()

Eliminar menú contextual

1 ltv = [Link]()
2 mp = [Link]()
3 [Link](None)
4 # Restore
5 [Link](mp)

21.8 TOC avanzado

Nodo raíz

1 from [Link] import QgsVectorLayer, QgsProject, QgsLayerTreeLayer


2

3 root = [Link]().layerTreeRoot()
4 node_group = [Link]("My Group")
5

6 layer = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like", "memory")


7 [Link]().addMapLayer(layer, False)
8

9 node_group.addLayer(layer)
10

11 print(root)
12 print([Link]())

Acceder al primer nodo hijo

1 from [Link] import QgsLayerTreeGroup, QgsLayerTreeLayer, QgsLayerTree


2

3 child0 = [Link]()[0]
4 print ([Link]())
5 print (type(child0))
6 print (isinstance(child0, QgsLayerTreeLayer))
7 print (isinstance([Link](), QgsLayerTree))

My Group
<class 'qgis._core.QgsLayerTreeGroup'>
False
True

Encontrar grupos y nodos

1 from [Link] import QgsLayerTreeGroup, QgsLayerTreeLayer


2

3 def get_group_layers(group):
4 print('- group: ' + [Link]())
5 for child in [Link]():
6 if isinstance(child, QgsLayerTreeGroup):
7 # Recursive call to get nested groups
8 get_group_layers(child)
9 else:
10 print(' - layer: ' + [Link]())
(continúe en la próxima página)

21.7. Tabla de contenidos 167


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


11

12

13 root = [Link]().layerTreeRoot()
14 for child in [Link]():
15 if isinstance(child, QgsLayerTreeGroup):
16 get_group_layers(child)
17 elif isinstance(child, QgsLayerTreeLayer):
18 print ('- layer: ' + [Link]())

- group: My Group
- layer: layer name you like

Buscar grupo por nombre

print ([Link]("My Group"))

<QgsLayerTreeGroup: My Group>

Encontrar capa por id

print([Link]([Link]()))

<QgsLayerTreeLayer: layer name you like>

Añadir capas

1 from [Link] import QgsVectorLayer, QgsProject


2

3 layer1 = QgsVectorLayer("Point?crs=EPSG:4326", "layer name you like 2", "memory")


4 [Link]().addMapLayer(layer1, False)
5 node_layer1 = [Link](layer1)
6 # Remove it
7 [Link]().removeMapLayer(layer1)

Añadir grupo

1 from [Link] import QgsLayerTreeGroup


2

3 node_group2 = QgsLayerTreeGroup("Group 2")


4 [Link](node_group2)
5 [Link]().mapLayersByName("layer name you like")[0]

Mover capa cargada

1 layer = [Link]().mapLayersByName("layer name you like")[0]


2 root = [Link]().layerTreeRoot()
3

4 myLayer = [Link]([Link]())
5 myClone = [Link]()
6 parent = [Link]()
7

8 myGroup = [Link]("My Group")


9 # Insert in first position
10 [Link](0, myClone)
11

12 [Link](myLayer)

Mover capa cargada a un grupo específico

168 Capítulo 21. hoja de referencia para PyQGIS


PyQGIS 3.40 developer cookbook

1 [Link]().addMapLayer(layer, False)
2

3 root = [Link]().layerTreeRoot()
4 myGroup = [Link]("My Group")
5 myOriginalLayer = [Link]([Link]())
6 myLayer = [Link]()
7 [Link](0, myLayer)
8 [Link](myOriginalLayer)

Alternar la visibilidad de la capa activa

root = [Link]().layerTreeRoot()
node = [Link]([Link]())
new_state = [Link] if [Link]() == [Link] else [Link]
[Link](new_state)

Es el grupo seleccionado

1 def isMyGroupSelected( groupName ):


2 myGroup = [Link]().layerTreeRoot().findGroup( groupName )
3 return myGroup in [Link]().selectedNodes()
4

5 print(isMyGroupSelected( 'my group name' ))

False

Expandir nodo

print([Link]())
[Link](False)

Truco para ocultar nodo

1 from [Link] import QgsProject


2

3 model = [Link]().layerTreeModel()
4 ltv = [Link]()
5 root = [Link]().layerTreeRoot()
6

7 layer = [Link]().mapLayersByName('layer name you like')[0]


8 node = [Link]([Link]())
9

10 index = model.node2index( node )


11 [Link]( [Link](), [Link](), True )
12 [Link]( 'nodeHidden', 'true')
13 [Link](model.node2index(root))

Señales de nodo

1 def onWillAddChildren(node, indexFrom, indexTo):


2 print ("WILL ADD", node, indexFrom, indexTo)
3

4 def onAddedChildren(node, indexFrom, indexTo):


5 print ("ADDED", node, indexFrom, indexTo)
6

7 [Link](onWillAddChildren)
8 [Link](onAddedChildren)

Eliminar capa

[Link](layer)

21.8. TOC avanzado 169


PyQGIS 3.40 developer cookbook

Eliminar grupo

[Link](node_group2)

Crear nueva tabla de contenido (TOC)

1 root = [Link]().layerTreeRoot()
2 model = QgsLayerTreeModel(root)
3 view = QgsLayerTreeView()
4 [Link](model)
5 [Link]()

Mover nodo

cloned_group1 = node_group.clone()
[Link](0, cloned_group1)
[Link](node_group)

Cambiar nombre del nodo

cloned_group1.setName("Group X")
node_layer1.setName("Layer X")

21.9 Algoritmos de procesamiento

Obtener listado de algoritmos

1 from [Link] import QgsApplication


2

3 for alg in [Link]().algorithms():


4 if 'buffer' == [Link]():
5 print("{}:{} --> {}".format([Link]().name(), [Link](), alg.
,→displayName()))

QGIS (native c++):buffer --> Buffer

Obtener ayuda de los algoritmos


Selección aleatoria

from qgis import processing


[Link]("native:buffer")

...

Ejecutar algoritmo
Para este ejemplo, el resultado se almacena en una capa en memoria que se agrega al proyecto.

from qgis import processing


result = [Link]("native:buffer", {'INPUT': layer, 'OUTPUT': 'memory:'})
[Link]().addMapLayer(result['OUTPUT'])

Processing(0): Results: {'OUTPUT': 'output_d27a2008_970c_4687_b025_f057abbd7319'}

¿Cuántos algoritmos hay?

len([Link]().algorithms())

¿Cuántos proveedores hay?

170 Capítulo 21. hoja de referencia para PyQGIS


PyQGIS 3.40 developer cookbook

from [Link] import QgsApplication

len([Link]().providers())

¿Cuántas expresiones hay?

from [Link] import QgsExpression

len([Link]())

21.10 Decoradores

CopyRight

1 from [Link] import QTextDocument


2 from [Link] import QFont
3

4 mQFont = "Sans Serif"


5 mQFontsize = 9
6 mLabelQString = "© QGIS 2019"
7 mMarginHorizontal = 0
8 mMarginVertical = 0
9 mLabelQColor = "#FF0000"
10

11 INCHES_TO_MM = 0.0393700787402 # 1 millimeter = 0.0393700787402 inches


12 case = 2
13

14 def add_copyright(p, text, xOffset, yOffset):


15 [Link]( xOffset , yOffset )
16 [Link](p)
17 [Link]( [Link]() )
18

19 def _on_render_complete(p):
20 deviceHeight = [Link]().height() # Get paint device height on which this␣
,→painter is currently painting

21 deviceWidth = [Link]().width() # Get paint device width on which this␣


,→painter is currently painting

22 # Create new container for structured rich text


23 text = QTextDocument()
24 font = QFont()
25 [Link](mQFont)
26 [Link](int(mQFontsize))
27 [Link](font)
28 style = "<style type=\"text/css\"> p {color: " + mLabelQColor + "}</style>"
29 [Link]( style + "<p>" + mLabelQString + "</p>" )
30 # Text Size
31 size = [Link]()
32

33 # RenderMillimeters
34 pixelsInchX = [Link]().logicalDpiX()
35 pixelsInchY = [Link]().logicalDpiY()
36 xOffset = pixelsInchX * INCHES_TO_MM * int(mMarginHorizontal)
37 yOffset = pixelsInchY * INCHES_TO_MM * int(mMarginVertical)
38

39 # Calculate positions
40 if case == 0:
41 # Top Left
42 add_copyright(p, text, xOffset, yOffset)
43

(continúe en la próxima página)

21.10. Decoradores 171


PyQGIS 3.40 developer cookbook

(proviene de la página anterior)


44 elif case == 1:
45 # Bottom Left
46 yOffset = deviceHeight - yOffset - [Link]()
47 add_copyright(p, text, xOffset, yOffset)
48

49 elif case == 2:
50 # Top Right
51 xOffset = deviceWidth - xOffset - [Link]()
52 add_copyright(p, text, xOffset, yOffset)
53

54 elif case == 3:
55 # Bottom Right
56 yOffset = deviceHeight - yOffset - [Link]()
57 xOffset = deviceWidth - xOffset - [Link]()
58 add_copyright(p, text, xOffset, yOffset)
59

60 elif case == 4:
61 # Top Center
62 xOffset = deviceWidth / 2
63 add_copyright(p, text, xOffset, yOffset)
64

65 else:
66 # Bottom Center
67 yOffset = deviceHeight - yOffset - [Link]()
68 xOffset = deviceWidth / 2
69 add_copyright(p, text, xOffset, yOffset)
70

71 # Emitted when the canvas has rendered


72 [Link]().[Link](_on_render_complete)
73 # Repaint the canvas map
74 [Link]().refresh()

21.11 Compositor

Obtener diseño de impresión por nombre

1 composerTitle = 'MyComposer' # Name of the composer


2

3 project = [Link]()
4 projectLayoutManager = [Link]()
5 layout = [Link](composerTitle)

21.12 Fuentes

• QGIS Python (PyQGIS) API


• QGIS C++ API
• `Preguntas de StackOverFlow sobre QGIS<[Link]
• Script por Klas Karlsson

172 Capítulo 21. hoja de referencia para PyQGIS

También podría gustarte