How to define projection when adding features through an endpoint?

749
2
Jump to solution
09-09-2020 08:50 AM
KeonMonroe
New Contributor III

Using Python, I have an api with security incidents that I want to populate into a feature service layer. I've achieved this successfully using Add Features via the API endpoint (described in this documentation). However the original point feature class is stored in SDE which has a defined coordinate system of "WGS_1984_Web_Mercator_Auxiliary_Sphere".

Therefore my points are being added with the wrong projection (because I'm using just geographic coordinates).

Are there any programmatic solutions to change the geometry to a matching projection before adding the features?

My (slightly modified) working code is included. Basically I have two functions - the first one grabs the API data and then returns a list of reformatted features. Then, the next function takes that list as input and adds each feature to the feature service layer. 

Any help is much appreciated. 

Thanks. 

import urllib
import requests
import json, time
from datetime import datetime
import unicodedata
    
def getFeaturesReformatPayload(api_url):
    ''' Requests API, returns list with reformatted payload for adding features.
    '''
    # get planet risk data
    print('Getting Planet Risk data...')
    response = requests.get(api_url)
    if response.status_code == 200:
        print("Success") 
    else:
        print("There was an error")
    
    payload = response.json()
    
    # reformat the payload to be added to feature layer
    payload_reformatted = []

    for i, x in enumerate(payload['result']['resourceList'][0]['resource']):
        
        # convert datetime in time cols - 'updated', 'created'
        created_time = x['created'][:-3] # shortened epoch to seconds
        # print('Length of created timestamp: {}'.format(len(str(created_time))))
        updated_time = x['updated'][:-3]
        # print('Length of updated timestamp: {}'.format(len(str(updated_time))))
        
        # convert unicode to string
        created_time_str = unicodedata.normalize('NFKD', created_time).encode('ascii', 'ignore')
        updated_time_str = unicodedata.normalize('NFKD', updated_time).encode('ascii', 'ignore')
        created_formatted = datetime.fromtimestamp(float(created_time_str)) 
        updated_formatted = datetime.fromtimestamp(float(updated_time_str)) 


        # copy dict then update formatted time in the dict
        copy_dict = x.copy()
        copy_dict.update({'created': str(created_formatted)[:10]}) # removing timestamp - just date
        copy_dict.update({'updated': str(updated_formatted)[:10]})
        # print('Feature #: {} , was created on {}, and was last updated on {}'.format(i, created_formatted, updated_formatted))

        # create geometry - delete unwanted fields - append to reformatted
        geometry_dict = dict(y = x['lat'], x = x['lng'])
        deleteFields = ['lat', 'lng', 'resourcetype', 'id']
        for x in deleteFields:
            copy_dict.pop(x)
        payload_out = dict(attributes = copy_dict, geometry = geometry_dict)
        payload_reformatted.append(payload_out)
        
    print('Total Number of Incidents: {}'.format(len(payload_reformatted)))
    
    return payload_reformatted

def addIncidentsToFSL(input_payload):
    ''' Adds input payload to the feature service layer via proxy.
    '''
    
    # proxy bypasses authentication 
    proxy_path = "https://servername.example.net/DotNet/proxy.ashx?"
    feature_layer_endpoint = "https://servername.example.com/arcgis/rest/services/National/examplePublishedMXD/FeatureServer/3/addFeatures"

    url = "".join([proxy_path,feature_layer_endpoint ])
    # print(url)
    for i, k in enumerate(input_payload):
        print('\nAdding Incident to Feature Service Layer: {}'.format(i))
        
        payload_body = {'f': 'json', 'features': json.dumps([input_payload[i]])}
        # print(payload_body)
        print('...')
        r = requests.post(url, data = payload_body, verify = False)
        
        # print response
        if r.status_code == 200:
            print('Success')
        else:
            print('Failed')
            
        # wait 3 seconds
        time.sleep(3)

if __name__ == "__main__":
    # define api, get features, reformat, add to feature service layer
    example_api = 'string_with_apiURL' 
    
    reformatted_payload = getFeaturesReformatPayload(example_api)
    addIncidentsToFSL(reformatted_payload)
    print('All Features Added from API to Feature Service Layer')
    
    ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
0 Kudos
1 Solution

Accepted Solutions
RandyBurton
MVP Alum

You should be able to specify a spatial reference in your geometry on line 42:

geometry_dict = dict(y = x['lat'], x = x['lng'], spatialReference = dict(wkid = 4326))# {'y': 39.948874, 'x': -75.948874, 'spatialReference': {'wkid': 4326}}

You could also try .projectAs:

import arcpy

def project(x,y): # lon,lat to web mercator
    # WGS 1984 : (4326) Lat/Lon
    # WGS 1984 Web Mercator (auxiliary sphere) : (102100) or (3857)
    ptGeometry = arcpy.PointGeometry(arcpy.Point(x,y),arcpy.SpatialReference(4326)).projectAs(arcpy.SpatialReference(3857))
    return (ptGeometry.firstPoint.X, ptGeometry.firstPoint.Y)

print(project(-75.948874, 39.948874))

# result: (-8454589.980002495, 4858515.567532215)

View solution in original post

0 Kudos
2 Replies
RandyBurton
MVP Alum

You should be able to specify a spatial reference in your geometry on line 42:

geometry_dict = dict(y = x['lat'], x = x['lng'], spatialReference = dict(wkid = 4326))# {'y': 39.948874, 'x': -75.948874, 'spatialReference': {'wkid': 4326}}

You could also try .projectAs:

import arcpy

def project(x,y): # lon,lat to web mercator
    # WGS 1984 : (4326) Lat/Lon
    # WGS 1984 Web Mercator (auxiliary sphere) : (102100) or (3857)
    ptGeometry = arcpy.PointGeometry(arcpy.Point(x,y),arcpy.SpatialReference(4326)).projectAs(arcpy.SpatialReference(3857))
    return (ptGeometry.firstPoint.X, ptGeometry.firstPoint.Y)

print(project(-75.948874, 39.948874))

# result: (-8454589.980002495, 4858515.567532215)
0 Kudos
KeonMonroe
New Contributor III

Thanks! Didn't know about defining spatial reference within geometry. 

0 Kudos