Читання необроблених даних у геопандах


14

Чи можна читати необроблені дані в a geopandas GeoDataFrame, a la a pandas DataFrame?

Наприклад, такі роботи:

import pandas as pd
import requests
data = requests.get("https://data.cityofnewyork.us/api/geospatial/arq3-7z49?method=export&format=GeoJSON")
pd.read_json(io.BytesIO(r.content))

Наступне не:

import geopandas as gpd
import requests
data = requests.get("https://data.cityofnewyork.us/api/geospatial/arq3-7z49?method=export&format=GeoJSON")
gpd.read_file(io.BytesIO(r.content))

Іншими словами, чи можна зчитувати геопросторові дані, що знаходяться в пам'яті, не зберігаючи ці дані на диску?

Відповіді:


16

Ви можете передати json безпосередньо конструктору GeoDataFrame:

import geopandas as gpd
import requests
data = requests.get("https://data.cityofnewyork.us/api/geospatial/arq3-7z49?method=export&format=GeoJSON")
gdf = gpd.GeoDataFrame(data.json())
gdf.head()

Виходи:

                                            features               type
0  {'type': 'Feature', 'geometry': {'type': 'Poin...  FeatureCollection
1  {'type': 'Feature', 'geometry': {'type': 'Poin...  FeatureCollection
2  {'type': 'Feature', 'geometry': {'type': 'Poin...  FeatureCollection
3  {'type': 'Feature', 'geometry': {'type': 'Poin...  FeatureCollection
4  {'type': 'Feature', 'geometry': {'type': 'Poin...  FeatureCollection

Для підтримуваних однофайлових форматів або формованих файлів-блискавок ви можете використовувати fiona.BytesCollectionта GeoDataFrame.from_features:

import requests
import fiona
import geopandas as gpd

url = 'http://www.geopackage.org/data/gdal_sample.gpkg'
request = requests.get(url)
b = bytes(request.content)
with fiona.BytesCollection(b) as f:
    crs = f.crs
    gdf = gpd.GeoDataFrame.from_features(f, crs=crs)
    print(gdf.head())
і для блискавок у формі файлів (підтримується на Fiona 1.7.2 )
url = 'https://www2.census.gov/geo/tiger/TIGER2010/STATE/2010/tl_2010_31_state10.zip'
request = requests.get(url)
b = bytes(request.content)
with fiona.BytesCollection(b) as f:
    crs = f.crs
    gdf = gpd.GeoDataFrame.from_features(f, crs=crs)
    print(gdf.head())

Ви можете дізнатися, які формати підтримує Fiona, використовуючи щось на кшталт:

import fiona
for name, access in fiona.supported_drivers.items():
    print('{}: {}'.format(name, access))

І лайливе вирішення для зчитування даних, що зберігаються в пам'яті, у файлі fiona 1.7.1 або новіших версій:

import requests
import uuid
import fiona
import geopandas as gpd
from osgeo import gdal

request = requests.get('https://github.com/OSGeo/gdal/blob/trunk/autotest/ogr/data/poly.zip?raw=true')
vsiz = '/vsimem/{}.zip'.format(uuid.uuid4().hex) #gdal/ogr requires a .zip extension

gdal.FileFromMemBuffer(vsiz,bytes(request.content))
with fiona.Collection(vsiz, vsi='zip', layer ='poly') as f:
    gdf = gpd.GeoDataFrame.from_features(f, crs=f.crs)
    print(gdf.head())

Це працює для GeoJSON, який відповідає на питання. Але це не буде працювати для інших геопросторових форматів файлів, таких як shapefiles або KML або KMZ. Чи знаєте ви вирішення цих випадків?
Олексій Білогур

Невелике уточнення в порядку. GeoPandas та Fiona підтримують форму та KML, але вони не можуть повністю підтримувати єдині API, такі як місто Нью-Йорк. Крім того, BytesCollectionповністю працює, але, ймовірно, буде видалено в наступній версії на користь одного з варіантів на github.com/Toblerity/Fiona/isissue/409 .
sgillies

Дякую. @sgillies чи слід це відкривати як запит на функцію geopandas, чи краще було б почекати змін, які ви згадали тут ?
Олексій Білогір

@sgillies ви заявляєте, що Fiona підтримує KML у вашому коментарі вище, але DriverError: unsupported driver: 'KML'він піднімається при спробі відкрити KML, оскільки його немає в supported_driversдиктаті (використовуючи Fiona 1.7.1), і я помітив ще кілька питань. відсутність підтримки KML (№23 та №97). Чи підтримує Fiona KML?
користувач2856

Дякуємо, що помітили from_featuresметод. Врятував мій день!
jlandercy

3

Оскільки fiona.BytesCollection, здається, TopoJSONтут не працює рішення, яке працює для всіх без потреби gdal:

import fiona
import geopandas as gpd
import requests

# parse the topojson file into memory
request = requests.get('https://vega.github.io/vega-datasets/data/us-10m.json')
visz = fiona.ogrext.buffer_to_virtual_file(bytes(request.content))

# read the features from a fiona collection into a GeoDataFrame
with fiona.Collection(visz, driver='TopoJSON') as f:
    gdf = gpd.GeoDataFrame.from_features(f, crs=f.crs)

З geopandas==0.4.0, Fiona==1.8.4і Python 3, я розумію DriverError: unsupported driver: 'TopoJSON'.
edesz

Ти правий. Він працював принаймні до версії 1.7.13зFiona
Mattijn

Прикро, що це не працює. Я намагався наслідувати ваш приклад на GitHub для сюжетів холоплету Altair, але це теж призводить до такої самої помилки gdf = gpd.read_file(counties, driver='TopoJSON'). Я думав, що використання with fiona.Collection...може працювати, але, на жаль, це не відбувається.
edesz

@edesz це помилка, і вона буде виправлена ​​у Fiona 1.8.5, дивіться: github.com/Toblerity/Fiona/isissue/721
Маттін


2

Якщо ви використовуєте Fiona 1.8, це можна (потрібно?) Зробити за допомогою проекту MemoryFileабоZipMemoryFile .

Наприклад:

import fiona.io
import geopandas as gpd
import requests

response = requests.get('http://example.com/Some_shapefile.zip')
data_bytes = response.content

with fiona.io.ZipMemoryFile(data_bytes) as zip_memory_file:
    with zip_memory_file.open('Some_shapefile.shp') as collection:
      geodf = gpd.GeoDataFrame.from_features(collection, crs=collection.crs)

0

Найпростіший спосіб - це введення URL-адреси GeoJSON безпосередньо в gpd.read (). Я намагався витягти файл з формату zip до цього за допомогою BytesIO & zipfile і мав проблеми з gpd (зокрема Fiona), приймаючи файлові об'єкти.

import geopandas as gpd
import David.SQL_pull_by_placename as sql
import os

os.environ['PROJ_LIB'] = r'C:\Users\littlexsparkee\Anaconda3\Library\share\proj'

geojson_url = f'https://github.com/loganpowell/census-geojson/blob/master/GeoJSON/500k/2018/{sql.state}/block-group.json?raw=true'
census_tracts_gdf = gpd.read_file(geojson_url)

0

Я віддаю перевагу результату, отриманому за допомогою незадокументованого, GeoDataFrame.from_features()а не для передачі GeoJSON конструктору GDF безпосередньо:

import geopandas as gpd
import requests
data = requests.get("https://data.cityofnewyork.us/api/geospatial/arq3-7z49?method=export&format=GeoJSON")
gpd.GeoDataFrame().from_features(data.json())

Вихідні дані

                       geometry                         name                                url           line objectid                                              notes
0    POINT (-73.99107 40.73005)                     Astor Pl  http://web.mta.info/nyct/service/  4-6-6 Express        1  4 nights, 6-all times, 6 Express-weekdays AM s...
1    POINT (-74.00019 40.71880)                     Canal St  http://web.mta.info/nyct/service/  4-6-6 Express        2  4 nights, 6-all times, 6 Express-weekdays AM s...
2    POINT (-73.98385 40.76173)                      50th St  http://web.mta.info/nyct/service/            1-2        3                              1-all times, 2-nights
3    POINT (-73.97500 40.68086)                    Bergen St  http://web.mta.info/nyct/service/          2-3-4        4           4-nights, 3-all other times, 2-all times
4    POINT (-73.89489 40.66471)             Pennsylvania Ave  http://web.mta.info/nyct/service/            3-4        5                        4-nights, 3-all other times

Отриманий GeoDataFrame має стовпчик з геометрією, встановлений правильно, і всі стовпці, як я очікував, не потребуючи видалення будь-яких FeatureCollections

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.