Vom hochgeladenen gezippten Shapefile zum Geopandas DataFrame in der Django-Anwendung
Ich versuche an einen Punkt zu gelangen, an dem ich schnell Tausende von Punkten in einem Shapefile filtern kann. Meine Django - Anwendung fragt nach einer ZIP - Shape - Datei hochladen, wo die komprimierte Datei enthält zumindest die .shp
, .shx
und .dbf
Dateien. In meiner Django-Ansicht lautet die Zip-Datei wie folgt:
request.FILES['file']
> <InMemoryUploadedFile: test.zip (application/x-zip-compressed)>
type(request.FILES['file'])
> <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
request.FILES['file'].file
> <_io.BytesIO object at 0x0000028E29F8FE00>
Angenommen, Geopandas ist die beste Option für eine effiziente Filterung / Maskierung (wenn ich mich irre, bin ich definitiv offen für Vorschläge), bin ich mir nicht sicher, wie ich vom aktuellen Status zu einem Geopandas-Datenrahmen wechseln soll. Wenn ich versuche, die read_file()
Methode zu verwenden
import geopandas as gpd
gpd.read_file(request.FILES['file'].file)
Ich erhalte folgende Fehlermeldung:
fiona.errors.DriverError: no driver
In den geopandas.read_file()
Dokumenten heißt es :
Entweder der absolute oder relative Pfad zu der zu öffnenden Datei oder URL oder ein Objekt mit einer
read()
Methode (z. B. eine geöffnete Datei oder StringIO)
Ich bin mir nicht sicher, wie ich das, was ich habe, in ein für die read_file()
Methode geeignetes Format bringen kann.
Hinweis: Die Maskierung und Filterung, die ich durchführen möchte, bezieht sich auf Attributdaten und nicht auf die Geometrie.
Antworten
Sie können fiona.io.ZipMemoryFile
und verwenden gpd.GeoDataFrame.from_features
.
Beispiel:
import geopandas as gpd
import io
from fiona.io import ZipMemoryFile
# Just to create a BytesIO object for the demo,
# similar to your request.FILES['file'].file
zipshp = io.BytesIO(open('test.zip', 'rb').read())
with (ZipMemoryFile(zipshp)) as memfile:
with memfile.open() as src:
crs = src.crs
gdf = gpd.GeoDataFrame.from_features(src, crs=crs)
print(gdf.head())
Beachten Sie, dass ich ursprünglich nicht angegeben habe, BytesCollection
wie der Fiona-Entwickler in einem Kommentar zu meiner vorherigen Antwort angegeben hat, dass die Klasse wahrscheinlich veraltet sein würde. Wenn Sie es jedoch verwenden, sollten Sie es nicht benötigen ZipMemoryFile
. Das funktioniert bei mir:
import geopandas as gpd
import io
import fiona
zipshp = io.BytesIO(open('test.zip', 'rb').read())
with fiona.BytesCollection(zipshp.read()) as src:
crs = src.crs
gdf = gpd.GeoDataFrame.from_features(src, crs=crs)
print(gdf.head())
Die Antwort von @ user2856 brachte mich auf halbem Weg zu einer Lösung. Ich hätte es nicht gewusst fiona.io.ZipMemoryFile
, und das führte mich zu dieser Antwort . Die Kombination der beiden Lösungen ergab:
with ZipMemoryFile(request.FILES['file'].file) as memfile:
with fiona.BytesCollection(memfile._initial_bytes) as f:
gdf = gpd.GeoDataFrame.from_features(f, crs='epsg:4326')
print(gdf.head())
Ich habe jetzt meine Shapefile-Daten in einem GeoDataFrame.
Für jeden, der neugierig ist, ging der Grund , warum ich mit BytesCollection
statt memfile.open()
, weil ich nicht bekommen konnte memfile.open()
an der Arbeit. Es würde einen Fehler auslösen, der besagt, dass der .open()
Methode ein Positionsargument 'path' fehlt.