# arcgis-python > Comprehensive ArcGIS Python API expertise for ArcGIS Online and Enterprise. Use when writing Python code for Feature Layers, Web Maps, geocoding, routing, spatial analysis, raster operations, portal administration, content management, or any arcgis package operations. Covers authentication patterns, Spatially Enabled DataFrames, geometry operations, batch editing, publishing workflows, and performance optimization. - Author: Jeff Franzen - Repository: franzenjb/claude-skills - Version: 20260206183911 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-07 - Source: https://github.com/franzenjb/claude-skills - Web: https://mule.run/skillshub/@@franzenjb/claude-skills~arcgis-python:20260206183911 --- --- name: arcgis-python description: Comprehensive ArcGIS Python API expertise for ArcGIS Online and Enterprise. Use when writing Python code for Feature Layers, Web Maps, geocoding, routing, spatial analysis, raster operations, portal administration, content management, or any arcgis package operations. Covers authentication patterns, Spatially Enabled DataFrames, geometry operations, batch editing, publishing workflows, and performance optimization. --- # ArcGIS Python API ## Authentication ```python from arcgis.gis import GIS # ArcGIS Notebooks (always use this in hosted notebooks) gis = GIS("home") # OAuth (interactive apps) gis = GIS("https://org.maps.arcgis.com", client_id="APP_ID") # API Key (public content only) gis = GIS(api_key="AAPK...") # Username/password (scripts only — use environment variables) import os gis = GIS("https://org.maps.arcgis.com", os.environ["AGOL_USER"], os.environ["AGOL_PASS"]) ``` ## Feature Layer Essentials ```python from arcgis.features import FeatureLayer, FeatureLayerCollection # From URL fl = FeatureLayer("https://services.arcgis.com/.../FeatureServer/0", gis=gis) # From Item item = gis.content.get("ITEM_ID") flc = FeatureLayerCollection.fromitem(item) fl = flc.layers[0] # First layer table = flc.tables[0] # First table # Layer properties print(fl.properties.name, fl.properties.geometryType) print([f["name"] for f in fl.properties.fields]) ``` ### Query Patterns ```python # Basic query → Spatially Enabled DataFrame sdf = fl.query(where="status='Active'", out_fields="name,status").sdf # All records (small datasets <10k) sdf = fl.query(where="1=1", return_all_records=True).sdf # Pagination (large datasets) — SEE references/large-datasets.md count = fl.query(return_count_only=True) # Spatial query from arcgis.geometry import Envelope bbox = Envelope({"xmin": -78, "ymin": 35, "xmax": -77, "ymax": 36, "spatialReference": {"wkid": 4326}}) sdf = fl.query(geometry_filter=bbox, spatial_rel="intersects").sdf # Return geometry or not sdf = fl.query(return_geometry=False).sdf # Faster for attribute-only queries # Statistics stats = fl.query(where="1=1", group_by_fields_for_statistics="region", out_statistics=[{"statisticType": "count", "onStatisticField": "OBJECTID", "outStatisticFieldName": "total"}]) ``` ### Edit Features ```python from arcgis.features import Feature from arcgis.geometry import Point # Add new_features = [ Feature(geometry=Point({"x": -77.0, "y": 38.9, "spatialReference": {"wkid": 4326}}), attributes={"name": "Site A", "status": "Active"}) ] result = fl.edit_features(adds=new_features) # Update (must include OBJECTID) updates = [Feature(attributes={"OBJECTID": 1, "status": "Closed"})] result = fl.edit_features(updates=updates) # Delete fl.edit_features(deletes="1,2,3") # By OID string # Or by query oids = fl.query(where="status='Inactive'", return_ids_only=True)["objectIds"] if oids: fl.edit_features(deletes=",".join(map(str, oids))) ``` ### Batch Edits (Chunk for Reliability) ```python def chunked_edit(fl, features, operation="updates", chunk_size=200): """Batch edit with chunking to avoid timeouts.""" results = [] for i in range(0, len(features), chunk_size): chunk = features[i:i + chunk_size] result = fl.edit_features(**{operation: chunk}) results.append(result) print(f"Processed {min(i + chunk_size, len(features))}/{len(features)}") return results ``` ## Spatially Enabled DataFrame (SEDF) ```python import pandas as pd from arcgis.features import GeoAccessor, GeoSeriesAccessor # Query to SEDF sdf = fl.query().sdf # DataFrame to SEDF df = pd.DataFrame({"name": ["A", "B"], "lat": [38.9, 39.0], "lon": [-77.0, -77.1]}) sdf = pd.DataFrame.spatial.from_xy(df, "lon", "lat", sr=4326) # From GeoJSON/Shapefile sdf = pd.DataFrame.spatial.from_featureclass("path/to/data.shp") # Export sdf.spatial.to_featureclass("output.shp") sdf.spatial.to_featurelayer("New Layer", gis=gis, folder="Analysis") # Spatial operations sdf["SHAPE"].geom.buffer(1000) # Buffer geometries sdf.spatial.project(3857) # Reproject ``` ## Geometry Objects ```python from arcgis.geometry import Point, Polyline, Polygon, Geometry from arcgis.geometry import project, buffer, union, intersect # Create geometries (always include spatialReference) pt = Point({"x": -77, "y": 38.9, "spatialReference": {"wkid": 4326}}) line = Polyline({"paths": [[[-77, 38], [-76, 39]]], "spatialReference": {"wkid": 4326}}) poly = Polygon({"rings": [[[-77, 38], [-76, 38], [-76, 39], [-77, 39], [-77, 38]]], "spatialReference": {"wkid": 4326}}) # Geometry operations buffered = buffer([pt], in_sr=4326, distances=[1000], unit="Meters")[0] projected = project([pt], in_sr=4326, out_sr=3857)[0] # From GeoJSON geom = Geometry({"type": "Point", "coordinates": [-77, 38.9]}) ``` ## Web Maps ```python from arcgis.mapping import WebMap import json # Load item = gis.content.get("WEBMAP_ID") wm = WebMap(item) # Inspect layers for layer in wm.layers: print(layer.title, layer.url) # Get raw definition for modification data = item.get_data() # Returns dict # Modify and save data["operationalLayers"][0]["visibility"] = False item.update(data=json.dumps(data)) # Create new web map from arcgis.mapping import WebMap wm = WebMap() wm.add_layer(fl) wm.save(item_properties={"title": "New Map", "tags": "analysis"}) ``` ## Content Management ```python # Search results = gis.content.search(f'title:"My Layer" owner:{gis.users.me.username} type:"Feature Service"') # Create/publish csv_item = gis.content.add({"title": "Data", "type": "CSV"}, data="data.csv") published = csv_item.publish() # Update item.update(item_properties={"description": "Updated"}) item.update(data="new_data.csv") # Replace data # Share item.share(org=True) item.share(groups=["GROUP_ID"]) item.share(everyone=True) # Move/delete item.move(folder="Archive") item.delete() ``` ## Common Patterns ### Check Before Create ```python def get_or_create_item(gis, title, item_type, create_func): results = gis.content.search(f'title:"{title}" owner:{gis.users.me.username} type:"{item_type}"') if results: return results[0] return create_func() ``` ### Error Handling ```python from arcgis.gis import GISError try: result = fl.edit_features(updates=features) # Check for partial failures for r in result.get("updateResults", []): if not r.get("success"): print(f"Failed OID {r.get('objectId')}: {r.get('error')}") except GISError as e: print(f"API Error: {e}") ``` ### NaN Handling ```python import pandas as pd import numpy as np # Convert NaN to None before edit_features def clean_for_agol(df): return df.replace({np.nan: None, pd.NaT: None}) ``` ## Reference Files - **Large dataset patterns** → See `references/large-datasets.md` - **Geocoding & routing** → See `references/geocoding-routing.md` - **Spatial analysis tools** → See `references/spatial-analysis.md` - **Admin & user management** → See `references/admin.md`