4 votos

¿Se puede utilizar AsShape de ArcPy con GeoJSON FeatureCollection de polígonos con etiquetas?

El AsShape La documentación proporciona ejemplos que funcionan muy bien.

Sin embargo, me han dado lo que creo que es un GeoJSON válido que es una FeatureCollection de dos polígonos cada uno con una Label.

Se valida bien con el Formateador y validador de JSON pero cuando trato de AsShape en él, según el código de abajo, lanza un AssertionError en FeatureCollection.

Supongo que esto se debe a que AsShape no es compatible con FeatureCollections, por lo que me pregunto si hay otro enfoque que pueda utilizar.

import arcpy

polyX2_string = {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.669111722222,-28.8913181547568],[151.669712422222,-28.890733765868],[151.670252222222,-28.8896441436458],[151.670847433333,-28.8891966436458],[151.670976977778,-28.8865389769791],[151.670112977778,-28.8846608880903]]]},"properties":{"Label":"National Park"}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.711278388889,-28.8201784658692],[151.710854355556,-28.8192543325359],[151.7100674,-28.8187800769803],[151.709037344444,-28.8184233992026],[151.707838755556,-28.8182234992026],[151.705821266667,-28.8180901992026],[151.705597933333,-28.8194629992025],[151.705198088889,-28.8212781880914]]]},"properties":{"Label":"National Park"}}]}

polygon = arcpy.AsShape(polyX2_string)

0 votos

Bueno, de entrada, no funcionará porque una forma sólo puede tener una característica, aunque esa característica puede estar compuesta por múltiples partes. Además, parece que una FeatureCollection puede contener diferentes tipos de características, mientras que un shapefile o feature class sólo puede contener un tipo de característica. Por lo tanto, necesitará alguna lógica adicional para descomponer el objeto JSON en características individuales, así como para que coincida sólo con el tipo de característica soportado por su clase de característica.

0 votos

Gracias blah238 - Voy a trabajar con el desarrollador que está escribiendo el GeoJSON que ingiero, para ver si el polígono (s) se puede pasar como polígonos en lugar de FeatureCollections.

4voto

UnkwnTech Puntos 21942

Voy a darle a theJones los puntos de Respuesta y a Jason un upvote porque ambos fueron útiles. En realidad, había elaborado una solución poco después de hacer la pregunta que había tenido la intención de publicar después de un mayor refinamiento - Voy a hacer ahora.

import arcpy,json

jsonGeometry_string = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.669111722222,-28.8913181547568],[151.669712422222,-28.890733765868],[151.670252222222,-28.8896441436458],[151.670847433333,-28.8891966436458],[151.670976977778,-28.8865389769791],[151.670112977778,-28.8846608880903]]]},"properties":{"Label":"National Park"}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.711278388889,-28.8201784658692],[151.710854355556,-28.8192543325359],[151.7100674,-28.8187800769803],[151.709037344444,-28.8184233992026],[151.707838755556,-28.8182234992026],[151.705821266667,-28.8180901992026],[151.705597933333,-28.8194629992025],[151.705198088889,-28.8212781880914]]]},"properties":{"Label":"National Park"}}]}'
jsonGeometry_object = json.loads(jsonGeometry_string)

testFolder = "C:\\Temp"
testGDBName = "PolyFromJSONtest.gdb"
testGDB = testFolder + "\\" + testGDBName
if arcpy.Exists(testGDB):
    arcpy.Delete_management(testGDB)
arcpy.CreateFileGDB_management(testFolder, testGDBName)

prjFile = "C:/Program Files/ArcGIS/Desktop10.0/Coordinate Systems/Geographic Coordinate Systems/Australia and New Zealand/Geocentric Datum of Australia 1994.prj"
sr = arcpy.SpatialReference(prjFile)

arcpy.CreateFeatureclass_management(testGDB, "PolyFromJSON", "POLYGON", spatial_reference=sr)
arcpy.AddField_management(testGDB + "\\PolyFromJSON", "ParkName", "TEXT", field_length=50)
arcpy.CopyFeatures_management(testGDB + "\\PolyFromJSON",testGDB + "\NewPolyNoValue")

for jsonFeat in jsonGeometry_object['features']:
    polygon = arcpy.AsShape(jsonFeat['geometry'])
    label_string = jsonFeat['properties']['Label']
    print label_string
    arcpy.CopyFeatures_management(testGDB + "\NewPolyNoValue",testGDB + "\\NewPolyWithValue")
    arcpy.Append_management([polygon], testGDB + "\\NewPolyWithValue", "NO_TEST")
    arcpy.CalculateField_management(testGDB + "\\NewPolyWithValue", "ParkName", "'" + label_string + "'","PYTHON")
    arcpy.AddMessage("Appending " + label_string + " polygon into " + testGDB + "\\PolyFromJSON")
    arcpy.Append_management([testGDB + "\\NewPolyWithValue"], testGDB + "\\PolyFromJSON", "NO_TEST")
    arcpy.Delete_management(testGDB + "\\NewPolyWithValue")

arcpy.Delete_management(testGDB + "\NewPolyNoValue")

3voto

Paul Puntos 555

arcpy.AsShape sólo acepta geometrías GeoJSON puras (Polígono, Polilínea, Punto) como las definidas por esta especificación No se trata de un registro de características.

3voto

Azim Puntos 4541

No he utilizado antes el AsShape. Mirando los ejemplos todos parecen empezar en la parte "type": del json. Por lo tanto, usted debe ser capaz de bucle a través de la json después de que se carga y llegar a esa parte. Debe ser un dictado de python que entonces sólo puede ir a través de la clave, los pares de valores y sacar lo que usted necesita. El código de abajo se ha ejecutado, pero lo más probable es que tenga que modificar. Una vez que llegue a la geometría puede empezar a filtrar por tipo. Eso debería permitirle procesar las diferentes formas dentro de la colección de características. No es necesario dividirlas primero, sólo ajustar el bucle del diccionario y añadir algunas comprobaciones de error. ¡Bang!

import json, arcpy

main_json_string = '{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.669111722222,-28.8913181547568],[151.669712422222,-28.890733765868],[151.670252222222,-28.8896441436458],[151.670847433333,-28.8891966436458],[151.670976977778,-28.8865389769791],[151.670112977778,-28.8846608880903]]]},"properties":{"Label":"National Park"}},{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[151.711278388889,-28.8201784658692],[151.710854355556,-28.8192543325359],[151.7100674,-28.8187800769803],[151.709037344444,-28.8184233992026],[151.707838755556,-28.8182234992026],[151.705821266667,-28.8180901992026],[151.705597933333,-28.8194629992025],[151.705198088889,-28.8212781880914]]]},"properties":{"Label":"National Park"}}]}'

jsonData = json.loads(main_json_string)

for key,value in jsonData.iteritems():
    if value == 'FeatureCollection': # skip the salad and get to the steak
        pass
    else:
        for i in value:                    
            try:
                for k,v in i.iteritems():
                    if k == 'geometry':
                        print v
                        polygon = arcpy.AsShape(v)
                        print "Made it this far with no errors"
                    else:
                        pass
            except:
                pass

3voto

John K Puntos 623

Tenía una necesidad similar de importar geoJson y tu script fue un gran punto de partida para mí. Sin embargo, el método de creación y eliminación de un conjunto de características de trabajo temporal era demasiado lento para mis necesidades, procesando miles de objetos mientras el usuario espera. Encontré el método InsertCursor, que permite construir e insertar filas en las características existentes. También intenta burdamente crear todos los campos e identificar los tipos básicos en la nueva clase de característica. Mi versión:

import urllib2, arcpy, json

url = arcpy.GetParameterAsText(0)
featureClassName = arcpy.GetParameterAsText(1)
featureClassPath = arcpy.GetParameterAsText(2)

def testFloat(s):
    try:
        float(s)
        return True
    except ValueError:
        return False

def testInt(s):
    try:
        int(s)
        return True
    except ValueError:
        return False

testJson = '{ "type": "FeatureCollection", "features": [ { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -98.7445, 33.387001 ] }, "properties": { "SiteCode": "447910", "VariableCode": "MPE", "Value": "0.639999991282821" } }, { "type": "Feature", "geometry": { "type": "Point", "coordinates": [ -98.7068, 33.347801 ] }, "properties": { "SiteCode": "446210", "VariableCode": "MPE", "Value": "0.949999986216426" } } ] }'

response = urllib2.urlopen(url)
rawJson = response.read()
#IIS result has UTF-8 BOM
rawJson = rawJson.decode("utf-8-sig")
jsonData = json.loads(rawJson)

#esriJson settings
jsonFeatures = "features"
jsonFields = "attributes"
jsonGeom = "geometry"
#geojson settings
jsonFeatures = "features"
jsonFields = "properties"
jsonGeom = "geometry"

#prjFile = "C:/Program Files/ArcGIS/Desktop10.0/Coordinate Systems/Geographic Coordinate Systems/Australia and New Zealand/Geocentric Datum of Australia 1994.prj"
#sr = arcpy.SpatialReference(prjFile)
sr = arcpy.SpatialReference(4269)

featureFullName = featureClassPath + "/" + featureClassName

fields = []

if arcpy.Exists(featureFullName):
    arcpy.Delete_management(featureFullName)
#Final result Feature Class
arcpy.CreateFeatureclass_management(featureClassPath, featureClassName, "POINT", spatial_reference=sr)

#scan json for all fields
# this could be much faster with esriJson by using the jsonData['fields'] attributes. No such luck in geoJson 
for jsonFeat in jsonData[jsonFeatures]:    
    print jsonFeat
    # Check for fields to be added
    print jsonFeat[jsonFields]
    for key, val in jsonFeat[jsonFields].iteritems():
        print key
        if (key[:10] not in fields):
            fields.append(key[:10])
            if(testInt(val)):
                arcpy.AddField_management(featureFullName, key[:10], "LONG")
            elif (testFloat(val)):
                arcpy.AddField_management(featureFullName, key[:10], "FLOAT")
            else:
                arcpy.AddField_management(featureFullName, key[:10], "TEXT", field_length=50)

# Create insert cursor for table
rows = arcpy.InsertCursor(featureFullName)

#Now read data from json
for jsonFeat in jsonData[jsonFeatures]:
    polygon = arcpy.AsShape(jsonFeat[jsonGeom])

    #add the json geometry to row
    row = rows.newRow()
    row.shape = polygon

    # set all field values
    for key,val in jsonFeat[jsonFields].iteritems():
        row.setValue(key[:10], val)

    rows.insertRow(row)

# Delete cursor and row objects to remove locks on the data
del row
del rows

0 votos

Gracias por publicar esto - mi aplicación sólo necesita ingerir un puñado de polígonos (con miles de vértices cada uno) por lo que no había notado ese cuello de botella en el código que armé. Usaré un InsertCursor en lugar de Append la próxima vez que me encuentre con este requisito.

0voto

Brendan Long Puntos 118

Encontré que esta biblioteca es una gran alternativa al uso de arcpy.AsShape que tiene problemas. No creo que ESRI quiera dar soporte completo a geojson.

https://gist.github.com/om-henners/4062925

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X