Hey members,
This is a big ask, so feel free to ignore. Although, if there is some knowledge you can throw my way I would be greatly appreciative. I have been going back and forth with errors on the buffer block and come to the conclusion that I am close. Anyhow, I will continue and thanks in advance if you see and help with this issue.
Sincerely, Christopher
Here is the logging information:
2025-07-24 13:59:14,552 - INFO - Connected to layer at https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey/FeatureServer/89 successfully. 2025-07-24 13:59:14,553 - INFO - Connected to layer at https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey_Buffe... successfully. 2025-07-24 13:59:14,553 - INFO - All layers connected successfully. 2025-07-24 13:59:14,795 - INFO - 0 existing buffer features found. 2025-07-24 13:59:14,796 - INFO - 2 new survey features to buffer. 2025-07-24 13:59:15,071 - INFO - 0 existing buffer features found. 2025-07-24 13:59:15,071 - INFO - Feature Attributes: 2025-07-24 13:59:15,072 - INFO - OBJECTID: 1 2025-07-24 13:59:15,073 - INFO - County: Oklahoma 2025-07-24 13:59:15,074 - INFO - FFY: 2025 2025-07-24 13:59:15,074 - INFO - Forester: Chris Mask 2025-07-24 13:59:15,075 - INFO - Path_Type: Road 2025-07-24 13:59:15,076 - INFO - GlobalID: 45932289-83cf-4f5b-84c4-18ff587df745 2025-07-24 13:59:15,077 - INFO - Survey_Focus: Forest Health 2025-07-24 13:59:15,077 - INFO - Shape__Length: 28861.232481266623 2025-07-24 13:59:15,079 - INFO - CreationDate: 1753293465437 2025-07-24 13:59:15,079 - INFO - Creator: CMask_OKForestry 2025-07-24 13:59:15,080 - INFO - EditDate: 1753293465437 2025-07-24 13:59:15,081 - INFO - Editor: CMask_OKForestry 2025-07-24 13:59:15,081 - INFO - Feature Geometry: 2025-07-24 13:59:15,082 - INFO - {'paths': [[[-97.373237047319, 35.4334389290588], [-97.284186283348, 35.402255788017]]], 'spatialReference': {'wkid': 4326, 'latestWkid': 4326}} 2025-07-24 13:59:15,083 - INFO - Feature Attributes: 2025-07-24 13:59:15,085 - INFO - OBJECTID: 2 2025-07-24 13:59:15,086 - INFO - County: Pottawatomie 2025-07-24 13:59:15,086 - INFO - FFY: 2025 2025-07-24 13:59:15,087 - INFO - Forester: Chris Mask 2025-07-24 13:59:15,088 - INFO - Path_Type: Trail 2025-07-24 13:59:15,089 - INFO - GlobalID: e21a7e3e-c67c-42af-ad37-833f6cf4c5d3 2025-07-24 13:59:15,089 - INFO - Survey_Focus: Health 2025-07-24 13:59:15,090 - INFO - Shape__Length: 58601.425958823864 2025-07-24 13:59:15,090 - INFO - CreationDate: 1753295800100 2025-07-24 13:59:15,091 - INFO - Creator: CMask_OKForestry 2025-07-24 13:59:15,093 - INFO - EditDate: 1753295800100 2025-07-24 13:59:15,093 - INFO - Editor: CMask_OKForestry 2025-07-24 13:59:15,094 - INFO - Feature Geometry: 2025-07-24 13:59:15,094 - INFO - {'paths': [[[-97.1184390528449, 35.2597503589496], [-96.9221785207107, 35.2581636601495]]], 'spatialReference': {'wkid': 4326, 'latestWkid': 4326}} 2025-07-24 13:59:15,249 - ERROR - Error buffering feature 45932289-83cf-4f5b-84c4-18ff587df745: list indices must be integers or slices, not str 2025-07-24 13:59:15,250 - ERROR - Error buffering feature e21a7e3e-c67c-42af-ad37-833f6cf4c5d3: list indices must be integers or slices, not str 2025-07-24 13:59:15,250 - INFO - No new buffer features to add.
Here is the code:
from arcgis.gis import GIS
from arcgis.features import FeatureLayer
#from shapely.geometry import Point, Polygon
from arcgis.geometry import Geometry, Polyline, Polygon, LengthUnits, Point, project, lengths, areas_and_lengths, union
from arcgis.geometry.filters import intersects, contains, overlaps, crosses, touches, within
from arcgis.geometry.filters import envelope_intersects, index_intersects
from arcgis.geoenrichment import Country
import pandas as pd
import logging
from arcgis.geometry import buffer as arcgis_buffer
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
# Connect to your active ArcGIS Online session (assumes you're signed in via Pro or Notebook)
gis = GIS("home")
# Function to connect to layers by URL
def connect_layers_by_url(*urls):
try:
layers = []
for url in urls:
# Connect to each FeatureLayer using the GIS object
layer = FeatureLayer(url, gis=gis)
layers.append(layer)
logging.info(f"Connected to layer at {url} successfully.")
return layers
except Exception as e:
logging.error(f"Error connecting to layers: {e}")
return [None] * len(urls)
# Define layer URLs
Survey_url = "https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey/Featu..."
SurveyBuffer_layer_url = "https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey_Buffe..."
# Connect to layers with authentication
Survey_layer, SurveyBuffer_layer = connect_layers_by_url(
Survey_url, SurveyBuffer_layer_url
)
# Validate layer connections
if any(layer is None for layer in [Survey_layer, SurveyBuffer_layer]):
logging.error("One or more layers failed to connect. Please check the URLs or GIS credentials.")
else:
logging.info("All layers connected successfully.")
all_features = Survey_layer.query(where="1=1", out_fields="*", return_geometry=True, out_sr=4326).features
new_features = [f for f in all_features if f.attributes["GlobalID"] not in existing_ids]
logging.info(f"{len(existing_ids)} existing buffer features found.")
logging.info(f"{len(new_features)} new survey features to buffer.")
# Step 1: Get existing FHGS_IDs
existing_ids = set()
buffer_features = SurveyBuffer_layer.query(where="1=1", out_fields="FHGS_ID").features
for feat in buffer_features:
fid = feat.attributes.get("FHGS_ID")
if fid:
existing_ids.add(fid)
logging.info(f"{len(existing_ids)} existing buffer features found.")
#print geometry
for feature in new_features:
attrs = feature.attributes
geom = feature.geometry
logging.info("Feature Attributes:")
for key, value in attrs.items():
logging.info(f" {key}: {value}")
logging.info("Feature Geometry:")
logging.info(geom)
# Step 2: Get new features from Survey_layer
# Step 3: Process each new feature and create buffers
new_buffer_features = []
for feat in new_features:
try:
attrs = feat.attributes
geom_dict = feat.geometry
path_type = attrs.get("Path_Type", "")
# Set buffer distance in feet
if path_type == "Road":
buffer_distance = 100
elif path_type == "Trail":
buffer_distance = 50
else:
buffer_distance = 0
if buffer_distance == 0:
logging.warning(f"Skipping feature with unknown Path_Type: {path_type}")
continue
buffer_result = arcgis_buffer(
geometries=[geom_dict],
in_sr=4326,
distances=[buffer_distance],
unit=9002, # unit can also be numeric (e.g. 9002 for feet)
union_results=False,
out_sr=4326
)
if not buffer_result or not buffer_result[0]:
logging.error(f"No buffered geometry returned for feature {attrs.get('GlobalID')}")
continue
buffered_geom = buffer_result[0]
# Calculate area in square feet, then convert to acres
area_result = areas_and_lengths(
[buffered_geom],
length_unit='FEET',
area_unit='SQUARE_FEET',
calculation_type='PLANAR'
)
acres = area_result['areas'][0] / 43560 # Convert sq ft to acres
# Prepare new feature
new_feature = {
"geometry": buffered_geom,
"attributes": {
"County": attrs.get("County"),
"FFY": attrs.get("FFY"),
"Forester": attrs.get("Forester"),
"Path_Type": path_type,
"FHGS_ID": attrs.get("GlobalID"),
"Acres": round(acres, 2)
}
}
new_buffer_features.append(new_feature)
except Exception as e:
logging.error(f"Error buffering feature {attrs.get('GlobalID', 'unknown')}: {str(e)}")
# Step 4: Add new buffered features to SurveyBuffer_layer
if new_buffer_features:
add_result = SurveyBuffer_layer.edit_features(adds=new_buffer_features)
logging.info(f"Added {len(new_buffer_features)} new buffer features.")
else:
logging.info("No new buffer features to add.")
I think the issue is the geometry format, needing conversion before buffering.
Untested.
from arcgis.geometry import Geometry
# After your buffer operation:
buffer_result = arcgis_buffer(geometries=[geom_dict], ...)
if buffer_result:
buffered_geom = Geometry(buffer_result[0]) # Convert to Geometry object
# Convert input geometry BEFORE buffering
from arcgis.geometry import Polyline, Geometry
for feat in new_features:
try:
# Convert source geometry first
geom = Geometry(feat.geometry) # or Polyline(feat.geometry)
# Buffer the converted geometry
buffer_result = arcgis_buffer(
geometries=[geom],
in_sr=4326,
distances=[buffer_distance],
unit=9002,
union_results=False,
out_sr=4326
)
# No need to convert buffer_result if just storing it
buffered_geom = buffer_result[0]
# Rest of your code...
That fixed the error, so thank you very much for your assistance. Although, I get this now
Logging information:
2025-07-24 16:09:38,921 - INFO - Connected to layer at https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey/FeatureServer/89 successfully. 2025-07-24 16:09:38,921 - INFO - Connected to layer at https://services3.arcgis.com/yrIZ0Nv0mSGTWJsH/arcgis/rest/services/Forest_Health_Ground_Survey_Buffe... successfully. 2025-07-24 16:09:38,922 - INFO - All layers connected successfully. 2025-07-24 16:09:39,365 - INFO - 0 existing buffer features found. 2025-07-24 16:09:39,366 - INFO - Feature Attributes: 2025-07-24 16:09:39,367 - INFO - OBJECTID: 1 2025-07-24 16:09:39,368 - INFO - GlobalID: 45932289-83cf-4f5b-84c4-18ff587df745 2025-07-24 16:09:39,368 - INFO - County: Oklahoma 2025-07-24 16:09:39,369 - INFO - FFY: 2025 2025-07-24 16:09:39,370 - INFO - Forester: Chris Mask 2025-07-24 16:09:39,371 - INFO - Path_Type: Road 2025-07-24 16:09:39,371 - INFO - Feature Geometry: 2025-07-24 16:09:39,372 - INFO - {'paths': [[[2155227.05450027, 158381.454784061], [2181840.23027768, 147214.108842507]]], 'spatialReference': {'wkid': 2911, 'latestWkid': 2911}} 2025-07-24 16:09:39,373 - INFO - Feature Attributes: 2025-07-24 16:09:39,373 - INFO - OBJECTID: 2 2025-07-24 16:09:39,375 - INFO - GlobalID: e21a7e3e-c67c-42af-ad37-833f6cf4c5d3 2025-07-24 16:09:39,375 - INFO - County: Pottawatomie 2025-07-24 16:09:39,376 - INFO - FFY: 2025 2025-07-24 16:09:39,377 - INFO - Forester: Chris Mask 2025-07-24 16:09:39,377 - INFO - Path_Type: Trail 2025-07-24 16:09:39,378 - INFO - Feature Geometry: 2025-07-24 16:09:39,379 - INFO - {'paths': [[[2231708.58234967, 95748.3537223102], [2290310.00669738, 95762.0951357639]]], 'spatialReference': {'wkid': 2911, 'latestWkid': 2911}} 2025-07-24 16:09:39,602 - INFO - 2 new survey features to buffer. 2025-07-24 16:09:39,603 - INFO - Geometry Type: Polyline 2025-07-24 16:09:39,817 - ERROR - No buffered geometry returned for feature 45932289-83cf-4f5b-84c4-18ff587df745 2025-07-24 16:09:39,818 - INFO - Geometry Type: Polyline 2025-07-24 16:09:40,807 - ERROR - No buffered geometry returned for feature e21a7e3e-c67c-42af-ad37-833f6cf4c5d3 2025-07-24 16:09:40,808 - INFO - No new buffer features to add.
Code:
for feat in new_features:
try:
attrs = feat.attributes
geom_dict = feat.geometry
path_type = attrs.get("Path_Type", "")
# Set buffer distance in feet
if path_type == "Road":
buffer_distance = 100
elif path_type == "Trail":
buffer_distance = 50
else:
buffer_distance = 0
if buffer_distance == 0:
logging.warning(f"Skipping feature with unknown Path_Type: {path_type}")
continue
#Convert source geometry first
geom = Polyline(feat.geometry) # Or Geometry(feat.geometry)
logging.info(f"Geometry Type: {geom.type}") # Should be 'polyline'
# Project to Web Mercator (EPSG:3857) before buffering
projected_geom = project([geom], in_sr=4326, out_sr=3857)[0]
buffer_result = arcgis_buffer(
geometries=[projected_geom],
in_sr=3857,
distances=[buffer_distance],
unit=9002,
union_results=False,
out_sr=3857
)
if not buffer_result or not buffer_result[0]:
logging.error(f"No buffered geometry returned for feature {attrs.get('GlobalID')}")
continue
#if buffer_result:
#buffered_geom = Geometry(buffer_result[0]) # Convert to Geometry object
#buffered_geom = project([Geometry(buffer_result[0])], in_sr=3857, out_sr=4326)[0]
#buffered_geom = buffer_result[0]
# Calculate area in square feet, then convert to acres
area_result = areas_and_lengths([buffered_geom], length_unit='FEET', area_unit='SQUARE_FEET', calculation_type='PLANAR')
acres = area_result['areas'][0] / 43560 # sq ft to acres
arcgis_buffer is returning either none or [None}, check your geometry projection and potentially incorrect spatial reference.
Add this before your loop to ensure compatibility
target_sr = SurveyBuffer_layer.properties.spatialReference['wkid']
if target_sr != 2911:
logging.info(f"Note: Will project from 2911 to {target_sr} before saving")
untested,
from arcgis.geometry import Polyline, Geometry
from arcgis.geometry.functions import buffer as arcgis_buffer, areas_and_lengths, project
# Get target layer's spatial reference ONCE before the loop
target_sr = SurveyBuffer_layer.properties.spatialReference['wkid']
if target_sr != 2911:
logging.info(f"Note: Will project from 2911 to {target_sr} before saving")
for feat in new_features:
try:
attrs = feat.attributes
geom_dict = feat.geometry
path_type = attrs.get("Path_Type", "")
# Set buffer distance in feet
if path_type == "Road":
buffer_distance = 100
elif path_type == "Trail":
buffer_distance = 50
else:
logging.warning(f"Skipping feature with unknown Path_Type: {path_type}")
continue
# 1. Create proper geometry object (using correct SRID from your data)
geom = Polyline(geom_dict) # Your data shows wkid=2911
logging.info(f"Processing feature {attrs.get('GlobalID')} with geometry type: {geom.type}")
# 2. Buffer in the original CRS (2911)
buffer_result = arcgis_buffer(
geometries=[geom],
in_sr=2911, # Oklahoma State Plane
distances=[buffer_distance],
unit=9002, # Feet (appropriate for State Plane)
union_results=False,
out_sr=2911 # Keep buffer in same CRS initially
)
if not buffer_result or not buffer_result[0]:
logging.error(f"No buffered geometry returned for feature {attrs.get('GlobalID')}")
continue
buffered_geom = buffer_result[0]
# 3. Project to target CRS if different from 2911
if target_sr != 2911:
try:
projected_geom = project(
[Geometry(buffered_geom)],
in_sr=2911,
out_sr=target_sr
)[0]
buffered_geom = projected_geom
logging.info(f"Successfully projected geometry to SRID {target_sr}")
except Exception as proj_error:
logging.error(f"Projection failed for feature {attrs.get('GlobalID')}: {str(proj_error)}")
continue
# Calculate area (in original CRS for accuracy)
try:
area_result = areas_and_lengths(
[buffered_geom if target_sr == 2911 else Geometry(buffer_result[0])], # Use original buffer for calculation
length_unit='FEET',
area_unit='SQUARE_FEET',
calculation_type='PLANAR'
)
acres = area_result['areas'][0] / 43560 # sq ft to acres
logging.info(f"Calculated area: {acres:.2f} acres")
except Exception as area_error:
logging.warning(f"Area calculation failed for feature {attrs.get('GlobalID')}: {str(area_error)}")
acres = 0
# Prepare feature for addition
new_feature = {
"geometry": buffered_geom,
"attributes": {
"County": attrs.get("County"),
"FFY": attrs.get("FFY"),
"Forester": attrs.get("Forester"),
"Path_Type": path_type,
"FHGS_ID": attrs.get("GlobalID"),
"Acres": round(acres, 2)
}
}
new_buffer_features.append(new_feature)
except Exception as e:
logging.error(f"Error processing feature {attrs.get('GlobalID', 'unknown')}: {str(e)}", exc_info=True)