Hi all, this is a re-upload of a previously asked question that I could have worded better. My issue is that when I use the FeatureLayer.edit_features(updates=FeatureSet) method, it is overwriting my geometries. I have done this with several layers now, and it seems to be an issue exclusively with polygons.
Here is my script, broken up with images of my outputs:
polygon_layer_get = gis.content.get("8c1e457fea0341aeb9c29cdf3a1dd64c") # dummy shapefile I made for testing
polygon_layer = polygon_layer_get.layers[0]
df = polygon_layer.query().sdf
For now, notice that the geometry is intact.
# dummy function where I overwrite a single value
unscored_df = df[(df['scored'] < 1) | df['scored'].isna()]
df = unscored_df.copy()
df['scored'] = 1
# pandas df to geopandas gdf
polygon_df = gpd.GeoDataFrame(df, geometry="SHAPE", crs="EPSG:4326")
# gpd gdf to sedf
polygon_sedf = GeoAccessor.from_geodataframe(polygon_df, column_name="SHAPE")
If we look at the SEDF, the SHAPE is still intact.
# sedf to feature set
polygon_fs = polygon_sedf.spatial.to_featureset()
If we look at the FS, we can see the geometry field is still intact.
polygon_layer.edit_features(updates=polygon_fs)
And finally, we edit the features with no issues. But now, if I re-run the first part to load in the polygon data:
All the SHAPEs are None, and looking in AGOL confirms these are now empty records.
Any ideas?
Solved! Go to Solution.
Thank you for your solution, although that specific line
return_geometry = False,
forces all geometry as "None", whether I have already broken the layer or not. But for now, adding this line after converting back to a FeatureSet:
polygon_fs_updated = [
{
"SHAPE": feature.geometry,
"attributes": feature.attributes
}
for feature in original_features
]
did end up fixing the issue. Thanks for your help though!
GeoPandas and the ArcGIS Python API don't really play nice in my experience.
What are you doing to the geometry, and how are you using GeoPandas as part of that process?
Hi Josh,
I am not doing anything to the geometry itself, I just need to keep track of which features have been scored or not scored. I am really only using GeoPandas because the .query().sdf makes a GeoDataFrame already, and GeoPandas is my go-to data manipulation library.
I'm not totally convinced GeoPandas is to blame here, because printing "polygon_fs" (the feature set that was created from the dataframe) still has the spatial data. Now that I think about it, I think my issue might be because the feature set is storing the geometry as "geometry" instead of "SHAPE".
However, .edit_features() doesn't have any field mapping unfortunately. I am trying to loop through the feature set (since it is basically a list of dictionaries), but there are some complications. I'll keep chugging away at this route until someone smarter than me suggests something else.
Nah, that shouldn't matter. "geometry" is just how you send spatial information to the REST endpoint.
Honestly, if you aren't messing with the shapes at all, just drop that column before you submit the edits. Any fields you omit from your edit, including the geometry, are simply left untouched.
You could have a layer with 100 fields, but if your dataframe only has 2 of those fields present, when you submit the FeatureSet, those are the only two fields that will be updated. It's a feature we rely on quite a lot, actually, as we have scripts that update subsets of columns on a number of layers.
A couple notes on the code. You can ask for the query to give you a dataframe directly, and you can have it omit unnecessary fields right from the start:
df = polygon_layer.query(
out_fields = ['the', 'fields', 'you', 'need', 'for', 'scoring'],
return_geometry = False,
as_df = True
)
Try either limiting your geometry that way, or else just dropping the SHAPE column prior to submitting the edits, see what happens.
Thank you for your solution, although that specific line
return_geometry = False,
forces all geometry as "None", whether I have already broken the layer or not. But for now, adding this line after converting back to a FeatureSet:
polygon_fs_updated = [
{
"SHAPE": feature.geometry,
"attributes": feature.attributes
}
for feature in original_features
]
did end up fixing the issue. Thanks for your help though!