Mehr

Formschön / Python, das durch eine Reihe von Polygonen schlingt

Formschön / Python, das durch eine Reihe von Polygonen schlingt


Ich versuche, mit Python eine Reihe von Polygonen formschön zu durchlaufen, um festzustellen, ob sie sich überlappen oder nicht. Ich möchte dies nicht manuell tun, da ich später das Verfahren verallgemeinern und dies für eine Reihe von Polygonen tun möchte, die aus einem Shapefile (über Fiona) importiert wurden. Das sind die Polygone, die ich gerade testepolA = Polygon([(0,0), (3,0), (3,3), (0,3)]) polB = Polygon([(2,-1), (5,-1), ( 5,2), (2,2)]) polC = Polygon([(5,2), (8,2), (8,5), (5,5)])Daraus habe ich eine Sammlung erstelltSammlung = [polA, polB, polC]und jetzt möchte ich, dass eine for-Schleife durch die Liste geht und jedes Polygon überprüft, ob es sich mit dem überschneidet Nächster. Aber nichts, was ich versuche, funktioniert, weil ich nicht weiß, wie man alle möglichen Kombinationen wiederholt und erfolgreich testet. Weiß nicht ob ich verstanden werde. Hat jemand eine Idee, wie man das mit Shapely von Fiona macht?


Einige Lösungen entsprechend der Position eines Elements in einer Liste:

polA = Polygon([(0,0), (3,0), (3,3), (0,3)]) polB = Polygon([(2,-1), (5,-1), ( 5,2), (2,2)]) polC = Polygon([(5,2), (8,2), (8,5), (5,5)]) Sammlung = [polA, polB, polC ]

Iteration nach Index:

for i in range(len(collection)-1): print collection[i], collection[i+1], collection[i].touches(collection[i+1]) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) Falsch POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) Richtig

Iterieren mit itertools (Standardmodul), alle Kombinationen ohne sich wiederholende Elemente

itertools für pol in itertools.combinations(collection, 2) importieren: print pol[0],pol[1], pol[0].touches(pol[1]) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) Falsch POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ( (5 2, 8 2, 8 5, 5 5, 5 2)) Falsch POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) Richtig

oder mit dem Vorschlag von Mike T

für pol1, pol2 in itertools.combinations(collection, 2): print pol1, pol2, pol1.touches(pol2) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((2 -1 , 5 -1, 5 2, 2 2, 2 -1)) Falsch POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((5 2, 8 2, 8 5, 5 5 , 5 2)) Falsch POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) Richtig

Vergleichen mit

für pol in itertools.permutations(collection, 2): print pol[0],pol[1], pol[0].touches(pol[1]) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) Falsch POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) Falsch POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) Falsch POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) Wahr POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) Falsch POLYGON ((5 2, 8 2, 8 5 , 5 5, 5 2)) POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) Wahr

Siehe auch Python - Vorherige und nächste Werte in einer Schleife

from itertools import tee, islice, chain, izip def previous_and_next(some_iterable): prevs, items, nexts = tee(some_iterable, 3) prevs = chain([None], prevs) nexts = chain(islice(nexts, 1, None) , [Keine]) Rückgabe von izip(prevs, items, nexts) für vorherige, item, nxt in previous_and_next(collection): print "Artikel ist jetzt", Artikel, "nächster ist", nxt, "vorheriger ist", vorheriger Artikel ist jetzt POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0)) nächste ist POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) vorherige ist Keine Artikel ist jetzt POLYGON ((2 -1, 5 -1, 5 2, 2 2, 2 -1)) nächste ist POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) vorherige ist POLYGON ((0 0 , 3 0, 3 3, 0 3, 0 0)) Artikel ist jetzt POLYGON ((5 2, 8 2, 8 5, 5 5, 5 2)) nächste ist keine vorherige ist POLYGON ((2 -1, 5 - 1, 5 2, 2 2, 2 -1))

GDAL und Python | Kapitel 3. Vektordaten lesen und schreiben

Kapitel 3. Vektordaten lesen und schreiben

Dieses Kapitel behandelt

  • Vektordaten verstehen
  • Einführung von OGR
  • Lesen von Vektordaten
  • Neue Vektordatensätze erstellen
  • Aktualisieren vorhandener Datensätze

Sie scheinen heutzutage selten zu sein, aber Sie haben wahrscheinlich eine Papier-Roadmap gesehen, die gefaltet und in Ihrem Auto aufbewahrt werden kann. Im Gegensatz zu den neueren Webkarten, die wir gewohnt sind, verwenden diese Karten keine Luftbilder. Stattdessen werden alle Features auf den Karten als geometrische Objekte gezeichnet, d. h. als Punkte, Linien und Polygone. Diese Arten von Daten, bei denen die geografischen Merkmale alle unterschiedliche Objekte sind, werden als bezeichnet Vektordatensätze .

Wenn Sie nicht nur Karten ansehen möchten, die jemand anderes erstellt hat, müssen Sie wissen, wie diese Datentypen gelesen und geschrieben werden. Wenn Sie in irgendeiner Weise mit vorhandenen Daten arbeiten möchten, sei es beim Zusammenfassen, Bearbeiten, Ableiten neuer Daten oder bei anspruchsvollen räumlichen Analysen, müssen Sie diese zuerst aus einer Datei einlesen. Außerdem müssen Sie alle neuen oder geänderten Daten wieder auf einen Datenträger schreiben. Wenn Sie beispielsweise über ein landesweites Städte-Dataset verfügen, aber nur Daten aus Städten mit 100.000 oder mehr Einwohnern analysieren möchten, können Sie diese Städte aus Ihrem ursprünglichen Dataset extrahieren und Ihre Analyse für sie ausführen, während Sie die kleineren Städte ignorieren. Optional können Sie auch den kleineren Datensatz zur späteren Verwendung in einer neuen Datei speichern.

In diesem Kapitel lernen Sie die grundlegenden Ideen hinter Vektordaten kennen und erfahren, wie Sie die OGR-Bibliothek zum Lesen, Schreiben und Bearbeiten dieser Arten von Datensätzen verwenden.

3.1. Einführung in Vektordaten

Am grundlegendsten, Vektordaten sind Daten, in denen geografische Features als diskrete Geometrien dargestellt werden, insbesondere Punkte, Linien und Polygone. Geografische Features mit unterschiedlichen Grenzen, z. B. Städte, funktionieren gut als Vektordaten, kontinuierliche Daten wie Höhen jedoch nicht. Es wäre schwierig, ein einziges Polygon um alle Gebiete mit der gleichen Höhe zu zeichnen, zumindest wenn Sie sich in einem bergigen Gebiet befinden. Sie können jedoch Polygone verwenden, um zwischen verschiedenen Höhenbereichen zu unterscheiden. Polygone mit subalpinen Zonen für eine Region wären beispielsweise ein guter Proxy für einen Höhenbereich, aber Sie würden viele der detaillierten Höhendaten innerhalb dieser Polygone verlieren. Viele Datentypen sind jedoch ausgezeichnete Kandidaten für eine Vektordarstellung, wie zum Beispiel Features in der oben erwähnten Roadmap. Straßen werden als Linien dargestellt, Landkreise und Bundesstaaten als Polygone, und je nach Kartenmaßstab werden Städte als Punkte oder Polygone gezeichnet. Tatsächlich werden alle Features auf der Karte wahrscheinlich als Punkte, Linien oder Polygone dargestellt.

Der zum Zeichnen eines Features verwendete Geometrietyp kann jedoch vom Maßstab abhängen. Abbildung 3.1 zeigt ein Beispiel dafür. Auf der Karte des Staates New York werden Städte als Punkte, Hauptstraßen als Linien und Landkreise als Polygone dargestellt. Eine Karte eines kleineren Gebiets wie New York City symbolisiert Features anders. In diesem Fall sind Straßen immer noch Linien, aber die Stadt und ihre Bezirke sind Polygone anstelle von Punkten. Jetzt würden Punkte verwendet, um Funktionen wie Bibliotheken oder Polizeistationen darzustellen.

Abbildung 3.1. Ein Beispiel dafür, wie der Maßstab die Geometrien ändert, die zum Zeichnen bestimmter Features verwendet werden. New York City ist ein Punkt auf dem Stadtplan, besteht aber auf dem Stadtplan aus mehreren Polygonen.

Sie können sich viele andere Beispiele für geografische Daten vorstellen, die sich auf diese Weise darstellen lassen. Alles, was mit einem einzigen Koordinatensatz beschrieben werden kann, z. B. Breiten- und Längengrad, kann als Punkt dargestellt werden. Dazu gehören Städte, Restaurants, Berggipfel, Wetterstationen und Geocache-Standorte. Zusätzlich zu ihren x- und y-Koordinaten (z. B. Breiten- und Längengrad) können Punkte eine dritte z-Koordinate haben, die die Höhe darstellt.

Geografische Gebiete mit geschlossenen Grenzen können als Polygone dargestellt werden. Beispiele sind Bundesstaaten, Seen, Kongressbezirke, Postleitzahlen und Landbesitz sowie viele der gleichen Merkmale, die als Punkte wie Städte und Parks symbolisiert werden können. Andere Features, die als Polygone, aber wahrscheinlich nicht als Punkte dargestellt werden könnten, sind Länder, Kontinente und Ozeane.

Lineare Merkmale wie Straßen, Flüsse, Stromleitungen und Buslinien lassen sich alle als Linien charakterisieren. Aber auch hier kann die Skalierung einen Unterschied machen. Zum Beispiel könnte eine Karte von New Orleans den Mississippi als Polygon und nicht als Linie zeigen, weil er so breit ist. Dadurch würde die Karte auch die unregelmäßigen Ufer des Flusses anzeigen und nicht nur eine glatte Linie, wie in Abbildung 3.2 gezeigt.

Abbildung 3.2. Der Unterschied zwischen der Verwendung von Polygon und Linie /> Geometrien, um den Mississippi darzustellen. Das Polygon zeigt die Details entlang der Ufer, während die Linie dies nicht tut.

Vektordaten sind jedoch mehr als Geometrien. Jede dieser Funktionen hat auch zugehörige Attribute. Diese Attribute können sich direkt auf die Geometrie selbst beziehen, z. B. die Fläche oder den Umfang eines Polygons oder die Länge einer Linie, aber es können auch andere Attribute vorhanden sein. Abbildung 3.3 zeigt ein einfaches Beispiel für ein Bundesstaat-Dataset, das den Bundesstaat, die Abkürzung, die Bevölkerung und andere Daten zusammen mit jedem Merkmal speichert. Wie Sie der Abbildung entnehmen können, können diese Attribute unterschiedlicher Art sein. Sie können numerisch sein, z. B. die Einwohnerzahl der Stadt oder die Geschwindigkeitsbegrenzung, Zeichenfolgen wie Städte- oder Straßennamen oder Daten wie das Datum, an dem das Grundstück gekauft oder zuletzt bewertet wurde. Bestimmte Arten von Vektordaten unterstützen auch BLOBs (Binary Large Objects), die zum Speichern von Binärdaten wie Fotos verwendet werden können.

Abbildung 3.3. Eine Attributtabelle für ein Dataset, das Bundesstaatengrenzen innerhalb der Vereinigten Staaten enthält. Jedes Bundesstaatspolygon hat eine zugehörige Zeile in der Datentabelle mit mehreren Attributen, einschließlich Bundesstaatsname und Bevölkerung im Jahr 2010.

Es sollte inzwischen klar sein, dass diese Art von Daten gut für die Erstellung von Karten geeignet ist, aber einige Gründe sind möglicherweise nicht so offensichtlich. Ein Beispiel ist, wie gut es beim Zeichnen skaliert. Wenn Sie mit Webgrafiken vertraut sind, wissen Sie wahrscheinlich, dass Vektorgrafiken wie SVG (skalierbare Vektorgrafiken) viel besser funktionieren als Rastergrafiken wie PNG, wenn sie in verschiedenen Maßstäben angezeigt werden. Auch wenn Sie nichts über SVG wissen, haben Sie sicherlich ein Bild auf einer Website gesehen, das verpixelt und hässlich ist. Das ist eine Rastergrafik, die mit einer höheren Auflösung angezeigt wird, als sie entworfen wurde. Dies ist bei Vektorgrafiken nicht der Fall, und genau das gleiche Prinzip gilt für Vektor-GIS-Daten. Es sieht immer glatt aus, egal in welchem ​​Maßstab.

Das bedeutet jedoch nicht, dass der Maßstab irrelevant ist. Wie Sie bereits gesehen haben, wirkt sich die Skalierung auf den Geometrietyp aus, der zur Darstellung eines geografischen Features verwendet wird, aber auch auf die Auflösung, die Sie für ein Feature verwenden sollten. Eine einfache Möglichkeit, sich Auflösung vorzustellen, besteht darin, sie mit Detail gleichzusetzen. Je höher die Auflösung, desto mehr Details können dargestellt werden. Beispielsweise würde eine Karte der Vereinigten Staaten nicht alle einzelnen San-Juan-Inseln vor der Küste des Staates Washington zeigen, und tatsächlich müsste der Datensatz sie nicht einmal enthalten. Eine Karte nur des Bundesstaates Washington würde jedoch definitiv einen höher aufgelösten Datensatz benötigen, der die Inseln einschließt, wie in Abbildung 3.4 zu sehen ist. Denken Sie daran, dass die Auflösung nicht nur für die Anzeige wichtig ist, sondern auch für die Analyse. Zum Beispiel würden die beiden Karten von Washington extrem unterschiedliche Maße für die Küstenlänge liefern.

Abbildung 3.4. Ein Beispiel, das den Unterschied zeigt, den die Auflösung ausmacht. Der mit der dicken Umrandung dargestellte Datensatz hat eine geringere Auflösung als der mit Schattierung dargestellte. Beachten Sie den Unterschied im Detailgrad, der in den beiden Datensätzen verfügbar ist.

DAS KÜSTENPARADOX

Haben Sie schon einmal darüber nachgedacht, wie man die Küstenlinie einer Landmasse misst? Wie der englische Mathematiker Lewis Fry Richardson zuerst betonte, ist dies nicht so einfach, wie Sie vielleicht denken, da die endgültige Messung vollständig von der Skala abhängt. Stellen Sie sich zum Beispiel einen wilden Küstenabschnitt mit mehreren Landzungen vor, an dem eine Straße entlangführt. Stellen Sie sich vor, Sie fahren diese Straße entlang und verwenden den Kilometerzähler Ihres Autos, um die Entfernung zu messen, und steigen dann aus dem Auto und gehen den Weg zurück, den Sie gekommen sind. Aber zu Fuß geht man an den Rändern der Landzunge entlang und folgt anderen Kurven in der Küste, die die Straße nicht macht. Es sollte leicht sein, sich vorzustellen, dass Sie weiter laufen als gefahren sind, weil Sie mehr Umwege genommen haben. Das gleiche Prinzip gilt für die Messung der gesamten Küstenlinie, da Sie mehr Variation messen können, wenn Sie in kleineren Schritten messen. Tatsächlich erhöht die Messung der Küste Großbritanniens in 50-km-Schritten statt in 100-km-Schritten die Endmessung um etwa 600 km. In Abbildung 3.3 sehen Sie ein weiteres Beispiel dafür, das einen Teil des Staates Washington verwendet. Wenn Sie alle Drehungen und Wendungen im Datensatz mit höherer Auflösung messen würden, erhalten Sie eine längere Küstenlinienmessung als wenn Sie die durch die dunkle Linie angezeigte Küstenlinie mit niedrigerer Auflösung messen würden, die nicht einmal viele der Inseln.

Wie bereits erwähnt, dienen Vektordaten nicht nur zum Erstellen von Karten. Tatsächlich könnte ich keine schöne Karte erstellen, wenn mein Leben davon abhinge, aber ich weiß ein bisschen mehr über Datenanalyse. Eine gängige Art der Vektordatenanalyse besteht darin, Beziehungen zwischen geografischen Merkmalen zu messen, in der Regel durch Überlagern derselben, um ihre räumliche Beziehung zu bestimmen. Sie können beispielsweise bestimmen, ob sich zwei Features räumlich überlappen und was dieser Überlappungsbereich ist. Abbildung 3.5 zeigt die Stadtgrenzen von New Orleans, die einem Feuchtgebietsdatensatz überlagert sind. Anhand dieser Informationen können Sie feststellen, wo in der Stadt New Orleans Feuchtgebiete vorhanden sind und wie viel von der Stadtfläche Feuchtgebiete sind oder nicht.

Abbildung 3.5. Ein Beispiel für eine Vektorüberlagerungsoperation. Der dunkle Umriss ist die Grenze der Stadt New Orleans, und die dunkleren Landbereiche sind Feuchtgebiete. Diese beiden Datensätze könnten verwendet werden, um den Prozentsatz der Landfläche innerhalb der Grenze von New Orleans zu bestimmen, die aus Feuchtgebieten besteht.

Ein weiterer Aspekt räumlicher Beziehungen ist der Abstand zwischen zwei Features. Sie können die Entfernung zwischen zwei Wetterstationen oder allen Sandwichläden im Umkreis von einer Meile von Ihrem Büro ermitteln. Ich habe vor einigen Jahren bei einer Studie mitgeholfen, bei der die Forscher sowohl Distanzen als auch räumliche Beziehungen brauchten. Sie mussten wissen, wie weit sich Hirsche mit GPS-Halsband zwischen den Messungen zurücklegten, aber auch die Fahrtrichtung und wie sie mit künstlichen Merkmalen wie Straßen interagierten. Eine besondere Frage war, ob sie die Straßen überquerten und wenn ja, wie oft.

Apropos Straßen: Vektor-Datasets können auch Netzwerke gut darstellen, z. B. Straßennetze. Ein richtig konfiguriertes Straßennetz kann verwendet werden, um Routen und Fahrzeiten zwischen zwei Orten zu finden, ähnlich den Ergebnissen, die Sie auf verschiedenen Web-Mapping-Sites sehen. Unternehmen können solche Informationen auch verwenden, um Dienstleistungen bereitzustellen. Beispielsweise kann eine Pizzeria mithilfe einer Netzwerkanalyse ermitteln, welche Stadtteile sie innerhalb einer 15-minütigen Fahrt erreichen können, um ihr Liefergebiet festzulegen.

Wie bei anderen Datentypen haben Sie mehrere Möglichkeiten, Vektordaten zu speichern. Ähnlich wie Sie ein Foto als JPEG, PNG, TIFF, Bitmap oder einen von vielen anderen Dateitypen speichern können, können viele verschiedene Dateiformate zum Speichern von Vektordaten verwendet werden. Ich werde im nächsten Kapitel mehr über die Möglichkeiten sprechen, aber jetzt werde ich kurz einige gängige Formate erwähnen, von denen wir einige in diesem Kapitel verwenden werden.

Shapefiles sind ein beliebtes Format zum Speichern von Vektordaten. Ein Shapefile besteht jedoch nicht aus einer einzelnen Datei. Tatsächlich erfordert dieses Format mindestens drei Binärdateien, von denen jede einem anderen Zweck dient. Geometrieinformationen werden in .shp- und .shx-Dateien gespeichert, und Attributwerte werden in einer .dbf-Datei gespeichert. Darüber hinaus können andere Daten wie Indizes oder Raumbezugsinformationen in noch mehr Dateien gespeichert werden. Im Allgemeinen müssen Sie nichts über diese Dateien wissen, aber Sie müssen sicherstellen, dass sie alle im selben Ordner aufbewahrt werden.

Ein weiteres weit verbreitetes Format, insbesondere für Web-Mapping-Anwendungen, ist GeoJSON. Dies sind reine Textdateien, die Sie in jedem Texteditor öffnen und anzeigen können. Im Gegensatz zu einem Shapefile besteht ein GeoJSON-Dataset aus einer Datei, in der alle erforderlichen Informationen gespeichert sind.

Vektordaten können auch in relationalen Datenbanken gespeichert werden, was einen Mehrbenutzerzugriff sowie verschiedene Arten der Indizierung ermöglicht. Zwei der häufigsten Optionen hierfür sind räumliche Erweiterungen für weit verbreitete Datenbanksysteme. Die PostGIS-Erweiterung läuft auf PostgreSQL und SpatiaLite arbeitet mit SQLite-Datenbanken. Ein weiteres beliebtes Datenbankformat ist die File-Geodatabase von Esri, die sich darin unterscheidet, dass sie nicht Teil eines vorhandenen Datenbanksystems ist.

3.2. Einführung in OGR

Die OGR Simple Features Library ist Teil der Geospatial Data Abstraction Library (GDAL), einer äußerst beliebten Open-Source-Bibliothek zum Lesen und Schreiben von Geodaten. Der OGR-Teil von GDAL ist der Teil, der die Möglichkeit bietet, viele verschiedene Vektordatenformate zu lesen und zu schreiben. OGR ermöglicht es Ihnen auch, Geometrien zu erstellen und zu bearbeiten, Attributwerte zu bearbeiten, Vektordaten basierend auf Attributwerten oder räumlicher Position zu filtern und bietet auch Datenanalysefunktionen. Kurz gesagt, wenn Sie GDAL verwenden möchten, um mit Vektordaten zu arbeiten, ist OGR das, was Sie in den nächsten vier Kapiteln lernen müssen.

Die GDAL-Bibliothek wurde ursprünglich in C und C++ geschrieben, hat aber Bindungen für mehrere andere Sprachen, einschließlich Python, sodass es eine Schnittstelle zur GDAL/OGR-Bibliothek von Python gibt, nicht dass der Code in Python umgeschrieben wurde. Um GDAL mit Python zu verwenden, müssen Sie daher sowohl die GDAL-Bibliothek als auch die Python-Bindungen dafür installieren. Falls Sie dies noch nicht getan haben, finden Sie in Anhang A detaillierte Installationsanweisungen.

Wofür steht das Akronym OGR überhaupt? Früher stand es für OpenGIS Simple Features Reference Implementation, aber da OGR nicht vollständig mit der OpenGIS Simple Features Spezifikation kompatibel ist, wurde der Name geändert und jetzt steht der OGR-Teil davon für nichts und ist nur historischer Natur.

Mehrere in diesem Kapitel verwendete Funktionen stammen aus dem ospybook-Python-Modul, das unter www.manning.com/books/geoprocessing-with-python heruntergeladen werden kann. Sie sollten dieses Modul auch installieren. Die Beispieldatensätze sind auf derselben Site verfügbar.

Bevor Sie mit der Arbeit mit OGR beginnen, ist es hilfreich, sich anzusehen, wie verschiedene Objekte im OGR-Universum miteinander verbunden sind, wie in Abbildung 3.6 gezeigt. Wenn Sie diese Hierarchie nicht verstehen, machen die zum Lesen und Schreiben von Daten erforderlichen Schritte nicht viel Sinn. Wenn Sie OGR verwenden, um eine Datenquelle zu öffnen, z. B. ein Shapefile, eine GeoJSON-Datei, SpatiaLite oder eine PostGIS-Datenbank, haben Sie ein DataSource-Objekt. Diese Datenquelle kann ein oder mehrere untergeordnete Layer-Objekte haben, eines für jedes in der Datenquelle enthaltene Dataset. Viele Vektordatenformate, wie die in diesem Kapitel verwendeten Shapefile-Beispiele, können nur einen Datensatz enthalten. Andere, wie SpatiaLite, können jedoch mehrere Datensätze enthalten, und Sie werden Beispiele dafür im nächsten Kapitel sehen. Unabhängig davon, wie viele Datasets sich in einer Datenquelle befinden, wird jedes von OGR als Layer betrachtet. Sogar einige meiner Studenten, die GIS regelmäßig für ihren Unterricht und ihre Forschung verwenden, werden dadurch verwirrt, wenn sie hauptsächlich Shapefiles verwenden, weil es für sie kontraintuitiv ist, dass zwischen der Datenquelle und den eigentlichen Daten ein sogenannter Layer sitzt.

Abbildung 3.6. Die OGR-Klassenstruktur. Jede Datenquelle kann über mehrere Layer verfügen, jeder Layer kann über mehrere Features verfügen und jedes Feature enthält eine Geometrie und ein oder mehrere Attribute.

Und was die eigentlichen Daten angeht, jeder Layer enthält eine Sammlung von Feature-Objekten, die die Geometrien und ihre Attribute enthalten. Wenn Sie Vektordaten in ein GIS wie QGIS laden und sich dann die Attributtabelle ansehen, sehen Sie etwas Ähnliches wie in Abbildung 3.7 . Jede Zeile in der Tabelle entspricht einem Merkmal, z. B. dem Merkmal, das Afghanistan repräsentiert. Jede Spalte entspricht einem Attributfeld, und in diesem Fall sind zwei der Attribute SOVEREIGNT und TYPE . Obwohl Sie Datentabellen öffnen können, die keine mit den Features verknüpften räumlichen Informationen oder Geometrien enthalten, arbeiten wir mit Datasets, die über Geometrien verfügen. Wie Sie in Abbildung 3.7 sehen können, werden die Geometrien nicht in der Attributtabelle in QGIS angezeigt, obwohl andere GIS-Softwarepakete wie ArcGIS eine Formspalte in der Attributtabelle anzeigen.

Abbildung 3.7. Ein Beispiel für eine in QGIS angezeigte Attributtabelle. Jede Zeile entspricht einem Feature und jede Spalte ist ein Attributfeld.

Der erste Schritt für den Zugriff auf Vektordaten besteht darin, die Datenquelle zu öffnen. Dazu benötigen Sie einen entsprechenden Treiber, der OGR mitteilt, wie mit Ihrem Datenformat umzugehen ist. Die GDAL/OGR-Website listet mehr als 70 Vektorformate auf, die OGR lesen kann, obwohl es nicht alle schreiben kann. Jeder von ihnen hat seinen eigenen Treiber. Es ist wahrscheinlich, dass Ihre OGR-Version nicht alle aufgeführten unterstützt, aber Sie können sie jederzeit selbst kompilieren, wenn Sie etwas benötigen, das fehlt (beachten Sie, dass dies in vielen Fällen leichter gesagt als getan ist). Unter www.gdal.org/ogr_formats.html finden Sie eine Liste aller verfügbaren Formate und spezifische Details zu jedem.

Ein Treiber ist ein Übersetzer für ein bestimmtes Datenformat wie Geo-JSON oder Shapefile. Es teilt OGR mit, wie dieses bestimmte Format gelesen und geschrieben wird. Wenn kein Treiber für ein Format in OGR kompiliert ist, kann OGR damit nicht arbeiten.

Wenn Sie sich nicht sicher sind, ob Ihre Installation von GDAL/OGR ein bestimmtes Datenformat unterstützt, können Sie das Befehlszeilenprogramm ogrinfo verwenden, um herauszufinden, welche Treiber verfügbar sind. Der Speicherort dieses Dienstprogramms auf Ihrem Computer hängt von Ihrem Betriebssystem und der Installation von GDAL ab, daher müssen Sie möglicherweise auf Anhang A zurückgreifen. Wenn Sie nicht daran gewöhnt sind, eine Befehlszeile zu verwenden, sind Sie möglicherweise versucht, auf die ausführbare Datei von ogrinfo zu doppelklicken, aber das bringt Ihnen nichts weiter. Stattdessen müssen Sie ogrinfo über ein Terminalfenster oder eine Windows-Eingabeaufforderung ausführen. Sobald Sie die ausführbare Datei gefunden haben, sollten Sie sie auf jeden Fall mit der Option --formats ausführen. Abbildung 3.8 zeigt ein Beispiel für die Ausführung auf meinem Windows 7-Rechner, obwohl ich den Großteil der Ausgabe abgeschnitten habe.

Abbildung 3.8. Ein Beispiel für die Ausführung des Dienstprogramms ogrinfo über eine GDAL-Eingabeaufforderung auf einem Windows-Computer

Wie Sie sehen können, sagt Ihnen ogrinfo nicht nur, welche Treiber in Ihrer OGR-Version enthalten sind, sondern auch, ob es auf jeden schreiben und daraus lesen kann.

Informationen zu den von OGR unterstützten Vektorformaten finden Sie unter www.gdal.org/ogr_formats.html .

Sie können auch mithilfe von Python ermitteln, welche Treiber verfügbar sind. Versuchen wir es tatsächlich. Öffnen Sie zunächst Ihre bevorzugte interaktive Python-Umgebung. Ich werde IDLE ( Abbildung 3.9 ) verwenden, weil es das Paket ist, das mit Python gepackt ist, aber Sie können jedes verwenden, mit dem Sie vertraut sind. Das erste, was Sie tun müssen, ist das ogr-Modul zu importieren, damit Sie es verwenden können. Dieses Modul befindet sich im osgeo-Paket, das installiert wurde, als Sie die Python-Bindungen für GDAL installiert haben. Alle Module in diesem Paket sind mit Kleinbuchstaben benannt, so dass Sie in Python darauf verweisen müssen. Nachdem Sie ogr importiert haben, können Sie ogr.GetDriverByName verwenden, um einen bestimmten Treiber zu finden:

von osgeo importieren ogr

Treiber = ogr.GetDriverByName( 'GeoJSON' )

Abbildung 3.9. Beispiel einer interaktiven Python-Sitzung, die zeigt, wie Sie Treiber erhalten

Verwenden Sie den Namen aus der Spalte „Code“ auf der Webseite „OGR-Vektorformate“. Wenn Sie einen gültigen Treiber erhalten und ihn ausdrucken, sehen Sie Informationen darüber, wo das Objekt im Speicher gespeichert ist. Wichtig ist, dass es etwas zum Ausdrucken gibt, denn das bedeutet, dass Sie erfolgreich einen Treiber gefunden haben. Wenn Sie einen ungültigen Namen oder den Namen eines fehlenden Treibers übergeben, gibt die Funktion None zurück. Siehe Abbildung 3.9 für Beispiele.

Eine Funktion namens print_drivers im ospybook-Modul druckt auch eine Liste der verfügbaren Treiber aus. Dies ist in Abbildung 3.9 dargestellt.

3.3. Lesen von Vektordaten

Da Sie nun wissen, mit welchen Formaten Sie arbeiten können, ist es an der Zeit, Daten zu lesen. Sie beginnen mit einem Städte-Shapefile, dem Datensatz ne_50m_populated_places.shp im globalen Unterordner Ihres osgeopy-data-Ordners. Fühlen Sie sich frei, es in QGIS zu öffnen und zu sehen. Sie sehen nicht nur die in Abbildung 3.10 gezeigten Städte, sondern auch, dass die Attributtabelle eine Sammlung von Feldern enthält, von denen die meisten im Screenshot nicht sichtbar sind.

Abbildung 3.10. Die Geometrien und Attribute von ne_50m_populated_places.shp wie in QGIS zu sehen

Listing 3.1 zeigt ein kleines Skript, das die Namen, Populationen und Koordinaten für die ersten 10 Merkmale in diesem Datensatz ausgibt. Machen Sie sich keine Sorgen, wenn es auf den ersten Blick nicht viel Sinn macht, denn wir werden gleich in quälenden Details darauf eingehen. Die Datei ist im Quellcode für dieses Kapitel enthalten. Wenn Sie sie also ausprobieren möchten, können Sie sie in IDLE öffnen, den Dateinamen in der dritten Codezeile entsprechend Ihrem Setup ändern und dann Run Module unter dem Run . wählen Speisekarte.

Auflistung 3.1. Drucken von Daten aus den ersten zehn Features in einem Shapefile

Die grundlegende Gliederung ist einfach. Das erste, was Sie tun, ist das Shapefile zu öffnen und sicherzustellen, dass das Ergebnis dieser Operation nicht gleich None ist, da dies bedeuten würde, dass die Datenquelle nicht geöffnet werden könnte. Ich neige dazu, diese Variable ds zu nennen, kurz für Datenquelle. Nachdem Sie sichergestellt haben, dass die Datei geöffnet ist, rufen Sie die erste Ebene aus der Datenquelle ab. Dann durchlaufen Sie die ersten 10 Features im Layer und rufen für jedes das Geometrieobjekt, seine Koordinaten und die Attributwerte NAME und POP_MAX ab. Dann drucken Sie die Informationen über das Feature aus, bevor Sie mit dem nächsten fortfahren. Wenn Sie fertig sind, löschen Sie die Variable ds, um das Schließen der Datei zu erzwingen.

Wenn Sie den Code erfolgreich ausgeführt haben, sollten Sie 10 Ausgabezeilen haben, die ungefähr so ​​​​aussehen, obwohl Sie bei Verwendung von Python 3 keine Klammern haben:

( 'Bombo' , 75000, 32.533299524864844, 0.5832991056146284)

( 'Fort Portal' , 42670, 30.27500161597942, 0.671004121125236)

( 'Clermont-Ferrand' , 233050, 3.080008095928406, 45.779982115759424)

Schauen wir uns das etwas genauer an. Sie öffnen eine Datenquelle, indem Sie den Dateinamen und ein optionales Update-Flag an die Open-Funktion übergeben. Dies ist eine eigenständige Funktion im OGR-Modul, daher stellen Sie dem Funktionsnamen den Modulnamen voran, damit Python ihn finden kann. Wenn der zweite Parameter nicht bereitgestellt wird, wird standardmäßig 0 verwendet, wodurch die Datei im schreibgeschützten Modus geöffnet wird. Sie hätten 1 oder True übergeben können, um es stattdessen im Aktualisierungs- oder Bearbeitungsmodus zu öffnen.

Wenn die Datei nicht geöffnet werden kann, gibt die Open-Funktion None zurück. Als Nächstes überprüfen Sie dies, drucken eine Fehlermeldung aus und beenden sie bei Bedarf. Ich prüfe dies gerne, damit ich das Problem sofort und auf die Weise meiner Wahl lösen kann (in diesem Fall das Beenden), anstatt darauf zu warten, dass das Skript abstürzt, wenn es versucht, die nicht vorhandene Datenquelle zu verwenden. Ändern Sie den Dateinamen in Listing 3.1 in einen falschen und führen Sie das Skript aus, wenn Sie dieses Verhalten in Aktion sehen möchten:

wenn ds ist Keiner :

sys.exit( 'Konnte <0> nicht öffnen.' .format(fn))

Denken Sie daran, dass Datenquellen aus einem oder mehreren Layern bestehen, die die Daten enthalten. Nach dem Öffnen der Datenquelle müssen Sie also den Layer daraus abrufen. Datenquellen verfügen über eine Funktion namens GetLayer, die entweder einen Layer-Index oder einen Layer-Namen verwendet und das entsprechende Layer-Objekt in dieser bestimmten Datenquelle zurückgibt. Layer-Indizes beginnen bei 0, also hat der erste Layer den Index 0, der zweite den Index 1 und so weiter. Wenn Sie GetLayer keine Parameter bereitstellen, wird die erste Schicht in der Datenquelle zurückgegeben. Das Shapefile hat nur eine Ebene, daher wird der Index in diesem Fall technisch nicht benötigt.

Jetzt möchten Sie die Daten aus Ihrem Layer holen. Denken Sie daran, dass jeder Layer aus einem oder mehreren Features besteht, wobei jedes Feature ein geografisches Objekt darstellt. Die Geometrien und Attributwerte sind an diese Features angehängt, sodass Sie sie sich ansehen müssen, um Ihre Daten zu erhalten. Die zweite Hälfte des Codes in Listing 3.1 durchläuft die ersten 10 Features im Layer und gibt Informationen zu jedem aus. Hier nochmal der interessante Teil:

zum feat in lyr:

Pop = feat.GetField( 'POP_MAX' )

drucken(Name, Pop, x, ja)

Der Layer ist eine Sammlung von Features, die Sie mit einer for-Schleife durchlaufen können. Bei jedem Schleifendurchlauf ist die Variable feat das nächste Feature im Layer, und die Schleife durchläuft alle Features im Layer, bevor sie beendet wird. Sie möchten jedoch nicht alle 1.249 Funktionen ausdrucken, also erzwingen Sie, dass es nach den ersten 10 stoppt.

Das erste, was Sie innerhalb der Schleife tun, ist, die Geometrie aus dem Feature abzurufen und in eine Variable namens pt zu speichern. Sobald Sie die Geometrie haben, erfassen Sie ihre x- und y-Koordinaten und speichern sie in Variablen, um sie später zu verwenden.

Als nächstes rufen Sie die Werte aus den Feldern NAME und POP_MAX ab und speichern diese ebenfalls in Variablen. Die GetField-Funktion nimmt entweder einen Attributnamen oder einen Index an und gibt den Wert dieses Felds zurück. Sobald Sie die Attribute haben, drucken Sie alle Informationen aus, die Sie über das aktuelle Feature gesammelt haben.

Beachten Sie, dass die GetField-Funktion Daten zurückgibt, die denselben Datentyp wie im zugrunde liegenden Dataset aufweisen. In diesem Beispiel ist der Wert in der Variablen name ein String, aber der in pop gespeicherte Wert ist eine Zahl. Wenn Sie die Daten in einem anderen Format haben möchten, lesen Sie Anhang B, um eine Liste von Funktionen anzuzeigen, die Werte als einen bestimmten Typ zurückgeben. Wenn Sie beispielsweise pop als Zeichenfolge verwenden möchten, damit Sie sie mit einer anderen Zeichenfolge verketten können, können Sie GetFieldAsString verwenden.

pop = feat.GetFieldAsString( 'POP_MAX' )

Beachten Sie, dass nicht alle Datenformate alle Feldtypen unterstützen und nicht alle Daten erfolgreich zwischen Typen konvertiert werden können. Daher sollten Sie die Dinge gründlich testen, bevor Sie sich auf diese automatischen Konvertierungen verlassen. Diese Funktionen sind nicht nur nützlich, um Daten zwischen Typen zu konvertieren, sondern Sie können sie auch verwenden, um Datentypen in Ihrem Code deutlicher zu machen. Wenn Sie beispielsweise GetFieldAsInteger verwenden, ist es für jeden, der Ihren Code liest, offensichtlich, dass der Wert eine Ganzzahl ist.

3.3.1. Zugriff auf bestimmte Funktionen

Manchmal benötigen Sie nicht alle Funktionen, sodass Sie keinen Grund haben, alle wie bisher durchzugehen. Eine leistungsstarke Methode, um Features auf eine Teilmenge zu beschränken, besteht darin, sie nach Attributwert oder räumlicher Ausdehnung auszuwählen, und Sie werden dies in Kapitel 5 tun. Eine andere Möglichkeit besteht darin, sich Features mit bestimmten Offsets anzusehen, auch . genannt Feature-IDs (FID). Der Offset ist die Position, an der sich das Feature im Dataset befindet, beginnend mit Null. Dies hängt vollständig von der Position des Merkmals in der Datei ab und hat nichts mit der Sortierreihenfolge im Speicher zu tun. Wenn Sie beispielsweise das Shapefile ne_50m_populated_places in QGIS öffnen und sich die Attributtabelle ansehen, wird Bombo als erster Datensatz in der Tabelle angezeigt, wie in Abbildung 3.11 A. Sehen Sie die Zahlen in der Spalte ganz links? Das sind die Offsetwerte. Now try sorting the table by name by clicking on the NAME column header, as shown in figure 3.11 B. Now the first record shown in the table is the one for Abakan, but it has an offset of 346. As you can see, that left-most column isn’t a row number like you see in spreadsheets, where the row numbers are always in the right order no matter how you sort the data. These numbers represent the order in the file instead.

Figure 3.11. The attribute table for the ne_50m_populated_places shapefile. Table A shows the native sort order, with the FIDs in order. Table B has been sorted by city name, and the FIDs are no longer ordered sequentially.

If you know the offset of the feature you want, you can ask for that feature by FID. To get the feature for Vatican City, you use GetFeature(7) .

You can also get the total number of features with GetFeatureCount , so you could grab the last feature in the layer like this:

>> > last_feature = lyr.GetFeature(num_features - 1 )

You have to subtract one from the total number of features because the first index is zero. If you had tried to get the feature at index num_features, you’d have gotten an error message saying that the feature ID was out of the available range. This snippet also shows an alternate way of retrieving an attribute value from a feature, instead of using GetField , but it only works if you know the names beforehand so that you can hardcode them into your script.

The current feature

Another important point is that the functions that return features keep track of which feature was last accessed this is the current feature . When you first get the layer object, it has no current feature. But if you start iterating through features, the first time through the loop, the current feature is the one with an FID of zero. The second time through the loop, the current feature is the one with offset 1, and so on. If you use GetFeature to get the one with an FID of 5, that’s now the current feature, and if you then call GetNextFeature or start a loop, the next feature returned will be the one with offset 6. Yes, you read that right. If you iterate through the features in the layer, it doesn’t start at the first one if you’ve already set the current feature.

Based on what you’ve learned so far, what do you think would happen if you iterated through all of the features and printed out their names and populations, but then later tried to iterate through a second time to print out their names and coordinates? If you guessed that no coordinates would print out, you were right. The first loop stops when it runs out of features, so the current feature is pointing past the last one and isn’t reset to the beginning (see figure 3.12 ). No next feature is there when the second loop starts, so nothing happens. How do you get the current feature to point to the beginning again? You wouldn’t want to use a FID of zero, because if you tried to iterate through them all, the first feature would be skipped. To solve this problem, use the layer.ResetReading() function, which sets the current feature pointer to a location before the first feature, similar to when you first opened the layer.

Figure 3.12. The location of the current feature pointer at various times

3.3.2. Viewing your data

Before we continue, you might find it useful to know about functions in the ospybook module that will help you visualize your data without opening it in another software program. These don’t allow the level of interaction with the data that a GIS does, so opening it in QGIS is still a much better option for exploring the data in any depth.

Viewing attributes

You can print out attribute values to your screen using the print_attributes function, which looks like this:

print_attributes (lyr_or_fn, [n] , [fields] , [geom] , [reset] )

  • lyr_or_fn is either a layer object or the path to a data source. If it’s a data source, the first layer will be used.
  • n is an optional number of records to print. The default is to print them all.
  • fields is an optional list of attribute fields to include in the printout. The default is to include them all.
  • geom is an optional Boolean flag indicating whether the geometry type is printed. The default is True.
  • reset is an optional Boolean flag indicating whether the layer should be reset to the first record before printing. The default is True.

For example, to print out the name and population for the first three cities in the populated places shapefile, you could do something like this from a Python interactive window:


Schau das Video: Lab 25 Part 1: Text File Read Write Operations Python Programming Basics