Du fichier de formes compressé téléchargé à Geopandas DataFrame dans l'application Django
J'essaie d'arriver à un point où je peux filtrer rapidement des milliers de points dans un fichier de formes. Mon application Django demande un shapefile zippé à télécharger, où le fichier compressé contient au moins .shp
, .shx
et les .dbf
fichiers. Une fois dans ma vue Django, le fichier zip est le suivant:
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>
En supposant que Geopandas est la meilleure option pour un filtrage / masquage efficace (si je me trompe, je suis définitivement ouvert aux suggestions), je ne sais pas comment passer de l'état actuel à un Geopandas DataFrame. Quand j'essaye d'utiliser la read_file()
méthode
import geopandas as gpd
gpd.read_file(request.FILES['file'].file)
J'obtiens l'erreur suivante:
fiona.errors.DriverError: no driver
L' état de la geopandas.read_file()
documentation :
Soit le chemin absolu ou relatif du fichier ou de l'URL à ouvrir, soit tout objet avec une
read()
méthode (comme un fichier ouvert ou StringIO)
Je ne sais pas comment obtenir ce que j'ai dans un format approprié pour la read_file()
méthode.
Remarque: Le masquage et le filtrage que je cherche à effectuer sont sur les données d'attribut et non sur la géométrie.
Réponses
Vous pouvez utiliser fiona.io.ZipMemoryFile
et gpd.GeoDataFrame.from_features
.
Exemple:
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())
Notez BytesCollection
qu'à l' origine, je n'ai pas inclus le comme le développeur fiona l'a déclaré dans un commentaire sur ma réponse précédente que la classe serait probablement obsolète. Cependant, si vous l'utilisez, vous ne devriez pas en avoir besoin ZipMemoryFile
. Cela fonctionne pour moi:
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())
La réponse de @ user2856 m'a amené à mi-chemin vers une solution. Je ne l'aurais pas su fiona.io.ZipMemoryFile
, et cela m'a conduit à cette réponse . La combinaison des deux solutions m'a donné:
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())
J'ai maintenant mes données de fichier de formes dans un GeoDataFrame.
Pour tous ceux qui sont curieux, la raison pour laquelle je suis allé avec BytesCollection
plutôt que memfile.open()
parce que je ne pouvais pas me rendre memfile.open()
au travail. Cela lèverait une erreur indiquant que la .open()
méthode manquait un argument de position «chemin».