Claude Code Plugins

Community-maintained marketplace

Feedback

Perform spatial analysis, geometry operations, and use ArcGIS REST services. Use for routing, geocoding, geoprocessing, elevation analysis, viewshed, and feature queries with statistics.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name arcgis-analysis-services
description Perform spatial analysis, geometry operations, and use ArcGIS REST services. Use for routing, geocoding, geoprocessing, elevation analysis, viewshed, and feature queries with statistics.

ArcGIS Analysis & Services

Use this skill for spatial analysis, geometry operations, REST services, and feature reduction (clustering/binning).

Geometry Operators

ArcGIS Maps SDK provides geometry operators for client-side spatial operations.

Loading Operators

import bufferOperator from "@arcgis/core/geometry/operators/bufferOperator.js";
import intersectOperator from "@arcgis/core/geometry/operators/intersectOperator.js";
import centroidOperator from "@arcgis/core/geometry/operators/centroidOperator.js";

// Load before use (most operators require this)
await bufferOperator.load();

Buffer

import bufferOperator from "@arcgis/core/geometry/operators/bufferOperator.js";
await bufferOperator.load();

const buffered = bufferOperator.execute(point, 1000); // 1000 meters

Geodesic Buffer (accurate over large distances)

import geodesicBufferOperator from "@arcgis/core/geometry/operators/geodesicBufferOperator.js";
await geodesicBufferOperator.load();

const buffered = geodesicBufferOperator.execute(point, {
  distances: [100],
  unit: "kilometers"
});

Intersect

import intersectOperator from "@arcgis/core/geometry/operators/intersectOperator.js";
await intersectOperator.load();

const intersection = intersectOperator.execute(geometry1, geometry2);

Union

import unionOperator from "@arcgis/core/geometry/operators/unionOperator.js";
await unionOperator.load();

const unioned = unionOperator.execute([polygon1, polygon2, polygon3]);

Centroid

import centroidOperator from "@arcgis/core/geometry/operators/centroidOperator.js";
await centroidOperator.load();

const centroid = centroidOperator.execute(polygon);

Contains / Within

import containsOperator from "@arcgis/core/geometry/operators/containsOperator.js";
await containsOperator.load();

const isContained = containsOperator.execute(polygon, point); // true/false

Distance

import geodeticLengthOperator from "@arcgis/core/geometry/operators/geodeticLengthOperator.js";
await geodeticLengthOperator.load();

const length = geodeticLengthOperator.execute(polyline, { unit: "miles" });

Area

import geodeticAreaOperator from "@arcgis/core/geometry/operators/geodeticAreaOperator.js";
await geodeticAreaOperator.load();

const area = geodeticAreaOperator.execute(polygon, { unit: "square-kilometers" });

Available Operators

Operator Purpose
bufferOperator Create buffer around geometry
geodesicBufferOperator Geodetic buffer (accurate)
intersectOperator Find intersection
unionOperator Combine geometries
differenceOperator Subtract geometries
clipOperator Clip geometry by envelope
convexHullOperator Create convex hull
centroidOperator Get centroid point
containsOperator Test if contains
withinOperator Test if within
intersectsOperator Test if intersects
distanceOperator Calculate planar distance
geodeticLengthOperator Calculate geodetic length
geodeticAreaOperator Calculate geodetic area
simplifyOperator Simplify geometry
densifyOperator Add vertices to geometry
projectOperator Project to spatial reference

Analysis Objects

ElevationProfileAnalysis

import ElevationProfileAnalysis from "@arcgis/core/analysis/ElevationProfileAnalysis.js";

const analysis = new ElevationProfileAnalysis({
  profiles: [
    { type: "ground", color: "brown" },
    { type: "input", color: "blue" }
  ],
  displayUnits: {
    distance: "meters",
    elevation: "meters"
  }
});

// Add to SceneView
view.analyses.add(analysis);

// Set line geometry
analysis.geometry = polyline;

// Get analysis view for results
const analysisView = await view.whenAnalysisView(analysis);

// Watch progress and results
reactiveUtils.watch(
  () => analysisView.progress,
  (progress) => {
    if (progress === 1) {
      console.log("Results:", analysisView.results);
    }
  }
);

LineOfSightAnalysis

import LineOfSightAnalysis from "@arcgis/core/analysis/LineOfSightAnalysis.js";

const analysis = new LineOfSightAnalysis({
  observer: {
    type: "point",
    x: -122.4,
    y: 37.8,
    z: 100,
    spatialReference: { wkid: 4326 }
  },
  targets: [
    { type: "point", x: -122.41, y: 37.81, z: 50 },
    { type: "point", x: -122.42, y: 37.79, z: 75 }
  ]
});

view.analyses.add(analysis);

ViewshedAnalysis

import ViewshedAnalysis from "@arcgis/core/analysis/ViewshedAnalysis.js";

const analysis = new ViewshedAnalysis({
  observer: {
    type: "point",
    x: -122.4,
    y: 37.8,
    z: 100,
    spatialReference: { wkid: 4326 }
  },
  farDistance: 1000,
  heading: 45,
  tilt: 90,
  horizontalFieldOfView: 120,
  verticalFieldOfView: 90
});

view.analyses.add(analysis);

ShadowCastAnalysis

import ShadowCastAnalysis from "@arcgis/core/analysis/ShadowCastAnalysis.js";

const analysis = new ShadowCastAnalysis();
view.analyses.add(analysis);

// Configure date/time for shadow calculation
view.environment.lighting.date = new Date("2024-06-21T12:00:00");

SliceAnalysis

import SliceAnalysis from "@arcgis/core/analysis/SliceAnalysis.js";

const analysis = new SliceAnalysis({
  plane: {
    position: { type: "point", x: -122.4, y: 37.8, z: 50 },
    heading: 0,
    tilt: 0
  }
});

view.analyses.add(analysis);

REST Services

Routing

import route from "@arcgis/core/rest/route.js";

const routeParams = {
  stops: [
    { geometry: { x: -122.4, y: 37.8 } },
    { geometry: { x: -122.5, y: 37.7 } }
  ],
  outSpatialReference: { wkid: 4326 },
  returnDirections: true,
  returnRoutes: true
};

const result = await route.solve(
  "https://route.arcgis.com/arcgis/rest/services/World/Route/NAServer/Route_World",
  routeParams
);

const routeGeometry = result.routeResults[0].route.geometry;
const directions = result.routeResults[0].directions;

Geocoding (Address to Location)

import locator from "@arcgis/core/rest/locator.js";

const results = await locator.addressToLocations(
  "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer",
  {
    address: { SingleLine: "380 New York St, Redlands, CA" },
    outFields: ["*"],
    maxLocations: 5
  }
);

results.forEach(result => {
  console.log(result.address, result.location);
});

Reverse Geocoding (Location to Address)

import locator from "@arcgis/core/rest/locator.js";

const result = await locator.locationToAddress(
  "https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer",
  {
    location: { x: -117.195, y: 34.057 }
  }
);

console.log(result.address);

Geoprocessing

import geoprocessor from "@arcgis/core/rest/geoprocessor.js";

const params = {
  inputLayer: featureSet,
  distance: 1000,
  distanceUnits: "Meters"
};

const result = await geoprocessor.execute(
  "https://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/Buffer/GPServer/Buffer",
  params
);

const outputFeatures = result.results[0].value;

Print

import print from "@arcgis/core/rest/print.js";

const params = {
  view: view,
  template: {
    format: "pdf",
    layout: "letter-ansi-a-landscape",
    layoutOptions: {
      titleText: "My Map"
    }
  }
};

const result = await print.execute(
  "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task",
  params
);

// Download the PDF
window.open(result.url);

Places Service

import places from "@arcgis/core/rest/places.js";
import PlacesQueryParameters from "@arcgis/core/rest/support/PlacesQueryParameters.js";
import FetchPlaceParameters from "@arcgis/core/rest/support/FetchPlaceParameters.js";

// Query places near a point
const queryParams = new PlacesQueryParameters({
  categoryIds: ["4d4b7104d754a06370d81259"], // Arts and Entertainment
  radius: 500, // meters
  point: { type: "point", longitude: -87.626, latitude: 41.882 },
  icon: "png"
});

const results = await places.queryPlacesNearPoint(queryParams);

// Process results
results.results.forEach(place => {
  console.log(place.name, place.location, place.categories[0].label);
  console.log("Distance:", place.distance / 1000, "km");
});

// Fetch detailed information about a place
const fetchParams = new FetchPlaceParameters({
  placeId: results.results[0].placeId,
  requestedFields: ["all"]
});

const details = await places.fetchPlace(fetchParams);
const placeDetails = details.placeDetails;

console.log("Address:", placeDetails.address.streetAddress);
console.log("Phone:", placeDetails.contactInfo.telephone);
console.log("Website:", placeDetails.contactInfo.website);

Places Category IDs

Category ID
Arts and Entertainment 4d4b7104d754a06370d81259
Business Services 4d4b7105d754a06375d81259
Community and Government 63be6904847c3692a84b9b9a
Dining and Drinking 63be6904847c3692a84b9bb5
Health and Medicine 63be6904847c3692a84b9bb9
Landmarks and Outdoors 4d4b7105d754a06377d81259
Retail 4d4b7105d754a06378d81259
Sports and Recreation 4f4528bc4b90abdf24c9de85
Travel and Transportation 4d4b7105d754a06379d81259

Feature Queries with Statistics

Basic Statistics

const query = featureLayer.createQuery();
query.outStatistics = [
  {
    statisticType: "sum",
    onStatisticField: "population",
    outStatisticFieldName: "totalPop"
  },
  {
    statisticType: "avg",
    onStatisticField: "population",
    outStatisticFieldName: "avgPop"
  },
  {
    statisticType: "max",
    onStatisticField: "population",
    outStatisticFieldName: "maxPop"
  },
  {
    statisticType: "min",
    onStatisticField: "population",
    outStatisticFieldName: "minPop"
  },
  {
    statisticType: "count",
    onStatisticField: "population",
    outStatisticFieldName: "count"
  },
  {
    statisticType: "stddev",
    onStatisticField: "population",
    outStatisticFieldName: "stdDev"
  }
];

const result = await featureLayer.queryFeatures(query);
console.log(result.features[0].attributes);

Group By Statistics

const query = featureLayer.createQuery();
query.groupByFieldsForStatistics = ["state"];
query.outStatistics = [{
  statisticType: "sum",
  onStatisticField: "population",
  outStatisticFieldName: "totalPop"
}];
query.orderByFields = ["totalPop DESC"];

const result = await featureLayer.queryFeatures(query);
// Returns one feature per state with total population

Spatial Statistics Query

const query = featureLayer.createQuery();
query.geometry = view.extent;
query.spatialRelationship = "intersects";
query.outStatistics = [{
  statisticType: "count",
  onStatisticField: "ObjectID",
  outStatisticFieldName: "featureCount"
}];

const result = await featureLayer.queryFeatures(query);
console.log("Features in view:", result.features[0].attributes.featureCount);

Feature Reduction

Clustering

const clusterConfig = {
  type: "cluster",
  clusterRadius: "100px",
  clusterMinSize: "24px",
  clusterMaxSize: "60px",
  popupTemplate: {
    title: "Cluster summary",
    content: "This cluster represents {cluster_count} features.",
    fieldInfos: [{
      fieldName: "cluster_count",
      format: { digitSeparator: true, places: 0 }
    }]
  },
  labelingInfo: [{
    deconflictionStrategy: "none",
    labelExpressionInfo: {
      expression: "Text($feature.cluster_count, '#,###')"
    },
    symbol: {
      type: "text",
      color: "white",
      font: { size: "12px", weight: "bold" }
    },
    labelPlacement: "center-center"
  }]
};

featureLayer.featureReduction = clusterConfig;

// Toggle clustering
featureLayer.featureReduction = null; // Disable
featureLayer.featureReduction = clusterConfig; // Enable

Cluster with Aggregated Fields

const clusterConfig = {
  type: "cluster",
  clusterRadius: "100px",
  fields: [{
    name: "avg_magnitude",
    statisticType: "avg",
    onStatisticField: "magnitude"
  }, {
    name: "total_count",
    statisticType: "count",
    onStatisticField: "ObjectID"
  }],
  renderer: {
    type: "simple",
    symbol: {
      type: "simple-marker",
      style: "circle",
      color: "#69dcff"
    },
    visualVariables: [{
      type: "size",
      field: "total_count",
      stops: [
        { value: 1, size: 8 },
        { value: 100, size: 40 }
      ]
    }]
  }
};

Binning

const binConfig = {
  type: "binning",
  fixedBinLevel: 4, // Level of detail
  renderer: {
    type: "simple",
    symbol: {
      type: "simple-fill",
      outline: { color: "white", width: 0.5 }
    },
    visualVariables: [{
      type: "color",
      field: "aggregateCount",
      stops: [
        { value: 1, color: "#feebe2" },
        { value: 50, color: "#fbb4b9" },
        { value: 100, color: "#f768a1" },
        { value: 500, color: "#c51b8a" },
        { value: 1000, color: "#7a0177" }
      ]
    }]
  },
  popupTemplate: {
    title: "Bin",
    content: "{aggregateCount} features in this bin"
  }
};

featureLayer.featureReduction = binConfig;

Projection

import projectOperator from "@arcgis/core/geometry/operators/projectOperator.js";
await projectOperator.load();

// Project to Web Mercator
const projected = projectOperator.execute(geometry, { wkid: 3857 });

// Project to WGS 84
const wgs84 = projectOperator.execute(geometry, { wkid: 4326 });

TypeScript Usage

Feature reduction configurations use autocasting with type properties. For TypeScript safety, use as const:

// Use 'as const' for type safety
const clusterConfig = {
  type: "cluster",
  clusterRadius: "100px",
  renderer: {
    type: "simple",
    symbol: {
      type: "simple-marker",
      color: "#69dcff"
    }
  } as const,
  labelingInfo: [{
    labelExpressionInfo: {
      expression: "Text($feature.cluster_count, '#,###')"
    },
    symbol: {
      type: "text",
      color: "white"
    } as const
  }]
} as const;

featureLayer.featureReduction = clusterConfig;

Tip: See arcgis-core-maps skill for detailed guidance on autocasting vs explicit classes.

Common Pitfalls

  1. Operator not loaded: Most operators require await operator.load() before use

  2. API key required: Some REST services (routing, geocoding) require an API key

  3. Analysis only in SceneView: Some analyses (viewshed, line of sight) only work in 3D

  4. Cluster fields: Use cluster_count to access feature count in clusters

  5. Statistics query returns features: Statistics queries return features with calculated attributes, not raw numbers