1

I have some code that connects to a gis server, esr rest service, and returns the geometries of the features on that layer. I can pick html, json, geojson, kmz, and pdf as returns and I can export the json and geojson to featureclasses using arcpy. What I am trying to do is, without arcpy or downloading the data, is use those geometries to identify if a series of input points are within any of the polygons. I figured the best way was to use geopandas.within but I cannot get geopandas to read the response from gis server as polygons. I tried a number of solutions from other stack resources and using the geopandas site but the errors indicate either the input is wrong or the format is unsupported. I think it has something to do with the fact I am using a return from a url.

import urllib.parse, urllib.request, geopandas, requests, json

testPTS = [[61.5620807,44.2004590],[60.4736610,42.1696271]] ## My Test points
url = "https://server.domain.com/server/rest/services/servicename/MapServer/0/query?" ## A Map Service Query URL
## Search Parameters
params = {'where': '1=1',
           'geometryType': 'esriGeometryPolygon',
           'spatialRel': 'esriSpatialRelIntersects',
           'relationParam': '',
           'outFields': '*',
           'returnGeometry': 'true',
           'geometryPrecision':'',
           'outSR': '',
           'returnIdsOnly': 'false',
           'returnCountOnly': 'false',
           'orderByFields': '',
           'groupByFieldsForStatistics': '',
           'returnZ': 'false',
           'returnM': 'false',
           'returnDistinctValues': 'false',
           'f': 'geojson',
           }

encode_params = urllib.parse.urlencode(params).encode("utf-8")

response = urllib.request.urlopen(url, encode_params)
json = response.read()

df = geopandas.read_file(str(response), driver = 'GeoJSON')
2
  • geopandas.read_file() "returns a GeoDataFrame from a file or URL"-- you're feeding in a response string, which is neither of those things. Try wrapping it in a StringIO object as the docs suggest. If that fails, it may help to get answers if you post the actual response text and error traceback
    – mikewatt
    Apr 19 at 21:25
  • I usually do post the response text, in this case I had tried several different minor adjustments all giving me different responses. I couldn't think of a good way to communicate them in reference to each approach I tried. Going back to the original esri code I added this with open("mapservice.json", "wb") as ms_json: ms_json.write(json) df = geopandas.read_file('mapservice.json', driver = 'GeoJSON') print(df) The print at the end prints polygon geometries so I think what I was missing was that with open (mapservice.json)... creates a json in memory named mapservice for geopanadas. Apr 20 at 11:18

2 Answers 2

1

Using

with open("mapservice.json", "wb") as ms_json:
ms_json.write(json)

polygons = geopandas.read_file('mapervices.json', driver = 'GeoJSON')
print(type(polygons))

Output is <class 'geopandas.geodataframe.GeoDataFrame'>

It isn't a whole lot different from the esri code I started with from https://support.esri.com/en/technical-article/000019645.

Replacing

df = geopandas.read_file(str(response), driver = 'GeoJSON')

with

with open("BWEZones.json", "wb") as ms_json:
ms_json.write(json)

zones = geopandas.read_file('BWEZones.json', driver = 'GeoJSON')
print(type(zones))

However, it creates files in the root of my python project and I want it to do the work in memory without saving files.

3
  • 1
    Pass in StringIO(json_string) instead of writing a file-- it will give back a "file-like object" but hold everything in memory
    – mikewatt
    Apr 20 at 17:56
  • I created a new variable called jsonStr and added it in the original code by replacing the with open... like this jsonStr = StringIO(json) zones = geopandas.read_file(jsonStr, driver = 'GeoJSON') print(type(zones)) error is "jsonStr = StringIO(json) TypeError: initial_value must be str or None, not bytes" Apr 21 at 10:51
  • StringIO may not have worked but BytesIO seems to have, you got me moving in the right direction Apr 21 at 11:42
1

I had to use BytesIO to pass the Geojson to geopandas

After getting your url response from the rest service

response = urllib.request.urlopen(url, encode_params)
json = response.read()

jsonIO = BytesIO(json)

zones = geopandas.read_file(jsonIO, driver = 'GeoJSON')
print(type(zones))

The result is <class 'geopandas.geodataframe.GeoDataFrame'> from the print type command. I am assuming this means geopandas read the geojson from the BytesIO and understands it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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