Gerando grande número de mapas usando o PyQGIS?

10

Eu tenho que fazer um grande número (centenas) de mapas de distribuição de espécies. Eu tenho um shapefile que contém as distribuições de cada espécie e, para cada uma, gostaria de obter um mapa como uma imagem (jpg, png ou outra) que contenha o nome da espécie em questão, a legenda (para distinguir áreas de distribuições anuais, criação, não criação, etc. ...).

Eu gostaria de usar o QGIS para fazer isso.

Onesime
fonte
1
Você poderia especificar um pouco mais sobre as especificidades dos mapas? Por exemplo, você deseja que todos esses mapas mostrem a mesma área, como um continente ou país específico, ou deseja que a extensão do mapa mude dinamicamente? Além disso, você deseja todos os subtipos de intervalo em um mapa ou eles estão em vários mapas? Dependendo dessas respostas, seu problema pode ser bastante simples ou exigir uma abordagem mais sofisticada. Um bom lugar para começar a procurar é o plug-in Atlas para GIS, ou se você tiver o ArcGIS 10 ou superior disponível, os livros de mapas da ESRI também ajudarão.
Jay Guarneri
1
Desculpe pela falta de detalhes. Sim para todos os mapas, será a mesma área (Europa). Eu tenho um shapefile com todas as espécies e, nos atributos, a distribuição correspondente. Esse arquivo de forma, eu posso facilmente dividi-lo em diferentes arquivos de forma (um para cada espécie). No final, gostaria de ter para cada espécie uma foto, com, a cada vez, exatamente a mesma área (Europa), as mesmas cores (por exemplo, distribuições anuais em verde escuro, reprodução em verde claro, sem reprodução em azul, etc. ...), a mesma legenda e, como título, o nome da espécie.
Onesime 22/02
Eu acho que o que você precisa fazer é planejar cada passo que você precisa executar para criar cada mapa, depois codificar as seleções e mapear as exportações no Python. Sei que isso pode ser feito facilmente no ArcGIS Python, mas não sei o suficiente sobre a interface do QGIS Python para dar muita orientação. No entanto, estou confiante de que você pode fazer isso funcionar com um shapefile.
Jay Guarneri
Eu fiz algo semelhante com o QGIS usando um plugin Python. No meu caso, minhas camadas foram armazenadas no PostGIS, mas acho que você poderia fazer algo semelhante usando um shapefile. Fico feliz em compartilhar meu código. PM me.
Brian Edmond
1
Você pode enviar uma amostra dos seus dados para brincarmos?
22713 Nathan W

Respostas:

4

Eu tinha um requisito semelhante e montei um plug-in QGIS para gerar os mapas, com base em um shapefile com localidades de pontos para todas as espécies (ele assume um nome de taxon exclusivo na tabela de atributos como identificador comum). Meus requisitos não eram tão complexos - eu não precisava de informações, títulos ou legendas sazonais, mas pode ser um ponto de partida útil para você. Para os aspectos mais complexos, você precisará usar o compositor de mapas. Veja o livro de receitas do PyQGIS para mais informações.

Plugar

O plug-in automatiza a criação dos mapas e permite configurar extensões, resolução e outros aspectos. Aplica o mesmo estilo à saída que a sobreposição da grade. Atualmente, ele é executado apenas na versão de desenvolvimento do QGIS (1.9 ou posterior).

Script Sextante

Antes de criar o plugin, elaborei a lógica usando o SEXTANTE. Este script de usuário também deve funcionar no 1.8 (não o testou). O arquivo de estilo de distribuição (.qml) é o estilo das distribuições de saída (ignora o estilo da sobreposição de distribuição). Atualmente, ele coloca os mapas de saída no diretório temp com base nos padrões do sistema operacional (/ tmp no Linux e em vários locais no Windows - definidos pela variável de ambiente TEMP). Você pode facilmente definir isso no código. Você também precisará editar a extensão e a resolução de saída no código (e a cor do plano de fundo, se desejar uma cor diferente para o 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
fonte
Olá a todos, Obrigado por todas as suas respostas. Para fornecer mais alguns elementos, são dados provenientes do BirdLife (um exemplo para a espécie: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). Resumidamente, existe um arquivo shapefile com todos os polígonos para todas as espécies (portanto, para algumas delas, muitas linhas para uma única espécie), e existe um atributo que corresponde à distribuição sazonal (com valores de 1 a 5 correspondentes a diferentes usos). ), outro para a origem etc. A legenda e o título não são indispensáveis.
Onesime 13/03
- Eu uso uma camada de país em segundo plano, apenas para uma localização fácil. - Para a cor diferente para o valor diferente do atributo "sazonal", acho que para isso, um arquivo .qml de uso é adequado. - Opcionalmente, para o título e a legenda, acho que tenho que usar um arquivo do compositor, se for muito difícil, posso adicioná-lo com outro software. - A operação deve ser repetida para todas as espécies, portanto, isso corresponde a uma seleção por atributo, que será usada para dar o nome da imagem final.
Onesime 13/03
Eu tentei o plugin "Atlas", mas parece ser mais apropriado para vários locais, no meu caso, está o tempo todo na mesma área: Europa. Eu tentei o plugin "Distribution map manager", que parece corresponder neste ponto, porque é possível corrigir a área de cobertura, mas não preciso do processo que cruza os pontos com uma camada de grade, pois já tenho uma camada de polígono. Tentei no ArcGis, mas é bem a mesma coisa para o plugin qgis Atlas, a solução parece ser a de escrever um script python ...
Onesime
Então, acho que vou usar o Sextante, com base no script "rudivonstaden" (obrigado por isso!) E para adaptá-lo ao meu caso. Finalmente, Desculpe por estes diferentes comentários, mas há um limite de número de caracteres ...
Onesime
@Onesime, exceto pelo título e pela legenda, acho que você poderá adaptar o script sextante acima para fazer o que você precisa. Você precisará provavelmente remover a selectbylocationpasso, e adicionar um adicional selectbyattributee saveselectedfeaturespasso para cada temporada (mudança grid_layerde all_localities). Em seguida, carregue mais arquivos .qml e adicione anexos aos seus shapefiles sazonais (camada superior anexada primeiro). Se você não tiver certeza de como, provavelmente poderia tentar editar o script acima para um trabalho mais ou menos.
Rudivonstaden
2

Levei pouco tempo para trabalhar nisso hoje. Então, eu fiz algumas alterações no seu script. Não preciso adicionar uma etapa adicional de seleção por atributo e salvar recursos selecionados, pois uso arquivos .qml e o campo Sazonal está no mesmo arquivo de forma. Abaixo, você pode ver o que eu fiz:

#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 você tiver algum comentário ou conselho para melhorá-lo, não hesite.

Para melhorá-lo, o melhor seria quando selecionássemos a extensão (por exemplo, Europa), use essa extensão para selecionar apenas as espécies incluídas nessa extensão. Isso porque eu obtenho mapas para todas as espécies, mesmo aquelas que estão fora da Europa, por exemplo (então eu tenho muitos mapas vazios). Você acha que é possível?

Felicidades,

Onesime

Onesime
fonte