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')
Solved! Go to Solution.
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)
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)
Thanks! Didn't know about defining spatial reference within geometry.