This guide shows advanced usage of VisualVariables and other Renderer options in Map Widget, e.g. Class Breaks in size and colors, and Unique Value Renderers. The purpose is to give users more freedom into customizing their own style or symbolizing. For previous coverage of map widgets, please go to using the map widget and Advanced Map Widget Usage
As usual, start by connecting to your GIS. You can use either an existing profile, or just type GIS(url="your enterprise", username='user name', password='password')
to set up the connection.
from arcgis.gis import GIS
gis = GIS(url='https://pythonapi.playground.esri.com/portal', username='arcgis_python', password='amazing_arcgis_123')
Part 1. Style based on numeric values in your data
Map Viewer gives you control over styling elements such as color ramps, line weights, transparency, and symbols. Let's being with several styling options useful for visualizing features according to numeric values in your data.
map1 = gis.map("USA", 4)
map1
Section 1.1 Styled using only one numeric attribute
If you have numeric data, you may want to distinguish features using graduated colors to reflect a count or an amount. Different kinds of color ramps can be used—for example, a simple light-to-dark color ramp is good for showing low-to-high data values such as age, income, or ratio. Color ramps like this can be applied to points, lines, or polygons. For example, you can use a light-to-dark color ramp to represent the ratio of cropland area to general land area from low to high by county. More documentation can be found in Style numbers.
"""
# only 1 numeric attribute
# (a) to visualize with counts and amounts (color)
# field_name here represents "The acres of total cropland as a percentage of land area in acres"
"""
from arcgis.features import FeatureLayer
usa_flayer = FeatureLayer("https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/USA_County_Crops_2007/FeatureServer/0")
map1.add_layer(usa_flayer, { "type": "FeatureLayer",
"renderer":"ClassedColorRenderer",
"field_name":"M086_07"})
While smart mapping will automatically choose the class breaks, users can also use autocasting if they want finer control by providing their own class breaks and symbology for each class. By specifying renderer: "autocast"
for any renderer, you are directing Python to allow the Javascript API to attempt to infer the renderer by following Javascript API rules. Since Python dict's map directly to JavaScript JSON, you can specify any Javascript Renderer for a large range of visualization options! Please look at the example of map2
below to explore how to provide your own customized class breaks and specific symbols with color, size, labels, etc.
"""
# only 1 numeric attribute
# (a) to visualize with counts and amounts (color) + Customized class breaks
# field_name here represents "The acres of total cropland as a percentage of land area in acres"
"""
map2 = gis.map("USA", 4)
map2_renderer = {"renderer": "autocast", #This tells python to use JS autocasting
"type": "classBreaks",
"field":"M086_07",
"minValue":-9007199254740991}
map2_renderer["visualVariables"] = [{ "type": "colorInfo",
"field": "M086_07",
"stops": [ {
"value": 10,
"color": [237,248,251,204],
"label": "< 10"
},
{
"value": 25,
"color": [178,226,226,204],
"label": "10~39.5"
},
{
"value": 39.5,
"color": [102,194,164,204],
"label": "39.5"
},
{
"value": 54,
"color": [44,162,95,204],
"label": "39.5~68"
},
{
"value": 68,
"color": [0,109,44,204],
"label": "> 68"
}]
}]
map2_renderer["classBreakInfos"] = [{ "symbol": {
"color": [170,170,170,204],
"outline": {
"color": [153,153,153,255],
"width": 0.375,
"type": "esriSLS",
"style": "esriSLSSolid"
},
"type": "esriSFS",
"style": "esriSFSSolid"
},
"classMaxValue": 9007199254740991
}]
map2.add_layer(usa_flayer,
{ "type": "FeatureLayer",
"renderer": map2_renderer,
"field_name":"M086_07",
"minValue":-9007199254740991,
"definitionExpression": "AREA > 0.001"})
map2
The two examples shown above demonstrate how color differences in visualization can help audience form a sense of the orderable sequence of the numeric data or ranks. On the other hand, size differences also play an important role in mapping.
The map style (as shown below) uses an orderable sequence of different sizes to represent your numeric data or ranked categories. Points, lines, and areas can all be drawn using this approach. Polygon features are displayed as proportional points over polygons. These proportional symbol maps use an intuitive logic that larger symbols equate to larger numbers. Adjust the size of the symbols to clarify the story you’re telling. More documentation can be found in Counts and Amounts (Size)
"""
# only 1 numeric attribute
# (b) counts and amounts (size)
# The field used here represent the harvested acres of Upland Cotton
"""
map3 = gis.map("USA", 4)
map3_renderer = {"renderer": "autocast", #This tells python to use JS autocasting
"type": "classBreaks",
"field":"M188_07",
"transparency":20,
"minValue":-9007199254740991}
map3_renderer["visualVariables"] = [{ "type": "sizeInfo",
"field": "M188_07",
"valueUnit": "unknown",
"minSize": {
"type": "sizeInfo",
"expression": "view.scale",
"stops": [{ "value": 1128,
"size": 16
},
{ "value": 144447,
"size": 16
},
{ "value": 18489298,
"size": 4
},
{ "value": 147914382,
"size": 4
},
{ "value": 591657528,
"size": 2
}]
},
"maxSize": {
"type": "sizeInfo",
"expression": "view.scale",
"stops": [{ "value": 1128,
"size": 80
},
{ "value": 144447,
"size": 80
},
{ "value": 18489298,
"size": 50
},
{ "value": 147914382,
"size": 50
},
{ "value": 591657528,
"size": 25
}]
},
"minDataValue": 0,
"maxDataValue": 150000
},
{ "type": "sizeInfo",
"target": "outline",
"expression": "view.scale",
"stops": [{ "size": 2,
"value": 1080478
},
{ "size": 1,
"value": 6752990
},
{ "size": 1,
"value": 27011958
},
{ "size": 0,
"value": 54023916
}]
}]
map3_renderer["classBreakInfos"] = [{ "symbol": {
"color": [227,139,79,255],
"size": 9,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": [51,51,51,255],
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSSolid"
}
},
"classMaxValue": 9007199254740991
}]
map3.add_layer(usa_flayer,
{ "type": "FeatureLayer",
"renderer":map3_renderer,
"field_name":"M188_07"})
map3
Section 1.2 Compare A to B
This style allows you to map the ratio between two numbers and express that relationship as percentages, simple ratios, or overall percentage. For example, you can map the estimated population for 2025 as a percentage of the known population in 2015 to observe the trend of population shift. Find out more via Compare A to B.
"""
# with 2 numeric attributes
# compare A to B
# The field used here represent percentage of [population of projected 2025] as pf [population of 2015]
"""
map4 = gis.map("France", 2)
map4_renderer = {"renderer": "autocast", #This tells python to use JS autocasting
"type": "classBreaks",
"field":"POP2025",
"transparency":80,
"minValue":-9007199254740991}
map4_renderer["visualVariables"] = [{ "type": "colorInfo",
"field": "POP2025",
"normalizationField": "POP2015",
"stops": [
{ "value": 1.12,
"color": [230,97,1,255],
"label": "< 112%"
},
{ "value": 1.1800000000000002,
"color": [253,184,99,255],
"label": "112% ~ 124%"
},
{ "value": 1.24,
"color": [247,247,247,255],
"label": "124%"
},
{ "value": 1.3,
"color": [178,171,210,255],
"label": "124% ~ 136%"
},
{ "value": 1.36,
"color": [94,60,153,255],
"label": "> 136%"
}]
}]
map4_renderer["classBreakInfos"] = [{ "symbol": {
"color": [170,170,170,255],
"size": 10.5,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": [153,153,153,255],
"width": 0.375,
"type": "esriSLS",
"style": "esriSLSSolid"
}
},
"classMaxValue": 9007199254740991
}]
world_flayer = FeatureLayer("http://services.arcgis.com/nGt4QxSblgDfeJn9/arcgis/rest/services/World_LargestUrbanAreas_fs/FeatureServer/0")
map4.add_layer(world_flayer,
{ "type": "FeatureLayer",
"renderer": map4_renderer,
"field_name":"POP2025",
"normalizationType": "esriNormalizeByField",
"normalizationField": "POP2015"})
map4
Section 1.3 Predominant category and size
Use this map style to compare multiple related attributes with the same unit of measure. Like the Predominant Category style, this style uses color to visualize the predominant attribute and transparency in order to show the degree of its predominance compared to the other attributes. In addition, the Predominant Category and Size style uses a third element—size—to represent the sum of the attributes for each feature. For example, in a layer that shows crop production by United States county, you can apply this style to see which crop—wheat, corn, soybeans, and so on—has the highest value in each county, and how much higher the predominant crop's value is compared to the other crops. In addition, by applying proportional symbols to the layer, you can compare total crop production across counties, visualizing which counties have high total crop production and which have a lower yield. Find out more about this style at Predominant Category.
"""
# with 2 to 10 related numeric attributes with the same unit of measurement
# Predominant category and size
# The field used here represent the predominant crop production
"""
map5 = gis.map("USA", 4)
map5_renderer = {"renderer": "autocast", #This tells python to use JS autocasting
"type": "uniqueValue"}
map5_renderer["valueExpression"] = "var fieldNames = [ \"M163_07\", \"M172_07\", \"M193_07\", \"M188_07\", \"M217_07\" ];\
var numFields = 5;\
var maxValueField = null;\
var maxValue = -Infinity;\
var value, i, totalValue = null;\
for(i = 0; i < numFields; i++) {\
value = $feature[fieldNames[i]];\
if(value > 0) {\
if(value > maxValue) {\
maxValue = value;\
maxValueField = fieldNames[i];\
}\
else if (value == maxValue) {\
maxValueField = null;\
}\
}\
}\
return maxValueField;"
transparencyInfo_valueExpression = "var fieldNames = [ \"M163_07\", \"M172_07\", \"M193_07\", \"M188_07\", \"M217_07\" ];\
var numFields = 5;\
var maxValueField = null;\
var maxValue = -Infinity;\
var value, i, totalValue = null;\
for(i = 0; i < numFields; i++) {\
value = $feature[fieldNames[i]];\
if(value > 0) {\
if(value > maxValue) {\
maxValue = value;\
maxValueField = fieldNames[i];\
}\
else if (value == maxValue) {\
maxValueField = null;\
}\
}\
if(value != null && value >= 0) {\
if (totalValue == null) { totalValue = 0; }\
totalValue = totalValue + value;\
}\
}\
var strength = null;\
if (maxValueField != null && totalValue > 0) {\
strength = (maxValue / totalValue) * 100;\
}\
return strength;"
sizeInfo_valueExpression = "var fieldNames = [ \"M163_07\", \"M172_07\", \"M193_07\", \"M188_07\", \"M217_07\" ];\
var numFields = 5;\
var value, i, totalValue = null;\
for(i = 0; i < numFields; i++) {\
value = $feature[fieldNames[i]];\
if(value != null && value >= 0) {\
if (totalValue == null) { totalValue = 0; }\
totalValue = totalValue + value;\
}\
}\
return totalValue;"
map5_renderer["visualVariables"] = [{ "type": "transparencyInfo",
"valueExpression": transparencyInfo_valueExpression,
"stops": [{ "value": 20,
"transparency": 85
},
{ "value": 95,
"transparency": 0
}],
"legendOptions": {"title": "Strength of predominance"}
},
{ "type": "sizeInfo",
"valueExpression": sizeInfo_valueExpression,
"valueUnit": "unknown",
"minSize": {
"type": "sizeInfo",
"expression": "view.scale",
"stops": [{ "value": 1128,
"size": 16
},
{ "value": 72223,
"size": 16
},
{ "value": 9244649,
"size": 6
},
{ "value": 147914382,
"size": 4
},
{ "value": 591657528,
"size": 2
}]
},
"maxSize": {
"type": "sizeInfo",
"expression": "view.scale",
"stops": [{ "value": 1128,
"size": 80
},
{ "value": 72223,
"size": 80
},
{ "value": 9244649,
"size": 50
},
{ "value": 147914382,
"size": 50
},
{ "value": 591657528,
"size": 25
}]
},
"minDataValue": 50000,
"maxDataValue": 800000,
"legendOptions": { "title": "Sum of categories"}
}]
map5_renderer["uniqueValueInfos"] = [{ "value": "M163_07",
"symbol": {
"color": [255,255,0,255],
"size": 6,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": "White",
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSNull"
}
},
"label": "Corn for grain, harvested acres."
},
{ "value": "M172_07",
"symbol": {
"color": [255,170,0,255],
"size": 6,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": "White",
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSNull"
}
},
"label": "All wheat for grain, harvested acres."
},
{ "value": "M193_07",
"symbol": {
"color": [152,230,0,255],
"size": 6,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": "White",
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSNull"
}
},
"label": "Soybeans for beans, harvested acres."
},
{ "value": "M188_07",
"symbol": {
"color": [255,255,255,255],
"size": 6,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": "White",
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSNull"
}
},
"label": "Upland cotton, harvested acres."
},
{ "value": "M217_07",
"symbol": {
"color": [255,0,0,255],
"size": 6,
"angle": 0,
"xoffset": 0,
"yoffset": 0,
"type": "esriSMS",
"style": "esriSMSCircle",
"outline": {
"color": "White",
"width": 0.75,
"type": "esriSLS",
"style": "esriSLSNull"
}
},
"label": "Vegetables, acres harvested for sale."
}]
map5.add_layer(usa_flayer,
{ "type": "FeatureLayer",
"renderer": map5_renderer})
map5
Conclusion
When you style a layer, the styling options offered depend on the type of features you are mapping (point, line, or polygon) as well as the type of data attributes (numbers, categories, dates, and so on) and number of attributes you choose. Each style helps you tell a slightly different story and answer different questions with your data. Samples shown here are meant to give you basic ideas of how built-in renderer types like Class Breaks Renderers or Unique Value Renderers are being used, or when you need to customize your styles, how to direct Python in allowing the Javascript API to attempt to infer the renderer by some of the Javascript API rules.
Now that we have mastered some basic styles of visualizing numeric or orderable data, let's move on to the second half of the topic (advanced-cartography-part2.ipynb
) for guides of how to style your map based on categorical data.