Convert Dictionary To Temp FeatureClass

953
10
Jump to solution
12-18-2017 11:31 AM
JamesCrandall
MVP Frequent Contributor

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
  }
 ]
}
1 Solution

Accepted Solutions
RandyBurton
MVP Regular Contributor

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.

View solution in original post

10 Replies
JoshuaBixby
MVP Esteemed Contributor

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.

0 Kudos
JamesCrandall
MVP Frequent Contributor

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.

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor

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

0 Kudos
JamesCrandall
MVP Frequent Contributor

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
RandyBurton
MVP Regular Contributor

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.

RandyBurton
MVP Regular Contributor

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.

JamesCrandall
MVP Frequent Contributor

Thanks! -- I think the missing part was I really just needed a second .iteritems() instance that captures the attributes along with the geometry info. 

0 Kudos
NikSands
New Contributor II

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"]])
RandyBurton
MVP Regular Contributor

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.

0 Kudos