Programming ArcGIS Pro With Python (2nd Edition) by Pimpler, Eric - Opt
Programming ArcGIS Pro With Python (2nd Edition) by Pimpler, Eric - Opt
Commenting code
Python scripts should follow a common structure. It is a commonly
accepted practice that the beginning of each script should serve as
documentation, detailing the script name, author, and a general
description of the processing provided by the script. This introductory
documentation will help you and other programmers in the future to
quickly scan the details and purpose of a script. This documentation is
accomplished in Python through the use of comments. Comments are
lines of code that you add to your script that serve as documentation
of what functionality the script provides. These lines of code begin
with a single pound sign (#) or a double pound sign (##), and are
followed by whatever text you need to document the code. The
Python interpreter does not execute these lines of code. They are
simply used to document your code. You should also strive to include
comments throughout your script to describe important sections of
your script. This will be useful to you (or another programmer) when
the time comes to update your scripts. In the code example below, the
commented lines of code are displayed with a single pound sign that
prefixes the line of code.
# This script programmatically adds layers to an ArcGIS
Project
# Author: Eric Pimpler
# Last Editied: 10/01/2017
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.name == “Zoning”:
m.removeLayer(lyr)
#lyr = map.LayerFile(r”C:\Student\Zoning.lyrx”)
#m.addLayer(lyr)
#m.addBasemap(“Imagery”)
#m.addDataFromPath(r”C:\Student\
Trippville_GIS.gdb\Floodplains”)
except Exception as e:
print(“Error: “ + e.args[0])
Importing modules
Although Python includes many built-in functions, you will
frequently need to access specific bundles of functionality, which are
stored in external modules. For instance, the Math module stores
specific functions related to processing numeric values and the os
module provides functionality for working with files and folders at
the operating system level. Modules are imported through the use of
an import statement. When writing geoprocessing scripts with ArcGIS,
you will always need to import the arcpy module, which is the Python
package that is used to access GIS tools and functions provided by
ArcGIS. The import statements will be the first lines of code (not
including comments) in your scripts. The following lines of code
import the arcpy and os modules. The Python os module provides a
way of interfacing with the underlying operating system:
import arcpy
import os
ArcGIS Notebooks
ArcGIS Notebooks, built on top of Jupyter Notebooks, is an open-
source application for creating and sharing documents that contain
live Python code, data visualizations, perform analysis, and add
narrative text. Notebooks are an excellent way of presenting a story
about your data. They are built directly into ArcGIS Pro.
How to do it…
New ArcGIS Notebooks can be created by going to the Analysis tab
and then selecting Python | Python Notebook. That will display the
ArcGIS Notebook in a new view window where you can then begin to
add code. You can also create a new notebook by going to the Insert
tab and selecting New Notebook. After a notebook has been created
you can begin writing code in the cells.
2. From the Insert tab select New Notebook (or you can select the
Analysis tab and then Python | Python Notebook. This will open
a notebook called New Notebook as seen below.
The Notebook tab is active anytime a Notebook is an active
view. It contains a small set of buttons for creating and saving
notebook as well as interrupting the execution of a kernel. A
kernel is a currently executing programming environment.
Type in the code “Markdown cells can act like comments” and
click SHIFT + ENTER.
7. Finally, use the print() function to print a value to the screen.
Click SHIFT + ENTER to execute the code. This will be the last
time that I prompt you to click SHIFT + ENTER. From now on
in this chapter it will be assumed that this is how you execute
the code in a cell.
Notice that the output has been displayed directly in the
Notebook. You get immediate feedback from each cell that you
execute.
In conclusion…
ArcGIS Pro Notebooks can be used to write and execute Python code
and are one of many potential environments you can use. One big
advantage of using ArcGIS Pro Notebooks is that they provide
seamless integration with ArcGIS Pro along with instant feedback
from commands. We’ll continue to use Notebooks as we move
through the exercises in this chapter.
featureClassParcel
fieldPopulation
field2
ssn
my_name
We will discuss each of these data types in greater detail in the coming
sections.
In other languages like C#, you would need to define a variable’s
name and type before using it. This is not necessary in Python. To use
a variable, simply give it a name and value, and you can begin using it
right away. Python does the work behind the scenes to figure out
what type of data is being held in the variable.
In the following C# code example, we’ve created a new variable called
aTouchdown, which is defined as an integer variable, meaning that it
can contain only integer data. We then assign the 6 value to the
variable:
int aTouchdown;
aTouchdown = 6;
In Python, this variable can be created and assigned data through
dynamic typing. The Python interpreter is tasked with dynamically
figuring out what type of data is assigned to the variable:
aTouchdown = 6
There may be times when you know that your script will need a
variable, but don’t necessarily know ahead of time what data will be
assigned to the variable. In these cases, you could simply define a
variable without assigning data to it. Here, you will find a code
example that depicts creating a variable without assigning data:
aVariable = ‘’
aVariable = None
Data that is assigned to the variable can also be changed while the
script is running.
How to do it…
In this exercise you’ll learn how to create variables and assign data.
In conclusion…
In this exercise you learned how to create variables and assign data.
You also learned about variable naming, case sensitivity of variables,
and how to compare variables. Finally, you learned about some of the
different types of primitive data that can be assigned to variables. In
the next exercise you’ll learn how to manipulate string variables.
How to do it…
First, you’ll learn how to test the type of data stored in a variable. This
is often a necessary step before you attempt to use a variable in other
functions since the parameters of function require specific data types.
3. Now add a variable called age and assign it the value of 21 and
check the type just as you did in the last step.
4. Add the code blocks below to see how you can use a decision
support statement to branch your code based on the variable
type. Here you are testing a variable type and then branching
your code if it is of a specific type.
11. The + operator, when used with two string variables, is used to
concatenate two separate string values. Add the code you see
below to a new cell and run it to see how this works. It will
print out the text Floodplains, which is the concatenation of
Flood and plains.
14. The next method we’ll cover is the split() function against a
comma delimited string to separate the values into separate
columns of information. Add and run the code you see below to
see the split() function in action. The split() function, when
passed a comma, will split a comma delimited text string into a
list. (listInfo in this case). We can then use list indexing to pull
out the individual columns of information. List indexing will be
covered extensively in a later exercise, but list indexing works
in a similar manner to string indexing where an index number
corresponds to each item in the list.
In conclusion…
Python provides a wide variety of functions for manipulating strings.
We’ve only scratched the surface of ways that you can manipulate
strings, but hopefully you’ve now learned some basic techniques.
Exercise 4: String Formatting
Getting ready
String formatting enables you to create a dynamic string using string
substitution. For example, it is common to pull data from data sources
like files or databases. Each row in the file or database table can have
variable data for each column. However, some parts of the string that
you are constructing may be static.
For the parts of the string that are variable you are going to want to
insert the dynamic or variable part of the data. The illustration below
provides an example. Here we are constructing a string that describes
a variable size pipe and how it should be placed relative to another
pipe structure.
We can divide this statement into two sections. The section on the left
side up to the % sign highlighted in blue is the dynamic string that
will be created. It contains a combination of static and dynamic text.
The placeholder locations for dynamic text are indicated with a % sign
followed by a letter such as f or s. These indicate the data type. For
example, a %i indicates that an integer will be placed into this
location, and a %s indicates that a string will be placed in this location.
The right side of the equation after the % sign highlighted in blue is
the data that will be placed into the placeholder locations on the left-
hand side. The values will be placed into the placeholder locations
based on the order provided. For example, the number 6 will be
inserted into the first placeholder at %i and the term main will be
inserted into the second placeholder at the %s location. You can have
as many insertion points as are needed for the constructions of the
string.
How to do it…
1. To see an example of how this works, enter the following code
into a new cell in your notebook and execute the block. The
listInfo variable being used was created in the exercise above
and contain sample customer information.
customerFormatted = “Customer first name is %s and last name is
%s. Age is %i and weight %f. Hair color is %s” % (listInfo[0],
listInfo[1], int(listInfo[2]), float(listInfo[3]), listInfo[4])
2. When run, this should produce the following string:
Customer first name is John and last name is Doe. Age is 21 and
weight 185.400000. Hair color is Brown
In conclusion…
String formatting is a great way to add dynamic content into a text
string.
How to do it…
1. In your ArcGIS Notebook, create a new cell if necessary.
2. While you can certainly create a list object by hard coding the
content, it is also common to call a function that creates a list for
you. In this first section you’ll call the split() function against a
comma delimited string. The split() function creates a list object
with each item stored as a separate value. In the first cell of
your jupyter notebook add the following code and execute to
see the results.
Notice the structure of the list that was created. Each item in the
list is separated by a comma and enclosed with square braces.
3. Get the number of items in the list by calling the len() function
and executing the command.
len(listInfo)
4. You can pull items out of a list using list indexing or list slicing.
They work in the same manner as string indeding and slicing.
Lists are ordered with each item in the list occupying a specifc
index number. The first item in the list occupies position 0. In a
new cell add and execute the following code to pull out the item
located as position 1.
listInfo[1]
5. Now use list slicing to pull out the first two items.
listInfo[0:2]
6. You can also change the contents of a list by referencing the
item number you want to change and then setting it equal to a
new value.
listInfo[0] = “Jane”
7. Now we’ll create a new list containing a variety of names. Add
the following code.
listOfNames = [‘John’, ‘Eric’, ‘Julie’, ‘Elizabeth’, ‘Jackson’,
‘Betty’, ‘June’]
8. Let’s sort this list alphabetically by calling the sort() function.
listOfNames.sort()
9. Now take a look at the contents of the list after it has been
sorted.
10. Next, we’ll add a new item to the list. Add and execute the code
below.
listOfNames.append(“Henry”)
11. Now, remove an item from the list.
listOfNames.remove(“John”)
12. In the next section you’ll learn how to use list comprehension.
List comprehension provides an efficient way of creating a list.
It is efficient both from a coding standpoint as well as an
execution performance perspective. Not only does it require
less code to write, but it also executes much faster. Add and
execute the following code block.
L = [1, 2, 3, 4, 5]
Y = [x + 10 for x in L]
13. The output should appear as seen below. The second line of the
block is the statement that uses list comprehension to create a
new list. This statement y = [x + 10 for x in L] can be divided into
two sections. The for x in L statement loops through each item in
L (1,2,3,4,5) and add it to 10 with the statement x + 10.
14. The same thing could have been accomplished with the code
you see below, but list comprehension is much more efficient in
creating the list.
L = [1, 2, 3, 4, 5]
for x in L:
L[x] += 10
In conclusion…
Lists are one of the most commonly used data types in Python for good
reason. Programming often requires that we store multiple values with the
intent of being able to access that data at some point. Lists provide a perfect
solution for this and are versatile enough to be altered in various ways.
Getting ready
Dictionaries, like lists, are a container style object. However, the
structure of a dictionary is quite different than a list. Lists are an
ordered collection of values, meaning that the individual items within
a list can be accessed by referencing an index number associated with
the value to be accessed. Dictionaries on the other hand are
unordered, and the data is accessed through a combination of key-
value pairs. In some ways, dictionaries are like simple tables of
information that contains columns (keys) and rows (values).
How to do it…
1. In your ArcGIS Notebook, create a new cell if necessary.
2. In Python, a dictionary is created inside a set of curly braces as
a set of key/value pairs divided by commas. You can see this
illustrated in the figure below.
10. Key/value pairs can be deleted from a dictionary using the del
statement.
del dict[‘Age’]
11. The keys() method can be used to retrieve a list of keys
associated with a dictionary. This list of keys can then be used
to retrieve each of the values associated with the keys.
16. Now let’s get the list of trees associated with each state.
17. Finally, get the first tree in the list for each state.
In conclusion…
Python dictionaries are an ideal data structure for storing information
that takes the form key-value. These dynamic structures are capable of
being updated, as well as updated and deleted.
How to do it…
1. In this exercise we’re going to work with the File object that is
built into the standard Python library. The open() function can
be used to create a File object. This function takes a path and file
name to be opened along with a mode that indicates how the
file should be opened. We’ll open our file in read-only mode. In
a new cell in your ArcGIS Notebook, add the code you see
below and then we’ll discuss.
f = open(r’C:\Student\ProgrammingPro\Chapter1\tips.csv’, ‘r’)
Two parameters have been passed into the open() function. The
first is the path and file name to be opened, and the second is
the file mode. The lowercase ‘r’ indicates that the file should be
opened in read-only mode. The contents of the tips.csv file have
been stored in the variable called f. This variable is an object
that represents the tips.csv file.
2. The properties of an object give access to the information
associated with the object. For example, the File object includes
properties for the file mode, a Boolean indicator for whether the
file is open or closed, and the name of the file. Add the code
you see below to see how properties of an object are accessed.
Properties and methods are both accessed through dot notation.
Dot notation syntax includes the object followed by a dot and
then the property or method you are accessing.
3. Methods are the actions that an object can perform. For
example, the File object includes a number of methods related
to how the contents of a file are read along with the ability to
close a file and some other supporting functions. Add the code
you see below to read the contents of a file into a Python list
object. Each line of the file will be a new item that is added to
the list.
print(f.readlines())
Getting ready
In Python the if | elif | else statement serves as the decision support
statement. It allows you to branch your code based on expressions
that return a True or False value. The basic structure of the if | elif | else
statement appears as seen below. The structure of these statements is
highly versatile in that it can be constructed in different ways
depending upon what you’re trying to accomplish. In some cases, you
may only need the if statement. For other cases you may need
multiple elif statements. This decision support structure is versatile
enough to accommodate whatever structure is needed for your
processing.
if expression1:
statement(s)
elif expression2:
statement(s)
elif expression3:
statement(s)
else:
statement(s)
How to do it…
1. In a new cell in ArcGIS Notebook, add the code you see below
to create and test a simple if | else block. This is a very simple
example that doesn’t require any elif statements. It includes
only the if and else portions of the block. The expression
associated with the if statement is a statement that must
evaluate to True or False, and the code will then branch
depending upon the result.
In conclusion…
In this exercise you learned how to use decision support statements to
branch your code based on boolean expressions.
Getting ready
In this exercise you’ll learn how to create a for loop that iterates the
items in a list as well as how to create a while loop.
How to do it…
1. In a new cell in your ArcGIS Notebook create a list that contains
common rangeland grasses of Wyoming as seen below. Notice
that each grass has a first name and a last name. In this exercise
we’ll pull out second part of the time and print it.
grassesWY = [“Blue grama”, “Sandberg bluegrass”, “Foxtail
barley”, “Prairie junegrass”, “Idaho fescue”, “Basin wildrye”,
“Bluebunch wheatgrass”]
2. Click enter to stay in the same cell but start a new line. Create a
for loop that will loop through each of the values in the
grassesWY variable, which contains a list. In this case, grass is a
dynamic variable that will be assigned each of the values in the
grassesWY variable iteratively. Inside the for loop is a print
statement that will split the grass names into two words, and
grabs the second using index number 1.
for grass in grassesWY:
print(grass.split()[1])
3. The entire code block should appear as follows:
4. Click shift & enter to execute the code. This should print out the
generic names of each grass including:
grama
bluegrass
barley
junegrass
Fescue
fildrye
wheatgrass
5. Next, you’ll learn how while loops work. If necessary, create a
new grid cell.
6. Enter the code block you see below to create a while loop that
will basically serve as a very simple password protection
function. It will prompt the user to enter the password, and as
long as the password is NOT ‘password’ it will continue to
prompt the user to input a password. If the user enters a
password of ‘password’ then it will allow the end user to enter.
password = ‘’
while password != ‘password’:
print(“What is the password?”)
password = input()
print(‘Yes, the password is ‘ + password + ‘.
You may enter.’)
7. Click SHIFT + ENTER to execute the code block and you will be
prompted to enter a value. Enter something other than the
word ‘password’ and click shift & enter. Enter another value that
is not the word ‘password’ and click shift & enter. Finally, enter
the word ‘password’ and click shift & enter. You can see my
results below.
In conclusion…
In this exercise you learned how to use the for and while looping
statements to loop through blocks of code. The for loop is particularly
useful for iterating through each item in a list.
Getting Ready
Python includes many built-in functions that you can use to perform
various tasks. Many of the functions work with numeric data
including sum(), max(), min() , round(), and others. Others, like all() and
any() return Boolean values if all or any of the values provided in an
iterable (list, tuple, etc) are true. Others are used to convert data to
other data types. In this exercise you’ll learn how to use some of these
built in Python functions.
How to do it…
1. In a new cell in ArcGIS Notebook, add the code you see below
to create and test a simple if | else block. This is a very simple
example that doesn’t require any elif statements. It includes
only the if and else portions of the block. The expression
associated with the if statement is a statement that must
evaluate to True or False, and the code will then branch
depending upon the result.
2. In a new cell in your ArcGIS Notebook, add the code you see
below to create a list of the 10 tallest mountains in Colorado.
This list is not sorted, but we’ll do so later.
coloradoMtnElevs = [14421, 14428, 14440, 14343, 14300, 14321,
14293, 14279, 14278, 14351]
3. Many of the built-in functions are designed to work with
numeric data. Enter the following lines of code to see how the
max(), min(), and sum() functions work.
if mountain in coordinates:
mtsCoord = coordinates[mountain]
return(mtsCoord)
else:
return(“Mountain not found”)
8. Click SHIFT + ENTER to execute the creation of the function.
9. Call the function and pass in the name Blanca Peak and execute
the code.
print(getMountainCoords(“Blanca Peak”))
10. This should return the following latitude, longitude coordinate
pair.
37.577, 105.485
11. Call the getMoutnainCoords() function again, this time passing in
Mount Lincoln as the mountain name.
12. Call the function again a third time, this time passing in a
mountain name that is not listed as a key in the dictionary. The
message Mountain not found should be returned.
In conclusion…
In this exercise you learned how to call functions. Functions serve as
named blocks of code that are used to accomplish some sort of task.
Getting Ready
The try statement in Python is used to denote a block of code that
handles exception conditions. There are two basic types of try
statements; try | except | else and try | finally. We’ll take a look at both of
these types in more detail. The basic syntax of a try| except block is
illustrated below. The bulk of your processing code will go inside the
try block. If there are not any error conditions, then the code will be
confined to this try block. However, if an error condition occurs,
processing stops, an Exception object is generated, and the object is
passed to the Exception handlers for processing.
try:
<statements>
except <name>:
<statements>
except <name>:
<statements>
else:
<statements>
This first exercise will have you open a file for reading and will
include an exception handler for a file that can’t be found. It’s a very
simple example but will introduce you to the basic structure of a try |
except block.
This would be helpful for situations where an incorrect path or
filename is passed into the Python open() function. A list of built-in
Python exceptions can be found at:
https://docs.python.org/3/library/exceptions.html
How to do it…
1. In a new cell in your ArcGIS Pro Notebook, add the code you
see below and execute it.
try:
f = open(r’C:\Student\ProgrammingPro\Chapter1\tips2.
csv’, ‘r’)
print(f.readlines())
except FileNotFoundError:
print(“File not found”)
2. The tips2.csv file does not exist so when this code is executed it
should return a message that indicates File not found. The script
generated a FileNotFoundError object when it couldn’t open the
file from the path and filename that were passed into the open()
function.
3. Now change the file name from tips2.csv to tips.csv and execute
the cell again to see the result. This time it should read the file
and print out the results.
4. In this next step you’ll add a finally block to the existing code. A
finally block is always placed at the end of the try | except
handling block and is guaranteed to execute regardless of
whether an error condition occurs in the code. Finally blocks are
used for cleanup operations such as closing files and database
connections, deleting temporary files, and any other cleanup
that needs to occur regardless of what happens elsewhere in the
script. In a new cell enter the following code:
try:
f = open(r’C:\Student\ProgrammingPro\Chapter1\tips.\
csv’, ‘r’)
print(f.readlines())
except FileNotFoundError:
print(“File not found”)
finally:
print(“Closing the file”)
f.close()
5. Execute the code to see the result. This will print the contents of
the file and then at the very end you should see a message that
indicates the file is going to be closed.
6. Update the file name from tips.csv to tips2.csv to introduce the
error again.
try:
f = open(r’C:\Student\ProgrammingPro\Chapter1\tips2.
csv’, ‘r’)
print(f.readlines())
except FileNotFoundError:
print(“File not found”)
finally:
print(“Closing the file”)
f.close()
7. Run the script again and now you should see two messages.
Even though an error occurred, the code in the finally block that
closes the file is still executed at the very end.
File not found
Closing the file
8. You can also add multiple exception handlers designed to deal
with multiple potential errors in your code. In this section you’ll
learn how to do this.
9. In a new cell, add the code that you see below.
try:
x = float(input(“Your number: “))
inverse = 1.0 / x
except ValueError:
print(“You should have given either an int or a float”)
except ZeroDivisionError:
print(“Infinity”)
finally:
print(“There may or may not have been an exception”)
10. Execute the code and enter a letter as a value. For example, I
entered a value of A. This should return the following
messages:
Your number: A
You should have given either an int or a float
There may or may not have been an exception
This particular situation triggered the ValueError exception.
11. Run the code block again, but this time enter a value of 0. This
should return the following messages:
Your number: 0
Infinity
There may or may not have been an exception
This value triggered the ZeroDivisionError exception.
12. Run the code block one last time and this time enter a numeric
value greater than 0. In this case I entered the value 10.
Your number: 10
There may or may not have been an exception
In conclusion…
Error handling is an important structure that should be added to all
Python scripts. By intercepting errors as they occur, Python scripts can
effectively handle error conditions that could occur in your code.
Getting Ready
In Python the open() function accepts a path to the file that you’d like
to open along with a mode in which the file will be opened. The most
commonly used modes are read, write, and append. This function
creates a new File object which can then be iterated to extract or write
information. In this exercise you’ll learn how to open a file and
various ways for reading the content from a file.
How to do it…
1. In a new cell in your ArcGIS Pro Notebook, add the code you
see below and execute it. This is the same code block that we
used in the previous exercise on error handling. This code
simply opens a file and reads the contents of the file using the
readlines() function. The readlines() function reads the entire
contents into a Python list object with each line as a separate
value in the list.
try:
f = open(r’C:\GeospatialTraining\IntroPython\Data\tips.
csv’, ‘r’)
print(f.readlines())
except FileNotFoundError:
print(“File not found”)
finally:
print(“Closing the file”)
f.close()
2. Now let’s look at a better way of opening and reading a file. In
a new cell of your notebook, update your code as seen below.
The with statement is used in this case to open a file and store it
in a new variable called f. That looks similar to how we opened
the file before, but the big advantage of opening a file using a
with statement is that the file will automatically be closed when
you’re done. You no longer need to use the close() method
when you’re done reading the file. When you execute this code
block it will read the file in exactly the same way as before.
try:
with open(r’C:\Student\ProgrammingPro\Chapter1\tips.
csv’, ‘r’) as f:
print(f.readlines())
except FileNotFoundError:
print(“File not found”)
3. The File object has a number of properties that you can access
for returning the name, mode, and whether the file is open or
closed. Add and execute the code that you see below to see how
these work on the tips.csv file that you have opened.
try:
with open(r’C:\Student\ProgrammingPro\Chapter1\tips.
csv’, ‘r’) as f:
print(“Name of the file: “, f.name)
print(“Closed or not : “, f.closed)
print(“Opening mode : “, f.mode)
except FileNotFoundError:
print(“File not found”)
Name of the file: C:\GeospatialTraining\IntroPython\Data\tips.csv
Closed or not : False
Opening mode : r
4. A for loop can be used to read the contents of a text file one line
at a time. Update and run your code block as seen below to see
how this works.
try:
with open(r’C:\Student\ProgrammngPro\Chapter1\tips.
csv’, ‘r’) as f:
for line in f:
print(line)
except FileNotFoundError:
print(“File not found”)
5. You have probably noticed that this is a comma delimited text
file, which is a very common format. You can split the values in
a comma delimited text file into separate ‘columns’ of data
using the split() function. Update and run your code as seen
below to see how this works. The split() function in this case will
split the values into separate columns using a comma as the
divider.
try:
with open(r’C:\Student\ProgrammingPro\Chapter1\tips.
csv’, ‘r’) as f:
for line in f:
values = line.split(“,”)
totalbill = values[0]
tip = values[1]
smoker = values[2]
day = values[3]
time = values[4]
size = values[5]
print(“Total bill %s with a tip of %s. The day
was %s and the time was %s. Part size was %s”
% (totalbill, tip, day, time, size))
except FileNotFoundError:
print(“File not found”)
6. You may have noticed that the first line of the file is the header
that defines the columns of the data. You can add a line of code
that will skip the header. The highlighted line below illustrates
how this is done.
try:
with open(r’C:\Student\ProgrammingPro\Chapter1\tips.
csv’, ‘r’) as f:
next(f)
for line in f:
values = line.split(“,”)
totalbill = values[0]
tip = values[1]
smoker = values[2]
day = values[3]
time = values[4]
size = values[5]
except FileNotFoundError:
print(“File not found”)
7. CSV files are one of the most common import and exports
formats for spreadsheets and databases. Think about Microsoft
Excel and it’s ubiquitous .csv files. However, not all
applications create csv files the same. There can be slight
differences which can cause some big problems if you’re
dealing with csv files that are exported from multiple
applications. Previously in this exercise you learned how to
process delimited text files using the split() function. At some
point if you are using files from multiple applications this split()
function will fail. The Python csv module was designed to
handle these differences and make your csv processing much
easier! The csv module contains both Reader and Writer objects.
In a new row of your notebook add and execute the code below.
import csv
f = open(r’C:\Student\ProgrammingPro\Chapter1\tips.csv’, ‘r’)
try:
reader = csv.reader(f)
for row in reader:
print(row)
except FileNotFoundError:
print(“File not found”)
finally:
f.close()
8. Just as is the case with reading files, there are a number of
methods that you can use to write data to a file. The write()
function is probably the easiest to use and takes a single string
argument and writes it to a file. The writelines() function can be
used to write out the contents of a list structure to a file. In this
exercise you’ll learn some methods for writing information to a
file.
In this exercise we’re going to build on the code we introduced
in the first exercise in this chapter that used the split() function
to read data from a comma delimited text file. Add the code
you see below and then we’ll build on that in the next step. You
can copy and paste from a prior cell to a new cell.
try:
with open(r’C:\Student\ProgrammingPro\Chapter1\tips.
csv’, ‘r’) as f:
next(f)
for line in f:
values = line.split(“,”)
totalbill = values[0]
tip = values[1]
smoker = values[2]
day = values[3]
time = values[4]
size = values[5]
except FileNotFoundError:
print(“File not found”)
9. Now, add the highlighted lines of code you see below. The first
highlighted line of code creates a new file in write mode and the
second writes information to the file. Because we have defined
the new file using a with block it will automatically be closed
when the script completes.
try:
with open(r’C:\GeospatialTraining\IntroPython\Data\tip_
info.txt’, ‘w’) as fw:
with open(r’C:\GeospatialTraining\IntroPython\Data\
tips.csv’, ‘r’) as f:
next(f)
for line in f:
values = line.split(“,”)
totalbill = values[0]
tip = values[1]
smoker = values[2]
day = values[3]
time = values[4]
size = values[5]
fw.write(“Total bill %s with a tip of %s.
The day was %s and the time was %s. Part
size was %s” % (totalbill, tip, day, time,
size))
print(“Total bill %s with a tip of %s.
The day was %s and the time was %s. Part
size was %s” % (totalbill, tip, day, time,
size))
except FileNotFoundError:
print(“File not found”)
In conclusion…
In this exercise you learned how to read and write data from text files.
Text files are an important interchange format in GIS so it's important
to know how to read and write data in this format.
Summary
In this chapter, we covered some of the fundamental Python
programming concepts that you’ll need to understand before you can
write effective geoprocessing scripts. We covered the basic language
constructs, including importing modules, creating and assigning
variables, if/else statements, looping statements, and the various data-
types including strings, numbers, lists, dictionaries, and objects. You
also learned how to read and write text files.
In the next chapter, you will learn the basic techniques used to write
geoprocessing scripts for ArcGIS Pro with Python. You’ll learn how to
install and configure the PyCharm development environment, use the
embedded Python window in ArcGIS Pro, import the arcpy module to
your scripts, use variables to store data, and access the various arcpy
modules.
Introduction to Using
Arcpy in ArcGIS Pro
In this chapter, we will cover the following topics:
Arcpy is a Python library for ArcGIS Pro that enables you to automate
your geoprocessing tasks, perform geographic data analysis, data
conversion, data management, and much more. It also offers code
completion and a rich set of reference documentation. Code
completion is best illustrated by typing a keyword and then a dot and
then a dropdown list of available choices appears, offering a set of
choices from which you can make a selection. This makes you a faster
more accurate programmer.
Arcpy consists of a core library along with several additional modules
including the Mapping (mp), Data Access (da), Network Analyst (na),
and Spatial Analyst (sa) modules illustrated below. These additional
modules can be thought of as extensions to the primary arcpy module.
Introducing conda
Python is the primary language for automating geoprocessing tasks in
ArcGIS Pro and ArcGIS 10.x. It is a highly versatile and extensible
language with many third party libraries that can be used alongside
ArcGIS. This includes statistical, image processing, charting and
graphing, and many others. Organizing and managing all these
libraries can be difficult. ArcGIS Pro uses the conda package manager
to install third party libraries, associate libraries with specific projects,
and in general simplify the process of sharing tools.
You’re probably going to see a number of different, but similar terms
when reading about conda. So before we go any further let’s discuss
some of those terms so that you’ll understand them. Conda, which is
what ArcGIS Pro uses, is an open source package and environment
management system. Conda includes the installation of a number of
default packages.
ArcGIS Pro has it’s own conda environment as you’ll soon see. A
conda environment is a set of Python packages that can be used in one
or multiple projects. Pip, which is similar to conda, is also an open
source package and environment management system. Many Python
developers have used pip for many years, and if so you’ll be glad to
hear that pip can still be used from inside conda. Anaconda is a data
science platform that has several hundred commonly used packages
specifically for data science. It uses conda at the core. Finally,
Miniconda is a minimal version of conda that doesn’t include any
installed packages by default.
There are literally thousands of pre-existing Python packages that can
be used in your scripts alongside arcpy. Managing these packages,
including installation and association with a particular project can be
difficult. Conda serves as a package manager, installs third party
Python libraries, associates libraries with specific projects, and in
general simplifies the process of sharing tools. You’ll become more
familiar with the conda environment as we move through the book.
Python scripts that use arcpy for geoprocessing scripts must be run
from inside the conda environment. The ArcGIS Pro conda
environment is called arcgispro-py3.
ArcGIS Notebooks
In Chapter 1: Fundamentals of the Python Language you learned how to
use the embedded ArcGIS Notebooks to write and document code.
This is another of the many options that you can use to write and test
Python code for ArcGIS Pro.
How to do it…
Follow these steps to learn how to download, install, and configure
PyCharm to work with the ArcGIS Pro conda environment. Please
note that these instructions may change over time with new releases
of ArcGIS Pro and PyCharm. If the version of PyCharm that you are
using differs significantly from the instructions provided below,
please visit our website for updated instructions at
http://geospatialtraining.com/programming-arcgis-pro-with-python-
2nd-edition/
12. You’ll be prompted to select the location for where the new
project will be created. Navigate to the
C:\Student\ProgrammingPro\Scripts folder seen in the screenshot
below. If you loaded the exercise data to a different folder
location (other than c:\Student) please define your path to the
Scripts folder accordingly. Click the Create button to create the
project.
13. Your PyCharm environment should now appear as seen in the
screenshot below.
20. In the Add Python Interpreter dialog box choose the System
Interpreter tab on the left.
21. Click the breadcrumbs (…) to the right of the Interpreter path
box and browse to the following location:
c:\Program files\ArcGIS\Pro\bin\Python\envs\arcgispro-py3
24. Press the OK button on the Settings dialog box. It will take a
few minutes for the new packages to be registered with the
project, but you will soon be able to write your geoprocessing
scripts.
25. After a few minutes you are now ready to create a new script
and start to work with Arcpy.
In conclusion…
In this exercise you learned more about the ArcGIS Pro conda
environment, how to use ArcGIS Pro to view existing Python
packages, update packages, and delete packages. You also learned
how to install and configure PyCharm to use the ArcGIS Pro conda
environment. In the next exercise you’ll learn some fundamentals of
using arcpy.
1. Open PyCharm
2. Your PyCharm environment should appear as seen in the
screenshot below.
13. Click the Enter key on your keyboard to execute the code (you
may need to click Enter twice). The results should be displayed
as seen in the screenshot below. Note that the name of the Map
has been displayed along with all the layers in the Map, which
have been indented.
15. Update the line of code that references the ArcGISProject object
as seen below and re-run the script to see the output.
aprx =
arcpy.mp.ArcGISProject(r’c:\Student\ProgrammingPro\Chapter2\Ex
2A.aprx’)
16. The output should now appear as seen in the screenshot below.
In conclusion…
In this exercise you learned some basic techniques for structuring
your Python scripts, importing the arcpy Python package, generating a
list of information in an ArcGIS Pro project, and executing the script in
various environments. We’ll build on the knowledge you gained in
this basic exercise in the upcoming
How to do it…
1. Open ArcGIS Pro and load the Ex 2A project found in the
c:\Student\ProgrammingPro\Chapter2 folder.
2. Click the Analysis tab.
3. Click the Python button.
In conclusion…
ArcGIS Pro includes an integrated Python Window that you can use
to write geoprocessing scripts using Python and arcpy. This window
includes code completion and color-coding to assist with the
development of your scripts. While not an ideal environment for the
development of larger scripts, this window is a good place to begin
learning about Python and arcpy.
Executing Geoprocessing
Tools from Scripts
In this we’ll cover the following topics:
How to do it…
1. Open ArcGIS Pro with the Ex 2A.aprx file found in the
c:\Student\ProgrammingPro\Chapter2 folder. This project has
already been created for you.
2. You should see a map containing several layers including
Parcels, Creeks and Streams, Lakes and Ponds, City Limits and a
Topographic basemap.
3. Open PyCharm
4. Select File | New | Python File.
5. Name the file ExecutingTools and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts.
6. Import the arcpy module and create the basic error handling
structure.
7. Import the env object from arcpy and set the current workspace.
The env object is used in arcpy to set any of the available
environment variables. The workspace property sets the current
working directory for the script. After setting the current
directory, it becomes the default location for any input or
output from geoprocessing tools.
import arcpy
from arcpy import env
env.workspace =
r”C:\Student\ProgrammingPro\Databases\Trippville_GIS.gdb”
try:
except Exception as e:
print(“Error: “ + e.args[0])
8. In this next step you’re going to use the Buffer tool to buffer the
Lakes and Ponds layer. The output from this tool will be used to
perform an intersect operation against the Parcels layer to
determine which parcels fall within the buffered distance of the
Lakes and Ponds.
If you were to run the Buffer tool from the ArcGIS Pro Toolbox
you’d be presented with a dialog that prompts you to enter the
various parameters. Running the Buffer tool, or any other tool,
from a Python script requires that the parameters be passed as
arguments to a method call for the Buffer tool.
Add the code below to call the Buffer tool, passing in Lakes and
Ponds as the input layer, an output feature layer called
Buffered_Water, and a buffer distance of 250 Feet. The output
from the Buffer tool will be a feature class called Buffered_Water.
We’ll use this output parameter as input to another tool in a
later step.
import arcpy
from arcpy import env
env.workspace =
r”C:\Student\ProgrammingPro\Databases\Trippville_GIS.gdb”
try:
9. The Make Feature Layer tool is used to create a feature layer from
a feature class. A feature layer is a temporary, in-memory copy
of a feature class used specifically for the purposes of creation a
selection set with the Select by Attribute and Select Layer by
Location tools. Unless specifically saved, a feature layer will be
discarded after use.
Call the Make Feature Layer tool passing in the Parcels layer to
create a new feature layer called Parcels_FL.
import arcpy
from arcpy import env
env.workspace =
r”C:\Student\ProgrammingPro\Databases\Trippville_GIS.gdb”
try:
In conclusion…
Any geoprocessing tool found in ArcGIS Pro that you are licensed to
use can be called from your script using a native method call. This
means that rather than having a visual interface for entering the
parameters; you simply pass the parameters as arguments in a
method call. This includes any custom script tools that you have
access to as well. It is also possible to chain together tools using the
output from one tool as input to another tool.
Using Arcpy Mapping to
Manage Projects, Maps,
Layers and Tables
In this we’ll cover the following topics:
The arcpy mapping module brings some really exciting features for
mapping automation including the ability to manage projects and
layer files as well as the data within these files. Support is also
provided for automating the export and printing of maps and layouts,
map production and the creation of map books, finding and fixing
broken data sources, and more. In this chapter you’ll learn how to use
the arcpy mapping module to manage projects, maps, layers, and tables.
The diagram below provides a visual picture of where the mapping
package fits into the hierarchy of the arcpy site package.
How to do it…
Your first task before attempting any operations on an ArcGIS Pro
project is to get a reference to the project you want to work with. This
can be done using either the CURRENT keyword or a path passed into
the constructor for the ArcGISProject object. After creating a reference
to an ArcGISProject object you can then retrieve various properties and
call methods.
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file ArcGISProjectProperties and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. In the new script window import the arcpy mapping module as
seen in the code below. This will import the mapping module
and store it in a variable called map. Storing it in a variable will
cut down on the amount of code you have to write when
referring to classes and functions in this module.
import arcpy.mp as map
5. Add the try/except block as seen below.
import arcpy.mp as map
try:
except Exception as e:
print(“Error: “ + e.args[0])
6. Call the ArcGISProject function and pass in the path to the Ex
2A.aprx file as seen in the code below.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
except Exception as e:
print(“Error: “ + e.args[0])
7. Return the default geodatabase, toolbox, and home folder and
then print them out with the lines of code below.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
geo = aprx.defaultGeodatabase
tool = aprx.defaultToolbox
home = aprx.homeFolder
print(“Default geodatabase: %s \n Default toolbox: %s
\n Home Folder: %s” % (geo, tool, home))
except Exception as e:
print(“Error: “ + e.args[0])
8. Return the document version and the last date the project was
saved.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
geo = aprx.defaultGeodatabase
tool = aprx.defaultToolbox
home = aprx.homeFolder
version = aprx.documentVersion
dtSaved = aprx.dateSaved
print(“Default geodatabase: %s \n Default toolbox: %s
\n Home Folder: %s” % (geo, tool, home))
print(“ArcGIS Pro Document version: %s \n Last Date
Saved: %s” % (version, dtSaved))
except Exception as e:
print(“Error: “ + e.args[0])
9. You can check your work against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\
ArcGISProjectProperties.py.
10. Run the script. If everything has been written correctly you
should see the output seen below.
Default geodatabase:
C:\Student\ProgrammingPro\Chapter2\IntroArcGISPro Exercise
2A.gdb
Default toolbox:
C:\Student\ProgrammingPro\Chapter2\IntroArcGISPro Exercise
2A.tbx
Home Folder: C:\Student\ProgrammingPro\Chapter2
ArcGIS Pro Document version: 2.0.0
Last Date Saved: 2017-07-21 18:50:52.000505
In conclusion…
The ArcGISProject object is the focal point of working with the arcpy
mapping module. It provides an entry point for your scripts and can be
used to retrieve properties of a project and to call methods.
How to do it…
1. In PyCharm select File | New | Python File.
2. Name the file RetrievingArcGISProjectLists and click OK.
3. In the script window import the arcpy mapping package.
import arcpy.mp as map
4. Add the try/except block as seen below.
import arcpy.mp as map
try:
except Exception as e:
print(“Error: “ + e.args[0])
5. Call the ArcGISProject function and pass in the path to the Ex
2A.aprx file as seen in the code below.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Get a list of Map objects in the project and loop over each of
them using a for loop. Inside the loop, print the name of the
map, get a list of all the layers in the map, and print out the
names of the layers.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps():
print(“Map: “ + m.name)
for lyr in m.listLayers():
print(“ “ + lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
7. There aren’t any layouts in this particular project, but the
concept is the same. Instead of calling listMaps() you’d simply
call listLayouts().
8. Run the script. If everything has been written correctly you
should see the output seen below. You can check your work
against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\RetrievingArcGISProjectLists.py
Map: Map
Creeks and Streams
Lakes and Ponds
City Limits
Parcels
Topographic
9. With both the listMaps() and listLayouts() methods you can also
pass a wildcard as a parameter to limit the Map or Layout objects
that are returned. The wildcard is based on the name and is not
case sensitive. A combination of asterisks and characters can be
used to help limit the resulting list. In the next few steps you’ll
see how this is done. If necessary, open the Ex 2A.aprx file in
ArcGIS Pro.
10. In the Project Pane right click Maps and select New Map. This
will create a map called Map1. Right click on Map1 in the
Project Pane and select rename. Call it Streets and Railroads.
11. In the Project Pane select the arrow next to Databases. Open the
IntroArcGISPro Exercise 2A.gdb entry and add the RR_Tracks
and Street_Centerlines layers to the map. Your ArcGIS Pro
project should appear similar to the screenshot below.
In conclusion…
A list of maps and layouts can be generated from the ArcGISProject
object. You can also use wildcards to limit the list that is returned.
How to do it…
1. In PyCharm select File | New | Python File.
2. Name the file SavingArcGISProProject and click OK.
3. In the script window import the arcpy mapping package.
import arcpy.mp as map
4. Add the try/except block as seen below.
import arcpy.mp as map
try:
except Exception as e:
print(“Error: “ + e.args[0])
5. Call the ArcGISProject function and pass in the path to the Ex
2A.aprx file as seen in the code below.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”C:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Call the ArcGISProject.saveACopy() method to save a copy of the
.aprx file and write a message indicating the completion of the
script.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
aprx.saveACopy(r”c:\Student\ProgrammingPro\Chapter2\Ex
2A Copy.aprx”)
print(“Finished saving a copy of the file”)
except Exception as e:
print(“Error: “ + e.args[0])
7. Run the script. If everything has been written correctly you
should see a message indicating the completion of the script.
Open File Explorer in Windows and check the Chapter 2 folder
to see the new file that was created.
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\
SavingArcGISProProject.py.
In conclusion…
You can programmatically save an ArcGIS Project file by calling either
the ArcGISProject.save() or ArcGISProject.saveACopy() method.
How to do it…
1. In PyCharm select File | New | Python File.
2. Name the file ImportingMapDocumentFile and click OK.
3. In the script window import the arcpy mapping package.
import arcpy.mp as map
4. Add the try/except block as seen below.
import arcpy.mp as map
try:
except Exception as e:
print(“Error: “ + e.args[0])
5. Get a reference to an existing ArcGIS Pro project, call the
importDocument() method, and save the project.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
My Projects\ImportedCrime\ImportedCrime.aprx”)
aprx.importDocument(r”c:\Student\ProgrammingPro\
Databases\Crime.mxd”)
aprx.save()
except Exception as e:
print(“Error: “ + e.args[0])
6. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\
ImportingMapDocumentFile.py.
7. Open ArcGIS Pro and create a new project with the Map
template. Name the project ImportedCrime and save it to
c:\Student\ProgrammingPro\My Projects. This will create an empty
project.
8. Close ArcGIS Pro.
9. In PyCharm, run the ImportingMapDocumentFile.py script. If
everything runs correctly you should see a message in the
console window that indicates the script has finished
10. Open the ImportedCrime.aprx file in ArcGIS Pro.
11. Open the Project pane and you should see four Maps: Crime,
Crime_Inset, Inset_Map, and Test_Performance. There will also
be a Layout called Crime. You can see this in the screenshot
below.
In conclusion…
You can use the ArcGISProject object to import an existing map
document file created in ArcGIS Desktop. The data frames and layout
will be imported along with the data contained within the map
document.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file RetrievingListsMapsLayers and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the Ex 2A.aprx project located in the
c:\Student\ProgrammingPro\Chapter2 folder.
5. The Ex 2A project contains two maps: Map and Streets and
Railroads. Call the ArcGISProject.listMaps() method and pass a
wildcard to return only the “Map” map (as opposed to the
Streets and Railroads) map. This will return a Python list object
containing any Map objects that have been called “Map”.
Obviously in this case there will only be one.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps(“Map”):
except Exception as e:
print(“Error: “ + e.args[0])
6. Inside the for loop that you just created, add a new for loop that
will loop through the list of layers in the map and print out the
name of each layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
print(lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
7. Run the script and you should see the output below.
Creeks and Streams
Lakes and Ponds
City Limits
Parcels
Topographic
8. Update the listLayers() method as seen below and re-run the
script. Here you’ve introduced a wildcard to the search for
layers in a map. It will return any layers that begin with the
letter C.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“C*”):
print(lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
9. This script should now return the following:
Creeks and Streams
City Limits
10. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\AddLayers.py.
In conclusion…
The Map object can be used to retrieve a list of layers that have been
added to the map. You can also use a wildcard to limit the results that
are returned.
How to do it…
1. Open PyCharm and create a new script called AddLayers.
2. In the script, import the arcpy mapping module, create a
try/except handling block, and get a reference to the CURRENT
map document. You’re going to run this script in the ArcGIS
Pro Python window.
3. Call the Map.addDataFromPath() method and pass in the path to
the Floodplains feature class located in the Trippville
geodatabase.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
m.addDataFromPath(r”C:\Student\ProgrammingPro\
Databases\Trippville_GIS.gdb\Floodplains”)
except Exception as e:
print(“Error: “ + e.args[0])
4. Open the Ex 2A project in ArcGIS Pro and display the Python
window from the Analysis tab. In the prompt section, select
Load Code and navigate to the AddLayers.py script.
5. Run the script and you should see the Floodplains layer added
to the Map object as seen in the screenshot below. A default
symbol will be applied to all the features in the Floodplain
layer. In a future exercise we’ll add some additional code to this
script that symbolizes the polygons based on the floodplain
type.
12. The next thing we’ll do in this exercise is use the addLayer()
function to add a LayerFile to a Map. In PyCharm comment out
the line of code that sets the basemap.
13. Get a reference to the Zoning layer file.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
lyr = map.LayerFile(r”C:\Student\ProgrammingPro\
Databases\Zoning.lyrx”)
except Exception as e:
print(“Error: “ + e.args[0])
14. Call the Map.addLayer() method to add the layer file to the map.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
lyr = map.LayerFile(r”C:\Student\ProgrammingPro\
Databases\Zoning.lyrx”)
m.addLayer(lyr)
except Exception as e:
print(“Error: “ + e.args[0])
15. Add the script to the prompt section in the Python window in
ArcGIS Pro and run the script. You should see the output
shown in the screenshot below.
except Exception as e:
print(“Error: “ + e.args[0])
18. Add an if statement that test to see if the layer name is equal to
Zoning and if so, call the Map.removeLayer() method.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.name == “Zoning”:
m.removeLayer(lyr)
except Exception as e:
print(“Error: “ + e.args[0])
19. Load the script into the Python window and run it to see the
Zoning layer removed.
In conclusion…
Using the Map object in arcpy mapping you can add layers and
basemaps using a variety of methods. You can also remove layers
using the removeLayer() function.
How to do it…
1. Open PyCharm and create a new script called MoveLayers.
2. In the script, import the arcpy mapping module, create a
try/except handling block, and get a reference to the CURRENT
map document. You’re going to run this script in the ArcGIS
Pro Python window.
3. Add a for loop that loops through a list of Maps called Map.
4. Get a list of layers in the map, test each layer to find the City
Limits and Wetlands layers. We’re going to use the City Limits
layer as the reference layer. Using City Limits as a reference
layer we’ll then move the Wetlands layer so that it is located just
before the City Limits layer in the table of contents. Wetlands is
the target (or move) layer. The target layer is moved so that it is
located either before or after the reference layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.name == “City Limits”:
refLayer = lyr
elif lyr.name == “Wetlands”:
moveLayer = lyr
m.moveLayer(refLayer, moveLayer, “BEFORE”)
except Exception as e:
print(“Error: “ + e.args[0])
5. You can check your code against a solution file found at
c:\StudentProgrammingPro\Solutions\Scripts\ MoveLayers.py.
6. Open ArcGIS Pro with the Ex 2A.aprx file.
7. In the Catalog pane navigate to Databases | Trippville_GIS.gdb
and add the Wetlands feature class to Map. Initially it will be
added just below Creeks and Streams, but our script will move it
just above City Limits so that it doesn’t obscure the Lakes and
Ponds layer.
8. Open the Python window and add the MoveLayers.py script to
the prompt section. Run the script and you should see the
Wetlands layer moved below Lakes and Ponds.
9. Now let’s take a look at the insertLayer() method which works
on the concept of reference and source layers. Open PyCharm
and create a new script called InsertLayers.
10. In the script, import the arcpy mapping module, create a
try/except handling block, and get a reference to the CURRENT
map document. You’re going to run this script in the ArcGIS
Pro Python window.
11. Get the Map object called Streets and Railroads, get a list of all the
layers in this Map and find the layer called Street_Centerlines.
Assign this layer to a new variable called insertLayer. This is the
layer we will be inserting into the Map.
12. Call the Map.addDataFromPath() method to
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers():
if lyr.name == ‘Street_Centerlines’:
insertLayer = lyr
except Exception as e:
print(“Error: “ + e.args[0])
13. Create another for loop through the “Map” Map object, get a list
of layers, and find the layer called Creeks and Streams. This will
be assigned as the reference layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers():
if lyr.name == ‘Street_Centerlines’:
insertLayer = lyr
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.name == “Creeks and Streams”:
refLayer = lyr
except Exception as e:
print(“Error: “ + e.args[0])
14. Finally, call the insertLayer() method to programmatically insert
the Street_Centerlines layer at the top of the Map table of
contents.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers():
if lyr.name == ‘Street_Centerlines’:
insertLayer = lyr
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.name == “Creeks and Streams”:
refLayer = lyr
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file LayerTypeAndProperties and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the Ex 2A.aprx project located in the
c:\Student\ProgrammingPro\Chaper 2 folder.
5. The Ex 2A project contains two maps: Map and Streets and
Railroads. Call the ArcGISProject.listMaps() method and pass a
wildcard to return only the “Map” Map (as opposed to the
Streets and Railroads) map. This will return a Python list object
containing any Map objects that have been called “Map”.
Obviously in this case there will only be one. Then, generate a
list layers and test each layer to see if it is a feature layer or a
web layer. You could include other layer checks for group
layers, network analyst layers, and raster layers, but we’ll keep
this script simple since we’re dealing with the more common
types of layers.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers():
if lyr.isFeatureLayer:
print(lyr.name + “ is a Feature Layer”)
elif lyr.isWebLayer:
print(lyr.name + “ is a Web Layer”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Run this script to see the result seen in the output below.
Creeks and Streams is a Feature Layer
Lakes and Ponds is a Feature Layer
City Limits is a Feature Layer
Parcels is a Feature Layer
Topographic is a Web Layer
The supports() method on the Layer object can be used to test a
layer for support of a particular property before attempting to
apply a property to that layer. This reduces the need for error
trapping since you can determine if it’s even possible to apply a
particular property to a Layer beforehand.
Layers have various properties that can be set. For example,
you may want to set a definition query on a feature layer to
limit the features that are displayed for that layer. Remember
though that not every layer type supports every property so
you should use the supports() method first to determine if the
layer supports that property. This ensures that an error is not
generated when you attempt to apply the property.
7. Update the code in your script as shown below to provide a
check to see if the Parcels layer supports definition query.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(r”c:\Student\ProgrammingPro\
Chapter2\Ex 2A.aprx”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
if lyr.supports(“DEFINITIONQUERY”):
print(lyr.name + “ supports definition
query”)
except Exception as e:
print(“Error: “ + e.args[0])
8. Run the script and the output should indicate the Parcel layer
supports the use of a definition query.
In conclusion…
Because the Layer object in arcpy mapping has a generic design meant
to support a variety of layers it is necessary to use a variety of
checking methods to determine the type of layer and whether a
specific property is supported before using it. The is* methods are
used to determine the type of layer, and the supports() method queries
for the support of a\ specific property before you attempt to use it.
How to do it…
1. In the LayerTypeAndProperties script make the following
changes. We’re going to run this script in the Python window of
ArcGIS Pro so that we can see the results so we’ll update the
reference to the project to CURRENT. Then, use the
definitionQuery property to display only parcels where the acres
are greater than 5.0.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
if lyr.supports(“DEFINITIONQUERY”):
lyr.definitionQuery = “ACRES > 5.0”
except Exception as e:
print(“Error: “ + e.args[0])
2. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\LayerTypeAndProperties.py
Open the Ex 2A project in ArcGIS Pro, load the script into the
Python window and run it. The result should be presented as
seen in the screenshot below. Notice that only parcels that are
greater than 5.0 acres are displayed. You can use an identify
operation to verify this by clicking on any of the parcels or you
can open the Properties window for the Parcels layer and go the
Definition Query setting.
In conclusion…
The Layer.definitionQuery property can be used to limit the display of
features in a layer to only those that match an attribute query.
How to do it…
1. In ArcGIS Pro clear the definition query that was set in the last
exercise. Right click on the Parcels layer in the Contents tab and
select Properties. In the Layer Properties dialog select Definition
Query and then mouse over the existing query Acres is Greater
Than 5 and then click the red X to the right side of the existing
query.
2. In PyCharm return to the LayerTypeAndProperties script and
update it as seen below to comment out the definition query
section and add code that tests for the ability to apply a
threshold and then apply a minimum threshold so that the
parcels won’t display out beyond 1:50,000.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
if lyr.supports(“MINTHRESHOLD”):
lyr.minThreshold = 50000
#if lyr.supports(“DEFINITIONQUERY”):
#lyr.definitionQuery = “ACRES > 5.0”
except Exception as e:
print(“Error: “ + e.args[0])
3. Load the script into the ArcGIS Pro Python window and run it.
After running the script, right click the Parcel layer in the
Contents pane and select Properties. Click General and you
should see that Out beyond (minimum scale) should now be set
to 1:50,000 as seen in the screenshot below.
4. In the Map, zoom out until you get past 1:50,000 and at that
point you’ll see that the Parcel layer is no longer visible. The
same process would apply if you wanted to set the maximum
threshold so that a layer no longer displays when you zoom in
to a specific scale.
5. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\LayerTypeAndProperties.py
In conclusion…
In this set of exercise you learned some basic techniques for testing
layer type, determining if a layer supports a particular property, and
applying various properties. In the next set of exercises you’ll learn
how to symbolize layers.
In this exercise you learned how to use the minThreshold and
maxThreshold properties of a Layer object to set a visibility scale range.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file SimpleRenderer and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the CURRENT project.
5. The Ex 2A project contains two maps: Map and Streets and
Railroads. Call the ArcGISProject.listMaps() method and pass a
wildcard to return only the “Map” Map (as opposed to the
Streets and Railroads) map. This will return a Python list object
containing any Map objects that have been called “Map”.
Obviously in this case there will only be one. Then get the
Parcels layer, test to see that it is a feature layer, and retrieve the
Symbology object.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
except Exception as e:
print(“Error: “ + e.args[0])
6. Set the symbol color, outline color, and size on the renderer
object, which in this case is a SimpleRenderer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.renderer.symbol.color =
{‘RGB’: [255, 255, 190, 25]}
sym.renderer.symbol.outlineColor =
{‘CMYK’: [25, 50, 75, 25, 100]}
sym.renderer.symbol.size = 1.0
except Exception as e:
print(“Error: “ + e.args[0])
7. Finally, apply the symbology to the layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.renderer.symbol.color =
{‘RGB’: [255, 255, 190, 25]}
sym.renderer.symbol.outlineColor =
{‘CMYK’: [25, 50, 75, 25, 100]}
sym.renderer.symbol.size = 1.0
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\SimpleRenderer.py
9. Load the script in the ArcGIS Pro Python window and run it.
The Parcels layer should be redrawn with the symbol style seen
in the screenshot below.
10. You can also use a pre-defined style from the symbol gallery.
Symbols have a pre-defined name that can be used in your
code. Click the symbol patch for the Parcels layer to display the
Symbology pane.
11. Click the Gallery tab and you’ll see a number of pre-defined
symbols as seen in the screenshot below. Each of the symbols
has a name. You can move your mouse over any of these
symbols to see the name. Scroll down until you get to the Extent
Transparent symbol. There are several so move your mouse
over each of them until you get to the Extent Transparent Wide
Gray symbol. This is the symbol from the gallery that we’ll
apply in the next step.
#sym.renderer.symbol.color =
{‘RGB’: [255, 255, 190, 25]}
#sym.renderer.symbol.outlineColor =
{‘CMYK’: [25, 50, 75, 25, 100]}
#sym.renderer.symbol.size = 1.0
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
In conclusion…
The SimpleRenderer object is used to apply a single symbol to all
features in a layer. A symbol is typically composed of a color, outline
color, and size. This symbol object is applied to a layer to define its
display symbology. You can also use pre-defined symbols defined in
the Symbol Gallery in your code and assign them to a layer.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file GraduatedColorsRenderer and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the CURRENT project.
5. Retrieve the symbology for the Parcels layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
except Exception as e:
print(“Error: “ + e.args[0])
6. The Parcels layer, as it currently exists, is a SimpleRenderer. Add
a line of code that updates the renderer to be a
GraduatedColorsRenderer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(
‘GraduatedColorsRenderer’)
except Exception as e:
print(“Error: “ + e.args[0])
7. Set the classification field to Acres (a numeric field on the
Parcels layer), the classification method to NaturalBreaks, and
the break count to 5 and apply the symbology to the layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘GraduatedColorsRenderer’)
sym.renderer.classificationField = “ACRES”
sym.renderer.classificationMethod =
“NaturalBreaks”
sym.renderer.breakCount = 5
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\GraduatedColorsRenderer.py
9. Load the script in the ArcGIS Pro Python window and execute
it to see the result shown in the screenshot below.
10. You probably noticed that this applied a default color ramp.
However, the color ramp can be changed by applying a specific
color ramp to the GraduatedColorsRenderer. To get a list of the
available color ramps, type the following code block into the
ArcGIS Pro Python window.
aprx = arcpy.mp.ArcGISProject(“CURRENT”)
for cr in aprx.listColorRamps():
print(cr.name)
11. This will print out a list similar to what you see below. Note,
that I’m only displaying a partial list since there are so many.
Accent (3 Classes)
Accent (4 Classes)
Accent (5 Classes)
Accent (6 Classes)
Accent (7 Classes)
Accent (8 Classes)
Aspect
Basic Random
Bathymetric Scale
Black to White
Blue-Green (3 Classes)
Blue-Green (4 Classes)
Blue-Green (5 Classes)
Blue-Green (6 Classes)
Blue-Green (7 Classes)
Blue-Green (8 Classes)
Blue-Green (9 Classes)
Blue-Green (Continuous)
Blue-Purple (3 Classes)
Blue-Purple (4 Classes)
Blue-Purple (5 Classes)
Blue-Purple (6 Classes)
Blue-Purple (7 Classes)
12. Update your code as seen below. Note: You can select a
different color ramp if you’d like. I used Reds (5 Classes) in this
case, but you can select something different.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Map”):
for lyr in m.listLayers(“Parcels”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘GraduatedColorsRenderer’)
sym.renderer.classificationField = “ACRES”
sym.renderer.classificationMethod =
“NaturalBreaks”
sym.renderer.breakCount = 5
sym.renderer.colorRamp =
aprx.listColorRamps(“Reds (5 Classes)”)[0]
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
Load and run the script to see the new color ramp applied as seen in
the screenshot below.
In conclusion…
The GraduatedColorsRenderer object can be used to create a color-coded
map based on a numeric attribute field along with the classification
method, number of breaks, and color ramp properties.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file UniqueValueRenderer and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the CURRENT project.
5. Retrieve the Streets and Railroads map and the Street_Centerlines
layer from the map. Test to make sure the Street_Centerlines
layer is a feature layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers(“Street_Centerlines”):
if lyr.isFeatureLayer:
except Exception as e:
print(“Error: “ + e.args[0])
6. Get the symbology object from the layer, and update the
renderer to UniqueValueRenderer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers(“Street_Centerlines”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘UniqueValueRenderer’)
except Exception as e:
print(“Error: “ + e.args[0])
7. Set the fields property on the UniqueValuesRenderer to the
Condition field and apply the symbology to the layer.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers(“Street_Centerlines”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘UniqueValueRenderer’)
sym.renderer.fields = [“Condition”]
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\UniqueValueRenderer.py
9. Load the code into the ArcGIS Pro Python window and run it.
The Street_Centerlines layer will be updated as seen in the
screenshot below.
10. Just as we saw with the GraduatedColorsRenderer, the
UniqueValuesRenderer can be assigned specific color ramps or
you can assign the symbols individually for each unique value.
The UniqueValuesRenderer object includes a groups property that
can be used to retrieve a list of ItemGroup objects. The ItemGroup
contains the unique values as Item objects. Add the code
highlighted below to see how this works.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers(“Street_Centerlines”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘UniqueValueRenderer’)
sym.renderer.fields = [“Condition”]
for grp in sym.renderer.groups:
for itm in grp.items:
print(itm.label)
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
11. Load this script into the ArcGIS Pro Python window and run it.
Now, in addition to symbolizing the layer the script will also
print out the values Fair, Good, and Poor. In the next step we’ll
apply a color to each of the unique values.
12. Add the following code to your script. This will define colors of
red for Poor, green for Good, and blue for Fair.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
for m in aprx.listMaps(“Streets and Railroads”):
for lyr in m.listLayers(“Street_Centerlines”):
if lyr.isFeatureLayer:
sym = lyr.symbology
sym.updateRenderer(‘UniqueValueRenderer’)
sym.renderer.fields = [“Condition”]
for grp in sym.renderer.groups:
for itm in grp.items:
if itm.label == ‘Poor’:
itm.symbol.color = {‘RGB’:
[255, 0, 0, 100]}
elif itm.label == ‘Fair’:
itm.symbol.color = {‘RGB’:
[0, 92, 230, 100]}
elif itm.label == ‘Good’:
itm.symbol.color = {‘RGB’:
[38, 115, 0, 100]}
lyr.symbology = sym
except Exception as e:
print(“Error: “ + e.args[0])
13. Load the script into the ArcGIS Pro Python window and run it
to see the result seen in the screenshot below.
In conclusion…
The UniqueValuesRenderer object is used to assign unique symbols to
categorical data from a feature class.
How to do it…
1. Open ArcGIS Pro with the Ex 2A.aprx file found in the
c:\Student\ProgrammingPro\Chapter2 folder.
2. On the Map tab find the Bookmarks tool and click the arrow
below to display a list of the current bookmarks. There should
only be a single bookmark: Washington Park. Click the
Washington Park bookmark to see how it works.
5. In ArcGIS Pro, select the Insert tab and then New Layout |
Letter. This will create a new layout in ArcGIS Pro. Rename the
layout to Park Layout.
6. With the Layout view active select Map Frame | Default and
then draw a rectangle on the layout to define the size and
location of the map.
7. If you’d like, add some additional layout elements including a
title, north arrow, and any other elements you’d like to add. I’ve
kept my layout very simple by adding a generic title and north
arrow. In future exercises you’ll learn more about how to
manipulate the layout and it’s elements so we’ll keep it simple
for now.
8. Save the project in ArcGIS Pro.
9. Open PyCharm
10. Select File | New | Python File.
11. Name the file Bookmarks and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
12. At this point I’m going to assume that you have enough
experience to know how to import the arcpy mapping module,
reference a project, and create the basic error handling structure
so I’m not going to provide explicit instructions on how to do
that going forward. Please refer back to previous exercises if
you are still unsure how to complete these steps. Go ahead and
import the arcpy mapping module, add a try/except handler, and
get a reference to the CURRENT project since we’ll be running
the script from the ArcGIS Pro Python window. This will be the
Ex 2A project.
13. Get a reference to the layout (Park Layout) as well as the map
frame element (MAPFRAME_ELEMENT).
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
lyt = aprx.listLayouts(“Park Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
except Exception as e:
print(“Error: “ + e.args[0])
14. The next lines of highlighted code will get a list of bookmarks,
loop through the list, zoom to each bookmark, and export the
layout to a PDF file where the name given to the file is the same
as the park name.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
lyt = aprx.listLayouts(“Park Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
bkmks = mf.map.listBookmarks()
for bkmk in bkmks:
mf.zoomToBookmark(bkmk)
lyt.exportToPDF(r”C:\Student\ProgrammingPro
\Scripts” + “\\” + bkmk.name + “.pdf”)
except Exception as e:
print(“Error: “ + e.args[0])
15. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\Bookmarks.py
16. Load the script in the ArcGIS Pro Python window and run it.
The result should be three PDF files written to the
C:\Student\ProgrammingPro\Scripts folder. You can see an
example in the screenshot below. A more complex script would
dynamically update the title of the map. You’ll learn how to do
that in a future exercise.
In conclusion…
In this exercise you learned some techniques for working with
bookmarks.
Managing Layouts
In this we’ll cover the following topics:
How to do it…
1. Open ArcGIS Pro with the Imported Crime.aprx file found in the
c:\Student\ProgrammingPro\My Projects\ImportedCrime folder. This
project was created in a previous exercise.
2. Open the Crime Layout. You should now see something similar
to the screenshot below.
How to do it…
1. Return to the ListLayoutElements.py script in PyCharm and
update your code as seen below. The first highlighted line of
code defines the output location and file name. The second,
calls the exportToPDF() method and passes in the output file
along with optional parameters for image quality and the
embedding of fonts. These define a high quality output
resolution and the embedding of Esri fonts so that the end user
doesn’t need to have Esri software installed to view the map.
There are many other optional parameters that you can include
for this method. Take some time to examine the help
documentation to determine which parameters you should
include.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
lyt = aprx.listLayouts(“Crime”)[0]
for el in lyt.listElements(“TEXT_ELEMENT”, “Title”):
el.text = “Crime and It\’s Impact on School Test
Performance - 2009”
outFile = r”C:\Student\ProgrammingPro\My Projects\
ImportedCrime\Layout.pdf”
lyt.exportToPDF(outFile, image_quality=”BEST”,
embed_fonts=True)
print(“Exported Layout to PDF”)
except Exception as e:
print(“Error: “ + e.args[0])
2. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\ListLayoutElements.py
3. Load the script in the ArcGIS Pro Python window and run it.
Examine the output PDF file.
4. There are a number of export methods related to exporting
various image file formats including exportToPNG,
exportToJPEG, and others. Open the ArcGIS Pro help
documentation and examine several of these methods. Pick one
and update your script to export the Layout to an image format.
In conclusion…
Creating high quality maps for output to either hard copy maps or image files
is a common use of ArcGIS Pro. This process can be automated through
arcpy mapping and the various export methods on the Layout object.
How to do it…
1. In a previous exercise on bookmarks you created a new layout
called Park Layout in the Ex 2A project. Open ArcGIS Pro with
the Ex 2A project to verify that the Park Layout exists and if not
re-create it.
2. Open PyCharm
3. You can use the WorkingWithMapFrame.py script that you used
in Exercise 3A. Comment out the existing code inside the try
block.
4. Reference the current project and get a list of maps. For this
exercise we’re going to use the Ex 2A.aprx file again with the
script loaded inside the Python window.
import arcpy.mp as map
try:
#Exercise 3B
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Map”)[0]
except Exception as e:
print(“Error: “ + e.args[0])
5. Get a reference to the Parcels layer.
import arcpy.mp as map
try:
#Exercise 3B
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Map”)[0]
parcelLyr = m.listLayers(“Parcels”)[0]
except Exception as e:
print(“Error: “ + e.args[0])
6. Get the Park Layout and retrieve the only MapFrame object
contained within this layout.
import arcpy.mp as map
try:
#Exercise 3B
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Map”)[0]
parcelLyr = m.listLayers(“Parcels”)[0]
lyt = aprx.listLayouts(“Park Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
except Exception as e:
print(“Error: “ + e.args[0])
7. The next line of code calls the MapFrame.zoomToAllLayers()
method and passes a value of True as the only parameter. This
is an optional parameter. If you don’t pass in a value of True the
method will zoom to the extent of all layers. However, passing
in a value of True will zoom to the selected features of selected
layers in a map.
import arcpy.mp as map
try:
#Exercise 3B
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Map”)[0]
parcelLyr = m.listLayers(“Parcels”)[0]
In conclusion…
The MapFrame object, associated with a Map object, can be used to
perform various operations including exporting to various image file
formats, zooming, panning, and other operations.
How to do it…
1. You’ll need to create a new ArcGIS Pro project for this exercise.
Open ArcGIS Pro and create a new project using the
Local_Scene.aptx template. Save the project with a name of
WorkingWithTheCamera in the c:\Student\ProgrammingPro\My
Projects folder. The new project will contain only a single 2D
basemap layer called Topographic.
2. Right click on the Scene in the Content pane and select
Properties.
3. Click the General option in the left-hand side of the window.
Rename the scene Union City.
4. Click on the Coordinate Systems option in the left-hand side of
the window. Then, click on the Add Coordinate System button
and finally the Import Coordinate System option.
5. In the Import Coordinate System window, navigate to
c:\Student\ProgrammingPro\Databases\UnionCity.gdb. Select the
DEM raster and click on the OK button. This sets your scene, so
it will use the same coordinate system as the DEM and other
layers you will add to the scene during the exercise.
6. Click OK in the Map Properties window.
7. In the Catalog pane, right click on Databases and select Add
Database. Navigate to c:\Student\ProgrammingPro\Databases and
select UnionCity.gdb. Click the OK button to add this existing
geodatabase to the project.
8. In the Contents pane scroll to the bottom and find the Elevation
Surfaces section. If necessary, open this section by clicking the
arrow. You should see an item for Ground.
9. Right click Ground and select Add Elevation Source.
10. Select DEM from the UnionCity geodatabase.
11. Remove the default Terrain3D elevation source by right clicking
the layer and selecting Remove.
12. Click the Map tab and the Add Data button.
13. Navigate to the c:\Student\ProgrammingPro\Chapter5 folder and
select 3D Buildings.lyrx.
14. The buildings will initially appear very small so zoom in on the
view until it looks similar to what you see in the screenshot
below. It doesn’t have to be exact though.
15. In ArcGIS Pro select the Insert tab and then New Layout |
Landscape Letter.
16. Rename the newly created layout to Union City Layout.
17. On the Insert tab select MapFrame | Union City to add a new
MapFrame to the view as seen in the screenshot below.
18. Open PyCharm
19. Select File | New | Python File.
20. Name the file WorkingWithCamera and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
21. Import the arcpy mapping module, reference the CURRENT
project, and create the basic error handling structure.
22. Initially we’re just going to retrieve the 3D properties of the
Camera object and then later we’ll set some of the properties to
see the affect. Retrieve the Union City map, the Union City
Layout, and the MAPFRAME_ELEMENT with the code below.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
except Exception as e:
print(“Error: “ + e.args[0])
23. Retrieve the Camera object from the MapFrame.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
camera = mf.camera
except Exception as e:
print(“Error: “ + e.args[0])
24. Check to see that the map is in 3D and if so, get the camera
pitch, heading, roll, X, Y, and Z properties and print them out.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
camera = mf.camera
if camera.mode == “LOCAL”: #check to make sure it’s 3D
print(“Pitch: “ + str(camera.pitch))
print(“Heading: “ + str(camera.heading))
print(“Roll: “ + str(camera.roll))
print(“X: “ + str(camera.X))
print(“Y: “ + str(camera.Y))
print(“Z: “ + str(camera.Z))
except Exception as e:
print(“Error: “ + e.args[0])
25. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\WorkingWithCamera.py
26. In ArcGIS Pro make Union City Layout the active view.
27. Load the script in the ArcGIS Pro Python window and run it.
The results should appear similar to what you see below. Keep
in mind though that your results will probably differ somewhat
from mine due to slight differences in how you initially set the
display.
Pitch: -20.0
Heading: 0.0
Roll: 0.0
X: 2174926.9290598724
Y: 1298845.05538592
Z: 3445.140564667932
28. Now we’ll change some of the properties to see how it affects
the display.
29. Return to the WorkingWithCamera script in PyCharm.
30. The pitch property is the equivalent of moving a plane’s nose up
or down with the axis passing directly through the wings of the
plane. Values can range from -90 to +90. Positive values are
above the horizon and negative values are below the horizon.
For example, a value of -90 would be looking down on the map,
while a value of +90 would be looking directly up. Alter your
code as seen below and run the script in ArcGIS Pro. You
screenshot may differ from what you see below, but the view
should be pointing directly down (-90).
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
camera = mf.camera
if camera.mode == “LOCAL”: #check to make sure it’s 3D
camera.pitch = -90.00
except Exception as e:
print(“Error: “ + e.args[0])
31. In the ArcGIS Pro Python window, put the cursor inside the
Python prompt and click the up arrow key on your keyboard to
display the code you last executed. Change the pitch property to
some other value such as –45 and run it again to see the affect.
Run this script a number of times with different values to get a
good feel for how the pitch property works. Values can range
from -90 to +90 with 0 being toward the horizon.
32. The roll property is the equivalent of tilting a plane’s wings up
or down. A zero value is perfectly horizontal. Positive values
will tilt the right side upward. Negative values do the opposite.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
camera = mf.camera
if camera.mode == “LOCAL”: #check to make sure it’s 3D
camera.pitch = 0.00
camera.roll = 45
except Exception as e:
print(“Error: “ + e.args[0])
33. You should now see something similar to the screenshot below,
but note that your view may be somewhat different.
34. The heading property provides the ability to either get or set the
map view rotation value. This is also known as yaw or azimuth.
It represents the number of degrees by which the map’s data
will be rotated, measured counter-clockwise from the north.
You can use negative values to rotate clockwise. Update the
script as seen below and run it in ArcGIS Pro to see the effect.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Union City”)[0]
lyt = aprx.listLayouts(“Union City Layout”)[0]
mf = lyt.listElements(“MAPFRAME_ELEMENT”)[0]
camera = mf.camera
if camera.mode == “LOCAL”: #check to make sure it’s 3D
camera.pitch = 0.00
camera.roll = 0.00
camera.heading = 90.00
except Exception as e:
print(“Error: “ + e.args[0]
In conclusion…
In this exercise you learned how to use the Camera object associated with a
MapFrame object to control the display characteristics of a 3D scene.
Creating a Map Series
In this chapter we’ll cover the following topics:
6. On the ArcGIS Pro Insert tab select Map Frame | Map | Default
Extent and draw a rectangle in the center of the guides so that it
appears as seen below.
7. On the Layout tab, click the lower part of the Map Series button
and then select Spatial. This will display the Layout Properties
dialog seen below with Map Series selected. The Enable toggle
button should automatically be toggled on, but if it’s not you’ll
need to enable it.
8. Since we’ve only added a single map frame to the layout this
will be the default choice for the Map frame. The index layer
will also be the default of Parcels_Tax_Delinquent in this case
since it’s the only available layer. This is the layer we’ll use as
the irregular index layer. It will create one map per feature just
like the grid and strip map index layers, but the features can be
of an irregular shape unlike those two types of index layers.
9. Select legal_description as the Name Field as well as the Sort
Field. The legal_description field contains the legal description
for each property, and we’ll display that as the title for each
sheet.
10. You can leave the defaults for the parameters under Optional
Fields. Expand the Map Extent section and ensure that Best Fit
Extent is selected.
11. Click OK to apply the Map Series parameters and create the
map series. After the map series has been generated you should
see a list of the pages in the Contents pane under List Map
Series Pages, with the first page selected and displayed in the
layout as seen in the screenshot below.
12. You can double click each of the individual pages in the
Contents pane to see the resulting map sheet.
13. You’ll often want to add some additional content to the map
sheets including things like a title, north arrow, scale bar, and
other supporting information. Text that you add can be
dynamic text or static text. We’ll keep it fairly simple here, but
let’s add a few items.
14. Click the Insert tab and then the dropdown arrow for Dynamic
Text. Scroll down to Map Series and select Page Name. Draw a
rectangle where you want the dynamic text to be placed. This
will ensure that the title of each sheet is tied to the name, which
in this case will be the legal description for the parcel. You may
need to zoom in a little on the layout to see the text more
clearly, but it should appear as seen below.
15. Right click the dynamic text you just added and select
Properties to display the Format Text pane seen below.
16. Remove the static text “Page Name:” In the Format Text pane
under Text remove “Page Name:” so that it appears as follows:
17. Increase the size of the text by going to Text Symbol | Properties
| Appearance and changing the size to 18 pt.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file MapSeries.py and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
get a reference to the BellCounty.aprx project found at
c:\Student\ProgrammingPro\Chapter6\BellCounty folder.
5. Retrieve the layout used to create the map series.
import arcpy
try:
aprx = arcpy.mp.ArcGISProject(r”C:\Student\
ProgrammingPro\Chapter6\BellCounty\BellCounty.aprx”
l = aprx.listLayouts()[0]
except Exception as e:
print(“Error: “ + e.args[0])
6. Retrieve the MapSeries object from the layout.
import arcpy
try:
aprx = arcpy.mp.ArcGISProject(r”C:\Student\
ProgrammingPro\Chapter6\BellCounty\BellCounty.aprx”
l = aprx.listLayouts()[0]
except Exception as e:
print(“Error: “ + e.args[0])
7. Make sure the MapSeries is enabled, and if it is, export the entire
series to a PDF file.
import arcpy
try:
aprx = arcpy.mp.ArcGISProject(r”C:\Student\
ProgrammingPro\Chapter6\BellCounty\BellCounty.aprx”
l = aprx.listLayouts()[0]
How to do it
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file MapSeries_SelectedFeatures.py and click OK. The
file should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
get a reference to the BellCounty.aprx project found at
c:\Student\ProgrammingPro\Chapter6\BellCounty folder.
5. The initial lines of codes for this script will be exactly as they
were in the previous MapSeries.py script so I have highlighted
only the lines of code that are new to this script in the code
below. You will need to add in all of the code but feel free to
copy and paste the lines that are exactly the same as the
previous script.
The highlighted lines of code below run the Select by Attributes
tool to select parcels where the land value is greater than
$50,000, and export the map series to PDF. Also notice that
we’ve added a parameter to the exportToPDF() function that will
export the selected features.
import arcpy
try:
aprx = arcpy.mp.ArcGISProject(r”C:\Student\
ProgrammingPro\Chapter6\BellCounty\BellCounty.aprx”
l = aprx.listLayouts()[0]
if not l.mapSeries is None:
ms = l.mapSeries
if ms.enabled:
ms = l.mapSeries
indexLyr = ms.indexLayer
arcpy.SelectLayerByAttribute_management(indexLyr,
“NEW_SELECTION”, “land_value >= 50000”)
ms.exportToPDF(r”C:\Student\ProgrammingPro\
Chapter6\BellCounty\DelinquentLandProperties_
Selected.pdf”, “SELECTED”)
except Exception as e:
print(“Error: “ + e.args[0])
6. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\MapSeries_SelectedFeatures.py
7. Run the script. This script will take some time to execute but it
will eventually complete and you should see a
DelinquentLandProperties_Selected.pdf file in the
c:\Student\ProgrammingPro\Chapter6\BellCounty folder.
8. The resulting file should contain only 40 maps, one for each
selected feature.
In conclusion…
The MapSeries class in the arcpy.mp module facilitates the automation
of exporting a series of maps from a spatial map series to a PDF file. In
addition, this class can also be used to export only the selected
features from an index layer
How to do it
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file MapSeries_SelectedFeatures_TitlePage.py and click
OK. The file should be written to your default project location
of c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
get a reference to the BellCounty.aprx project found at
c:\Student\ProgrammingPro\Chapter6\BellCounty folder.
5. The initial lines of codes for this script will be exactly as they
were in the previous MapSeries_SelectedFeatures.py script so I
have highlighted only the lines of code that are new to this
script in the code below. You will need to add in all of the code
but feel free to copy and paste the lines that are exactly the same
as the previous script.
6. The highlighted lines of code make a call to
PDFDocumentOpen(), which will open the map book you just
created and inserting a file called Title.pdf as the first page in
this document. The PDFDocument.saveAndClose() method
ensures that the saves are committed to the PDF file. We’re also
adding in a few print() statements so that you can get a sense of
how the script is progressing.
import arcpy
try:
aprx = arcpy.mp.ArcGISProject(r”C:\Student\
ProgrammingPro\Chapter6\BellCounty\BellCounty.aprx”
l = aprx.listLayouts()[0]
if not l.mapSeries is None:
ms = l.mapSeries
if ms.enabled:
ms = l.mapSeries
indexLyr = ms.indexLayer
arcpy.SelectLayerByAttribute_management(indexLyr,
“NEW_SELECTION”, “land_value >= 50000”)
print(“Beginning export...”)
ms.exportToPDF(r” C:\Student\ProgrammingPro\
Chapter6\BellCounty\DelinquentLandFeatures_
Selected_Title.pdf”, “SELECTED”)
pdfMapSeries = arcpy.mp.PDFDocumentOpen(r”
C:\Student\ProgrammingPro\Chapter6\BellCounty\
DelinquentLandFeatures_Selected_Title.pdf”)
print(“Adding title page....”)
pdfMapSeries.insertPages(r” C:\Student\
ProgrammingPro\Chapter6\BellCounty\Title.pdf”, 1)
pdfMapSeries.saveAndClose()
print(“Complete”)
except Exception as e:
print(“Error: “ + e.args[0])
7. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\MapSeries_SelectedFeatures_TitlePa
8. Run the script. This script will take some time to execute but it
will eventually complete and you should see a
DelinquentLandProperties_Selected_Title.pdf file in the
c:\Student\ProgrammingPro\Chapter6\BellCounty folder.
9. The resulting file should contain a title page (as the first page)
along with 40 maps, one for each selected feature. You can see
the title page in the screenshot below.
In conclusion…
Adding a title page and other ancillary pages in a map series can be facilitated
with the PDFDocument class in the arcpy.mp module. In this exercise we
used the PDFDocumentOpen() function to create an instance of
PDFDocument. A path to the output PDF file was passed into the
PDFDocumentOpen() function. We called the PDFDocument.insertPages()
method to insert a title page as the first page in the map series after creating
40 maps of delinquent properties.
Updating and
Fixing Data Sources
In this we’ll cover the following topics:
How to do it…
1. Open ArcGIS Pro and create a new blank project from the
Blank.aprx template. Call the project Crime_BrokenDataLinks.aprx
and save it in the c:\Student\ProgrammingPro\My Projects folder.
2. You’re going to import an existing map document file created
with ArcGIS Desktop for this exercise. With the project now
open, select Import Map from the Insert tab. Navigate to
c:\Student\ProgrammingPro\Databases and select
Crime_BrokenDataLinks.mxd and click OK to import the map
document to the project.
3. This will import several new Map objects including Crime,
Crime_Inset, Inset_Map, and Test_Performance. Each will have a
number of layers that are broken as seen in the screenshot
below.
4. Open PyCharm
5. Select File | New | Python File.
6. Name the file BrokenDataSources and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
7. Import the arcpy mapping module, set up a basic try/except
structure, and get a reference to the CURRENT project.
8. Call the ArcGISProject.listBrokenDataSources() method to return a
list of broken data sources in the project. Print out the layer
names.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
lyrs = aprx.listBrokenDataSources()
for lyr in lyrs:
print(lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
9. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\BrokenDataSources.py
10. Load the script into the Crime_BrokenDataLinks.aprx project in
the ArcGIS Pro Python window and run it. You should see the
list of layers printed out as seen below.
District_Crime_Join
Bexar_County_Boundary
Crime2009Table
School_Districts
Crime_surf
Bexar_County_Boundary
Bexar_County_Boundary
Texas_Counties_LowRes
District_Crime_Join
Bexar_County_Boundary
11. The Map and LayerFile objects also includes a
listBrokenDataSources() method as well. Update your code as
seen below to learn how to generate a list of broken data
sources from a map instead of the project.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
m = aprx.listMaps(“Crime*”)[0]
for lyr in m.listBrokenDataSources():
print(lyr.name)
#lyrs = aprx.listBrokenDataSources()
#for lyr in lyrs:
# print(lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
12. Load and run the script in the ArcGIS Pro Python window.
When you run this script it should print the output seen below.
District_Crime_Join
Bexar_County_Boundary
Crime2009Table
In conclusion…
The ArcGISProject, Map, and LayerFile objects all include a list function
that generates a list of broken data sources. It’s common to generate
this list and then iterate the items in the list and apply a fix to each of
the objects that are broken.
Exercise 2: Fixing broken data sources
Getting ready
Chances are that if you have a broken data source in one project it is
also broken in other projects, as it is common to reference the same
workspace only to have that location of that workspace change at
some point in time. Fixing these broken data sources can be
automated through a Python script that takes advantage of functions
designed to apply fixes at the project, layer, layerfile, map or table
levels.
The updateConnectionProperties() method is available on the
ArcGISProject, Layer, LayerFile, Map, and Table classes. It’s used to
replace current (old) connection information with new connection
information. The connection information can be provided as a partial
string or a Python dictionary data structure that represents a layer or
table connection properties. Although it can be used against
individual layers or tables it is most useful for updating multiple data
sources found in a project, layer file or map.
How to do it…
1. In ArcGIS Pro open the Crime_BrokenDataLinks.aprx and open
Crime Map.
2. Right click the District_Crime_Join layer and select Properties.
3. Click Source on the left hand side of the dialog box and find the
Database entry on the right hand side. This is the path to the
current connection information, which is now broken. You can
use your mouse to double click on the database entry, select it,
and copy the path.
4. Return to the BokenDataSources.py script in PyCharm and
update your code as seen below. The
updateConnectionProperties() method takes two required
parameters: the old connection path, and the new connection
path. You’ll also need to call the save() method on the
ArcGISProject object to save the changes.
import arcpy.mp as map
try:
aprx = map.ArcGISProject(“CURRENT”)
aprx.updateConnectionProperties(
r”C:\Student\ProgrammingPro\Databases\Data\OldData\
CityOfSanAn tonio.gdb”,r”C:\Student\ProgrammingPro\
Databases\CityOfSanAntonio.gdb”)
aprx.save()
#m = aprx.listMaps(“Crime*”)[0]
#for lyr in m.listBrokenDataSources():
# print(lyr.name)
#lyrs = aprx.listBrokenDataSources()
#for lyr in lyrs:
# print(lyr.name)
except Exception as e:
print(“Error: “ + e.args[0])
5. Load the script in the ArcGIS Pro Python window and run it.
Examine each of the Map objects and the layers should now be
updated as seen in the screenshot below.
6. You can also update a data source for individual Layers and
Tables using the updateConnectionProperties() method on each of
these objects.
In conclusion…
The updateConnectionProperties() method can be used to fix the data
connection for individual layers and tables.
Querying and Selecting Data
In this chapter you’ll learn the following about querying and selecting
data:
How to do it…
1. Open ArcGIS Pro and create a new project from the Map.aptx
template. You can give the project any name you’d like and
store it wherever you’d like as well. It should have only a
Topographic basemap.
2. Open PyCharm
3. Select File | New | Python File.
4. Name the file CreateFeatureLayer and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
5. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to the CityOfSanAntonio
geodatabase.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
except Exception as e:
print(“Error: “ + e.args[0])
6. Call the MakeFeatureLayer tool with the Burglary layer provided
as the input feature class and Burglary_Layer the output feature
layer.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
flayer = arcpy.MakeFeatureLayer_
management(“Burglary”,”Burglary_Layer”)
except Exception as e:
print(“Error: “ + e.args[0])
7. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\CreateFeatureLayer.py
8. Open the ArcGIS Pro Python window, load the script, and run
it. You should see a new layer called Burglary_Layer added to
the Contents pane. This is a feature layer that has been
temporarily created and added to the display. It can then be
used to facilitate the selection of features using the
SelectLayerByAttribute or SelectByLocation tools. Unless you
specifically save this layer it will be deleted at the end of your
current ArcGIS Pro session.
9. Return to the CreateFeatureLayer.py script and make the
following change to create a table view instead of a feature
layer.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
#flayer = arcpy.MakeFeatureLayer_
management(“Burglary”,”Burglary_Layer”)
tView = arcpy.MakeTableView_management
(“Crime2009Table”, “Crime2009TView”)
except Exception as e:
print(“Error: “ + e.args[0])
10. Load and run the script in the ArcGIS Pro Python window and
you should see a new table view called Crime2009TView added
to the Contents pane.
In conclusion…
Feature layers and table views are temporary, intermediate datasets
used for the explicit purpose of facilitating the creation of selection
sets using the Select by Location and Select by Attributes tools. In the
next exercise you’ll learn how to use these temporary datasets to
create a selection set using the Select Layer by Attributes tool.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file SelectLayerByAttribute and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
set the current workspace to the CityOfSanAntonio geodatabase.
5. Create the query below. This will serve as a where clause that
will select all the records with a service area of North. In an
attribute query the field to queried must be surrounded by
quotes. In this case that is the SVCAREA field.
If the field being queried is a Text datatype field, which is the
case here, the value being evaluated must also be surrounded
by quotes, and the quotes must be embedded inside the query.
The way this is accomplished in Python is to use a \’ both before
and after the value being evaluated. This specifies that the
quotes will be inserted into the where clause of the query.
Finally, the entire statement must be surrounded by quotes as
well. Because there are so many quotes that need to used in an
attribute query it makes sense to use a combination of single
and double quotes just to make your code more readable.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”SVCAREA” = \’North\’’
except Exception as e:
print(“Error: “ + e.args[0])
6. Create a feature layer with the MakeFeatureLayer tool from the
Burglary feature class.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”SVCAREA” = \’North\’’
flayer = arcpy.MakeFeatureLayer_
management(“Burglary”,”Burglary_Layer”)
except Exception as e:
print(“Error: “ + e.args[0])
7. Call the SelectLayerByAttribute tool by passing in a reference to
the feature layer you just created along with the query you
defined earlier, and a constant that defines this as a new
selection set.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”SVCAREA” = \’North\’’
flayer = arcpy.MakeFeatureLayer_
management(“Burglary”,”Burglary_Layer”)
arcpy.SelectLayerByAttribute_management(flayer,
“NEW_SELECTION”, qry)
except Exception as e:
print(“Error: “ + e.args[0])
8. Get a count of the number of features selected and print it out.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”SVCAREA” = \’North\’’
flayer = arcpy.MakeFeatureLayer_
management(“Burglary”,”Burglary_Layer”)
arcpy.SelectLayerByAttribute_management(flayer,
“NEW_SELECTION”, qry)
cnt = arcpy.GetCount_management(flayer)
print(“The number of selected records is: “ + str(cnt))
except Exception as e:
print(“Error: “ + e.args[0])
9. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\SelectLayerAttribute.py
10. Typically we think of a selection set as being a visible operation
performed in ArcGIS Pro where the features that have been
selected are symbolized differently. However, a script that
creates a selection set does not have to be run directly inside
ArcGIS Pro. It can also be run from a stand-alone script. To see
this in action, run the SelectLayerAttribute.py script from
PyCharm. If everything has been done correctly you should see
a message indicating that 7520 records have been selected.
The number of selected records is: 7520
In conclusion…
The creation of a selection set using the Select by Location or Select
Layer by Attributes tool requires an input feature layer or table view
along with a properly constructed attribute query in the case of the
Select Layer by Attributes tool.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file SelectByLocation and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
set the current workspace to the CityOfSanAntonio geodatabase.
5. Create a feature layer from the Burglary feature class.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Call the SelectLayerbyLocation tool, passing in a reference to the
feature layer you just created. The spatial relationship test will
be COMPETELY_WITHIN, meaning that we want to find all
burglaries that are completely within the boundaries of the
comparison layer. Define EdgewoodSD as the comparison layer.
Also, get a count of the number of features selected and print it
out.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
arcpy.SelectLayerByLocation_management(flayer,
“COMPLETELY_WITHIN”, “EdgewoodSD”)
cnt = arcpy.GetCount_management(flayer)
print(“The number of selected records is: “ + str(cnt))
except Exception as e:
print(“Error: “ + e.args[0])
7. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\SelectByLocation.py
8. Run the script. If everything was done correctly, you should see
a message indicating that 1470 records have been selected.
The number of selected records is: 1470
9. In the last example we did not define the optional search
distance and select type parameters. By default, a new selection
will be applied as the selection type. We didn’t apply a distance
parameter in this case, but we’ll do this in the next step to
illustrate how it works. Update the line of code that calls the
SelectLayerByLocation tool as seen below.
arcpy.SelectLayerByLocation_management (flayer,
“WITHIN_A_DISTANCE”, “EdgewoodSD”,”1 MILES”)
10. Run the script again in PyCharm. You should now see a
message indicating that 2976 records have been selected. This
will select all burglaries within one mile of the boundary.
The total number of selected records is 2976
11. The final thing you’ll do in this exercise is use the CopyFeatures
tool to write the temporary layer to a new feature class.
Comment out the two lines of code that get a count of the
number of features and print them to the screen.
#cnt = arcpy.GetCount_management(flayer)
#print(“The number of selected records is: “ + str(cnt))
12. Add a line of code that calls the CopyFeatures tool. This line
should be placed just below the line of code that calls the
SelectLayerByLocation tool. The CopyFeatures tool accepts a
feature layer as the first input parameter and an output feature
class, which in this case will be a feature class called
Edgewood_Burglaries.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
arcpy.SelectLayerByLocation_management (flayer,
“WITHIN_A_DISTANCE”, “EdgewoodSD”,”1 MILES”)
arcpy.CopyFeatures_management(flayer, “EDGEWOOD_
BURGLARIES”)
#cnt = arcpy.GetCount_management(flayer)
#print(“The number of selected records is: “ +
str(cnt))
except Exception as e:
print(“Error: “ + e.args[0])
In conclusion…
The Select by Location tool is used to select features from a layer that
meet a spatial relationship and use an input feature layer.
How to do it…
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file SpatialAttributeQuery and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module, set up a basic try/except structure, and
set the current workspace to the CityOfSanAntonio geodatabase.
5. Create a variable for the query and define the where clause.
This query will select records where the DOW field is equal to
Mon. In other words, burglaries that occurred on a Monday.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”DOW” = \’Mon\’’
except Exception as e:
print(“Error: “ + e.args[0])
6. Create the feature layer from the Burglary layer.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”DOW” = \’Mon\’’
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
except Exception as e:
print(“Error: “ + e.args[0])
7. Run the SelectLayerByLocation tool to find all burglaries within
the Edgwood School District.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”DOW” = \’Mon\’’
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
arcpy.SelectLayerByLocation_management(flayer,
“COMPLETELY_WITHIN”, “EdgewoodSD”)
except Exception as e:
print(“Error: “ + e.args[0])
8. Run the SelectLayerByAttributes tool to find all the burglaries
that match the query we previously defined in the qry variable.
This should be defined as a subset query.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”DOW” = \’Mon\’’
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
arcpy.SelectLayerByLocation_management(flayer,
“COMPLETELY_WITHIN”, “EdgewoodSD”)
arcpy.SelectLayerByAttribute_management(flayer,
“SUBSET_SELECTION”, qry)
except Exception as e:
print(“Error: “ + e.args[0])
9. Get the number of features that were selected and print it out.
import arcpy
arcpy.env.workspace =
“C:/Student/ProgrammingPro/Databases/CityOfSanAntonio.gdb”
try:
qry = ‘”DOW” = \’Mon\’’
flayer = arcpy.MakeFeatureLayer_management(“Burglary”,
“Burglary_Layer”)
arcpy.SelectLayerByLocation_management(flayer,
“COMPLETELY_WITHIN”, “EdgewoodSD”)
arcpy.SelectLayerByAttribute_management(flayer,
“SUBSET_SELECTION”, qry)
cnt = arcpy.GetCount_management(flayer)
print(“The total number of selected records is: “
+ str(cnt))
except Exception as e:
print(“Error: “ + e.args[0])
10. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\SpatialAttributeQuery.py
11. Run the script and you should see that 197 features have been
selected.
The total number of selected features is: 197
In conclusion…
Using a combination of the Select Layer by Attributes and Select by
Location tools run in sequence you can perform queries that have both
spatial and attribute components.
Using the Arcpy
Data Access Module
In this chapter, we will cover the following topics:
We’ll start this chapter with a basic question. What are cursors?
Cursors are in-memory objects containing one or more rows of data
from a table or feature class. Each row contains the attributes from
each field in the data source, along with the geometry for each feature
in the case of a feature class. Cursors allow you to search, add, insert,
update, and delete data from tables and feature classes.
The arcpy Data Access module or arcpy.da contains methods that allow
you to iterate through each row in a cursor. Various types of cursors
can be created depending upon the needs. For example, search cursors
can be created to read values from rows. Update cursors can be
created to update values in rows or delete rows, and insert cursors can
be created to insert new rows.
There are a number of cursor improvements that have been
introduced with the arcpy.da module. Prior to ArcGIS Desktop 10.1,
cursor performance had been notoriously slow. Now, cursors are
significantly faster. Esri has estimated that SearchCursors are up to 30
times faster while InsertCursors are up to 12 times faster.
In addition to these general performance improvements, the arcpy.da
module also provides a number of options that allow programmers to
speed up processing. Rather than returning all the fields in a cursor,
you can now specify that a subset of fields be returned. This increases
the performance, as less data needs to be returned. The same applies
to geometry. Traditionally, when accessing the geometry of a feature,
the entire geometric definition would be returned. You can now use
geometry tokens to return a portion of the geometry rather than the
full geometry for the feature. You can also use lists and tuples rather
than using rows. Also new are edit sessions and the ability to work
with versions, domains, and subtypes.
There are three cursor functions in arcpy.da. Each returns a cursor
object of the same name as the function. SearchCursor() creates a read-
only SearchCursor object containing rows from a table or feature class.
InsertCursor() creates an InsertCursor object that can be used to insert
new records into a table or feature class. UpdateCursor() returns a
cursor object that can be used to edit or delete records from a table or
feature class. Each of these cursor objects has methods for accessing
rows in the cursor. You can see the relationship between the cursor
functions, the objects they create, and how they are used as follows:
The SearchCursor() function is used to return a SearchCursor object. This
object can only be used to iterate through a set of rows returned for
read-only purposes. No insertions, deletions, or updates can occur
through this object. An optional where clause can be set to limit the
rows returned.
Once you’ve obtained a cursor instance, it is common to iterate the
records, particularly with a SearchCursor or UpdateCursor. There are
some peculiarities that you need to understand about navigating the
records in a cursor. Cursor navigation is forward moving only. A for
loop is typically used to iterate the contents of cursor objects one
record at a time. However, cursor objects do not provide the ability to
move backward one row at a time. The reset() method does provide a
way to “start-over” since it resets the cursor pointer to the top of the
cursor.
The InsertCursor() function is used to create an InsertCursor object that
allows you to programmatically add new records to feature classes
and tables. To insert rows call the insertRow() method on this object.
You can also retrieve a read-only tuple containing the field names in
use by the cursor through the fields property. A lock is placed on the
table or feature class being accessed through the cursor. It’s important
to always design your script in a way that releases the cursor when
you are done.
The UpdateCursor() function can be used to create an UpdateCursor
object that can update and delete rows in a table or feature class. As is
the case with an InsertCursor, this function places a lock on the data
while it’s being edited or deleted. If the cursor is used inside a Python
with a statement, the lock will automatically be freed after the data has
been processed. This hasn’t always been the case. Prior to ArcGIS
Desktop 10.1, cursor locks had to be explicitly released using the del
statement. Once an instance of UpdateCursor has been obtained, you
can then call the updateCursor() method to update records in tables or
feature classes and the deleteRow() method to delete a row.
The subject of data locks requires a little more explanation. Insert and
update cursors must obtain a lock on the data source they reference.
This means that no other application can concurrently access this data
source. Locks are a way of preventing multiple users from changing
data at the same time and thus corrupting the data. When the
InsertCursor() and UpdateCursor() methods are called in your code,
Python attempts to acquire a lock on the data. This lock must be
released after the cursor has finished processing, so that other users
running applications such as ArcGIS Pro, ArcMap or ArcCatalog can
access the data sources. Otherwise, no other application will be able to
access the data. Similarly, ArcGIS Pro acquires a data lock when
updating or deleting data. If a data source has been locked by either of
these applications, your Python code will not be able to access the
data. Therefore, best practice is to close ArcGIS Pro before running
any standalone Python scripts that use insert or update cursors.
In this chapter, we’re going to cover the use of cursors for accessing
and editing tables and feature classes.
How to do it…
Follow these steps to learn how to retrieve rows from a table or
feature class inside a SearchCursor object:
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file SearchCursor and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy.da module and set up a basic try/except
structure. Also, set the current workspace to
c:\Student\ProgrammingPro\Databases.
import arcpy.da
arcpy.env.workspace =
r”c:\Student\ProgrammingPro\Databases”
try:
except Exception as e:
print(“Error: “ + e.args[0])
5. Create a SearchCursor object using the Schools shapefile and
return the Facility and Name fields.
import arcpy.da
arcpy.env.workspace = r”c:\Student\ProgrammingPro\Databases”
try:
with arcpy.da.SearchCursor(“Schools.shp”, (“Facility”,
“Name”)) as cursor:
except Exception as e:
print(“Error: “ + e.args[0])
6. Loop through the records returned in the cursor, and print out
the school name.
import arcpy.da
arcpy.env.workspace = r”c:\Student\ProgrammingPro\Databases”
try:
with arcpy.da.SearchCursor(“Schools.shp”, (“Facility”,
“Name”)) as cursor:
for row in sorted(cursor):
print(“School name: “ + row[1])
except Exception as e:
print(“Error: “ + e.args[0])
7. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\SearchCursor_Step1.py
8. Run the script and you should see the output as shown in the
screenshot below. Please note that the text you see below is only
a portion of what you’ll see due to space limitations.
School name: ALLAN
School name: ALLISON
School name: ANDREWS
School name: BARANOFF
School name: BARRINGTON
School name: BARTON CREEK
School name: BARTON HILLS
School name: BATY
School name: BECKER
School name: BEE CAVE
In Conclusion…
The with statement, used with the SearchCursor() function, will create,
open, and close the cursor. So, you no longer have to be concerned
with explicitly releasing the lock on the cursor. The first parameter
passed into the SearchCursor() function is a feature class, represented
by the Schools.shp file. The second parameter is a Python tuple
containing a list of fields that we want returned in the cursor. For
performance reasons, it is a best practice to limit the fields returned in
the cursor to only those that you need to complete the task. Here,
we’ve specified that only the Facility and Name fields should be
returned. The SearchCursor object is stored in a variable called cursor.
Inside the with block, we are using a Python for loop to cycle through
each school returned. We’re also using the Python sorted() function to
sort the contents of the cursor. To access the values from a field on the
row, simply use the index number of the field you want to return. In
this case, we want to return the contents of the Name column, which
will be index number 1, since it is the second item in the tuple of field
names that are returned.
How to do it…
Follow these steps to apply a filter to a SearchCursor object that
restricts the rows returned from a table or feature class:
In conclusion…
We covered the creation of queries in Chapter 8: Querying and Selecting
Data, so hopefully you now have a good grasp of how these are
created along with all the rules you need to follow when coding these
structures. The where clause parameter accepts any valid SQL query,
and is used in this case to restrict the number of records that are
returned.
How to do it…
We will be importing North American wildland fire incident data
from a single day in October, 2007. This data is contained in a comma-
delimited text file containing one line for each fire incident on that
particular day. Each fire incident has a latitude, longitude coordinate
pair separated by commas along with a confidence value. This data
was derived by automated methods that use remote sensing data to
derive the presence or absence of a wildfire. Confidence values can
range from 0 to 100. Higher numbers represent a greater confidence
that this is indeed a wildfire:
except Exception as e:
print(“Error: “ + e.args[0])
8. Use the Python open() function to open the
NorthAmericaWildfires_2007275.txt file in read only mode, and
read all the lines into a Python list structure. In this step you’ll
also add a finally block that will close the file when you are
done reading the data.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
f = open(r”C:\Student\ProgrammingPro\Databases\
NorthAmericaWildfires_2007275.txt”, “r”)
lstFiles = f.readlines()
except Exception as e:
print(“Error: “ + e.args[0])
finally:
f.close()
9. Create an InsertCursor object that references the FireIncidents
feature class along with the SHAPE field information and
CONFIDENCEVALUE field.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
f = open(r”C:\Student\ProgrammingPro\Databases\
NorthAmericaWildfires_2007275.txt”, “r”)
lstFires = f.readlines()
with arcpy.da.InsertCursor(“FireIncidents”,
(“SHAPE@XY”,”CONFIDENCEVALUE”)) as cur:
except Exception as e:
print(“Error: “ + e.args[0])
finally:
f.close()
10. Loop through the text file line-by-line using a for loop. Since the
text file is comma-delimited, we’ll use the Python split()
function to separate each value into a list variable called vals.
We’ll then pull out the individual latitude, longitude, and
confidence value items and assign them to variables. Finally,
we’ll place these values into a list variable called rowValue,
which is then passed into the insertRow() function for the
InsertCursor object, and we print a message:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
f = open(r”C:\Student\ProgrammingPro\Databases\
NorthAmericaWildfires_2007275.txt”, “r”)
lstFires = f.readlines()
with arcpy.da.InsertCursor(“FireIncidents”,
(“SHAPE@XY”,”CONFIDENCEVALUE”)) as cur:
cntr = 1
for fire in lstFires:
if ‘Latitude’ in fire:
continue
vals = fire.split(“,”)
latitude = float(vals[0])
longitude = float(vals[1])
confid = int(vals[2])
rowValue = [(longitude,latitude),confid]
cur.insertRow(rowValue)
print(“Record number “ + str(cntr) + “ written
to feature class”)
cntr = cntr + 1
except Exception as e:
print(“Error: “ + e.args[0])
finally:
f.close()
11. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\InsertWildfires.py
12. Run the script. You should see the output below:
Record number 1 written to feature class
Record number 2 written to feature class
Record number 3 written to feature class
Record number 4 written to feature class
Record number 5 written to feature class
Record number 6 written to feature class
Record number 7 written to feature class
Record number 8 written to feature class
Record number 9 written to feature class
.......
.......
Record number 410 written to feature class
Record number 411 written to feature class
13. Open ArcGIS Pro and create a new project called Wildfires
using the Map template. You can save the project to the My
Projects folder
14. Click the Add Data button and navigate to
c:\Student\ProgrammingPro\Databases\WildlandFires.gdb and add
the FireIncidents feature class. You should see something similar
to the screenshot below.
In Conclusion…
Some additional explanation may be needed here. The lstFires variable
contains a list of all the wildfires that were contained in the comma-
delimited text file. The for will loop through each of these records one
by one, inserting each individual record into the fire variable. We also
include an if statement that is used to skip the first record in the file,
which serves as the header.
As I explained earlier, we then pull out the individual latitude,
longitude, and confidence value items from the vals variable, which is
just a Python list object and assign them to variables called latitude,
longitude, and confid. We then place these values into a new list
variable called rowValue in the order that we defined when we created
InsertCursor. That is, the latitude and longitude pair should be placed
first followed by the confidence value. Finally, we call the insertRow()
function on the InsertCursor object assigned to the variable cur, passing
in the new rowValue variable. We close by printing a message that
indicates the progress of the script and also creating except and finally
blocks to handle errors and close the text file. Placing the file.close()
method in the finally block ensures that it will execute, and close the
file, even if there is an error in the previous try statement.
How to do it…
Follow these steps to create an UpdateCursor object that will be used to
edit rows in a feature class:
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file UpdateWildfires and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to
c:\Student\ProgrammingPro\Databases\WildlandFires.gdb.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
except Exception as e:
print(“Error: “ + e.args[0])
5. Add a new field called CONFID_RATING to the FireIncidents
feature class. Make sure to indent inside the try statement:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
arcpy.AddField_management(“FireIncidents”, “CONFID_
RATING”, “TEXT”, “10”)
print(“CONFID_RATING field added to FireIncidents”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Create a new instance of UpdateCursor inside a with block
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
arcpy.AddField_management(“FireIncidents”, “CONFID_
RATING”, “TEXT”, “10”)
print(“CONFID_RATING field added to FireIncidents”)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
except Exception as e:
print(“Error: “ + e.args[0])
7. Loop through each of the rows in the FireIncidents fire class.
Update the CONFID_RATING field according to the following
guidelines:
Confidence value 0 to 40 = POOR
Confidence value 41 to 60 = FAIR
Confidence value 61 to 85 = GOOD
Confidence value 86 to 100 = EXCELLENT
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
arcpy.AddField_management(“FireIncidents”, “CONFID_
RATING”, “TEXT”, “10”)
print(“CONFID_RATING field added to FireIncidents”)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
cntr = 1
for row in cursor:
# update the confid_rating field
if row[0] <= 40:
row[1] = ‘POOR’
elif row[0] > 40 and row[0] <= 60:
row[1] = ‘FAIR’
elif row[0] > 60 and row[0] <= 85:
row[1] = ‘GOOD’
else:
row[1] = ‘EXCELLENT’
cursor.updateRow(row)
print(“Record number “ + str(cntr) + “ updated”)
cntr = cntr + 1
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\UpdateWildfires.py.
9. Make sure the FireIncidents layer has been removed from your
map in ArcGIS Pro before running the script. Otherwise the
script won’t be able to acquire a lock on the dataset.
10. Run the script. You should see messages being written to the
output windows as the script runs:
Record number 406 updated
Record number 407 updated
Record number 408 updated
Record number 409 updated
Record number 410 updated
Record number 411 updated
11. Examine the FireIncidents feature class in ArcGIS Pro. Open the
attribute table and you should see that a new CONFID_RATING
field has been added and populated by the UpdateCursor.py
script.
When you insert, update, or delete data in cursors, the changes
are permanent and can’t be undone if you’re working outside an
edit session. However, with edit session functionality, you can
now make these changes inside an edit session to avoid these
problems. We’ll cover edit sessions soon.
In Conclusion…
In this case, we’ve used UpdateCursor to update each of the features in
a feature class. We first used the Add Field tool to add a new field
called CONFID_RATING, which will hold new values that we assign
based on values found in another field. The groups are POOR, FAIR,
GOOD, and EXCELLENT and are based on numeric values found in
the CONFIDENCEVALUE field. We then created a new instance of
UpdateCursor based on the FireIncidents feature class, and returned the
two fields mentioned previously. The script then loops through each
of the features and assigns a value of POOR, FAIR, GOOD, or
EXCELLENT to the CONFID_RATING field (row[1]), based on the
numeric value found in CONFIDENCEVALUE. A Python if/elif/else
structure is used to control the flow of the script based on the numeric
value. The value for CONFID_RATING is then committed to the
feature class by passing in the row variable into the updateRow()
method.
How to do it…
Follow these steps to create an UpdateCursor object that will be used
delete rows from a feature class:
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file DeleteWildfires and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to
c:\Student\ProgrammingPro\Databases\WildlandFires.gdb.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
except Exception as e:
print(“Error: “ + e.args[0])
5. Create an UpdateCursor object for the FireIncidents feature class
inside a with block.
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
with arcpy.da.UpdateCursor(“FireIncidents”, (“CONFID_
RATING”), ‘CONFID_RATING = \’POOR\’’) as cursor:
except Exception as e:
print(“Error: “ + e.args[0])
6. Delete the returned rows by calling the deleteRow() method.
This is done by looping through the returned cursor and
deleting the rows one at a time:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
with arcpy.da.UpdateCursor(“FireIncidents”, (“CONFID_
RATING”), ‘CONFID_RATING = \’POOR\’’) as cursor:
cntr = 1
for row in cursor:
cursor.deleteRow()
print(“Record number “ + str(cntr) + “ deleted”)
cntr = cntr + 1
except Exception as e:
print(“Error: “ + e.args[0])
7. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\DeleteWildfires.py
8. Make sure the FireIncidents layer has been removed from your
map in ArcGIS Pro before running the script. Otherwise the
script won’t be able to acquire a lock on the dataset.
9. Run the script. You should see messages being written to the
output window as the script runs. 37 records should be deleted
from the FireIncidents feature class:
Record number 1 deleted
Record number 2 deleted
Record number 3 deleted
Record number 4 deleted
Record number 5 deleted
In Conclusion…
Rows from feature classes and tables can be deleted using the
deleteRow() method on UpdateCursor. In this recipe, we used a where
clause in the constructor for UpdateCursor to limit the records returned
to only those features with a CONFID_RATING of POOR. We then
looped through the features returned in the cursor and called the
deleteRow() method to delete the row from the feature class.
Edit sessions can also be ended without saving changes. In this event,
changes are not permanently applied. Edit sessions also allow for
operations to be applied inside the session and then either applied
permanently to the database or rolled back. In addition, the Editor
class also supports undo and redo operations.
The following code example shows the full edit session stack
including the creation of the Editor object, the beginning of an edit
session and an operation, edits to the data (an insert in this case),
stopping the operation, and finally the end of the edit session by
saving the data:
edit = arcpy.da.Editor(‘Database Connections/Portland.sde’)
edit.startEditing(False)
edit.startOperation()
with arcpy.da.InsertCursor(“Portland.jgp.schools”,(“SHAPE”,”Name”))
as cursor:
cursor.insertRow([7642471.100, 686465.725), ‘New School’])
edit.stopOperation()
edit.stopEditing(True)
The Editor class can be used with for file, and ArcSDE geodatabases. In
addition, sessions can also be started and stopped on versioned
databases. You are limited to editing only a single workspace at a
time, and this workspace is specified in the constructor for the Editor
object simply by passing in a string that references the workspace.
Once created, this Editor object then has access to all the methods for
starting, stopping, and aborting operations, and performing undo and
redo operations.
How to do it…
Follow these steps to wrap UpdateCursor inside an edit session:
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file EditSessionUpdateWildfires and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to
c:\Student\ProgrammingPro\Databases\WildlandFires.gdb.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
except Exception as e:
print(“Error: “ + e.args[0])
5. Create an instance of the Editor class and start an edit session.
These lines of code should be placed just inside the try block:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
edit = arcpy.da.Editor(r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”)
edit.startEditing(True)
except Exception as e:
print(“Error: “ + e.args[0])
6. Create an UpdateCursor object using a with statement:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
edit = arcpy.da.Editor(r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”)
edit.startEditing(True)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
except Exception as e:
print(“Error: “ + e.args[0])
7. Loop through the records in the cursor and apply the attribute
edits as seen below
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
edit = arcpy.da.Editor(r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”)
edit.startEditing(True)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
cntr = 1
for row in cursor:
# update the confid_rating field
if row[0] > 40 and row[0] <= 60:
row[1] = ‘GOOD’
elif row[0] > 60 and row[0] <= 85:
row[1] = ‘BETTER’
else:
row[1] = ‘BEST’
except Exception as e:
print(“Error: “ + e.args[0])
8. Call the updateRow() method on the UpdateCursor object and
print out progress information.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
edit = arcpy.da.Editor(r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”)
edit.startEditing(True)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
cntr = 1
for row in cursor:
# update the confid_rating field
if row[0] > 40 and row[0] <= 60:
row[1] = ‘GOOD’
elif row[0] > 60 and row[0] <= 85:
row[1] = ‘BETTER’
else:
row[1] = ‘BEST’
cursor.updateRow(row)
print(“Record number “ + str(cntr) + “ updated”)
cntr = cntr + 1
except Exception as e:
print(“Error: “ + e.args[0])
9. End the edit session and save edits. This line of code should line
up to the with statement.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”
edit = arcpy.da.Editor(r”C:\Student\ProgrammingPro\
Databases\WildlandFires.gdb”)
edit.startEditing(True)
with arcpy.da.UpdateCursor(“FireIncidents”,
(“CONFIDENCEVALUE”, “CONFID_RATING”)) as cursor:
cntr = 1
for row in cursor:
# update the confid_rating field
if row[0] > 40 and row[0] <= 60:
row[1] = ‘GOOD’
elif row[0] > 60 and row[0] <= 85:
row[1] = ‘BETTER’
else:
row[1] = ‘BEST’
cursor.updateRow(row)
print(“Record number “ + str(cntr) + “ updated”)
cntr = cntr + 1
edit.stopEditing(True)
except Exception as e:
print(“Error: “ + e.args[0])
10. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\EditSessionUpdateWildfires.py
11. Make sure the FireIncidents layer has been removed from your
map in ArcGIS Pro before running the script. Otherwise the
script won’t be able to acquire a lock on the dataset.
12. Run the script. You should see messages being written to the
output window as the script runs. 374 records should be
updated from the FireIncidents feature class:
In Conclusion…
Edit operations should take place inside an edit session, which can be
initiated with the Editor.startEditing() method. The startEditing() method
takes two optional parameters including with_undo and
multiuser_mode. The with_undo parameter accepts a Boolean value of
true or false, with a default of true. This creates an undo/redo stack
when set to true. The multiuser_mode parameter defaults to true. When
false, you have full control of editing a non-versioned or versioned
dataset. If your dataset is non-versioned and you use
stopEditing(False), your edit will not be committed. Otherwise, if set to
true, your edits will be committed to the underlying dataset. The
Editor.stopEditing() method takes a single Boolean value of true or false,
indicating whether changes should be saved or not. This defaults to
true.
The Editor class supports undo and redo operations. We’ll first look at
undo operations. During an edit session, various edit operations can
be applied. In the event that you need to undo a previous operation, a
call to Editor.undoOperation() will remove the most previous edit
operation in the stack. This is illustrated as follows:
How to do it…
Follow these steps to learn how to use the da.Walk() function to
navigate directories and workspaces to reveal the structure of a
geodatabase:
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file DAWalk.py and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy and os modules and set up a basic try/except
structure. Also, set the current workspace to
c:\Student\ProgrammingPro\Databases.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
except Exception as e:
print(“Error: “ + e.args[0])
5. Call the Python os.walk() method and print out the filenames in
the current workspace.
import arcpy
import os
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
for dirpath, dirnames, filenames in
os.walk(arcpy.env.workspace):
for filename in filenames:
print(filename)
except Exception as e:
print(“Error: “ + e.args[0])
6. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\DAWalk.py
7. Run the script and you should see each of the file names in the
current workspace printed out. Although os.walk() can be used
to print all file names within a directory you’ll notice that it
doesn’t have an understanding of the structure of Esri GIS
format datasets like file geodatabases. Files like
a000000001.gdbindexes are physical files that make up a feature
class but os.walk() can’t tell you the logical structure of a feature
class. In the next step we’ll use da.walk() to resolve this problem.
Schools.dbf
Schools.prj
Schools.sbn
Schools.sbx
Schools.shp
Schools.shp.xml
Schools.shx
Zoning.lyrx
a00000001.freelist
a00000001.gdbindexes
a00000001.gdbtable
a00000001.gdbtablx
a00000002.gdbtable
a00000002.gdbtablx
a00000003.gdbindexes
a00000003.gdbtable
a00000003.gdbtablx
a00000004.CatItemsByPhysicalName.atx
a00000004.CatItemsByType.atx
a00000004.FDO_UUID.atx
a00000004.freelist
a00000004.gdbindexes
8. Update the code in the DAWalk script as seen below to use the
arcpy.da.Walk() method.
import arcpy.da
import os
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
for dirpath, dirnames, filenames in arcpy.da.Walk
(arcpy.env.workspace, datatype=”FeatureClass”):
for filename in filenames:
print(os.path.join(dirpath,filename))
except Exception as e:
print(“Error: “ + e.args[0])
9. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\DAWalk.py
10. Run the script and now you should see the individual feature
class names inside the geodatabases in addition to the
shapefiles in the current workspace.
C:\Student\ProgrammingPro\Databases\coa_parcels.shp
C:\Student\ProgrammingPro\Databases\Schools.shp
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\Crimes2009
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\CityBoundaries
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\CrimesBySchoolD
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\SchoolDistricts
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\BexarCountyBoun
C:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb\Texas_Counties_L
In Conclusion…
The arcpy.da module includes a walk() function that is capable of
reading the internal structure of a geodatabase. This function is
similar to the Python os.walk() function, which doesn’t have the ability
to understand the logical structure of a geodatabase.
How to do it…
Follow these steps to learn how to obtain descriptive information
about a feature class.
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file DescribeFeatureClass and click OK. The file should
be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to
c:\Student\ProgrammingPro\Databases\CityOfSanAntonio.gdb.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\CityOfSanAntonio.gdb”
except Exception as e:
print(“Error: “ + e.args[0])
5. Call the Describe() function on the Burglary feature class and
print out the shape type:
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\CityOfSanAntonio.gdb”
desc = arcpy.da.Describe(“Burglary”)
print(“The shape type is: “ + desc[‘shapeType’])
except Exception as e:
print(“Error: “ + e.args[0])
6. Get a list of fields in the feature class and print out the name,
type, and length of each.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\CityOfSanAntonio.gdb”
desc = arcpy.da.Describe(“Burglary”)
print(“The shape type is: “ + desc[‘shapeType’])
for fld in desc[‘fields’]:
print(“Field: “ + fld.name)
print(“Type: “ + fld.type)
print(“Length: “ + str(fld.length))
except Exception as e:
print(“Error: “ + e.args[0])
7. Get the geographic extent of the feature class and print out the
coordinates that define the extent.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases\CityOfSanAntonio.gdb”
desc = arcpy.da.Describe(“Burglary”)
print(“The shape type is: “ + desc[‘shapeType’])
for fld in desc[‘fields’]:
print(“Field: “ + fld.name)
print(“Type: “ + fld.type)
print(“Length: “ + str(fld.length))
ext = desc[‘extent’]
print(“XMin: %f” % (ext.XMin))
print(“YMin: %f” % (ext.YMin))
print(“XMax: %f” % (ext.XMax))
print(“YMax: %f” % (ext.YMax))
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\DescribeFeatureClass.py
9. Run the script and you should see a print out of the shape type,
fields, and extent as seen below:
The shape type is: Point
Field: OBJECTID
Type: OID
Length: 4
Field: Shape
Type: Geometry
Length: 0
Field: CASE
Type: String
Length: 11
Field: LOCATION
Type: String
Length: 40
....
....
XMin: -103.518030
YMin: -6.145758
XMax: -98.243208
YMax: 29.676404
In conclusion…
Performing a Describe() against a feature class, which we have done in
this script, returns a FeatureClass property group along with access to
the Table and Dataset property groups, respectively. In addition to
returning a FeatureClass property group, you also have access to a
Table properties group.
The Table property group is important primarily because it gives you
access to the fields in a standalone table or feature class. You can also
access any indexes on the table or feature class through this property
group. The Fields property in Table properties returns a Python list
containing one Field object for each field in the feature class. Each field
has a number of read-only properties including the name, alias, length,
type, scale, precision, and so on. The most obviously useful properties
are name and type. In this script, we printed out the field name, type,
and length. Note the use of a Python for loop to process each field in
the Python list.
Finally, we printed out the geographic extent of the layer through the
use of the Extent object, returned by the extent property in the Dataset
property group. The Dataset property group contains a number of
useful properties. Perhaps the most used properties include extent and
spatialReference, as many geoprocessing tools and scripts require this
information at some point during execution. You can also obtain the
datasetType and versioning information along with several other
properties.
How to do it…
Follow these steps to learn how to obtain descriptive information
about a raster image file.
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file DescribeRaster and click OK. The file should be
written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy module and set up a basic try/except structure.
Also, set the current workspace to
C:\Student\ProgrammingPro\Databases.
import arcpy
try:
arcpy.env.workspace = r” C:\Student\ProgrammingPro\
Databases”
except Exception as e:
print(“Error: “ + e.args[0])
5. Call the Describe() function on a raster dataset.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
desc = arcpy.da.Describe(“AUSTIN_EAST_NW.sid”)
except Exception as e:
print(“Error: “ + e.args[0])
6. Get the extent of the raster dataset and print it out.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
desc = arcpy.da.Describe(“AUSTIN_EAST_NW.sid”)
ext = desc[‘extent’]
print(“XMin: %f” % (ext.XMin))
print(“YMin: %f” % (ext.YMin))
print(“XMax: %f” % (ext.XMax))
print(“YMax: %f” % (ext.YMax))
except Exception as e:
print(“Error: “ + e.args[0])
7. Get a reference to the SpatialReference object and print it out.
import arcpy
try:
arcpy.env.workspace = r”C:\Student\ProgrammingPro\
Databases”
desc = arcpy.da.Describe(“AUSTIN_EAST_NW.sid”)
ext = desc[‘extent’]
print(“XMin: %f” % (ext.XMin))
print(“YMin: %f” % (ext.YMin))
print(“XMax: %f” % (ext.XMax))
print(“YMax: %f” % (ext.YMax))
sr = desc[‘spatialReference’]
print(sr.name)
print(sr.type)
except Exception as e:
print(“Error: “ + e.args[0])
8. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\DescribeRaster.py
9. Run the script and you should see a print out of the extent and
spatial reference as seen below:
XMin: 3111134.862457
YMin: 10086853.262238
XMax: 10086853.262238
YMax: 10110047.019228
NAD_1983_Texas_Central
Projected
In conclusion…
This exercise is very similar to the previous. The difference is that
we’re using the Describe() function against a raster dataset instead of a
vector feature class. In both cases, we’ve returned the geographic
extent of the datasets using the Extent object. However, in the script,
we’ve also obtained the SpatialReference object for the raster dataset
and printed out information about this object including its name and
type.
Creating Custom
Geoprocessing Tools
In this chapter, we will cover the following exercises:
How to do it…
The custom Python geoprocessing scripts that you write can be added
to custom toolboxes. You are not allowed to add your scripts to any of
the system toolboxes, such as Analysis or Data Management. However,
by creating a new custom toolbox, you can add these scripts.
1. Open PyCharm
2. Select File | New | Python File.
3. Name the file InsertWildfiresToolbox and click OK. The file
should be written to your default project location of
c:\Student\ProgrammingPro\Scripts folder.
4. Import the arcpy and os modules and set up a basic try/except
structure.
import arcpy, os
try:
except Exception as e:
print(“Error: “ + e.args[0])
5. Create variables to hold the output feature class, feature class
template, and text file. Use the arcpy.GetParameterAsText()
function to retrieve these values from the script tool dialog.
import arcpy, os
try:
outputFC = arcpy.GetParameterAsText(0)
fClassTemplate = arcpy.GetParameterAsText(1)
f = open(arcpy.GetParameterAsText(2), ‘r’)
except Exception as e:
print(“Error: “ + e.args[0])
6. Create a new feature class using the input provided by the user
in the first parameter.
import arcpy, os
try:
outputFC = arcpy.GetParameterAsText(0)
fClassTemplate = arcpy.GetParameterAsText(1)
f = open(arcpy.GetParameterAsText(2), ‘r’)
arcpy.CreateFeatureclass_management(
os.path.split(outputFC)[0],
os.path.split(outputFC)[1],
“point”,
fClassTemplate)
except Exception as e:
print(“Error: “ + e.args[0])
7. Read each of the lines in the text file into a Python list.
import arcpy, os
try:
outputFC = arcpy.GetParameterAsText(0)
fClassTemplate = arcpy.GetParameterAsText(1)
f = open(arcpy.GetParameterAsText(2), ‘r’)
arcpy.CreateFeatureclass_management(
os.path.split(outputFC)[0],
os.path.split(outputFC)[1],
“point”,
fClassTemplate)
lstFires = f.readlines()
except Exception as e:
print(“Error: “ + e.args[0])
8. Defines a Python list containing the fields to be used when
inserting geometry and attributes.
import arcpy, os
try:
outputFC = arcpy.GetParameterAsText(0)
fClassTemplate = arcpy.GetParameterAsText(1)
f = open(arcpy.GetParameterAsText(2), ‘r’)
arcpy.CreateFeatureclass_management(
os.path.split(outputFC)[0],
os.path.split(outputFC)[1],
“point”,
fClassTemplate)
lstFires = f.readlines()
fields = [“SHAPE@XY”, “CONFIDENCEVALUE”]
except Exception as e:
print(“Error: “ + e.args[0])
9. Create an InsertCursor from the feature class, loop through each
of the fires found in the text file, extract the coordinates and
confidence value attributes, and insert the information into the
output feature class.
try:
outputFC = arcpy.GetParameterAsText(0)
fClassTemplate = arcpy.GetParameterAsText(1)
f = open(arcpy.GetParameterAsText(2), ‘r’)
arcpy.CreateFeatureclass_management(
os.path.split(outputFC)[0],
os.path.split(outputFC)[1],
“point”,
fClassTemplate)
lstFires = f.readlines()
fields = [“SHAPE@XY”, “CONFIDENCEVALUE”]
with arcpy.da.InsertCursor(outputFC, fields) as cur:
for fire in lstFires:
if ‘Latitude’ in fire:
continue
vals = fire.split(“,”)
latitude = float(vals[0])
longitude = float(vals[1])
confid = int(vals[2])
row_values = [(longitude, latitude), confid]
cur.insertRow(row_values)
except Exception as e:
print(“Error: “ + e.args[0])
10. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\InsertWildfiresToolbox.py.
Now we’ll attach the script to a tool using the ArcGIS Pro
interface.
11. Open ArcGIS Pro and create a new project using the Map
template. Name the project CustomWildfireTool and save it in
the c:\Student\ProgrammingPro\My Projects folder.
12. In the Catalog pane open the Toolboxes folder and find the
CustomWildfireTool.tbx toolbox.
13. Right click CustomWildfireTool.tbx and select New | Script.
14. The General dialog will be displayed initially. Here you will
enter the following parameters.
Name: InsertWildfires
Label: Insert Wildfires
Script File:
c:\Student\ProgrammingPro\Scripts\InsertWildfiresToolbox.py
15. Click the Parameters tab and enter the parameters seen in the
screenshot below.
16. This tool won’t include any custom validation so you can click
OK to create the custom script tool seen in the screenshot
below.
17. Before running the tool you’ll need to create a connection to the
geodatabase containing the Wildfire geodatabase. In the Catalog
pane, Open the Databases folder and select Add Database.
18. Navigate to the c:\Student\ProgrammingPro\Databases folder and
select WildlandFires.gdb.
19. Double click the InsertWildfires tool found in the
CustomWildfireTool toolbox and fill in the parameters as
defined below:
Output Feature Class –
C:\Student\ProgrammingPro\Databases\WildlandFires.gdb\TodaysWildfires
Attribute Template –
C:\Student\ProgrammingPro\Databases\WildlandFires.gdb\FireIncidents
Wildfire Data File –
C:\Student\ProgrammingPro\Databases\NorthAmericaWildfires_2007275.tx
20. Click Run to execute the tool. If everything goes correctly you
should see the TodaysWildfires layer added to the Contents
pane.
In conclusion…
Custom script tools in a custom toolbox are used to provide a visual
interface to your Python scripts. End users of these tools don’t need to
understand anything about Python to use the tools. They look just like
every other tool in the ArcGIS Pro toolbox. These tools can be used to
accomplish a wide variety of geoprocessing tasks.
How to do it…
Complete the steps below to create a Python Toolbox and create a
custom tool that connects to an ArcGIS Server map service,
downloads real time data, and inserts it into a feature class.
5. By default, when you right click on the toolbox and select Edit,
ArcGIS Pro will automatically open your code in Notebook. To
change this to the development environment of your choice.
You can go to Project | Options | Geoprocessing and enter the
path to your development environment as seen in the
screenshot below. In this example I’ve provided the path to the
Community Edition of PyCharm. You’ll want to update this to
the path specific to your environment and development
environment.
12. Almost all tools have parameters, and you set their values on
the tool dialog box or within a script. When the tool is executed,
the parameter values are sent to your tool’s source code. Your
tool reads these values and proceeds with its work. You use the
getParameterInfo() method to define the parameters for your tool.
Individual Parameter objects are created as part of this process.
Add the following parameters in the getParameterInfo() method
and then we’ll discuss.
def getParameterInfo(self):
“””Define parameter definitions”””
# First parameter
param0 = arcpy.Parameter(
displayName=”ArcGIS Server Wildfire URL”,
name=”url”,
datatype=”GPString”,
parameterType=”Required”,
direction=”Input”)
param0.value =
“https://services9.arcgis.com/RHVPKKiFTONKtxq3/ArcGIS/
rest/services/USA_Wildfires_v1/FeatureServer/0/query”
# Second parameter
param1 = arcpy.Parameter(
displayName=”Output Feature Class”,
name=”out_fc”,
datatype=”DEFeatureClass”,
parameterType=”Required”,
direction=”Input”)
params = [param0, param1]
return params
Each Parameter object is created using arcpy.Parameter and is
passed a number of arguments that define the object.
For the first Parameter object (param0) we are going to capture a
URL to an ArcGIS Server map service containing current
wildfire data. We give it a display name (ArcGIS Server
Wildfire URL), which will be displayed on the dialog box for
the tool, a name for the parameter, a data-type, parameter type
(Required), and direction.
In the case of the first parameter (param0) we also assign an
initial value, which is the URL to an existing map service
containing wildfire data.
For the second parameter we’re defining an output feature class
where the wildfire data that is read from the map service will
be written. An empty feature class for storing the data has
already been created for you. Finally, we added both
parameters to a Python list called params and return the list to
the calling function
13. The main work of a tool is done inside the execute() method.
This is where the geoprocessing of your tool takes place. The
execute() method, seen below, can accept a number of
arguments including the tool (self), parameters, and messages.
def execute(self, parameters, messages):
“””The source code of the tool. “””
return
To access the parameter values that are passed into the tool you
can use the valueAsText() method. Add the following code to
access the parameter values that will be passed into your tool.
Remember from a previous step that the first parameter will
contain a URL to a map service containing wildfire data and the
second parameter is the output feature class where the data will
be written.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
At this point you have created a Python toolbox, added a tool,
defined the parameters for the tool, and created variables that
will hold the parameter values that the end user has defined.
Ultimately this tool will use the URL that is passed into the tool
to connect to an ArcGIS Server map service, download the
current wildfire data, and write the wildfire data to a feature
class. We’ll do that next.
14. Next, add the code that connects to the wildfire map service to
perform a query. In this step you will also define the QueryString
parameters that will be passed into the query of the map
service. First we’ll import the requests and json modules by
adding the code below. The requests module is part of the
standard conda installation associated with ArcGIS Pro. The
import statements should go at the very top of your script.
import requests, json
15. Then, create the payload variable that will hold the QueryString
parameters. Notice that in this case we have defined a where
clause so that only fires where the acres are greater than 5 will
be returned. The inFeatures variable holds the URL.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
agisurl = inFeatures
payload = { ‘where’: ‘DailyAcres > 5’,’f’:
‘pjson’, ‘outFields’:
‘IncidentName,DailyAcres’}
16. Submit the request to the ArcGIS Server instance and the
response should be stored in a variable called r.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
agisurl = inFeatures
payload = { ‘where’: ‘DailyAcres > 5’,’f’: ‘pjson’,
‘outFields’: ‘IncidentName,DailyAcres’}
r = requests.get(inFeatures, params=payload)
17. Let’s test the code to make sure we’re on the right track. Add
the code below to your script.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
agisurl = inFeatures
payload = { ‘where’: ‘DailyAcres > 5’,’f’: ‘pjson’,
‘outFields’: ‘IncidentName,DailyAcres’}
r = requests.get(inFeatures, params=payload)
arcpy.AddMessage(r.text)
18. Save the file and refresh your toolbox in the Catalog pane.
Execute the tool and accept the default URL. If everything is
working as expected you should see a JSON object output to the
progress dialog. To view the output you’ll need to mouse over
or click the message on the progress dialog. Your output will
probably vary somewhat because we’re pulling live data.
19. Return to the execute() method and convert the JSON object to a
Python dictionary. Also, comment out the arcpy.AddMessage()
function call you implemented in the last step.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
agisurl = inFeatures
payload = { ‘where’: ‘DailyAcres > 5’,’f’: ‘pjson’,
‘outFields’: ‘IncidentName,DailyAcres’}
r = requests.get(inFeatures, params=payload)
#arcpy.AddMessage(r.text)
decoded = json.loads(r.text)
20. Create an InsertCursor by passing in the output feature class
defined in the tool dialog along with the fields that will be
populated. We then start a for loop that loops through each of
the features (wildfires) that have been returned from the
request to the ArcGIS Server map service. The decoded
variable is a Python dictionary. Inside the for loop we retrieve
the IncidentName, and DailyAcres information from the attributes
dictionary and x and y information from the geometry
dictionary. Finally, we call the insertRow() method to insert a
new row into the feature class along with the fire name and
acres as attributes. Progress information is written to the
Progress Dialog and the counter is updated.
def execute(self, parameters, messages):
inFeatures = parameters[0].valueAsText
outFeatureClass = parameters[1].valueAsText
agisurl = inFeatures
payload = { ‘where’: ‘DailyAcres > 5’,’f’: ‘pjson’,
‘outFields’: ‘IncidentName,DailyAcres’}
r = requests.get(inFeatures, params=payload)
decoded = json.loads(r.text)
with arcpy.da.InsertCursor(outFeatureClass,
(“SHAPE@XY”, “NAME”, “ACRES”)) as cur:
cntr = 1
for rslt in decoded[‘features’]:
fireName =
rslt[‘attributes’][‘IncidentName’]
latitude =
rslt[‘geometry’][‘y’]
longitude =
rslt[‘geometry’][‘x’]
acres = rslt[‘attributes’][‘DailyAcres’]
cur.insertRow([(longitude,latitude),
fireName, acres])
arcpy.AddMessage(“Record number: “ + str(cntr) +
“ written to feature class”)
cntr = cntr + 1
21. You can check your code against a solution file found at
c:\Student\ProgrammingPro\Solutions\Scripts\RealTimeWildfireTool.py.
22. Save the file and refresh your Python toolbox
23. Double click the USGS Download tool.
24. Leave the default URL and select the RealTimeFires feature
class in the WildlandFires geodatabase. The RealTimeFires
feature class is empty and has fields for NAME and ACRES.
25. Click OK to execute the tool. The number of features written to
the feature class will vary depending upon the current wildfire
activity. Remember that this tool is pulling real time data from a
map service. Most of the time there is at least a little activity,
but it is possible (but not likely) that there wouldn’t be any
wildfires in the U.S. depending upon the time of year you run
the tool.
26. View the feature class in ArcGIS Pro to see the features. Your
output will vary since this is real-time wildfire data.
In conclusion…
Python toolboxes provide a new way of creating custom
geoprocessing tools. The creation of these tools, including the
definition of parameters, validation, and execution is encapsulated
into a single Python script.