Từ tệp hình dạng nén đã tải lên thành Geopandas DataFrame trong Ứng dụng Django
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
và .dbf
tậ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
Bạn có thể sử dụng fiona.io.ZipMemoryFile
và gpd.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 BytesCollection
như 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())
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 BytesCollection
thay 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'.