Select to view content in your preferred language

ArcGIS Online Notebook Python - Create Buffer Issue

206
3
07-24-2025 07:12 AM
ChristopherMask
Regular Contributor

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.")

Tags (3)
0 Kudos
3 Replies
TonyAlmeida
MVP Regular Contributor

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...

 

 

 

0 Kudos
ChristopherMask
Regular Contributor

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

 

0 Kudos
TonyAlmeida
MVP Regular Contributor

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)
0 Kudos