▾
Median household income in southern California.
Data visualization has a paradox: to properly visualize a dataset, you first need to be familiar with it; but to understand the data, you usually first have to visualize it.
Understanding the data involves knowing summary statistics, such as the maximum and minimum values, the mean, standard deviation, and the overall distribution. Without that understanding, you can easily create misleading visualizations and spend a lot of time on trial and error before getting a visualization right.
In addition to understanding the data, you should also be familiar with basic principles of cartography and color theory when creating a spatial data visualization. Not everyone has an eye for design and understands problems associated with visualizing numeric and categorical data with color.
In short, data visualization is hard and requires a lot of patience.
What is Smart Mapping?
Smart Mapping is designed to help developers get started with data visualization. It consists of more than a dozen APIs that generate renderers specific to an input dataset. These APIs are designed to help users and developers understand their data so they can make informed decisions best suited for visualizing it.
Smart mapping will help you understand the nature of the data (the statistics and spread), and suggest a set of color ramps designed by seasoned cartographers specifically for the desired style.
Developers can use the Smart Mapping APIs to:
- Familiarize themselves with an unknown or unfamiliar dataset.
- Select colorblind-friendly color ramps and schemes best suited for a layer given its background.
- Build apps that allow users to explore unfamiliar datasets using a variety of styles and widgets.
- Build apps that allow users to style layers and save them to webmaps.
How Smart Mapping works
Smart mapping consists of the following modules, organized by style:
- colorRendererCreator
- dotDensityRendererCreator
- heatmapRendererCreator
- locationRendererCreator
- opacityVariableCreator
- predominanceRendererCreator
- relationshipRendererCreator
- sizeRendererCreator
- typeRendererCreator
- univariateColorSizeRendererCreator
The createRenderer method in each of these modules queries the summary statistics of the data, and selects a color scheme best suited for the given basemap or background color of the view.
Each smart mapping method typically requires the following:
- The layer to which the output renderer will be applied
- The view where the layer is rendered
- The field or Arcade expression containing the data for the visualization
A continuous color renderer can use a diverging, or above-and-below, color ramp.
const { renderer } = await colorRendererCreator.createContinuousRenderer({ layer: featureLayer, view: mapView, field: "Median_HH_Income", theme: "above-and-below",});
featureLayer.renderer = renderer;20 collapsed lines
<!doctype html><html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Smart mapping - income by color</title>
<!-- Load the ArcGIS Maps SDK for JavaScript from CDN --> <script type="module" src="https://js.arcgis.com/5.2/"></script>
<style> html, body { height: 100%; margin: 0; } </style> </head>
<body> <arcgis-map item-id="d81a583f288f48f3afe4947a71fa3065"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-expand slot="top-right"> <arcgis-legend></arcgis-legend> </arcgis-expand> </arcgis-map>2 collapsed lines
</body></html>83 collapsed lines
<!doctype html><html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> <title>Smart mapping - income by color</title>
<link rel="stylesheet" href="https://js.arcgis.com/5.2/esri/themes/light/main.css" /> <!-- Load the ArcGIS Maps SDK for JavaScript from CDN --> <script type="module" src="https://js.arcgis.com/5.2/"></script>
<style> html, body { height: 100%; margin: 0; }
#containerDiv { background-color: white; padding: 3px; text-align: center; min-width: 260px; width: 280px; height: 300px; overflow: auto; } </style> </head>
<body> <arcgis-map center="-117.603514, 33.955457" scale="1155581"> <arcgis-zoom slot="top-left"></arcgis-zoom> <arcgis-expand slot="top-right"> <arcgis-legend></arcgis-legend> </arcgis-expand> <div id="containerDiv" class="esri-widget" slot="top-right"> <div id="title"><h3>2019 Median Household Income</h3></div> <div id="description"> This app allows you to explore median household incomes in the Los Angeles Area. The slider contains two lines that indicate values of interest: the federal poverty level and the low-income threshold for a family of four in Los Angeles. </div> <div id="slider"></div> </div> </arcgis-map>
<script type="module"> const [Map, FeatureLayer, colorRendererCreator, colorSymbology, histogram, ColorSlider, Color, intl] = await $arcgis.import([ "@arcgis/core/Map.js", "@arcgis/core/layers/FeatureLayer.js", "@arcgis/core/smartMapping/renderers/color.js", "@arcgis/core/smartMapping/symbology/color.js", "@arcgis/core/smartMapping/statistics/histogram.js", "@arcgis/core/widgets/smartMapping/ColorSlider.js", "@arcgis/core/Color.js", "@arcgis/core/intl.js", ]);
const viewElement = document.querySelector("arcgis-map");
// Create a map and add it to the map component
const layer = new FeatureLayer({ portalItem: { id: "340a8efc331f4cd59fecbc4ab8e2a311", }, definitionExpression: "MEDHINC_CY > 0", visible: false, });
const map = new Map({ basemap: { portalItem: { id: "3582b744bba84668b52a16b0b6942544", }, }, layers: [layer], });
viewElement.map = map;
// configure parameters for the color renderer generator // the layer must be specified along with a field name // or arcade expression. The basemap and other properties determine // the appropriate default color scheme.
const redAndGreenScheme = colorSymbology.getSchemeByName({ basemap: map.basemap, geometryType: "polygon", theme: "above-and-below", name: "Red and Green 4", });
// flip the red and green scheme so green is on top const moneyScheme = colorSymbology.flipColors(redAndGreenScheme);
const colorParams = { layer: layer, field: "MEDHINC_CY", theme: "above-and-below", colorScheme: moneyScheme, };
// create reference to histogram bar elements for updating // their style as the user drags slider thumbs const bars = []; let rendererResult = null; let vv = null;
colorRendererCreator .createContinuousRenderer(colorParams) .then(function (response) { // set the renderer to the layer and add it to the map rendererResult = response; vv = rendererResult.visualVariable; layer.renderer = response.renderer; layer.visible = true;
return histogram({ layer: colorParams.layer, field: colorParams.field, numBins: 60, }); }) .then(function (histogramResult) { const slider = ColorSlider.fromRendererResult(rendererResult, histogramResult);
// format slider labels as currency
slider.set({ container: "slider", primaryHandleEnabled: true, labelFormatFunction: function (value, type) { return intl.formatNumber(value, { style: "currency", currency: "USD", currencyDisplay: "symbol", maximumFractionDigits: 0, minimumFractionDigits: 0, }); }, });
// hide default statistic lines from slider histogram
slider.histogramConfig.average = null; slider.histogramConfig.standardDeviation = null;
// update the slider bars to match renderer values slider.histogramConfig.barCreatedFunction = function (index, element) { const bin = histogramResult.bins[index]; const midValue = (bin.maxValue - bin.minValue) / 2 + bin.minValue; const color = getColorFromValue(vv.stops, midValue); element.setAttribute("fill", color.toHex()); bars.push(element); };
// render meaningful data lines on the slider for // communicating policy issues slider.histogramConfig.dataLines = [ { value: 83500, label: "HUD low income", }, { value: 25750, label: "Fed poverty line", }, ];
// slider values will only go to 2 decimal places (money) slider.viewModel.precision = 2;
// Update the renderer for each change made to the slider
slider.on(["thumb-change", "thumb-drag", "min-change", "max-change"], function () { const renderer = layer.renderer.clone(); const colorVariable = renderer.visualVariables[0].clone(); colorVariable.stops = slider.stops; renderer.visualVariables = [colorVariable]; layer.renderer = renderer;
// update the color of each histogram bar based on the // values of the slider thumbs bars.forEach(function (bar, index) { const bin = slider.histogramConfig.bins[index]; const midValue = (bin.maxValue - bin.minValue) / 2 + bin.minValue; const color = getColorFromValue(slider.stops, midValue); bar.setAttribute("fill", color.toHex()); }); }); }) .catch(function (error) { console.log("there was an error: ", error); });42 collapsed lines
// infers the color for a given value // based on the stops from a ColorVariable function getColorFromValue(stops, value) { let minStop = stops[0]; let maxStop = stops[stops.length - 1];
const minStopValue = minStop.value; const maxStopValue = maxStop.value;
if (value < minStopValue) { return minStop.color; }
if (value > maxStopValue) { return maxStop.color; }
const exactMatches = stops.filter(function (stop) { return stop.value === value; });
if (exactMatches.length > 0) { return exactMatches[0].color; }
minStop = null; maxStop = null; stops.forEach(function (stop, i) { if (!minStop && !maxStop && stop.value >= value) { minStop = stops[i - 1]; maxStop = stop; } });
const weightedPosition = (value - minStop.value) / (maxStop.value - minStop.value);
return Color.blendColors(minStop.color, maxStop.color, weightedPosition); } </script> </body></html>The methods exposed by these modules may be used in conjunction with the following slider components:
- Classed Color Slider
- Classed Size Slider
- Color Size Slider
- Color Slider
- Heatmap Slider
- Opacity Slider
- Size Slider
Related samples and resources
Size visual variable themes
Generate continuous color visualization
Generate data-driven visualization of unique values
Generate a class breaks visualization
Generate a relationship visualization
Generate a predominance visualization
Generate a dot density visualization
Customize ColorSlider Histogram
API support
| 2D | 3D | Arcade | Points | Lines | Polygons | Mesh | |
|---|---|---|---|---|---|---|---|
| | | | | | | | |
| | | | | | | | |
| | | | | | | ||
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | | | | | | |
| | | |
- Color only
- Size variable creators only supported for points
- Size variable creators not supported in 3D