จาก shapefile ซิปที่อัพโหลดไปยัง Geopandas DataFrame ใน Django Application

Jan 05 2021

ฉันกำลังพยายามไปถึงจุดที่สามารถกรองจุดหลายพันจุดใน Shapefile ได้อย่างรวดเร็ว แอพลิเคชัน Django ฉันขอ shapefile ซิปไปกับการอัปโหลดที่ไฟล์ซิปมีอย่างน้อย.shp, .shxและ.dbfไฟล์ เมื่ออยู่ในมุมมอง Django ของฉันไฟล์ zip จะเป็นดังนี้:

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>

สมมติว่า Geopandas เป็นตัวเลือกที่ดีที่สุดสำหรับการกรอง / การกำบังที่มีประสิทธิภาพ (ถ้าฉันผิดฉันยินดีรับข้อเสนอแนะอย่างแน่นอน) ฉันไม่แน่ใจว่าจะเปลี่ยนจากสถานะปัจจุบันเป็น Geopandas DataFrame ได้อย่างไร พอลองใช้read_file()วิธี

import geopandas as gpd
gpd.read_file(request.FILES['file'].file)

ฉันได้รับข้อผิดพลาดต่อไปนี้:

fiona.errors.DriverError: no driver

geopandas.read_file() เอกสารระบุ:

เส้นทางสัมบูรณ์หรือสัมพัทธ์ไปยังไฟล์หรือ URL ที่จะเปิดหรือวัตถุใด ๆ ที่มีread()วิธีการ (เช่นไฟล์ที่เปิดหรือ StringIO)

ฉันไม่แน่ใจว่าจะนำสิ่งที่ฉันมีไปใช้เป็นรูปแบบที่เหมาะสมสำหรับread_file()วิธีนี้ได้อย่างไร

หมายเหตุ:การมาสก์และการกรองที่ฉันต้องการดำเนินการนั้นอยู่บนข้อมูลแอตทริบิวต์ไม่ใช่รูปทรงเรขาคณิต

คำตอบ

4 user2856 Jan 05 2021 at 06:19

คุณสามารถใช้fiona.io.ZipMemoryFileและgpd.GeoDataFrame.from_features.

ตัวอย่าง:

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())

หมายเหตุเดิมทีฉันไม่ได้รวมสิ่งBytesCollectionที่ผู้พัฒนา Fiona ระบุไว้ในความคิดเห็นในคำตอบก่อนหน้าของฉันว่าชั้นเรียนน่าจะเลิกใช้แล้ว ZipMemoryFileแต่ถ้าคุณใช้มันคุณไม่ควรจำเป็น สิ่งนี้ใช้ได้กับฉัน:

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

คำตอบของ @ user2856 ทำให้ฉันมีทางออกได้ครึ่งทาง ฉันคงไม่รู้เรื่องfiona.io.ZipMemoryFileนี้และนั่นทำให้ฉันได้รับคำตอบนี้ การรวมสองวิธีแก้ปัญหาทำให้ฉัน:

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())

ตอนนี้ฉันมีข้อมูล shapefile ของฉันใน GeoDataFrame

สำหรับใครที่สงสัยเหตุผลที่ฉันไปด้วยBytesCollectionแทนที่จะmemfile.open()เป็นเพราะฉันไม่สามารถmemfile.open()ไปทำงานได้ มันจะทำให้เกิดข้อผิดพลาดว่า.open()เมธอดไม่มีอาร์กิวเมนต์ตำแหน่ง 'เส้นทาง'