Từ tệp hình dạng nén đã tải lên thành Geopandas DataFrame trong Ứng dụng Django

Jan 05 2021

Tôi đang cố gắng đạt đến điểm mà tôi có thể nhanh chóng lọc hàng nghìn điểm trong một tệp hình dạng. Ứng dụng Django của tôi yêu cầu một shapefile nén để upload, nơi mà các tập tin nén chứa ít nhất .shp, .shx.dbftập tin. Khi ở trong chế độ xem Django của tôi, tệp zip như sau:

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>

Giả sử Geopandas là tùy chọn tốt nhất để lọc / tạo mặt nạ hiệu quả (nếu tôi sai, tôi chắc chắn sẵn sàng nhận các đề xuất), tôi không chắc làm thế nào để chuyển từ trạng thái hiện tại sang Geopandas DataFrame. Khi tôi cố gắng sử dụng read_file()phương pháp

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

Tôi nhận được lỗi sau đây:

fiona.errors.DriverError: no driver

Các geopandas.read_file() tài liệu nêu:

Đường dẫn tuyệt đối hoặc tương đối đến tệp hoặc URL sẽ được mở hoặc bất kỳ đối tượng nào có read()phương thức (chẳng hạn như tệp đang mở hoặc StringIO)

Tôi không chắc làm thế nào để chuyển những gì tôi có vào một định dạng thích hợp cho read_file()phương pháp.

Lưu ý: Việc tạo mặt nạ và lọc mà tôi đang tìm cách thực hiện dựa trên dữ liệu thuộc tính chứ không phải hình học.

Trả lời

4 user2856 Jan 05 2021 at 06:19

Bạn có thể sử dụng fiona.io.ZipMemoryFilegpd.GeoDataFrame.from_features.

Thí dụ:

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

Lưu ý, ban đầu tôi không đưa vào BytesCollectionnhư nhà phát triển fiona đã nêu trong nhận xét về câu trả lời trước đây của tôi rằng lớp này có thể sẽ không được dùng nữa. Tuy nhiên, nếu bạn sử dụng nó, bạn không nên cần ZipMemoryFile. Điều này phù hợp với tôi:

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

Câu trả lời của @ user2856 đã giúp tôi có được một nửa giải pháp. Tôi sẽ không biết về fiona.io.ZipMemoryFile, và điều đó đã dẫn tôi đến câu trả lời này . Kết hợp hai giải pháp đã cho tôi:

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

Bây giờ tôi có dữ liệu tệp hình dạng của mình trong GeoDataFrame.

Đối với bất kỳ ai tò mò, lý do tôi đi BytesCollectionthay memfile.open()vì tôi không thể memfile.open()đi làm. Nó sẽ xuất hiện một lỗi nói rằng .open()phương thức này thiếu đối số vị trí 'đường dẫn'.