Generare un gran numero di mappe usando PyQGIS?


10

Devo creare un gran numero (centinaia) di mappe di distribuzione delle specie. Ho uno shapefile che contiene le distribuzioni per ogni specie, e per ognuna vorrei ottenere una mappa come immagine (jpg, png o altro) che contenga il nome della specie in questione, la legenda (per distinguere le aree di distribuzioni annuali, riproduzione, non riproduzione, ecc ...).

Mi piacerebbe usare QGIS per farlo.


1
Potresti specificare qualcosa in più sulle specifiche delle mappe? Ad esempio, vuoi che tutte queste mappe mostrino la stessa area, come un continente o un paese specifico, o vuoi che l'estensione della mappa cambi in modo dinamico? Inoltre, vuoi tutti i sottotipi di intervallo su una mappa o sono su più mappe? A seconda di queste risposte, il tuo problema potrebbe essere abbastanza semplice o potrebbe richiedere un approccio un po 'più sofisticato. Un buon punto di partenza è il plug-in Atlas per GIS, o se hai ArcGIS 10 o versione successiva, anche i mapbook di ESRI ti aiuteranno.
Jay Guarneri,

1
Ci scusiamo per la mancanza di dettagli. Sì per tutte le mappe, sarà la stessa area (Europa). Ho un file di forma con tutte le specie e, negli attributi, la distribuzione corrispondente. Questo shapefile, posso facilmente dividerlo in diversi shapefile (uno per ogni specie). Alla fine, vorrei avere per ogni specie un'immagine, con, sempre, esattamente la stessa area (Europa), gli stessi colori (ad esempio distribuzioni annuali in verde scuro, riproduzione in verde chiaro, non riproduzione in blu, ecc ...), la stessa leggenda e come titolo il nome della specie.
Onesime,

Penso che ciò che devi fare sia pianificare ogni passaggio che devi compiere per creare ogni mappa, quindi codificare le selezioni e esportare le mappe in Python. So che questo può essere fatto facilmente in ArcGIS Python, ma non so abbastanza sull'interfaccia di QGIS Python per fornire molte indicazioni. Tuttavia, sono sicuro che puoi farlo funzionare con un solo shapefile.
Jay Guarneri,

Ho fatto qualcosa di simile con QGIS usando un plugin Python. Nel mio caso, i miei layer sono stati memorizzati in PostGIS, ma penso che potresti fare qualcosa di simile usando uno shapefile. Sono felice di condividere il mio codice. PM me.
Brian Edmond,

1
Puoi caricare un campione dei tuoi dati con cui possiamo giocare.
Nathan W,

Risposte:


4

Avevo un requisito simile e ho messo insieme un plug-in QGIS per generare le mappe, basato su un file di forma con località punto per tutte le specie (presuppone un nome taxon univoco nella tabella degli attributi come identificatore comune). Le mie esigenze non erano così complesse: non avevo bisogno di informazioni stagionali, titoli o legende, ma potrebbe essere un utile punto di partenza per te. Per gli aspetti più complessi, dovrai utilizzare il compositore di mappe. Vedi il libro di cucina PyQGIS per ulteriori informazioni al riguardo.

Collegare

Il plug-in automatizza la creazione delle mappe e consente di configurare estensioni, risoluzione e altri aspetti. Applica lo stesso stile all'output dell'overlay della griglia. Attualmente funziona solo con la versione di sviluppo di QGIS (1.9 o successiva).

Script Sextante

Prima di creare il plugin, ho elaborato la logica usando SEXTANTE. Questo script utente dovrebbe funzionare anche in 1.8 (non l'ho testato). Il file di stile di distribuzione (.qml) è lo stile delle distribuzioni di output (ignora lo stile dell'overlay di distribuzione). Attualmente posiziona le mappe di output nella directory temp in base alle impostazioni predefinite del sistema operativo (/ tmp in Linux e varie posizioni in Windows, definite dalla variabile ambientale TEMP). Tuttavia, puoi facilmente definirlo nel codice. Sarà inoltre necessario modificare l'estensione e la risoluzione di output nel codice (e il colore di sfondo se si desidera un colore diverso per il mare).

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

Ciao a tutti, grazie per tutte le vostre risposte. Per darti qualche elemento in più, sono i dati provenienti da BirdLife (un esempio per specie: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). In breve, esiste un file di forma con tutti i poligoni per tutte le specie (quindi, per alcune di esse, molte linee per una singola specie) e c'è un attributo che corrisponde alla distribuzione stagionale (con valori da 1 a 5 corrispondenti a usi diversi ), un altro per l'origine ecc. La legenda e il titolo non sono indispensabili.
Onesime

- Uso un livello Paese in background, solo per una posizione semplice. - Per il colore diverso per il valore diverso dall'attributo "stagionale", penso che sia adatto un file .qml di utilizzo. - Opzionalmente, per il titolo e la legenda, penso di dover usare un file dal compositore, se è troppo difficile, posso aggiungerlo con un altro software. - L'operazione deve essere ripetuta per tutte le specie, quindi ciò corrisponde a una selezione per attributo, che verrà utilizzata per dare il nome dell'immagine finale.
Onesime

Ho provato il plug-in "Atlas", ma sembra essere più appropriato per varie località, nel mio caso, è sempre per la stessa area: l'Europa. Ho provato il plug-in "Gestore mappe di distribuzione" che sembra corrispondere in questo punto perché è possibile correggere l'area di copertura, ma non ho bisogno del processo che interseca i punti con un livello griglia poiché ho già un livello poligono. Ho provato in ArcGis, ma è abbastanza lo stesso per il plugin QGis Atlas, la soluzione sembra essere quella di scrivere uno script python ...
Onesime

Quindi penso che userò Sextante, basato sullo script "rudivonstaden" (grazie per questo!) E per adattarlo al mio caso. Infine, mi dispiace per questi diversi commenti, ma c'è un limite al numero di caratteri ...
Onesime

@Onesime, ad eccezione del titolo e della legenda, penso che sarai in grado di adattare lo script sestante sopra per fare ciò di cui hai bisogno. Probabilmente dovrai rimuovere il selectbylocationpassaggio e aggiungere un passaggio aggiuntivo selectbyattributee saveselectedfeaturesper ogni stagione (cambia grid_layerin all_localities). Quindi carica più file .qml e aggiungi aggiungi i tuoi shapefile stagionali (primo strato aggiunto prima). Se non sei sicuro di come, probabilmente potrei provare a modificare lo script sopra per lavorare più o meno.
Rududonstaden

2

Oggi ho impiegato poco tempo per lavorarci su. Quindi ho apportato alcune modifiche alla tua sceneggiatura. Non ho bisogno di aggiungere un ulteriore passaggio di selezione per attributo e salvataggio delle funzioni mentre utilizzo un file .qml e il campo Stagionale è nello stesso file di forma. Di seguito, puoi vedere cosa ho fatto:

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

Se hai qualche commento o consiglio per migliorarlo, non esitare.

Per migliorarlo, il migliore sarebbe quando selezioniamo l'estensione (per esempio l'Europa), questa utilizza per selezionare solo le specie incluse all'interno di questa estensione. Questo, perché ottengo mappe per tutte le specie, anche quelle al di fuori dell'Europa, ad esempio (quindi ho molte mappe vuote). Pensi che sia possibile?

Saluti,

Onesime

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.