¿Generando gran cantidad de mapas usando PyQGIS?

10

Tengo que hacer una gran cantidad (cientos) de mapas de distribución de especies. Tengo un archivo de formas que contiene las distribuciones para cada especie, y para cada una, me gustaría obtener un mapa como una imagen (jpg, png u otro) que contenga el nombre de la especie en cuestión, la leyenda (para distinguir áreas de distribuciones anuales, mejoramiento, no mejoramiento, etc. ...).

Me gustaría usar QGIS para hacer esto.

Onesime
fuente
1
¿Podría especificar un poco más sobre las características específicas de los mapas? Por ejemplo, ¿desea que todos estos mapas muestren la misma área, como un continente o país específico, o desea que la extensión del mapa cambie dinámicamente? Además, ¿desea todos los subtipos de rango en un mapa o están en mapas múltiples? Dependiendo de estas respuestas, su problema podría ser bastante simple o podría requerir un enfoque un poco más sofisticado. Un buen lugar para comenzar a buscar es el complemento Atlas para SIG, o si tiene ArcGIS 10 o superior disponible, los libros de mapas de ESRI también ayudarán.
Jay Guarneri
1
Perdón por la falta de detalles. Sí, para todos los mapas, será la misma área (Europa). Tengo un archivo de forma con todas las especies y, en los atributos, la distribución correspondiente. Este archivo de forma, puedo dividirlo fácilmente en diferentes archivos de forma (uno para cada especie). Al final, me gustaría tener para cada especie una imagen, con, en cada momento, exactamente la misma área (Europa), los mismos colores (por ejemplo, distribuciones anuales en verde oscuro, reproducción en verde claro, no reproducción en azul, etc. ...), la misma leyenda, y como título el nombre de la especie.
Onesime
Creo que lo que debe hacer es planificar cada paso que necesita dar para hacer cada mapa, luego codificar las selecciones y exportaciones de mapas en Python. Sé que esto se puede hacer fácilmente en ArcGIS Python, pero no sé lo suficiente sobre la interfaz de QGIS Python para dar mucha orientación. Sin embargo, estoy seguro de que puede hacer que esto funcione con un archivo de forma.
Jay Guarneri
He hecho algo similar con QGIS usando un complemento de Python. En mi caso, mis capas se almacenaron en PostGIS, pero creo que podría hacer algo similar con un shapefile. Estoy feliz de compartir mi código. Me pm.
Brian Edmond
1
¿Puedes subir una muestra de tus datos para que podamos jugar?
Nathan W

Respuestas:

4

Tenía un requisito similar y armé un complemento QGIS para generar los mapas, basado en un archivo de forma con localidades puntuales para todas las especies (se asume un nombre de taxón único en la tabla de atributos como el identificador común). Mis requisitos no eran tan complejos: no necesitaba información de temporada, títulos o leyendas, pero puede ser un punto de partida útil para usted. Para los aspectos más complejos, deberá utilizar el compositor de mapas. Consulte el libro de cocina PyQGIS para obtener más información al respecto.

Enchufar

El complemento automatiza la creación de los mapas y le permite configurar extensiones, resolución y otros aspectos. Aplica el mismo estilo a la salida que la superposición de cuadrícula. Actualmente solo se ejecuta en la versión de desarrollo de QGIS (1.9 o posterior).

Guión sextante

Antes de crear el complemento, resolví la lógica usando SEXTANTE. Este script de usuario también debería funcionar en 1.8 (no lo he probado). El archivo de estilo de distribución (.qml) es el estilo de las distribuciones de salida (ignora el estilo de la superposición de distribución). Actualmente coloca mapas de salida en el directorio temporal según los valores predeterminados del sistema operativo (/ tmp en Linux y varios lugares en Windows, definidos por la variable de entorno TEMP). Sin embargo, puedes definirlo fácilmente en el código. También deberá editar la extensión y la resolución de salida en el código (y el color de fondo si desea un color diferente para el mar).

#Definition of inputs and outputs
#==================================
##[Scratch]=group
##all_localities=vector
##taxon_field=field all_localities
##africa_map=vector
##sa_map=vector
##grid_layer=vector
##distribution_style_file=file

#Algorithm body
#==================================
from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteVectorWriter import SextanteVectorWriter
import tempfile
import os

def print_map(taxon,taxon_shp):
    #load taxon layer (necessary?)
    #QGisLayers.load(taxon_shp,name = "taxon",style = distribution_style_file)
    taxon_layer = QgsVectorLayer(taxon_shp,"taxon","ogr")
    QgsMapLayerRegistry.instance().addMapLayer(taxon_layer)
    taxon_layer.loadNamedStyle(distribution_style_file)

    # create image (dimensions 325x299)
    img = QImage(QSize(325,299), QImage.Format_ARGB32_Premultiplied)

    # set image's background color
    color = QColor(192,192,255)   # blue sea
    img.fill(color.rgb())

    # create painter
    p = QPainter()
    p.begin(img)
    p.setRenderHint(QPainter.Antialiasing)

    render = QgsMapRenderer()

    # create layer set
    africa_layer = QGisLayers.getObjectFromUri(africa_map)
    sa_layer = QGisLayers.getObjectFromUri(sa_map)
    #taxon_layer = QGisLayers.getObjectFromUri(taxon_shp)

    lst = []
    lst.append(taxon_layer.id())    
    lst.append(sa_layer.id())
    lst.append(africa_layer.id())

    render.setLayerSet(lst)

    # set extent (xmin,ymin,xmax,ymax)
    rect = QgsRectangle(14.75,-36.00,34.00,-21.00)
    render.setExtent(rect)

    # set output size
    render.setOutputSize(img.size(), img.logicalDpiX())

    # do the rendering
    render.render(p)
    p.end()

    # save image
    #outdir = os.path.dirname(os.path.abspath(output))
    tempdir = tempfile.gettempdir()
    img.save(os.path.join(tempdir,taxon+".png"),"png")

    # remove taxon layer from project
    QgsMapLayerRegistry.instance().removeMapLayers([taxon_layer.id()])

tempdir = tempfile.gettempdir()   
taxa = sextante.runalg('qgis:listuniquevalues', all_localities, taxon_field, None)['UNIQUE_VALUES'].split(";")
for taxon in taxa:
    sextante.runalg('qgis:selectbyattribute', all_localities, taxon_field, 0, taxon)
    sextante.runalg('qgis:selectbylocation', grid_layer, all_localities, 0)
    filename = os.path.join(tempdir,"taxon.shp")    #memory file better?
    sextante.runalg('qgis:saveselectedfeatures', grid_layer, filename)
    print_map(taxon,filename)
rudivonstaden
fuente
Hola a todos, gracias por todas sus respuestas. Para darle algunos elementos más, son datos provenientes de BirdLife (un ejemplo para especie: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). Brevemente, hay un archivo de forma con todos los polígonos para todas las especies (por lo tanto, para algunas de ellas, muchas líneas para una sola especie), y hay un atributo que corresponde a la distribución estacional (con valores del 1 al 5 correspondientes a diferentes usos). ), uno para el origen, etc. La leyenda y el título no son indispensables.
Onesime
- Utilizo una capa de país en segundo plano, solo para una ubicación fácil. - Para el color diferente para el valor diferente del atributo "estacional", creo que para eso, un archivo .qml de uso es adecuado. - Opcionalmente, para el título y la leyenda, creo que tengo que usar un archivo del compositor, si es demasiado difícil, puedo agregarlo con otro software. - La operación debe repetirse para todas las especies, por lo tanto, esto corresponde a una selección por atributo, que se utilizará para dar el nombre de la imagen final.
Onesime
Probé el complemento "Atlas", pero parece ser más apropiado para varias ubicaciones, en mi caso, es todo el tiempo para la misma área: Europa. Probé el complemento "Administrador de mapas de distribución" que parece corresponder en este punto porque es posible arreglar el área de cobertura, pero no necesito el proceso que cruza los puntos con una capa de cuadrícula ya que ya tengo una capa de polígono. Intenté en ArcGis, pero es lo mismo para el complemento QGis Atlas, la solución parece ser escribir un script de Python ...
Onesime
Así que creo que usaré Sextante, basado en el guión "rudivonstaden" (¡gracias por ello!) Y para adaptarlo a mi caso. Finalmente, lo siento por estos diferentes comentarios, pero hay un límite de número de personajes ...
Onesime
@Onesime, excepto por el título y la leyenda, creo que podrás adaptar el script sextante anterior para hacer lo que necesites. Usted tendrá que quitar probablemente el selectbylocationpaso, y añadir un adicional selectbyattributey saveselectedfeaturespaso para cada temporada (modificar grid_layera all_localities). Luego cargue más archivos .qml y agregue y agregue sus archivos de forma estacionales (la capa superior se agrega primero). Si no está seguro de cómo, probablemente podría intentar editar el script anterior para trabajar más o menos.
rudivonstaden
2

Me tomé poco tiempo para trabajar en esto hoy. Así que hice algunos cambios en tu guión. No necesito agregar un paso selectbyattribute adicional y guardar las funciones seleccionadas, ya que uso archivos .qml y el campo Seasonal está en el mismo archivo de forma. A continuación, puedes ver lo que he hecho:

#Definition of inputs and outputs
#==================================
##[Scratch]=group
##all_localities=vector
##taxon_field=field all_localities
##seasonal_field=field all_localities
##countries_map=vector
##distribution_style_file=file
##output_folder=folder

#Algorithm body
#==================================
from qgis.core import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from sextante.core.QGisLayers import QGisLayers
from sextante.core.SextanteVectorWriter import SextanteVectorWriter
import tempfile
import os

def print_map(taxon,taxon_shp):
#load taxon layer (necessary?)
#QGisLayers.load(taxon_shp,name = "taxon",style = distribution_style_file)
taxon_layer = QgsVectorLayer(taxon_shp,"taxon","ogr")
QgsMapLayerRegistry.instance().addMapLayer(taxon_layer)
taxon_layer.loadNamedStyle(distribution_style_file)

# create image (dimensions 325x299)
img = QImage(QSize(325,299), QImage.Format_ARGB32_Premultiplied)

# set image's background color
color = QColor(221,249,254)   # blue sea
img.fill(color.rgb())

# create painter
p = QPainter()
p.begin(img)
p.setRenderHint(QPainter.Antialiasing)

render = QgsMapRenderer()

# create layer set
countries_layer = QGisLayers.getObjectFromUri(countries_map)
taxon_layer = QGisLayers.getObjectFromUri(taxon_shp)

lst = []
lst.append(taxon_layer.id())    
lst.append(countries_layer.id())
render.setLayerSet(lst)

# set extent (xmin,ymin,xmax,ymax)
rect = QgsRectangle(-11,32,39,71)
render.setExtent(rect)
# set output size
render.setOutputSize(img.size(), img.logicalDpiX())

# do the rendering
render.render(p)
p.end()

#save image
#outdir = os.path.dirname(os.path.abspath(output))
tempdir = output_folder
img.save(os.path.join(tempdir,taxon+".png"),"png")

# remove taxon layer from project
QgsMapLayerRegistry.instance().removeMapLayers([taxon_layer.id()])

tempdir = tempfile.gettempdir()  

taxa = sextante.runalg('qgis:listuniquevalues', all_localities, taxon_field, None)        ['UNIQUE_VALUES'].split(";")

for taxon in taxa:
sextante.runalg('qgis:selectbyattribute', all_localities, taxon_field, 0, taxon)
filename = os.path.join(tempdir,"taxon.shp")    #memory file better?
sextante.runalg('qgis:saveselectedfeatures', all_localities, filename)
print_map(taxon,filename)

Si tiene algún comentario o consejo para mejorarlo, no lo dude.

Para mejorarlo, lo mejor sería cuando seleccionamos la extensión (por ejemplo, Europa), use esta extensión para seleccionar solo las especies incluidas dentro de esta extensión. Esto, porque obtengo mapas para todas las especies, incluso aquellas que están fuera de Europa, por ejemplo (así que tengo muchos mapas vacíos). ¿Cree que es posible?

Salud,

Onesime

Onesime
fuente