Dallo shapefile zippato caricato a Geopandas DataFrame nell'applicazione Django
Sto cercando di arrivare a un punto in cui posso filtrare rapidamente migliaia di punti in uno shapefile. La mia applicazione Django chiede uno shapefile zip da caricare, in cui il file zip contiene almeno i .shp
, .shx
e .dbf
file. Una volta nella mia vista Django, il file zip è il seguente:
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>
Supponendo che Geopandas sia l'opzione migliore per un filtraggio / mascheramento efficiente (se sbaglio, sono decisamente aperto ai suggerimenti), non sono sicuro di come passare dallo stato corrente a un DataFrame Geopandas. Quando provo a usare il read_file()
metodo
import geopandas as gpd
gpd.read_file(request.FILES['file'].file)
Ottengo il seguente errore:
fiona.errors.DriverError: no driver
I geopandas.read_file()
documenti affermano:
Il percorso assoluto o relativo del file o dell'URL da aprire o qualsiasi oggetto con un
read()
metodo (come un file aperto o StringIO)
Non sono sicuro di come ottenere ciò che ho in un formato appropriato per il read_file()
metodo.
Nota: il mascheramento e il filtro che sto cercando di eseguire sono sui dati degli attributi e non sulla geometria.
Risposte
Puoi usare fiona.io.ZipMemoryFile
e gpd.GeoDataFrame.from_features
.
Esempio:
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())
Nota, originariamente non includevo il, BytesCollection
come ha dichiarato lo sviluppatore Fiona in un commento alla mia precedente risposta, che la classe sarebbe probabilmente deprecata. Tuttavia, se lo usi, non dovresti averne bisogno ZipMemoryFile
. Questo funziona per me:
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())
La risposta di @ user2856 mi ha portato a metà strada verso una soluzione. Non avrei saputo fiona.io.ZipMemoryFile
, e questo mi ha portato a questa risposta . La combinazione delle due soluzioni mi ha dato:
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())
Ora ho i miei dati shapefile in un GeoDataFrame.
Per chiunque sia curioso, il motivo per cui sono andato al BytesCollection
posto di memfile.open()
è perché non riuscivo memfile.open()
a lavorare. Avrebbe generato un errore che indicava che al .open()
metodo mancava un argomento posizionale "percorso".