Dari shapefile zip yang diunggah ke Geopandas DataFrame dalam Aplikasi Django

Jan 05 2021

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, .shxdan .dbffile. 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

4 user2856 Jan 05 2021 at 06:19

Anda dapat menggunakan fiona.io.ZipMemoryFiledan 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 BytesCollectionseperti 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())
1 GISUser9 Jan 06 2021 at 00:04

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 BytesCollectionbukannya memfile.open()karena saya tidak bisa memfile.open()bekerja. Ini akan memunculkan kesalahan yang mengatakan bahwa .open()metode tersebut kehilangan argumen posisi 'jalur'.