Rastere ein Shapefile mit Geopandas oder Fiona - Python


10

Ich muss ein wirklich einfaches Shapefile ein bisschen wie dieses http://tinyurl.com/odfbanu rastern . Welches ist nur ein Shapefile, das Counties in den USA umfasst. Ich habe diese vorherige Antwort gesehen: GDAL RasterizeLayer brennt nicht alle Polygone zu Raster? aber ich habe mich gefragt, ob es eine Möglichkeit gibt, dies mit Geopandas oder Fiona und vielleicht Rasterio für den Tiff-Schreibteil zu tun.

Mein Ziel ist es also, es zu rastern und jedem Polygon, das einen gemeinsamen Wert, LSAD im Beispiel, teilt, einen Wert zuzuweisen.

Also schrieb ich den Anfang des von Shongololo inspirierten Codes in den Thread: Auflösen von Polygonen basierend auf Attributen mit Python (Shapely, Fiona)? .

from geopandas import GeoDataFrame

name_in = 'cb_2013_us_county_20m.shp'

#Open the file with geopandas
counties = GeoDataFrame.from_file(name_in)

#Add a column to the Geodataframe containing the new value
for i in range (len(counties)):
    LSAD = counties.at[i,'LSAD']
    if LSAD == 00 :
        counties['LSAD_NUM'] == 'A'
    elif LSAD == 03 :
        counties['LSAD_NUM'] == 'B'
    elif LSAD == 04 :
        counties['LSAD_NUM'] == 'C'
    elif LSAD == 05 :
        counties['LSAD_NUM'] == 'D'
    elif LSAD == 06 :
        counties['LSAD_NUM'] == 'E'
    elif LSAD == 13 :
        counties['LSAD_NUM'] == 'F'
    elif LSAD == 15 :
        counties['LSAD_NUM'] == 'G'  
    elif LSAD == 25 :
        counties['LSAD_NUM'] == 'I'          
    else :
        counties['LSAD_NUM'] == 'NA'

Wirklich einfaches Zeug, also frage ich mich jetzt, wie ich diese Formen tatsächlich auf einen Tiff schreiben kann. Ich begann mit Geopandas zu arbeiten, da ich glaubte, dass dies die beste Option sei, aber wenn Sie einen Fiona-Vorschlag haben, bin ich auch dazu bereit.

Ich habe einen Code von rasterio gefunden, der in der Lage zu sein scheint, eine formschöne Geometrie in ein neues Raster zu brennen http://tinyurl.com/op49uek

# I guess that my goal should be to load my list of geometries under geometry to be able to pass it to rasterio later on
geometry = {'type':'Polygon','coordinates':[[(2,2),(2,4.25),(4.25,4.25),(4.25,2),(2,2)]]}

with rasterio.drivers():
    result = rasterize([geometry], out_shape=(rows, cols))
    with rasterio.open(
            "test.tif",
            'w',
            driver='GTiff',
            width=cols,
            height=rows,
            count=1,
            dtype=numpy.uint8,
            nodata=0,
            transform=IDENTITY,
            crs={'init': "EPSG:4326"}) as out:
                 out.write_band(1, result.astype(numpy.uint8))

Die Antwort bezieht sich auf GDALrasterize. Ich frage genau, ob jemand eine Idee hat, dasselbe mit Geopandas und Rasterio zu tun. Kein Duplikat
User18981898198119

Fand einen Code, der helfen könnte, post bearbeitet
User18981898198119

Antworten:


19

Sie sind auf dem richtigen Weg und der Geopandas GeoDataFrame ist eine gute Wahl für die Rasterung über Fiona. Fiona ist ein großartiges Toolset, aber ich denke, dass der DataFrame besser für Shapefiles und Geometrien geeignet ist als verschachtelte Wörterbücher.

import geopandas as gpd
import rasterio
from rasterio import features

Richten Sie Ihre Dateinamen ein

shp_fn = 'cb_2013_us_county_20m.shp'
rst_fn = 'template_raster.tif'
out_fn = './rasterized.tif'

Öffnen Sie die Datei mit GeoPANDAS read_file

counties = gpd.read_file(shp_fn)

Fügen Sie die neue Spalte hinzu (wie in Ihrem obigen Code)

for i in range (len(counties)):
    LSAD = counties.at[i,'LSAD']
    if LSAD == 00 :
        counties['LSAD_NUM'] == 'A'
    elif LSAD == 03 :
        counties['LSAD_NUM'] == 'B'
    elif LSAD == 04 :
        counties['LSAD_NUM'] == 'C'
    elif LSAD == 05 :
        counties['LSAD_NUM'] == 'D'
    elif LSAD == 06 :
        counties['LSAD_NUM'] == 'E'
    elif LSAD == 13 :
        counties['LSAD_NUM'] == 'F'
    elif LSAD == 15 :
        counties['LSAD_NUM'] == 'G'  
    elif LSAD == 25 :
        counties['LSAD_NUM'] == 'I'          
    else :
        counties['LSAD_NUM'] == 'NA'

Öffnen Sie die Rasterdatei, die Sie als Vorlage für das Brennen von Features mit Rasterio verwenden möchten

rst = rasterio.open(rst_fn)

Kopieren und aktualisieren Sie die Metadaten aus dem Eingabe-Raster für die Ausgabe

meta = rst.meta.copy()
meta.update(compress='lzw')

Brennen Sie nun die Features in das Raster und schreiben Sie es aus

with rasterio.open(out_fn, 'w+', **meta) as out:
    out_arr = out.read(1)

    # this is where we create a generator of geom, value pairs to use in rasterizing
    shapes = ((geom,value) for geom, value in zip(counties.geometry, counties.LSAD_NUM))

    burned = features.rasterize(shapes=shapes, fill=0, out=out_arr, transform=out.transform)
    out.write_band(1, burned)

Die Gesamtidee besteht darin, ein iterables Element zu erstellen, das Tupel von (Geometrie, Wert) enthält, wobei die Geometrie eine formschöne Geometrie ist und der Wert das ist, was Sie an der Position dieser Geometrie in das Raster einbrennen möchten. Sowohl Fiona als auch GeoPANDAS verwenden formschöne Geometrien, sodass Sie dort Glück haben. In diesem Beispiel wird ein Generator verwendet, um die (Geometrie-, Wert-) Paare zu durchlaufen, die aus dem GeoDataFrame extrahiert und mit zip () zusammengefügt wurden.

Stellen Sie sicher, dass Sie die out_fnDatei im w+Modus öffnen , da sie zum Lesen und Schreiben verwendet werden muss.


1

geocube ist ein neues Tool, das speziell für die Rasterung von Geopandadaten entwickelt wurde, die Rasterio umschließen. Dies vereinfacht den Prozess und macht ein Vorlagenraster überflüssig.

https://github.com/corteva/geocube

Im Zusammenhang mit dem obigen Beispiel:

from geocube.api.core import make_geocube
import geopandas

counties = geopandas.read_file("zip://cb_2013_us_county_20m.zip/cb_2013_us_county_20m.shp")

Der Buchstabe kann wie folgt auf dem Datenrahmen eingestellt werden:

counties["LSAD_LETTER"] = 'NA'
lsad_letter = counties.LSAD_LETTER.copy()
lsad_letter[counties.LSAD=='00'] = 'A'
lsad_letter[counties.LSAD=='03'] = 'B'
lsad_letter[counties.LSAD=='04'] = 'C'
lsad_letter[counties.LSAD=='05'] = 'D'
lsad_letter[counties.LSAD=='06'] = 'E'
lsad_letter[counties.LSAD=='13'] = 'F'
lsad_letter[counties.LSAD=='15'] = 'G'
lsad_letter[counties.LSAD=='25'] = 'I'
counties["LSAD_LETTER"] = lsad_letter

Es können jedoch nur numerische Werte gerastert werden. Hier ist ein kategorisches Beispiel: https://corteva.github.io/geocube/stable/examples/categorical.html

Verwenden Sie stattdessen die Zahlen im Zeichenfolgenformat und konvertieren Sie sie in Ganzzahlen:

counties["LSAD_NUM"] = counties.LSAD.astype(int)

Rasteren Sie dann die Daten:

cube = make_geocube(
    counties,
    measurements=["LSAD_NUM"],
    resolution=(1, -1),
)

Geben Sie hier die Bildbeschreibung ein

Zuletzt exportieren Sie es in ein Raster:

cube.LSAD_NUM.rio.to_raster("lsad_num.tif")
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.