Generujesz dużą liczbę map za pomocą PyQGIS?


10

Muszę wykonać dużą liczbę (setki) map rozmieszczenia gatunków. Mam plik kształtu, który zawiera rozkłady dla każdego gatunku, a dla każdego z nich chciałbym uzyskać mapę jako obraz (jpg, png lub inny), który zawiera nazwę danego gatunku, legendę (w celu rozróżnienia obszarów roczne dystrybucje, hodowla, hodowla itp.).

Chciałbym do tego użyć QGIS.


1
Czy możesz podać więcej szczegółów na temat specyfiki map? Na przykład, czy chcesz, aby wszystkie te mapy pokazywały ten sam obszar, jak określony kontynent lub kraj, czy też chcesz, aby zasięg mapy zmieniał się dynamicznie? Czy chcesz też wszystkich podtypów zakresu na jednej mapie, czy są one na wielu mapach? W zależności od tych odpowiedzi Twój problem może być dość prosty lub może wymagać nieco bardziej wyrafinowanego podejścia. Dobrym miejscem do rozpoczęcia poszukiwań jest wtyczka Atlas do GIS, a jeśli masz ArcGIS 10 lub nowszy, pomocne będą również mapy ESRI.
Jay Guarneri

1
Przepraszamy za brak szczegółów. Tak dla wszystkich map, będzie to ten sam obszar (Europa). Mam jeden plik kształtu ze wszystkimi gatunkami i, w atrybutach, odpowiedni rozkład. Ten plik kształtu mogę łatwo podzielić na różne pliki kształtu (po jednym dla każdego gatunku). Na koniec chciałbym mieć dla każdego gatunku jedno zdjęcie, za każdym razem dokładnie ten sam obszar (Europa), te same kolory (na przykład roczne rozkłady w kolorze ciemnozielonym, hodowla w jasnozielonym, nie rozmnażanie w niebieski itp.), ta sama legenda i jako tytuł nazwa gatunku.
Onesime

Myślę, że musisz zaplanować każdy krok, aby wykonać każdą mapę, a następnie zakodować wybrane opcje i eksportować mapy w Pythonie. Wiem, że można to łatwo zrobić w ArcGIS Python, ale nie wiem wystarczająco dużo o interfejsie QGIS Python, aby dać wiele wskazówek. Jestem jednak pewien, że możesz to zrobić za pomocą jednego pliku kształtu.
Jay Guarneri

Z QGIS zrobiłem coś podobnego, używając wtyczki Python. W moim przypadku moje warstwy były przechowywane w PostGIS, ale myślę, że możesz zrobić coś podobnego za pomocą pliku kształtu. Z przyjemnością udostępniam mój kod. PM do mnie.
Brian Edmond

1
Czy możesz przesłać próbkę swoich danych, abyśmy mogli się nimi bawić?
Nathan W

Odpowiedzi:


4

Miałem podobne wymaganie i stworzyłem wtyczkę QGIS do generowania map w oparciu o plik kształtu z lokacjami punktowymi dla wszystkich gatunków (przyjmuje on unikalną nazwę taksonu w tabeli atrybutów jako wspólny identyfikator). Moje wymagania nie były tak skomplikowane - nie potrzebowałem sezonowych informacji, tytułów ani legend, ale może to być przydatny punkt wyjścia. W przypadku bardziej złożonych aspektów konieczne będzie skorzystanie z narzędzia do tworzenia map. Więcej informacji na ten temat zawiera książka kucharska PyQGIS .

Podłącz

Wtyczka automatyzuje tworzenie map i pozwala konfigurować zakresy, rozdzielczość i inne aspekty. Stosuje ten sam styl do wydruku, co nakładka siatki. Obecnie działa tylko w wersji rozwojowej QGIS (1.9 lub nowszej).

Skrypt Sextante

Przed stworzeniem wtyczki opracowałem logikę za pomocą SEXTANTE. Ten skrypt użytkownika powinien również działać w wersji 1.8 (nie testowałem go). Plik stylu dystrybucji (.qml) to styl dystrybucji danych wyjściowych (ignoruje styl nakładki dystrybucji). Obecnie umieszcza mapy wyników w katalogu temp w oparciu o wartości domyślne systemu operacyjnego (/ tmp w systemie Linux i różne miejsca w systemie Windows - zdefiniowane przez zmienną środowiskową TEMP). Możesz jednak dość łatwo to zdefiniować w kodzie. Będziesz także musiał edytować zakres i rozdzielczość wyjściową w kodzie (i kolor tła, jeśli chcesz inny kolor dla morza).

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

Cześć wszystkim, dziękuję za wszystkie odpowiedzi. Aby dać ci więcej elementów, są to dane pochodzące z BirdLife (przykład dla gatunku: birdlife.org/datazone/speciesfactsheet.php?id=2794 ). W skrócie, istnieje jeden plik kształtu ze wszystkimi wielokątami dla wszystkich gatunków (więc dla niektórych z nich wiele linii dla jednego gatunku), i istnieje atrybut, który odpowiada rozkładowi sezonowemu (z wartościami od 1 do 5 odpowiadającymi różnym zastosowaniom ), jeden inny dla pochodzenia itp. Legenda i tytuł nie są niezbędne.
Onesime

- Używam warstwy kraju w tle, tylko dla łatwej lokalizacji. - Dla innego koloru dla innej wartości niż atrybut „sezonowy”, myślę, że do tego odpowiedni jest plik .qml. - Opcjonalnie, jeśli chodzi o tytuł i legendę, myślę, że muszę użyć pliku od kompozytora, jeśli jest zbyt trudny, mogę dodać go z innym oprogramowaniem. - Operację należy powtórzyć dla wszystkich gatunków, więc odpowiada to selekcji według atrybutu, która zostanie użyta do nadania nazwy ostatecznego zdjęcia.
Onesime

Próbowałem wtyczki „Atlas”, ale wydaje się, że jest bardziej odpowiednia dla różnych lokalizacji, w moim przypadku jest to cały czas dla tego samego obszaru: Europy. Wypróbowałem wtyczkę „Menedżer mapy dystrybucji”, która wydaje się odpowiadać w tym punkcie, ponieważ można naprawić obszar pokrycia, ale nie potrzebuję procesu, który przecina punkty z warstwą siatki, ponieważ mam już warstwę wielokąta. Próbowałem w ArcGis, ale jest tak samo w przypadku wtyczki QGis Atlas, wydaje się, że rozwiązaniem jest napisanie skryptu python ...
Onesime

Myślę więc, że użyję Sextante, opartego na skrypcie „rudivonstaden” (dziękuję za to!) I dostosuję go do mojego przypadku. Na koniec przepraszam za te różne komentarze, ale istnieje limit liczby znaków ...
Onesime

@Onesime, oprócz tytułu i legendy, myślę, że będziesz w stanie dostosować powyższy skrypt sextante, aby zrobić to, czego potrzebujesz. Trzeba będzie prawdopodobnie usunąć selectbylocationkrok i dodać dodatkowy selectbyattributei saveselectedfeatureskrok dla każdego sezonu (zmiana grid_layercelu all_localities). Następnie załaduj więcej plików .qml i dodaj dołącz sezonowe pliki kształtów (pierwsza warstwa dołączana jako pierwsza). Jeśli nie masz pewności, jak to zrobić, prawdopodobnie mógłbym spróbować zmodyfikować powyższy skrypt, by mniej więcej działał.
rudivonstaden

2

Pracowałem dziś nad tym trochę czasu. Wprowadziłem więc kilka zmian w twoim skrypcie. Nie muszę dodawać dodatkowego kroku selectbyattribute i saveselectedfeatures, ponieważ używam plików .qml, a pole Seasonal znajduje się w tym samym pliku kształtu. Poniżej możesz zobaczyć, co zrobiłem:

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

Jeśli masz jakieś uwagi lub porady, aby je poprawić, nie wahaj się.

Aby to poprawić, najlepiej byłoby, gdybyśmy wybrali zakres (na przykład w Europie), wykorzystują ten zakres, aby wybrać tylko gatunki objęte tym zakresem. To dlatego, że otrzymuję mapy dla wszystkich gatunków, nawet tych, które są na przykład poza Europą (więc mam wiele pustych map). Czy uważasz, że to możliwe?

Twoje zdrowie,

Onesime

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.