アップロードされたzip形式のシェープファイルからDjangoアプリケーションのGeopandasDataFrameへ

Jan 05 2021

シェープファイル内の何千ものポイントをすばやくフィルタリングできるポイントに到達しようとしています。私のDjangoアプリケーションは、zipファイルが少なくとも含まれている場合は、アップロードするzip形式のシェープファイルを要求.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が効率的なフィルタリング/マスキングに最適なオプションであると仮定すると(私が間違っている場合は、間違いなく提案を受け入れます)、現在の状態からGeopandasDataFrameに移行する方法がわかりません。この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.ZipMemoryFilegpd.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、そしてそれは私をこの答えに導きました。2つのソリューションを組み合わせると、次のことがわかりました。

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

これで、GeoDataFrameにシェープファイルデータがあります。

好奇心旺盛な方のために、BytesCollection代わりに一緒に行ったのmemfile.open()は、仕事ができなかったmemfile.open()からです。.open()メソッドに「パス」の位置引数がないというエラーがスローされます。