Skip to content

Learn how to perform a hot spot feature analysis.

Run a find hot spot analysis on traffic and parking violations in San Francisco.

The spatial analysis service allows you to perform server-side geometric and analytic operations on feature data, also known as feature analysis. All feature analysis requests are job requests.

In this tutorial, use ArcGIS REST JS to perform a hot spot analysis to find statistically significant clusters of parking violations.

Prerequisites

You need an ArcGIS Location Platform or ArcGIS Online account.

Steps

Get the starter app

  1. Go to the Display a scene tutorial and download the solution.
  2. 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.

  1. Go to the Create OAuth credentials for user authentication tutorial to create an OAuth credential.
  2. 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

  1. In both the index.html and callback.html files, set the properties of clientId and redirectUri with the client ID and redirect URL of your OAuth credentials.

    index.html
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82  /* Use for user authentication */  const clientId = "YOUR_CLIENT_ID"; // Your client ID from OAuth credentials  const redirectUri = ""YOUR_REDIRECT_URI""; // The redirect URL registered in your OAuth credentials  const session = await arcgisRest.ArcGISIdentityManager.beginOAuth2({  clientId,  redirectUri,  portal: "https://www.arcgis.com/sharing/rest" // Your portal URL  });   const accessToken = session.token; 
    callback.html
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  arcgisRest.ArcGISIdentityManager.completeOAuth2({  clientId: "YOUR_CLIENT_ID", // Your client ID from OAuth credentials  redirectUri: "YOUR_REDIRECT_URI", // The redirect URL registered in your OAuth credentials  portal: "https://www.arcgis.com/sharing/rest" // Your portal URL  }); 
  2. Run the app and ensure you can sign in successfully.

  3. Set the defaultAccessToken included with Cesium to authenticate requests to the ArcGIS services used in this tutorial.

    index.html
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82  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.

  1. Go to your Cesium ion dashboard to generate an access token. Copy the key to your clipboard.

  2. Create a cesiumAccessToken variable and replace YOUR_CESIUM_ACCESS_TOKEN with the access token you copied from the Cesium ion dashboard.

    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82  <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_URI", // 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> 
  3. Configure Cesium.Ion.defaultAccessToken with the Cesium access token to validate the application.

    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82  <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_URI", // 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.

  1. Add references to the ArcGIS REST JS helper classes.

    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  <!-- 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.136/Build/Cesium/Cesium.js"></script>  <link href="https://cesium.com/downloads/cesiumjs/releases/1.136/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

  1. Update the camera's viewpoint to focus in San Francisco, CA.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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); 
    Expand

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.

  1. Add the SF Parking Violations map tile service to the map.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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); 
    Expand
  2. Add the data attribution for the map tile layer source.

    • Go to the sf_traffic_parking_violations_image_tile item.
    • Scroll down to the Acknowledgments section and copy its value.
    • Paste the copied value to the credit property.
      Expand
      Use dark colors for code blocks
      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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); 
      Expand
  3. Run the application and navigate to your localhost, for example https://localhost:8080. After you sign in, you will see the map tile layer rendered on the map.

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.

  1. Call the getSelf operation from ArcGIS REST JS to obtain the analysis URL.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  const getAnalysisUrl = async (withAuth) => {  const portalSelf = await arcgisRest.getSelf({  authentication: withAuth  });  return portalSelf.helperServices.analysis.url;  }; 
    Expand

Make the request

Use the Job class and set the operationURL and params required for the selected analysis.

  1. Create a function that submits a Job request to the spatial analysis service using your organization's analysis URL. Set the params required for a hot spot analysis and authenticate using the session token.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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 service.  };   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();  return jobResp;  }; 
    Expand
  2. Create an HTML div element called status and a loader to display the job status.

    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  <body>   <div id="status" style="visibility: hidden">  <span class="loader"></span>  <div id="info"></div>  </div>   <div id="map"></div> 
  3. Apply CSS styling to the status and the loader.

    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  #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);  }  } 
  4. Create a function called showInfo to control the visibility and content of the status element.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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 service.  };   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();  return jobResp;  };  
    Expand
  5. Use the function to dynamically update the status element with the current status of the analysis.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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 service.  };   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, () => {  showInfo(true, "Hot spot analysis running...");  });    // Get all the results, this will start monitoring and trigger events  const jobResp = await jobReq.getAllResults();  return jobResp;  }; 
    Expand
  6. Call the runAnalysis function and store its response in jobResponse.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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 service.  };   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, () => {  showInfo(true, "Hot spot analysis running...");  });    // Get all the results, this will start monitoring and trigger events  const jobResp = await jobReq.getAllResults();  return jobResp;  };   const jobResults = await runAnalysis(); 
    Expand

Display results

The results of a feature analysis are returned as feature data.

  1. Access the URL of the result layer when the analysis completes and run a query to access the features as GeoJSON.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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) => {   }); 
    Expand
  2. 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.

    Expand
    Use dark colors for code blocks
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241  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, "");   }); 
    Expand

Run the app

Run the application and navigate to your localhost, for example https://localhost:8080.

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.

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.

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.