Learn how to perform a hot spot feature analysis with the spatial analysis service.
A feature analysis is the process of using the spatial analysis service to perform server-side geometric and analytic operations on feature data. All feature analysis requests are job requests. The easiest way to programmatically run an analysis request to the spatial analysis service is to use ArcGIS REST JS, which provides a Job
class that handles long- running operations.
In this tutorial, you use ArcGIS REST JS to perform a hot spot analysis to find statistically significant clusters of parking violations.
Prerequisites
An ArcGIS Location Platform or ArcGIS Online account.
Steps
Get the starter app
- Go to the Display a scene tutorial and download the solution.
- Unzip the folder and open it in a text editor of your choice, such as Visual Studio Code. The starter app includes the following:
- callback.html: This contains callback as part of the authentication process.
- index.html: This contains app logic and the OAuth 2.0 code necessary to perform the authentication.
Set up authentication
Create a new OAuth credential to register the application.
- Go to the Create OAuth credentials for user authentication tutorial to create an OAuth credential.
- Copy the Client ID and Redirect URL from your OAuth credentials item and paste them to a safe location. They will be used in a later step.
Set developer credentials
-
In both the
index.html
andcallback.html
files, set the properties ofclient
andId redirect
with the client ID and redirect URL of your OAuth credentials.Uri index.htmlUse dark colors for code blocks const session = await arcgisRest.ArcGISIdentityManager.beginOAuth2({ clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials redirectUri: "YOUR_REDIRECT_URL", // The redirect URL registered in your OAuth credentials portal: "https://www.arcgis.com/sharing/rest" // Your portal URL }) const accessToken = session.token;
callback.htmlUse dark colors for code blocks arcgisRest.ArcGISIdentityManager.completeOAuth2({ clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials redirectUri: "YOUR_REDIRECT_URL", // The redirect URL registered in your OAuth credentials portal: "https://www.arcgis.com/sharing/rest" // Your portal URL })
-
Run the app and ensure you can sign in successfully.
If you are unable to sign in, make sure you have the correct redirect URL and port. This URL varies based on your application and typically takes the format of
https
or:// <server >[ :port]/callback.html http
. For example, if you are running an application on://my-arcgis-app :/auth http
, set://127.0.0.1 :5500/ http
as your redirect URL in the index.html and callback.html file and your developer credential. They all have to match!://127.0.0.1 :5500/callback.html -
Set the
default
included with Cesium to authenticate requests to the ArcGIS services used in this tutorial.Access Token index.htmlUse dark colors for code blocks Cesium.ArcGisMapService.defaultAccessToken = accessToken;
Get a Cesium ion access token
All Cesium applications must use an access token provided through Cesium ion. This token allows you to access assets such as Cesium World Terrain in your application.
-
Go to your Cesium ion dashboard to generate an access token. Copy the key to your clipboard.
-
Create a
cesium
variable and replaceAccess Token YOUR
with the access token you copied from the Cesium ion dashboard._CESIUM _ACCESS _TOKEN Use dark colors for code blocks <script> /* Use for API key authentication */ const accessToken = "YOUR_ACCESS_TOKEN"; // or /* Use for user authentication */ // const session = await arcgisRest.ArcGISIdentityManager.beginOAuth2({ // clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials // redirectUri: "YOUR_REDIRECT_URL", // The redirect URL registered in your OAuth credentials // portal: "YOUR_PORTAL_URL" // Your portal URL // }) // const accessToken = session.token; Cesium.ArcGisMapService.defaultAccessToken = accessToken; const cesiumAccessToken = "YOUR_CESIUM_ACCESS_TOKEN"; </script>
-
Configure
Cesium.
with the Cesium access token to validate the application.Ion.default Access Token Use dark colors for code blocks <script> /* Use for API key authentication */ const accessToken = "YOUR_ACCESS_TOKEN"; // or /* Use for user authentication */ // const session = await arcgisRest.ArcGISIdentityManager.beginOAuth2({ // clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials // redirectUri: "YOUR_REDIRECT_URL", // The redirect URL registered in your OAuth credentials // portal: "YOUR_PORTAL_URL" // Your portal URL // }) // const accessToken = session.token; Cesium.ArcGisMapService.defaultAccessToken = accessToken; const cesiumAccessToken = "YOUR_CESIUM_ACCESS_TOKEN"; Cesium.Ion.defaultAccessToken = cesiumAccessToken; </script>
Add script references
In addition to ArcGIS REST JS Request
, you also reference the Portal
and Feature service helper classes from ArcGIS REST JS to access the spatial analysis service.
-
Add references to the ArcGIS REST JS helper classes.
Use dark colors for code blocks <!-- require ArcGIS REST JS libraries from https://unpkg.com --> <script src="https://unpkg.com/@esri/arcgis-rest-request@4/dist/bundled/request.umd.js"></script> <!-- CesiumJS --> <script src="https://cesium.com/downloads/cesiumjs/releases/1.121/Build/Cesium/Cesium.js"></script> <link href="https://cesium.com/downloads/cesiumjs/releases/1.121/Build/Cesium/Widgets/widgets.css" rel="stylesheet" /> <!--ArcGIS REST JS used for spatial analysis --> <script src="https://unpkg.com/@esri/arcgis-rest-feature-service@4/dist/bundled/feature-service.umd.js"></script> <script src="https://unpkg.com/@esri/arcgis-rest-portal@4/dist/bundled/portal.umd.min.js"></script>
Update the map
-
Update the camera's viewpoint to focus in San Fransisco, CA.
Use dark colors for code blocks const arcgisBaseLayer = await Cesium.ArcGisMapServerImageryProvider.fromBasemapType(Cesium.ArcGisBaseMapType.SATELLITE); const viewer = new Cesium.Viewer("map", { baseLayer: Cesium.ImageryLayer.fromProviderAsync(arcgisBaseLayer), timeline: false, animation: false, minZoom: 2 }); viewer.camera.setView({ destination: Cesium.Cartesian3.fromDegrees(-122.445, 37.76, 7000), orientation: { pitch: Cesium.Math.toRadians(-55), heading: Cesium.Math.toRadians(-5) } }); // Add Esri attribution // Learn more in https://esriurl.com/attribution const poweredByEsri = new Cesium.Credit("Powered by <a href='https://www.esri.com/en-us/home' target='_blank'>Esri</a>", true); viewer.creditDisplay.addStaticCredit(poweredByEsri);
Display parking violations
To perform feature analysis, you need to provide feature data as input. In this tutorial, you use the SF parking violations hosted feature layer as input data for the hot spot analysis.
-
Add the SF Parking Violations map tile service to the map.
Use dark colors for code blocks const pointsSource = await Cesium.ArcGisMapServerImageryProvider.fromUrl( "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_image_tile/MapServer", { maximumLevel: 16, } ); //add map tile layer of points viewer.imageryLayers.addImageryProvider(pointsSource);
-
Add the data attribution for the map tile layer source.
- Go to the sf_traffic_parking_violations_image_tile item.
- Scroll down to the Credits (Attribution) section and copy its value.
- Create an
attribution
property and paste the attribution value from the item.Use dark colors for code blocks const pointsSource = await Cesium.ArcGisMapServerImageryProvider.fromUrl( "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_image_tile/MapServer", { maximumLevel: 16, //Attribution text retrieved from https://www.arcgis.com/home/item.html?id=3d7cbd4c925e4aba823775d1e0f80795 credit: "San Francisco 311, City and County of San Francisco" } ); //add map tile layer of points viewer.imageryLayers.addImageryProvider(pointsSource);
-
Run the application and navigate to your localhost, for example
https
. After you sign in, you will see the map tile layer rendered on the map.://localhost :8080
Get the analysis URL
To make a request to the spatial analysis service, you need to get the URL first. The analysis service URL is unique to your organization.
-
Call the
get
operation from ArcGIS REST JS to obtain the analysis URL.Self Use dark colors for code blocks const getAnalysisUrl = async (withAuth) => { const portalSelf = await arcgisRest.getSelf({ authentication: withAuth }); return portalSelf.helperServices.analysis.url; };
Make the request
Use the Job
class and set the operation
and params
required for the selected analysis.
-
Create a function that submits a
Job
request to the spatial analysis service using your organization's analysis URL. Set theparams
required for a hot spot analysis and authenticate using thesession
token.Use dark colors for code blocks const runAnalysis = async () => { const analysisUrl = await getAnalysisUrl(session); const operationUrl = `${analysisUrl}/FindHotSpots/submitJob`; const params = { analysisLayer: { url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_sa_osapi/FeatureServer/0" }, shapeType: "Hexagon", outputName: { serviceProperties: { name: `CesiumJS_find_hot_spots_${new Date().getTime()}` } } //Outputs results as a hosted feature serivce. }; const jobReq = await arcgisRest.Job.submitJob({ url: operationUrl, params: params, authentication: session }); // get all the results, this will start monitoring and trigger events const jobResp = await jobReq.getAllResults(); // jobResp.aggregatedLayer.value.url return jobResp; };
-
Create an HTML
div
element calledstatus
and a loader to display the job status.Use dark colors for code blocks <body> <div id="status" style="visibility: hidden"> <span class="loader"></span> <div id="info"></div> </div> <div id="map"></div>
-
Apply CSS styling to the
status
and the loader.Use dark colors for code blocks #status { width: 400px; background-color: #303336; color: #edffff; z-index: 1000; position: absolute; font-family: Arial, Helvetica, sans-serif; top: 50%; left: 50%; transform: translate(-50%, -50%); display: flex; flex-direction: row; justify-content: center; padding: 5px; border-radius: 5px; gap: 10px; align-content: center; align-items: center; margin: auto; } .loader { width: 24px; height: 24px; border: 5px solid #edffff; border-bottom-color: #303336; border-radius: 50%; display: inline-block; box-sizing: border-box; animation: rotation 2s linear infinite; } @keyframes rotation { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
-
Create a function called
show
to control the visibility and content of the status element.Info Use dark colors for code blocks const showInfo = (visible, msg) => { const statusUi = document.getElementById("status"); !visible ? (statusUi.style.visibility = "hidden") : (statusUi.style.visibility = "visible"); const infoUi = document.getElementById("info"); infoUi.innerText = msg; }; const runAnalysis = async () => { const analysisUrl = await getAnalysisUrl(session); const operationUrl = `${analysisUrl}/FindHotSpots/submitJob`; const params = { analysisLayer: { url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_sa_osapi/FeatureServer/0" }, shapeType: "Hexagon", outputName: { serviceProperties: { name: `CesiumJS_find_hot_spots_${new Date().getTime()}` } } //Outputs results as a hosted feature serivce. }; const jobReq = await arcgisRest.Job.submitJob({ url: operationUrl, params: params, authentication: session }); // get all the results, this will start monitoring and trigger events const jobResp = await jobReq.getAllResults(); // jobResp.aggregatedLayer.value.url return jobResp; };
-
Use the function to dynamically update the status element with the current status of the analysis.
Use dark colors for code blocks const runAnalysis = async () => { const analysisUrl = await getAnalysisUrl(session); const operationUrl = `${analysisUrl}/FindHotSpots/submitJob`; const params = { analysisLayer: { url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_sa_osapi/FeatureServer/0" }, shapeType: "Hexagon", outputName: { serviceProperties: { name: `CesiumJS_find_hot_spots_${new Date().getTime()}` } } //Outputs results as a hosted feature serivce. }; const jobReq = await arcgisRest.Job.submitJob({ url: operationUrl, params: params, authentication: session }); showInfo(true, "Initializing analysis..."); // listen to the status event to get updates every time the job status is checked. jobReq.on(arcgisRest.JOB_STATUSES.Status, (jobInfo) => { console.log(jobInfo.status); showInfo(true, "Hot spot analysis running..."); }); // get all the results, this will start monitoring and trigger events const jobResp = await jobReq.getAllResults(); // jobResp.aggregatedLayer.value.url return jobResp; };
-
Call the
run
function and store its response inAnalysis job
.Response Use dark colors for code blocks const runAnalysis = async () => { const analysisUrl = await getAnalysisUrl(session); const operationUrl = `${analysisUrl}/FindHotSpots/submitJob`; const params = { analysisLayer: { url: "https://services3.arcgis.com/GVgbJbqm8hXASVYi/arcgis/rest/services/sf_traffic_parking_violations_sa_osapi/FeatureServer/0" }, shapeType: "Hexagon", outputName: { serviceProperties: { name: `CesiumJS_find_hot_spots_${new Date().getTime()}` } } //Outputs results as a hosted feature serivce. }; const jobReq = await arcgisRest.Job.submitJob({ url: operationUrl, params: params, authentication: session }); showInfo(true, "Initializing analysis..."); // listen to the status event to get updates every time the job status is checked. jobReq.on(arcgisRest.JOB_STATUSES.Status, (jobInfo) => { console.log(jobInfo.status); showInfo(true, "Hot spot analysis running..."); }); // get all the results, this will start monitoring and trigger events const jobResp = await jobReq.getAllResults(); // jobResp.aggregatedLayer.value.url return jobResp; }; const jobResults = await runAnalysis();
Display results
The results of a feature analysis are returned as feature data.
-
Access the URL of the result layer when the analysis completes and run a query to access the features as GeoJSON.
Use dark colors for code blocks const params = { url: jobResults.hotSpotsResultLayer.value.url, f: "geojson", where: "Gi_Bin<>0", authentication: session }; const queryResponse = await arcgisRest.queryFeatures(params); const data = Cesium.GeoJsonDataSource.load(queryResponse, { stroke: Cesium.Color.fromCssColorString("#bbbbbb") }); data.then((layer) => { });
-
Once the GeoJSON results have been loaded, style the layer, extrude each hex bin then add the layer to the map. Then, hide the status element.
Use dark colors for code blocks const params = { url: jobResults.hotSpotsResultLayer.value.url, f: "geojson", where: "Gi_Bin<>0", authentication: session }; const queryResponse = await arcgisRest.queryFeatures(params); const data = Cesium.GeoJsonDataSource.load(queryResponse, { stroke: Cesium.Color.fromCssColorString("#bbbbbb") }); data.then((layer) => { const fillColors = { "Hot Spot with 99% Confidence": "#d62f27", "Hot Spot with 95% Confidence": "#ed7551", "Hot Spot with 90% Confidence": "#fab984", "Not Significant": "#f7f7f2", "Cold Spot with 90% Confidence": "#c0ccbe", "Cold Spot with 95% Confidence": "#849eba", "Cold Spot with 99% Confidence": "#4575b5" }; layer.name = "analysisResults"; const hexBins = layer.entities.values; for (let i = 0; i < hexBins.length; i++) { const bin = hexBins[i]; bin.polygon.material = Cesium.Color.fromCssColorString(fillColors[bin.properties["Gi_Text"]]); bin.polygon.extrudedHeight = (bin.properties["Gi_Bin"] + 4) * 100; } viewer.dataSources.add(layer); showInfo(false, ""); });
Run the app
Run the application and navigate to your localhost, for example https
.
After signing in, a request is sent to the spatial analysis service to perform a hot spot analysis. When the job is complete, the results of the analysis will display on the map. The analysis can take up to a minute to complete.
What's next?
To learn how to perform other types of feature analysis, go to the related tutorials in the Spatial analysis services guide:
Go to these tutorials to find, create, and enrich data for spatial analysis.
Find data sources
Discover data in ArcGIS that you can use for feature analysis.
Create data sources
Import, create, and generate data for feature analysis.
Enrich data sources
Enrich data with demographics and local facts for feature analysis.
Go to these tutorials to learn how to perform analyses interactively with the Map Viewer and programmatically with ArcGIS REST JS, ArcGIS API for Python, and ArcGIS REST API.
Find and extract data
Find data with attribute and spatial queries using find analysis operations.
Combine data
Overlay, join, and dissolve features using combine analysis operations.
Summarize data
Aggregate and summarize features using summarize analysis operations.
Discover patterns in data
Find patterns and trends in data using spatial analysis operations.