What's fastest way to convert the dictionary below of polygon features into an in_memory feature class?
{
"COUNTIES": [
{
"COUNTY": "COUNTY 1",
"COUNTYRINGFEATURE": {
"rings": [
[
[
-8930981.5967,
3040606.1534
],
[
-8930880.296,
3040593.7322000004
],
[
-8930860.2585,
3040604.911200002
],
[
-8930361.547,
3040438.4703
],
[
-8929910.703,
3040288.178100001
],
[
-8929241.6727,
3040065.848200001
],
[
-8928384.5124,
3039780.1779000014
],
[
-8928253.1552,
3039740.4329000004
],
[
-8930981.5967,
3040606.1534
]
]
]
},
"COUNTYOID": 50
},
{
"COUNTY": "COUNTY 2",
"COUNTYRINGFEATURE": {
"rings": [
[
[
-8947371.1721,
3118264.7214
],
[
-8947243.1547,
3118263.4723999985
],
[
-8946191.1852,
3118252.2322999984
],
[
-8946173.3741,
3118252.2322999984
],
[
-8946160.0158,
3118250.9833999984
],
[
-8946099.9032,
3118250.9833999984
],
[
-8945873.9246,
3118249.7346
],
[
-8945723.6431,
3118244.7388000004
],
[
-8945527.7209,
3118244.7388000004
],
[
-8945303.9686,
3118242.2410999984
],
[
-8945138.1025,
3118238.4943999983
],
[
-8945100.2539,
3118238.4943999983
],
[
-8941077.1663,
3118199.7786
],
[
-8937553.9034,
3118162.3117000014
],
[
-8947371.1721,
3118264.7214
]
]
]
},
"COUNTYOID": 61
}
]
}
Solved! Go to Solution.
To use the input from your original post, you might try:
import json
jsonIn = r'input.json'
jsonOut = r'output.json'
input_file=open(jsonIn, 'r')
result = json.loads(input_file.read())
# start a geojson file - change spatial reference as required
geo = {
"type" : "FeatureCollection",
"crs" : { "type" : "name",
"properties" : {
"name" : "EPSG:4326"
}
},
"features" : None
}
feature_list = []
fCount = 0
for k, v in result.iteritems():
for x in v: # values are in a list
fCount += 1
features = {"type" : "Feature", "id" : fCount, "properties" : None, "geometry" : None }
props = []
if isinstance(x, dict):
for k1, v1 in x.iteritems():
if isinstance(v1, dict):
# found dictionary, assume geometry
for k2, v2 in v1.iteritems():
features["geometry"] = {k2: v2}
else:
props.append({k1: v1})
features["properties"] = props
feature_list.append(features)
geo["features"] = feature_list
with open(jsonOut, 'w') as outfile:
json.dump(geo, outfile)
This reformats your original json into geojson.
This looks like JSON, but it isn't valid GeoJSON or Esri JSON. Is this actually JSON output? If so, how is it being generated because there are many simple ways to create features and feature classes when working with valid GeoJSON or Esri JSON.
It's a dictionary populated from a map service layer. My requirement is to be able to clip polygon features in this map service, but that is not available via REST, so I plan to get the features of interest from the map service with its attributes (NOT just the coordinate info), then convert to a temporary feature class that I can then clip.
There is some json to esri json function buried in the 'argis' module... I had a quick look, but I usually just ignore anything json
I think I've been able to work thru this. Pretty sure it's your original code that I'm trying to parse a JSON result --- that iteritems() always confused me on how to access other attributes from the source.
countyCount = (jsonResult['features'])
if countyCount > 0:
for key,value in jsonResult.iteritems():
if value == 'FeatureCollection':
pass
else:
for i in value:
try:
for k1,v1 in i.iteritems():
if k1 == 'attributes':
cn = v1['POLYGON_NM']
for k,v in i.iteritems():
if k == 'geometry':
features = []
feature = v['rings']
#countyPolygon = arcpy.Polygon(arcpy.Array([arcpy.Point(*coords) for coords in feature]), inSr)
for feat in feature:
polyArray = arcpy.Array()
for pointsPair in feat:
newpoint = arcpy.Point(*pointsPair)
polyArray.add(newpoint)
countyPolygon = arcpy.Polygon(polyArray)
insertCursor = arcpy.da.InsertCursor(tmpCounties, ['SHAPE@','COUNTYNAME'])
insertData = countyPolygon, cn
insertCursor.insertRow(insertData)
else:
pass
except:
pass
And it might also be helpful to review this question: Convert JSON into FeatureCollection. You will probably want to insert some projection info, to make this valid ESRI json. COUNTYRINGFEATURE would become geometry; and COUNTY and COUNTYOID would become attributes.
To use the input from your original post, you might try:
import json
jsonIn = r'input.json'
jsonOut = r'output.json'
input_file=open(jsonIn, 'r')
result = json.loads(input_file.read())
# start a geojson file - change spatial reference as required
geo = {
"type" : "FeatureCollection",
"crs" : { "type" : "name",
"properties" : {
"name" : "EPSG:4326"
}
},
"features" : None
}
feature_list = []
fCount = 0
for k, v in result.iteritems():
for x in v: # values are in a list
fCount += 1
features = {"type" : "Feature", "id" : fCount, "properties" : None, "geometry" : None }
props = []
if isinstance(x, dict):
for k1, v1 in x.iteritems():
if isinstance(v1, dict):
# found dictionary, assume geometry
for k2, v2 in v1.iteritems():
features["geometry"] = {k2: v2}
else:
props.append({k1: v1})
features["properties"] = props
feature_list.append(features)
geo["features"] = feature_list
with open(jsonOut, 'w') as outfile:
json.dump(geo, outfile)
This reformats your original json into geojson.
Thanks! -- I think the missing part was I really just needed a second .iteritems() instance that captures the attributes along with the geometry info.
Here's another take on it... (sorry, I don't know the geonet way to use code tags yet)
import arcpy tempFC = arcpy.CreateFeatureclass_management("in_memory", "counties", "POLYGON", spatial_reference=arcpy.SpatialReference(3857)) # web mercator, eg arcpy.AddField_management(tempFC, "Name", "TEXT") arcpy.AddField_management(tempFC, "CountyOID", "TEXT") countiesList = theDictionary["COUNTIES"] with arcpy.da.InsertCursor(tempFC, ["SHAPE@", "Name", "CountyOID"]) as cur: for county in countiesList: outerRing = county["COUNTYRINGFEATURE"]["rings"][0] arr = arcpy.Array() for coordPair in outerRing: arr.add(arcpy.Point([coordPair[0], coordPair[1]])) polygon = arcpy.Polygon(arr) cur.insertRow([polygon, county["COUNTY"], county["COUNTYOID"]])
And actually the Spatial Reference should be Web Mercator (3857) - I didn't pay attention to the coordinates being greater/less than 180. Geojson is only supposed to use lat/lon as the crs type has been depreciated.