Performing analysis with the Con tool

‘Con’, abbreviated for condition, is one of the most used and powerful tools in Spatial Analyst. It allows you to vary how the output is determined based on the value of the input locations, which is key for building simple as well as complex models. Let’s go through a scenario to better understand how the tool works.

Assume you are a coffee grower and you wish to expand your growing operation by purchasing additional land. To identify which areas to buy, you are considering various factors such as elevation, land use type, slope, aspect, and so on. The ideal conditions for growing the plants that produce Arabica coffee beans include areas that are between 1800 and 3600 feet in elevation, are flat and open, and are near roads and streams. South facing aspects are desirable, but not mandatory. So, you would like to identify areas that maximize the above-mentioned factors.

Before you start with the analysis, let’s quickly recap the Geoprocessing Con tool (see Figure 1). The basic premise of the tool is to create output based on some condition. The syntax for the Con tool is: Con(in_conditonal_raster, in_true_raster_or_constant, {in_false_raster_or_constant}, {where_clause}). For more details, you can read the help page here.

Figure 1: Geoprocessing Dialog box for the Con tool.

Figure 1: Geoprocessing Dialog box for the Con tool.

The Con tool is available in the Conditional toolset in the Spatial Analyst toolbox. It is also available from the sa module in arcpy and can also be accessed using the Raster Calculator tool.

Now that you have the basics of how Con works, let’s start the analysis.

Where are the best locations to grow my coffee?

First, you are interested in locations where the elevations are greater than 1800 feet. If a location meets the criteria, you want to assign the location a “1” (True) and locations not meeting the criteria, you want to assign a “0” (False).

To do this in the Con tool dialog, specify your elevation raster (elevation.tif) as the Input condition raster and the value greater than 1800 feet as the condition in the Expression. To achieve the desired output, you will assign a “1” to the locations with elevations meeting this criterion and a “0” for elevations equal to or lower than 1800 (see Figure 1). To specify the input to the Con tool as a raster, create a raster object from the input dataset. It is recommended to first create the raster object from the elevation dataset and then use the resulting object in the subsequent Con statement.

import arcpy 
from import *

elev = Raster("elevation.tif") # Creating a raster object from the elevation dataset 
outElev1wc = Con(elev, 1, 0, "Value > 1800")

While the preceding statement will work fine, writing it in the following way is preferred, since it allows for some optimizations to be made on execution and thus should run faster:

outElev1 = Con(elev > 1800, 1, 0)

Both these statements would give you the same output. Any location with an elevation greater than 1800 feet (the where_condition) meets your criteria and will be assigned “1” (the in_true_raster_or_constant), while locations equal to or below 1800 feet are assigned a “0” (the in_false_raster_or_constant).

Notice the second Con statement does not use the where_clause parameter explicitly, but specifies the condition directly to the in_conditonal_raster parameter instead.

Functionality: Defining ranges using Boolean evaluations (“&”) in a complex expression

Once you have the minimum elevation set, you also need to identify the upper elevation limit, 3600 feet. An efficient way to identify the elevation range is to use a Boolean evaluation. You also realize that for subsequent analysis, you wish to know the elevation values for locations within the desired range, not just assign them a “1”, and you do not want to consider locations with elevations outside the range. Therefore, you must alter the above Con statement and replace ’1′ with ‘elev’ to maintain the elevation values for those locations within the range, and eliminate the other locations from consideration by assigning them ‘NoData’ instead of ’0′, as below:

outElevRange = Con(((elev > 1800) & (elev < 3600)), elev)

In the statement, make note of the following: the condition is not a simple evaluation but a Boolean, the true condition is a raster and not a constant, and no false statement is specified. As a result, locations above 1800 feet and (“&”) below 3600 feet are assigned their elevation value using elev for the input_true_raster_or_constant parameter. By leaving the input_false_raster_or_constant parameter empty, you will assign locations equal to or below 1800 feet or equal to or above 3600 feet to NoData.

Functionality: When to use the where clause in Map Algebra

Let’s now incorporate another criterion in our analysis for identifying the best locations to grow coffee. Not only do you want elevations between 1800 and 3600 feet, you prefer the locations that are open and not forested within that range. You have a land use raster with a field called “Category” which identifies the land use type for each location. To query a field other than “Value” in a raster, you must use the optional where clause.

inlanduse = Raster('landuse') # Creating a raster object from the landuse dataset
outElevLU = Con(inlanduse, outElevRange,'', "Category = 'OpenArea'")

In the above statement the condition is based on a field other than “Value”, thus, a where clause is necessary. As a result, all locations that are designated as “OpenArea” land use are assigned the elevation values from outElevRange and all other locations are assigned NoData. As you recall, in outElevRange, only locations with elevation values greater than 1800 and less than 3600 feet have values and all other locations are NoData.

Functionality: Creating a condition from multiple rasters

The above types of conditions are the most common use for Con, but let’s explore a few additional conditions to address more complex problems. Continuing your analysis, since you prefer locations that you can access and that have water nearby, the best locations to grow coffee would be within a mile of a road and a half of mile of a stream.

inDistRoads = EucDistance('roads')
inDistStreams = EucDistance('streams')

outElevDist = Con(((inDistRoads < 5280) & (inDistStreams < 2640)), outElevLU)

You first need to create two rasters, one identifying how far each location is from the closest road and a second identifying how far each location is from the closest stream using the Spatial Analyst Euclidean Distance tool.

In the Con statement above two different rasters are used in the conditional statement. As a result, only locations that are within a mile of road, within a half a mile (2640 feet) of a stream, have a land use of “OpenArea”, and are within elevations of 1800 and 3600 feet will be assigned their elevation values, while all other locations are assigned NoData.

Functionality: Using a nested Con

Let’s complete the analysis.  From the possible locations selected so far, you prefer flatter slopes with more southerly aspects for growing your coffee, but maintaining the southerly aspect is not mandatory.

inSlope = Slope(elev)
inAspect = Aspect(elev)

outRaster = Con((inSlope < 10) & (outElevDist > 0), Con((inAspect > 135) & (inAspect < 225), outElevDist, 0))

First, two rasters are created identifying the slope and aspect for each location determined from the elevation surface using the Spatial Analyst Slope and Aspect tools. Then, you will incorporate the slope and aspect preferences into the condition.

This Con statement is much more complex than the previous ones. In this statement, the in_true_raster_or_constant parameter for the first Con (the outer Con) is another Con (the inner Con, specifying southerly aspect) with its own condition and true and false statements. In the outer Con, the first condition determines if a location is less than 10 percent slope but also meets the other criteria identified above (being within the elevation range, open, within a mile from a road, and within a half a mile of a stream). If the location meets these criteria, it is then evaluated by a second condition, the inner Con, to see if the location faces south. If it does, then the location is assigned the elevation value (the in_true_raster_or_constant of the inner Con), if not, instead of assigning it NoData, it is assigned a “0” (the in_false_raster_or_constant of the inner Con) so that you can later identify these locations. Since the in_false_raster_or_constant for the outer Con is blank, any location that is steep and/or does not meet the series of criteria defined above (the elevation, land use type, and distances criteria) will be assigned NoData.  Once you have mastered matching the conditions and the true and false statements within this complex Con statement, you will be able to unleash the power of Con to address many of your specific needs.

At this point, you know the locations that meet all your criteria. However, while selecting the area to expand your growing operation and to maintain a contiguous tract of land, you may need to relax one or more of the criteria (such as southerly aspect), and consider areas that are now assigned “0”, for your purchase.

Now get ready to plant!

This entry was posted in Analysis & Geoprocessing, ArcGIS Pro, ArcMap, Python and tagged , , , , , . Bookmark the permalink.

Leave a Reply


  1. Curtis Price says:

    This is a nice little article! I think it’s important to note that using the Raster Calculator or arcpy map algebra (ie python code) you can nest tools as map algebra functions inside a Con statement. I think this is where Con really gets powerful!
    Con(~ IsNull(raster1), 1, 0) # set all data cells to 1 others zero
    Con(FocalStatistics(raster1, "MINIMUM") == raster1, raster1) # Set all cells to NoData, except cells that are min of 3x3 neighborhood

    (Note, In Raster calculator you’d put the raster dataset names in double quotes. The easiest way to get that syntax right is to use Raster Calculator’s expression builder instead of just typing it in.)

  2. hornbydd says:

    Great example to show off the power of the CON tool, thanks.