Species tool: Version 2¶
Toolbox¶
For the more advanced version of our tool, we will create a new toolbox-interface:
In the Parameters
-tab, add the following parameters:
Task
Determine the Filter
parameter for Presence value
as a range of values from 1-5.
Note
The Direction
of the output folder needs to be Input
(the user needs to specify the location of an existing folder)
Let’s import those five parameters from the graphical interface into our Python script using GetParameterAsText() -function:
# 1. Get parameters from the toolbox using 'GetParametersAsText' method
#----------------------------------------------------------------------
# --> check ArcGIS help for info how to use methods
# Method info: http://desktop.arcgis.com/en/arcmap/latest/analyze/arcpy-functions/getparameterastext.htm
input_species_shp = arcpy.GetParameterAsText(0)
output_folder = arcpy.GetParameterAsText(1)
species_attribute = arcpy.GetParameterAsText(2)
attribute_name = arcpy.GetParameterAsText(3)
presence_value = arcpy.GetParameterAsText(4)
Adding a new field into attribute table¶
Next, we need to add a new field that is called in a way that the user wants it. The field name is stored in the attribute_name
variable. Adding new column can be done by using a function called AddField_management()
(see help).
# 2. Add a new field into the input shapefile with 'AddField_management' method
#------------------------------------------------------------------------------
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/add-field.htm
arcpy.AddField_management(in_table=input_species_shp, field_name=attribute_name, field_type="SHORT") # Other possible parameters can be left as default
Updating column with Field Calculator¶
Let’s update the newly created column with the Presence value
that was asked from the user and will be assigned to the raster cells. We can do calculations in attribute table with CalculateField_management() -function. Let’s update the column with value that is stored in presence_value
variable.
# 3. Update the presence value for our newly created attribute with 'CalculateField_management' method
#-----------------------------------------------------------------------------------------------------
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/calculate-field.htm
arcpy.CalculateField_management(in_table=input_species_shp, field=attribute_name, expression=presence_value)
Iterating over values in attribute table¶
As we wanted to save individual species into separate raster files, we need to determine the unique species in our attribute table. In Pandas / Geopandas there is a nice function called .unique()
for this purpose but unfortunately arcpy does not have such a function that would work with Shapefiles. Hence, we need to create the “unique” -function ourselves.
Let’s create a function that iterates over the values in a column and returns a list of unique values that are present in that column. We can iterate over the rows in attribute table by using SearchCursor() -function (read-only) in arcpy.
#-----------------------------------------------------------------------------------------------------------------------------------
# 4. Get a list of unique species in the table using 'SearchCursor' method
# Method info: http://desktop.arcgis.com/en/arcmap/latest/analyze/arcpy-data-access/searchcursor-class.htm
# More elegant version of the function in ArcPy Cafe: https://arcpy.wordpress.com/2012/02/01/create-a-list-of-unique-field-values/
# ----------------------------------------------------------------------------------------------------------------------------------
# 4.1 CREATE a function that returns unique values of a 'field' within the 'table'
def unique(table, field):
# Create a cursor object for reading the table
cursor = arcpy.da.SearchCursor(table, [field]) # A cursor iterates over rows in table
# Create an empty list for unique values
unique_values = []
# Iterate over rows and append value into the list if it does not exist already
for row in cursor:
if not row[0] in unique_values: # Append only if value does not exist
unique_values.append(row[0])
return sorted(unique_values) # Return a sorted list of unique values
Let’s apply our function in following manner:
# 4.2 USE the function to get a list of unique values
unique_species = unique(table=input_species_shp, field=species_attribute)
Note
If your data is in Geodatabase, you can use DISTINCT
operator in a sql_clause
that you can pass to the SearchCursor (see help).
Hint
Updating rows
If you need to update rows using similar iteration approach, it is possible to do with UpdateCursor()
-function
(see help).
Selecting data¶
Now that we have a list of unique species values we can iterate over that list and select all rows that correspond to a selected species and then rasterize those rows (polygons).
Before we can do selections in arcpy, we need to “prepare” the selection by creating a temporary feature layer (enables to make selections) using MakeFeatureLayer_management()
-function
(see help):
#--------------------------------------------------------------------------------------------------------------------------------
# 5. Create a feature layer from the shapefile with 'MakeFeatureLayer_management' method that enables us to select specific rows
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/make-feature-layer.htm
#--------------------------------------------------------------------------------------------------------------------------------
species_lyr = arcpy.MakeFeatureLayer_management(in_features=input_species_shp, out_layer="species_lyr")
Now the feature layer “lives” temporarily in the variable species_lyr
that we use for making the selections.
Next, we can start iterating over those unique species that are stored in unique_species
-list and select rows with SelectLayerByAttribute_management()
-function (see help)
based on the species name (in a similar manner that you would do with SelectByAttributes
-query
in ArcGIS, and save those selections into separate Shapefiles using CopyFeatures_management()
-function (see help).
#---------------------------------------------------
# 6. Iterate over unique_species list and:
# 6.1) export individual species as Shapefiles and
# 6.2) convert those shapefiles into Raster Datasets
#---------------------------------------------------
for individual in unique_species:
# 6.1):
# Create an expression for selection using Python String manipulation
expression = "%s = '%s'" % (species_attribute, individual)
# Select rows based on individual breed using 'SelectLayerByAttribute_management' method
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/select-layer-by-attribute.htm
arcpy.SelectLayerByAttribute_management(species_lyr, "NEW_SELECTION", where_clause=expression)
# Create an output path for Shapefile
shape_name = individual + ".shp"
individual_shp = os.path.join(output_folder, shape_name)
# Export the selection as a Shapefile into the output folder using 'CopyFeatures_management' method
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/copy-features.htm
arcpy.CopyFeatures_management(in_features=species_lyr, out_feature_class=individual_shp)
Convert Polygons to raster¶
Now we are saving the species into separate Shapefiles which we can convert to rasters using PolygonToRaster_conversion()
-function (see help).
Let’s also send information to the user about the process with AddMessage()
-function (see help). Let’s add the following lines in the same loop that we started previously:
# 6.2):
# Create an output path for the Raster Dataset (*.tif)
tif_name = individual + ".tif"
individual_tif = os.path.join(output_folder, tif_name)
# Convert the newly created Shapefile into a Raster Dataset using 'PolygonToRaster_conversion' method
# Method info: http://desktop.arcgis.com/en/arcmap/latest/tools/conversion-toolbox/polygon-to-raster.htm
arcpy.PolygonToRaster_conversion(in_features=individual_shp, value_field=attribute_name, out_rasterdataset=individual_tif)
# Print progress info for the user
info = "Processed: " + individual
arcpy.AddMessage(info)
The full script¶
Here is the full script that we prepared previously:
# Import arcpy module so we can use ArcGIS geoprocessing tools
import arcpy
import sys, os
input_species_shp = arcpy.GetParameterAsText(0)
output_folder = arcpy.GetParameterAsText(1)
species_attribute = arcpy.GetParameterAsText(2)
attribute_name = arcpy.GetParameterAsText(3)
presence_value = arcpy.GetParameterAsText(4)
# 2. Add a new field into the table using 'AddField_management' method
arcpy.AddField_management(in_table=input_species_shp, field_name=attribute_name, field_type="SHORT")
# 3. Update the presence value for our newly created attribute with 'CalculateField_management' method
arcpy.CalculateField_management(in_table=input_species_shp, field=attribute_name, expression=presence_value)
# 4. Get a list of unique species in the table using 'SearchCursor' method
# 4.1 CREATE a function that returns unique values of a 'field' within the 'table'
def unique_values(table, field):
# Create a cursor object for reading the table
cursor = arcpy.da.SearchCursor(table, [field]) # A cursor iterates over rows in table
# Create an empty list for unique values
unique_values = []
# Iterate over rows and append value into the list if it does not exist already
for row in cursor:
if not row[0] in unique_values: # Append only if value does not exist
unique_values.append(row[0])
return sorted(unique_values) # Return a sorted list of unique values
# 4.2 USE the function to get a list of unique values
unique_species = unique_values(table=input_species_shp, field=species_attribute)
# 5. Create a feature layer from the shapefile with 'MakeFeatureLayer_management' method that enables us to select specific rows
species_lyr = arcpy.MakeFeatureLayer_management(in_features=input_species_shp, out_layer="species_lyr")
# 6. Iterate over unique_species list and:
# 6.1) export individual species as Shapefiles and
# 6.2) convert those shapefiles into Raster Datasets
for individual in unique_species:
# 6.1):
# Create an expression for selection using Python String manipulation
expression = "%s = '%s'" % (species_attribute, individual)
# Select rows based on individual breed using 'SelectLayerByAttribute_management' method
arcpy.SelectLayerByAttribute_management(species_lyr, "NEW_SELECTION", where_clause=expression)
# Create an output path for Shapefile
shape_name = individual + ".shp"
individual_shp = os.path.join(output_folder, shape_name)
# Export the selection as a Shapefile into the output folder using 'CopyFeatures_management' method
arcpy.CopyFeatures_management(in_features=species_lyr, out_feature_class=individual_shp)
# 6.2):
# Create an output path for the Raster Dataset (*.tif)
tif_name = individual + ".tif"
individual_tif = os.path.join(output_folder, tif_name)
# Convert the newly created Shapefile into a Raster Dataset using 'PolygonToRaster_conversion' method
arcpy.PolygonToRaster_conversion(in_features=individual_shp, value_field=attribute_name, out_rasterdataset=individual_tif)
# Print progress info for the user
info = "Processed: " + individual
arcpy.AddMessage(info)
# 7. Print that the process was finished successfully
info = "Process was a great success! Wuhuu!"
arcpy.AddMessage(info)