3

I have some code that works on geopandas GeoDataFrames but due to a client requirement I suddenly have to access my input data via the ArcGIS Python library, which only allows me to access the data as an ArcGIS Spatially Enabled DataFrame.

Unsurprisingly, ESRI has only provided methods to convert from geopandas to their format, and provided no support for the opposite direction:

https://developers.arcgis.com/python/api-reference/arcgis.features.toc.html#arcgis.features.GeoAccessor.from_geodataframe

https://community.esri.com/t5/arcgis-api-for-python-questions/creating-updating-feature-layer-in-arcgis-online-from-geopandas/td-p/790989

Is there a way to easily convert one of these to a geopandas GeoDataFrame or am I now locked in the ESRI prison?

I guess I could temporarily write the results to the file system and then open it with geopandas from there, but I am hoping it doesn't come to that.

3 Answers 3

7

While there is no method in the ArcGIS Python API to convert from a SpatialDataFrame to a Geopandas GeoDataFrame, we can create a GeoDataFrame using another method.

I will assume you are accessing your ArcGIS Online feature layer using the .query() method, which returns a FeatureSet. You can convert a FeatureSet into a geojson string, read the geojson as a dict, and construct a GeoDataFrame from that dict.

from arcgis.gis import GIS
import geopandas as gpd
import json

# login to AGOL
gis = GIS('https://arcgis.com', username, password)

# get the hosted feature layer
flayer = gis.content.get('identifierstring').layers[0]

# .query() returns a FeatureSet
fset = flayer.query()

# get a GeoJSON string representation of the FeatureSet
gjson_string = fset.to_geojson

# read GeoJSON string into a dict
gjson_dict = json.loads(gjson_string)

gdf = gpd.GeoDataFrame.from_features(gjson_dict['features'])
# may need to specify CRS and geometry column name after GeoDataFrame construction
3
  • 1
    You are a life saver. I have this memory of ESRI encoding their GeoJSONs in a nonstandard way and that's why I thought geojson wouldn't work.. Bizarre though, how to_geojson is a property and not a method.
    – wfgeo
    Commented Dec 7, 2020 at 8:44
  • is this still the best way to go from arcgis to geopandas?
    – thus__
    Commented Jan 2, 2023 at 16:24
  • @thus__ check out my answer as an alternative method
    – jesnes
    Commented Jan 25, 2023 at 18:54
1

@Whiskers I found that instead of using gpd.GeoDataFrame.from_features() which didn't work with multipolygons. I was able to use gpd.GeoDataFrame.read_file() specifying the driver as 'GeoJSON' on all geometry types.

gpd.GeoDataFrame.read_file(gjson_string, driver='GeoJSON')
0
1

Late to the party, but thought I'd add that if you're trying to access a Map/Feature service outside of AGO (a common need for accessing Open Data!), you can use the requests library:

import requests

import geopandas as gpd

# query paramaters
crs = 4326
params = {
    "where": "1=1",
    "outFields": "*",
    "outSr": crs,
    "f": "geojson" # this is the important one to have!!
}

# access data
url = "https://path/to/your/MapService/0"
resp = requests.get(f"{url}/query", params=params)
gjson = resp.json()

# gdf it!
gdf = gpd.GeoDataFrame.from_features(gjson, crs=crs)

Just be sure to check that your parameters match the conventions set by ESRI. For the query endpoint, these are listed in the API documentation.

4
  • Nice! This is for reading directly off of a rest endpoint though and not converting!
    – thus__
    Commented Jan 26, 2023 at 14:59
  • 1
    you don't need to import json and then json.loads(resp.text), you can just do resp.json() Commented May 11, 2023 at 12:05
  • Did not know that. Thanks!
    – jesnes
    Commented May 11, 2023 at 16:54
  • This rocks. Performs better than any other method I've found.
    – dgrubman
    Commented May 9 at 18:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.