Dari shapefile zip yang diunggah ke Geopandas DataFrame dalam Aplikasi Django
Saya mencoba mencapai titik di mana saya dapat dengan cepat memfilter ribuan titik dalam sebuah shapefile. Aplikasi Django saya meminta untuk shapefile zip untuk upload, di mana file zip berisi setidaknya .shp
, .shx
dan .dbf
file. Sekali dalam tampilan Django saya, file zip adalah sebagai berikut:
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>
Dengan asumsi Geopandas adalah opsi terbaik untuk pemfilteran / masking yang efisien (jika saya salah, saya pasti terbuka untuk saran), saya tidak yakin bagaimana beralih dari keadaan saat ini ke Geopandas DataFrame. Ketika saya mencoba menggunakan read_file()
metode tersebut
import geopandas as gpd
gpd.read_file(request.FILES['file'].file)
Saya mendapatkan kesalahan berikut:
fiona.errors.DriverError: no driver
The geopandas.read_file()
docs menyatakan:
Baik jalur absolut atau relatif ke file atau URL yang akan dibuka, atau objek apa pun dengan
read()
metode (seperti file terbuka atau StringIO)
Saya tidak yakin bagaimana mendapatkan apa yang saya miliki ke dalam format yang sesuai untuk read_file()
metode tersebut.
Catatan: Pemaskeran dan pemfilteran yang ingin saya lakukan adalah pada data atribut dan bukan pada geometri.
Jawaban
Anda dapat menggunakan fiona.io.ZipMemoryFile
dan gpd.GeoDataFrame.from_features
.
Contoh:
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())
Catatan, saya awalnya tidak menyertakan BytesCollection
seperti yang dinyatakan pengembang fiona dalam komentar pada jawaban saya sebelumnya bahwa kelas tersebut kemungkinan besar akan dihentikan. Namun, jika Anda menggunakannya, Anda tidak perlu ZipMemoryFile
. Ini bekerja untuk saya:
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())
Jawaban @ user2856 membuat saya setengah jalan menuju solusi. Saya tidak akan tahu tentang itu fiona.io.ZipMemoryFile
, dan itu membawa saya pada jawaban ini . Menggabungkan dua solusi memberi saya:
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())
Saya sekarang memiliki data shapefile saya di GeoDataFrame.
Bagi siapa saja yang ingin tahu, alasan saya pergi dengan BytesCollection
bukannya memfile.open()
karena saya tidak bisa memfile.open()
bekerja. Ini akan memunculkan kesalahan yang mengatakan bahwa .open()
metode tersebut kehilangan argumen posisi 'jalur'.