This section introduces geospatial analysis of shapefiles with gdal, ogr, and osr. For interactive reading and executing code blocks and find geo01-shp.ipynb, or install Python and JupyterLab locally.
Watch this section and the Python tutorials in video formats
Watch this section as a video on the @Hydro-Morphodynamics channel on YouTube.
Laden Sie eine bestehende Shapefile¶
OSGeo’s ogr module is an excellent source for handling shapefiles. After importing the libraries, the correct driver for handling shapefiles ("ESRI Shapefile") with Python needs to be called. Next, with the driver object (ogr.GetDriverByName("SHAPEFILE")), we can open (instantiate) a shapefile (object with shp_driver.Open("SHAPEFILE")), which contains layer information. It is precisely the layer information (i.e., references to shapefile attributes) that we want to work with. Therefore we have to instantiate a shapefile layer object with shp_dataset.GetLayer().
from osgeo import ogr
shp_driver = ogr.GetDriverByName("ESRI Shapefile")
shp_dataset = shp_driver.Open("geodata/shapefiles/cities.shp")
shp_layer = shp_dataset.GetLayer()Erstellen Sie eine neue Formdatei¶
ogr ermöglicht auch eine neue Punkt-, Zeilen- oder Polygonformdatei zu erstellen. Der folgende Codeblock definiert eine Funktion zur Erstellung einer Formdatei, wobei das optionale Keyword-Argument overwrite verwendet wird, um zu kontrollieren, ob eine bestehende Formdatei mit dem gleichen Namen überschrieben werden soll (Standard: True).
Der Befehl shp_driver.CreateDataSource(SHP-FILE-DIR) erstellt eine neue Formdatei und der Rest der Funktion fügt der Formdatei eine Schicht hinzu, wenn die optionalen Keyword-Argumente layer_name und layer_type bereitgestellt werden. Beide optionalen Schlüsselwörter müssen strings sein, wobei layer_name für die neue Schicht jeder Name sein kann. layer_type muss entweder "point", "line" oder "polygon" sein, um einen Punkt, (Poly)line oder Polygon formfile zu erstellen. Die Funktion verwendet den geometry_dict dictionary, um der Schicht den richtigen ogr.SHP-TYPE zuzuordnen. Weitere Optionen zur Erweiterung der create_shp(...)-Funktion finden Sie unter pcjericks’ Github page.
from osgeo import ogr
import os
def create_shp(shp_file_dir, overwrite=True, *args, **kwargs):
"""
:param shp_file_dir: STR of the (relative shapefile directory (ends on ".shp")
:param overwrite: [optional] BOOL - if True, existing files are overwritten
:kwarg layer_name: [optional] STR of the layer_name - if None: no layer will be created (max. 13 chars)
:kwarg layer_type: [optional] STR ("point, "line", or "polygon") of the layer_name - if None: no layer will be created
:output: returns an ogr shapefile layer
"""
shp_driver = ogr.GetDriverByName("ESRI Shapefile")
# check if output file exists if yes delete it
if os.path.exists(shp_file_dir) and overwrite:
shp_driver.DeleteDataSource(shp_file_dir)
# create and return new shapefile object
new_shp = shp_driver.CreateDataSource(shp_file_dir)
# create layer if layer_name and layer_type are provided
if kwargs.get("layer_name") and kwargs.get("layer_type"):
# create dictionary of ogr.SHP-TYPES
geometry_dict = {"point": ogr.wkbPoint,
"line": ogr.wkbMultiLineString,
"polygon": ogr.wkbMultiPolygon}
# create layer
try:
new_shp.CreateLayer(str(kwargs.get("layer_name")),
geom_type=geometry_dict[str(kwargs.get("layer_type").lower())])
except KeyError:
print("Error: Invalid layer_type provided (must be 'point', 'line', or 'polygon').")
except TypeError:
print("Error: layer_name and layer_type must be string.")
except AttributeError:
print("Error: Cannot access layer - opened in other program?")
return new_shpThe create_shp function is also provided with flusstools (flusstools.geotools.create_shp()) and aids to create a new shapefile (make sure to get the directory right):
a_new_shp_file = create_shp(r"" + os.getcwd() + "/geodata/shapefiles/new_polygons.shp", layer_name="basemap", layer_type="polygon")
# release data source
a_new_shape_file = NoneShapefiles können auch in QGIS erstellt und gezeichnet werden und die folgenden Figuren führen durch die Prozedur der Erstellung einer Polygon-Formdatei. Wir brauchen nicht mehr die resultierende Formdatei in diesem Abschnitt, sondern später, damit sie mit Rasterdatensätzen interagiert.
The first step to making a shapefile with QGIS is obviously to run QGIS and create a new project. The following example uses water depth and flow velocity raster data as background information to delineate the so-called morphological unit of slackwater. Both the water depth and flow velocity rasters are part of the River Architect sample datasets (precisely located at RiverArchitect/SampleData/01_Conditions/2100_sample/). After downloading the sample data, they can be imported in QGIS by dragging the files from the Browser panel into the Layers panel. Then:

Figure 1:QGIS: Erstellen von Ebenen > Neue Formdateiebene...

Figure 2:Neue Formdateiebene definieren

Figure 3:Formdatei bearbeiten aktivieren

Figure 4:Zeichne Polygone in einer Formdatei in QGIS.
Holen Sie sich und setzen Sie Shapefile-Projektionen¶
Die in den .prj-Dateien einer Formdatei verwendete Terminologie entspricht den Definitionen im Abschnitt geospatial data. In Python erhalten Sie Informationen über das Koordinatensystem unter shp_layer.GetSpatialRef() der ogr Bibliothek:
shp_srs = shp_layer.GetSpatialRef()
print(shp_srs)GEOGCS["WGS 84",
DATUM["WGS_1984",
SPHEROID["WGS 84",6378137,298.257223563,
AUTHORITY["EPSG","7030"]],
AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
AUTHORITY["EPSG","9122"]],
AXIS["Latitude",NORTH],
AXIS["Longitude",EAST],
AUTHORITY["EPSG","4326"]]
Diese GEOGCS-Definition der obigen Formdatei entspricht Esri’s well-known Text (WKT). Da das Formdateiformat von Esri entwickelt wurde, muss esris WKT (esriwkt) Format in .prj Dateien verwendet werden. Das Open Geospatial Consortium (OGC) verwendet einen anderen bekannten Text in ihren EPSG:XXXXDefinitionen (z.B. erhältlich unter spatialreference
GEOGCS["WGS 84",
DATUM["WGS_1984", SPHEROID["WGS84", 6378137, 298.257223563, AUTHORITY["EPSG", "7030"]], AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich", 0, AUTHORITY["EPSG", "8901"]],
UNIT["degree",0.01745329251994328, AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]Um das Koordinatensystem einer Formdatei neu definieren oder neu definieren zu können, können wir spatialreferenceurllibbibliothek verwenden.
import urllib
# function to get spatialreferences with epsg code
def get_esriwkt(epsg):
# usage get_epsg_code(4326)
try:
with urllib.request.urlopen("https://spatialreference.org/ref/epsg/{0}/esriwkt/".format(epsg)) as response:
return str(response.read()).strip("b").strip("'")
except Exception:
pass
try:
with urllib.request.urlopen("https://spatialreference.org/ref/sr-org/epsg{0}-wgs84-web-mercator-auxiliary-sphere/esriwkt/".format(epsg)) as response:
return str(response.read()).strip("b").strip("'")
# sr-org codes are available at "https://spatialreference.org/ref/sr-org/{0}/esriwkt/".format(epsg)
# for example EPSG:3857 = SR-ORG:6864 -> https://spatialreference.org/ref/sr-org/6864/esriwkt/ = EPSG:3857
except Exception:
print("ERROR: Could not find epsg code on spatialreference.org. Returning default WKT(epsg=4326).")
return 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295],UNIT["Meter",1]]'Diese Funktion kann verwendet werden, um eine neue Projektionsdatei zu erstellen:
# open the hypy-area shapefile
shp_file = "hypy-area"
# create new .prj file for the shapefile (.shp and .prj must have the same name)
with open("geodata/shapefiles/{0}.prj".format(shp_file), "w") as prj:
epsg_code = get_esriwkt(4326)
prj.write(epsg_code)
print("Wrote projection file : " + epsg_code)Wrote projection file : GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
Eine Offline-Alternative zur Generierung einer .prj-Datei ist die osr-Bibliothek, die zusammen mit gdal:
from osgeo import osr
def get_wkt(epsg, wkt_format="esriwkt"):
default = 'GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295],UNIT["Meter",1]]'
spatial_ref = osr.SpatialReference()
try:
spatial_ref.ImportFromEPSG(epsg)
except TypeError:
print("ERROR: epsg must be integer. Returning default WKT(epsg=4326).")
return default
except Exception:
print("ERROR: epsg number does not exist. Returning default WKT(epsg=4326).")
return default
if wkt_format=="esriwkt":
spatial_ref.MorphToESRI()
# return a nicely formatted WKT string (alternatives: ExportToPCI(), ExportToUSGS(), or ExportToXML())
return spatial_ref.ExportToPrettyWkt()Transformieren (Re-Projekt) a Shapefile¶
Eine Re-Projektion kann beispielsweise erforderlich sein, um eine Formdatei in EPSG:4326 (z.B. mit QGIS erstellt) in einer Web-GIS-Anwendung (z.B. offene Straßenkarten) zu verwenden, die typischerweise EPSG:3857 verwendet. Um eine andere Projektion auf geometrische Objekte einer Formdatei anzuwenden, reicht es nicht aus, die .prj-Datei einfach neu zu schreiben. Das folgende Beispiel zeigt daher die Neuprojektion der countries.shp formfile aus der Natural Earth quick start kit. Der folgende Workflow führt die Reprojektion durch:
Die zu transformierende Formdatei befindet sich im Unterverzeichnis
geodata/shapefiles/countries.shpund öffnet sie wie oben beschrieben im Python-Skript.Lesen und identifizieren Sie das räumliche Referenzsystem in der Eingabeformdatei:
Erstellen Sie ein räumliches Referenzobjekt mit
in_sr = osr.SpatialReference(str(shapefile.GetSpatialRef())).Erkennen Sie das räumliche Referenzsystem im EPSG-Format mit
AutoIdentifyEPSG().Zuordnen des EPSG-formatierten räumlichen Referenzsystems an das räumliche Referenzobjekt der Eingabeformdatei (
ImportFromEPSG(int(in_sr.GetAuthorityCode(None)))).
Erstellen Sie die Ausgaberaumreferenz mit
out_sr = osr.SpatialReference()und wenden Sie den Ziel-EPSG-Code an (out_sr.ImportFromEPSG(3857)).Erstellen Sie ein Koordinatentransformationsobjekt (
coord_trans = osr.CoordinateTransformation(in_sr, out_sr)), das später eine Neuprojektierung von Geometrieobjekten ermöglicht.Erstellen Sie die Ausgabeformdatei, die einer Kopie der Eingabeformdatei entspricht (verwenden Sie die oben definierte
create_shpFunktion mitlayer_name="basemap"undlayer_type="line").Kopieren Sie die Feldnamen und Typen der Eingabeformdatei:
Lesen Sie die Attributschicht aus den Layer Definitionen der Eingabedatei mit
in_lyr_def = in_shp_lyr.GetLayerDefn()Iterate durch die Felddefinitionen und an die Ausgabeformfile-Schicht anhängen (
out_shp_lyr)
Iterate durch die Geometriemerkmale in der Eingabeformdatei:
Verwenden Sie die Layer-Definitionen der neuen (Output-)Formdatei (
out_shp_lyr_def = out_shp_lyr.GetLayerDefn()) um transformierte Geometrieobjekte später anzuhängen.Definieren Sie eine Iterationsvariable
in_featureals Instanz vonin_shp_lyr.GetNextFeature.In einer
while-Schleife wandeln Sie jede Geometrie (geometry = in_feature.GetGeometryRef()) in der Eingabeformdatei um, wandeln Sie diegeometry(geometry.Transform(coord_trans)) in eineogr.Feature()mit derSetGeometry(geometry)-Methode, kopieren Sie Felddefinitionen (nästedfor-loop) um und fügen Sie die neue Funktion an die Ausgabeformfile-Schicht (out_shp_lyr_def.CreateFeature(out_feature).Am Ende des
while-loop suchen Sie das nächste Feature in den Attributen der Eingabeformdatei mitin_feature = in_shp_lyr.GetNextFeature()
Entsperren Sie alle Schichten und Formdateien, indem Sie die Objekte mit
Noneüberschreiben (Nichts wird in jede Datei geschrieben, solange diese Variablen existieren!).Senden Sie die neue Projektion EPSG:3857 mit der oben definierten
get_wktFunktion.
from osgeo import ogr
from osgeo import osr
shp_driver = ogr.GetDriverByName("ESRI Shapefile")
# open input shapefile and layer
in_shp = shp_driver.Open(r"" + os.path.abspath("") + "/geodata/shapefiles/countries.shp")
in_shp_lyr = in_shp.GetLayer()
# get input SpatialReference
in_sr = osr.SpatialReference(str(in_shp_lyr.GetSpatialRef()))
# auto-detect epsg
in_sr.AutoIdentifyEPSG()
# assign input SpatialReference
in_sr.ImportFromEPSG(int(in_sr.GetAuthorityCode(None)))
# create SpatialReference for new shapefile
out_sr = osr.SpatialReference()
out_sr.ImportFromEPSG(3857)
# create a CoordinateTransformation object
coord_trans = osr.CoordinateTransformation(in_sr, out_sr)
# create output shapefile and get layer
out_shp = create_shp(r"" + os.path.abspath("") + "/geodata/shapefiles/countries-web.shp", layer_name="basemap", layer_type="line")
out_shp_lyr = out_shp.GetLayer()
# look up layer (features) definitions in input shapefile
in_lyr_def = in_shp_lyr.GetLayerDefn()
# copy field names of input layer attribute table to output layer
for i in range(0, in_lyr_def.GetFieldCount()):
out_shp_lyr.CreateField(in_lyr_def.GetFieldDefn(i))
# instantiate feature definitions object for output layer (currently empty)
out_shp_lyr_def = out_shp_lyr.GetLayerDefn()
# iteratively append all input features in new projection
in_feature = in_shp_lyr.GetNextFeature()
while in_feature:
# get the input geometry
geometry = in_feature.GetGeometryRef()
# re-project (transform) geometry to new system
geometry.Transform(coord_trans)
# create new output feature
out_feature = ogr.Feature(out_shp_lyr_def)
# assign in-geometry to output feature and copy field values
out_feature.SetGeometry(geometry)
for i in range(0, out_shp_lyr_def.GetFieldCount()):
out_feature.SetField(out_shp_lyr_def.GetFieldDefn(i).GetNameRef(), in_feature.GetField(i))
# add the feature to the shapefile
out_shp_lyr.CreateFeature(out_feature)
# prepare next iteration
in_feature = in_shp_lyr.GetNextFeature()
# release shapefiles and layers
in_shp = None
in_shp_lyr = None
out_shp = None
out_shp_lyr = None
# create .prj file for output shapefile for web application references
with open(r"" + os.path.abspath('') + "/geodata/shapefiles/countries-web.prj", "w+") as prj:
prj.write(get_wkt(3857))In the case of success, the code sequence in_sr.AutoIdentifyEPSG() returns 0 (i.e., it successfully recognized the EPSG number), but unfortunately, many EPSG numbers are not known to AutoIdentifyEPSG(). In the case that AutoIdentifyEPSG() did not function properly, the method does not return 0, but 7, for example. A workaround for the limited functionality of srs.AutoIdentifyEPSG() is srs.FindMatches. srs.FindMatches returns a matching srs_match from a larger database, which is somewhat nested; for instance, use:
matches = srs.FindMatches()Dann sieht matches so aus: [(osgeo.osr.SpatialReference, INT)]. So sieht ein kompletter Workaround für srs.AutoIdentifyEPSG() (oder in_sr.AutoIdentifyEPSG() im obigen Codeblock) so aus:
# set epsg and create spatial reference object
epsg = 3857
srs = osr.SpatialReference()
srs.ImportFromEPSG(epsg)
# identify spatial reference
auto_detect = srs.AutoIdentifyEPSG()
if auto_detect != 0:
srs = srs.FindMatches()[0][0] # Find matches returns list of tuple of SpatialReferences
srs.AutoIdentifyEPSG() # Re-perform auto-identificationFügen Sie Fields und Point Features zu einer Shapefile hinzu¶
Ein Shapefile-Feature kann ein Punkt, eine Zeile oder ein Polygon sein, das Feld-Attribute hat (z.B. "id"=1, um zu beschreiben, dass es sich um Polygon Nummer 1 handelt oder einem id Block 1 zugeordnet ist). Feldattribute können mehr als nur ein IDentifier sein und z.B. die Polygon- oder Stadtmarken enthalten, wie im oben dargestellten Beispiel, das cities.shp (shp_driver.Open("geodata/shapefiles/cities.shp")) illustriert.
Um ** einen Punkt formfile** zu erstellen, können wir die oben vorgestellte create_shp-Funktion (oder flusstools.geotools.create_shp(shp_file_dir="")) verwenden und die Projektion mit der get_wkt()-Funktion (auch oben vorgestellt) einstellen. Der folgende Codeblock zeigt die Nutzung beider Funktionen, um einen river zu erstellen. schp Punkt formfile, die drei Punkte an drei Flüssen in Mitteleuropa enthält. Der Codeblock verdeutlicht auch die Erstellung eines Feldes in der Attributtabelle und die Erstellung von drei Punktmerkmalen. Hier ist, wie der Code funktioniert:
Die Shapefile befindet sich in der Variable
rivers_pts. Beachten Sie, dass dielayer_typebereits die Art der Geometrien bestimmt, die in der Formdatei verwendet werden können. So wird z.B. das Hinzufügen einer Zeile oder eines Polygons zu einerogr.wkbPointSchicht zu einerERROR 1-Nachricht führen.Die
basemap(Schicht) wird der Variablenlyr = river_pts.GetLayer()zugeschrieben.Ein string-Feld wird hinzugefügt und der Attributtabelle angepasst:
sofort ein neues Feld mit
field_gname = ogr.FieldDefn("FIELD-NAME", ogr.OFTString)(Recall: der Feldname darf nicht mehr als 10 Zeichen haben!)das neue Feld mit
lyr.CreateField(field_gname)andere Feldtypen als
OFTStringkönnen sein:OFTInteger,OFTReal,OFTDate,OFTTime,OFTDateTime,OFTBinary,@@@@@,OFTIntegerList,OFTRealList, oderOFTStringList.
Fügen Sie drei Punkte hinzu, die unter
pt_names = {RIVER-NAME: (x-coordinate, y-coordinate)}in einer Schleife über die Wörterbuchschlüssel gespeichert sind:für jeden neuen Punkt, erstellen Sie eine Funktion als Kind der Schichtdefinitionen mit
feature = ogr.Feature(lyr.GetLayerDefn())den Wert des Feldnamens für jeden Punkt mit
feature.SetField(FIELD-NAME, FIELD-VALUE)eine Reihe des neuen Punktes im WKT-Format mit
wkt = "POINT(X-COORDINATE Y-COORDINATE)"den WKT-formatierten Punkt in eine Punktgeometrie mit
point = ogr.CreateGeometryFromWkt(wkt)den neuen Punkt als die Geometrie der neuen Funktion mit
feature.SetGeometry(point)die neue Funktion mit
lyr.CreateFeature(feature)
Entsperren Sie die Formdatei, indem Sie die Variable
lyrundriver_ptsmitNoneüberschreiben.
shp_dir = r"" + os.path.abspath('') + "/geodata/shapefiles/rivers.shp"
river_pts = create_shp(shp_dir, layer_name="basemap", layer_type="point")
# create .prj file for the shapefile for web application references
with open(shp_dir.split(".shp")[0] + ".prj", "w+") as prj:
prj.write(get_wkt(3857))
# get basemap layer
lyr = river_pts.GetLayer()
# add string field "rivername"
field_gname = ogr.FieldDefn("rivername", ogr.OFTString)
lyr.CreateField(field_gname)
# names and coordinates of central EU rivers in EPSG:3857 WG84 / Pseudo-Mercator
pt_names = {"Aare": (916136.03, 6038687.72),
"Ain": (623554.12, 5829154.69),
"Inn": (1494878.95, 6183793.83)}
# add the three rivers as points to the basemap layer
for n in pt_names.keys():
# create Feature as child of the layer
pt_feature = ogr.Feature(lyr.GetLayerDefn())
# define value n (river) in the rivername field
pt_feature.SetField("rivername", n)
# use WKT format to add a point geometry to the Feature
wkt = "POINT(%f %f)" % (float(pt_names[n][0]), float(pt_names[n][1]))
point = ogr.CreateGeometryFromWkt(wkt)
pt_feature.SetGeometry(point)
# append the new feature to the basemap layer
lyr.CreateFeature(pt_feature)
# release files
lyr = None
river_pts = NoneDie daraus resultierende rivers.shp formfile kann in QGIS zusammen mit einer Digitales Oberflächenmodell (DOM) aus dem Natural Earth quick start kit] importiert werden.

Figure 5:Die Flussnamen, die an Punkte in einer Punktformdatei in QGIS angezeigt.
Multiline (Polyline) Shapefile¶
Ähnlich wie bei dem Verfahren zum Erstellen und Hinzufügen von Punkten zu einer neuen Punktformdatei kann eine (multi) Linie (oder Polyline) zu einer Shapefile hinzugefügt werden. Die create_shp-Funktion erstellt eine Multi-Line-Formdatei, wenn der Schichttyp als "line" (flusstools.geotools.create_shp(shp_file_dir="", layer_type="line")) definiert ist. Das Koordinatensystem wird mit der oben definierten get_wkt()-Funktion erstellt.
Der folgende Codeblock verwendet die Koordinaten der Städte entlang des Rheins, die in einem Dictionary namens station_names gespeichert sind. Die Stadtnamen werden nicht verwendet und nur die Koordinaten werden mit line.AddPoint(X, Y) angehängt. Wie zuvor wird ein Feld geschaffen, um dem Fluss einen Namen zu geben. Die eigentliche Zeilenfunktion wird wieder als Kind der Schicht mit line_feature = ogr.Feature(lyr.GetLayerDefn()) erstellt. Dieser Codeblock führt eine Linie hervor, die etwa dem Rhein zwischen Frankreich und Deutschland folgt.
shp_dir = r"" + os.path.abspath("") + "/geodata/shapefiles/rhine_proxy.shp"
rhine_line = create_shp(shp_dir, layer_name="basemap", layer_type="line")
# create .prj file for the shapefile for web application references
with open(shp_dir.split(".shp")[0] + ".prj", "w+") as prj:
prj.write(get_wkt(3857))
# get basemap layer
lyr = rhine_line.GetLayer()
# coordinates for EPSG:3857 WG84 / Pseudo-Mercator
station_names = {"Basel": (844361.68, 6035047.42),
"Kembs": (835724.27, 6056449.76),
"Breisach": (842565.32, 6111140.43),
"Rhinau": (857547.04, 6158569.58),
"Strasbourg": (868439.31, 6203189.68)}
# create line object and add points from station names
line = ogr.Geometry(ogr.wkbLineString)
for stn in station_names.values():
line.AddPoint(stn[0], stn[1])
# create field named "river"
field_name = ogr.FieldDefn("river", ogr.OFTString)
lyr.CreateField(field_name)
# create feature, geometry, and field entry
line_feature = ogr.Feature(lyr.GetLayerDefn())
line_feature.SetGeometry(line)
line_feature.SetField("river", "Rhine")
# add feature to layer
lyr.CreateFeature(line_feature)
lyr = None
rhine_line = NoneDie daraus resultierende rhine_proxy.shp formfile kann in QGIS zusammen mit einer Digitales Oberflächenmodell (DOM) importiert werden und die Städte weisen formfile aus der Natural Earth quick start kit.

Figure 6:Die Linie rund um den Rhein in QGIS.
Polygon Shapefile¶
Polygone sind Oberflächenpatches, die punktweise, linienweise oder aus einer "Multipolygon"WKB-Definition erstellt werden können. Bei der Erstellung von Polygonen aus Punkten oder Linien wollen wir eine Oberfläche schaffen, und deshalb wird der entsprechende Geometrietyp wkbLinearRing zum Aufbau von Polygonen aus beiden Punkten oder Linien (anstatt wkbPoint bzw. wkbLine) genannt. Der folgende Codeblock bietet ein Beispiel für den Aufbau einer Polygon-Formdatei, die das Hydrauliklabor der Universität Stuttgart abgrenzt. Der Unterschied zwischen dem obigen Beispiel zum Erstellen einer Linienformdatei sind:
Die Projektion ist
EPSG:4326.Die Punktkoordinaten werden innerhalb eines
ogr.wkbLinearRingObjekt Schritt für Schritt anstatt in einer Schleife über diktionäre Einträge erzeugt.Datei, Variable und Feldnamen.
shp_dir = r"" + os.path.abspath("") + "/geodata/shapefiles/va4wasserbau.shp"
va_geo = create_shp(shp_dir, layer_name="basemap", layer_type="polygon")
# create .prj file for the shapefile for GIS map applications
with open(shp_dir.split(".shp")[0] + ".prj", "w+") as prj:
prj.write(get_wkt(4326))
# get basemap layer
lyr = va_geo.GetLayer()
# create polygon points
pts = ogr.Geometry(ogr.wkbLinearRing)
pts.AddPoint(9.103686, 48.744251)
pts.AddPoint(9.104689, 48.744198)
pts.AddPoint(9.104667, 48.743960)
pts.AddPoint(9.103557, 48.744009)
# create polygon geometry
poly = ogr.Geometry(ogr.wkbPolygon)
# build polygon geometry from points
poly.AddGeometry(pts)
# add field to classify building type
field = ogr.FieldDefn("building", ogr.OFTString)
lyr.CreateField(field)
poly_feature_defn = lyr.GetLayerDefn()
poly_feature = ogr.Feature(poly_feature_defn)
poly_feature.SetGeometry(poly)
poly_feature.SetField("building", "Versuchsanstalt")
lyr.CreateFeature(poly_feature)
lyr = None
va_geo = NoneGestaltdatei von JSON erstellen¶
Die Belastung von Geometriedaten aus in-line definierten Variablen ist in der Praxis umständlich, wo Geospatialdaten häufig auf öffentlichen Plattformen (z.B. Landnutzung oder Abdeckung) zur Verfügung gestellt werden. Das folgende Beispiel verwendet eine JSON-Datei, die mit Kartendienstdaten des Baden-Württemberg State Institute for the Environment, Survey and Nature Conservation (LUBW) erstellt wurde, in der Polygonknoten im WKT-Polygongeometrieformat gespeichert werden ("MultiPolygon (((node1_x node1_y, nodej_x, nodej_y, ... ...)))"):
Die JSON-Datei (herunterladen hq100-dreisam.json und speichern Sie sie an ein Unterverzeichnis namens
/geodata/json/) wird mit Pandas gelesen und die Formdatei wird wie zuvor mit dercreate_shp-Funktion erstellt.Die Projektion ist
EPSG:25832.Zwei Felder werden in Form von
"tbg_name"(der ursprüngliche Stringname der Polygone in den LUBW-Daten) und"area"(ein echtes Nummernfeld, in dem der Polygonbereich unter m2 unterpolygon.GetArea()berechnet wird).
Die Polygongeometrien stammen aus den WKT-formatierten Definitionen im Feld
"wkt_geom"des pandas Dataframe-Objektsdreisam_inundation.
import pandas as pd
# get data from json file
dreisam_inundation = pd.read_json(r"" + os.path.abspath("") + "/geodata/json/hq100-dreisam.json")
# create shapefile
shp_dir = r"" + os.path.abspath('') + "/geodata/shapefiles/dreisam_hq100.shp"
dreisam_hq100 = create_shp(shp_dir, layer_name="basemap", layer_type="polygon")
# create .prj file for the shapefile for GIS map applications
with open(shp_dir.split(".shp")[0] + ".prj", "w+") as prj:
prj.write(get_wkt(25832))
# get basemap layer
lyr = dreisam_hq100.GetLayer()
# add string field "tbg_name"
lyr.CreateField(ogr.FieldDefn("tbg_name", ogr.OFTString))
# add string field "area"
lyr.CreateField(ogr.FieldDefn("area", ogr.OFTReal))
for wkt, tbg in zip(dreisam_inundation["wkt_geom"], dreisam_inundation["TBG_NAME"]):
# create Feature as child of the layer
feature = ogr.Feature(lyr.GetLayerDefn())
# assign tbg_name
feature.SetField("tbg_name", tbg)
# use WKT format to add a polygon geometry to the Feature
polygon = ogr.CreateGeometryFromWkt(wkt)
# define default value of 0 to the area field
feature.SetField("area", polygon.GetArea())
feature.SetGeometry(polygon)
# append the new feature to the basemap layer
lyr.CreateFeature(feature)
lyr = None
dreisam_hq100 = NoneAuch GeoJSON Daten können verwendet werden, um eine ogr.Geometry mit ogr.createFromGeoJson(FILENAME) zu erstellen:
from osgeo import ogr
geojson_data = """{"type":"Point","coordinates":[1013452.282805,6231540.674235]}"""
point = ogr.CreateGeometryFromJson(geojson_data)
print("X=%d, Y=%d (EPSG:3857)" % (point.GetX(), point.GetY()))X=1013452, Y=6231540 (EPSG:3857)
Geometrische Attribute berechnen¶
Der oben genannte Codeblock verdeutlicht die Nutzung von polygon.GetArea(), um den Polygonbereich in m zu berechnen. Die ogr Bibliothek bietet viele weitere Funktionen, um geometrische Attribute von Features zu berechnen und hier eine Zusammenfassung:
Mehrere Polygone
wkt_... = ...
polygon_a = ogr.CreateGeometryFromWkt(wkt_1)
polygon_b = ogr.CreateGeometryFromWkt(wkt_2)
polygon_union = polygon_a.Union(polygon_b)Intersect zwei Polygone
polygon_intersection = polygon_a.Intersection(polygon_b)Envelope (minimale und maximale Ausdehnung) eines Polygons
env = polygon.GetEnvelope()
print("minX: %d, minY: %d, maxX: %d, maxY: %d" % (env[0],env[2],env[1],env[3])Convex Rumpf (Ummantelungsfläche) mehrerer Geometrien (Punkte, Linien, Polygone)
all_polygons = ogr.Geometry(ogr.wkbGeometryCollection)
for feature in POLYGON-SOURCE-LAYER: all_polygons.AddGeometry(feature.GetGeometryRef())
convexhull = all_polygons.ConvexHull()
Saveconvexhullto shapefile (use thecreate_shpfunction as shown in the above examples or read more at pcjericks’ Github pages)
Tip: To create a tight hull (e.g., of a point cloud), look forconcavehullfunctions.Länge (eine Zeile)
wkt = "LINESTRING (415128.5 5320979.5, 415128.6 5320974.5, 415129.75 5320974.7)"
line = ogr.CreateGeometryFromWkt(wkt)
print("Length = %d" % line.Length())Bereich (von einem Polygon):
polygon.GetArea()(siehe oben Beispiel)Beispiel für die Berechnung Zentrenkoordinaten von polygons.
Export in andere Formate¶
Die obigen Beispiele behandeln nur .shp-Dateien, aber andere Formate können nützlich sein (z.B. Web-Anwendungen erstellen oder auf Google Earth exportieren). Zu diesem Zweck illustrieren die folgenden Absätze die Erstellung von GeoJSON- und KML-Dateien. Mehrere andere Konvertierungen können durchgeführt werden, nicht nur zwischen Dateiformaten, sondern auch zwischen Merkmalstypen. So können beispielsweise Polygone aus Punktwolken erzeugt werden (u.a. mit der oben genannten ConvexHull-Methode). Interessierte Studenten können mehr über Umwandlungen in Michael Diener’s Python Geospatial Analysis Cookbook.
GeoJSON¶
GeoJSON-Dateien können wie zuvor einfach erstellt werden, auch ohne einen Treiber zu aktivieren:
triangle = ogr.Geometry(ogr.wkbLinearRing)
triangle.AddPoint(-11717151.498691, 2356192.894805)
triangle.AddPoint(-11717120.446149, 2355586.175893)
triangle.AddPoint(-11719392.059083, 2354012.050842)
polygon = ogr.Geometry(ogr.wkbPolygon)
polygon.AddGeometry(triangle)
with open(r"" + os.path.abspath('') + "/geodata/geojson/pitillal-triangle.geojson", "w+") as gjson:
gjson.write(polygon.ExportToJson())Für eine robustere Bearbeitung und Definition einer Projektion aktivieren Sie den Treiber ogr.GetDriverByName("GeoJSON"). So funktioniert die Erstellung und Manipulation von GeoJSON-Dateien ähnlich wie die oben gezeigten Shapefile-Handler.
gjson_driver = ogr.GetDriverByName("GeoJSON")
# make spatial reference
sr = osr.SpatialReference()
sr.ImportFromEPSG(3857)
# create GeoJSON file
gjson = gjson_driver.CreateDataSource("pitillal-full.geojson")
gjson_lyr = gjson.CreateLayer("pitillal-full.geojson", geom_type=ogr.wkbPolygon, srs=sr)
# get layer feature definitions
feature_def = gjson_lyr.GetLayerDefn()
# create new feature
new_feature = ogr.Feature(feature_def)
# assign the triangle from the above code block
new_feature.SetGeometry(polygon)
# add new feature to Layer
gjson_lyr.CreateFeature(new_feature)
# close links to data sources
gjson = None
gjson_lyr = NoneKML (Google Earth)¶
Um Punkt-, Zeilen- oder Polygon-Features in Google Earth anzuzeigen, können Funktionen in Googles KML (Keyhole Markup Language), ähnlich der Erstellung einer GeoJSON-Datei, und mit der Funktion geometry.ExportToKML:
triangle = ogr.Geometry(ogr.wkbLinearRing)
triangle.AddPoint(-11717151.498691, 2356192.894805)
triangle.AddPoint(-11717120.446149, 2355586.175893)
triangle.AddPoint(-11719392.059083, 2354012.050842)
polygon = ogr.Geometry(ogr.wkbPolygon)
polygon.AddGeometry(triangle)
#geojson = poly.ExportToJson()
with open(r"" + os.path.abspath("") + "/geodata/pitillal-triangle.kml", "w+") as gjson:
gjson.write(polygon.ExportToKML())Darüber hinaus können ähnlich wie GeoJSON-Dateien und Formdateien KML-Dateien robuster generiert werden (z.B. mit einer definierten Projektion). Sie müssen nur den KML-Treiber (kml_driver = ogr.GetDriverByName("KML")) einleiten und eine KML-Datenquelle definieren (kml_file = kml_driver.CreateDataSource(FILENAME.KML)).