Automate a geoprocessing workflow with Python

Open a project and review datasets

Before you begin using Python to run geoprocessing tools, you will download and review the datasets in ArcGIS Pro.

  1. Download the data for this lesson and extract the contents to a location on your computer.

    The .zip file contains a folder named PythonWorkflow.

    In this lesson, the data is shown at C:\Lessons\PythonWorkflow\. You can use a different folder, but if you do, you must adjust the paths in the instructions and code that follow.

  2. In the C:\Lessons\PythonWorkflow\ folder, double-click Workflow.aprx.

    The Workflow project opens in ArcGIS Pro.

  3. If the Catalog pane is not already visible, on the View tab, click Catalog Pane.
  4. In the Catalog pane, expand Folders and expand PythonWorkflow.
  5. Expand Transportation.gdb.

    The Transportation geodatabase expanded to show feature classes.

    The feature classes in this geodatabase are related to transportation. Suppose that you needed to build a network from theses feature classes. To make that possible, they would need to be stored in the same feature dataset and have the same coordinate systems. This is not currently the case.

    In this tutorial, you will use Python code to check the coordinate system of the feature classes and use the Project tool to convert any datasets that are not already in the correct coordinate system, copying them into a new geodatabase and feature dataset. This would allow you to create a network, though you will not build the network in this tutorial.

    Before working on the Python code, you will review the coordinate system of selected datasets and run the Project tool manually. This will give you information you will need to use Python code to automate the process.

  6. Right-click bike_racks and click Add To Current Map.

    Right-click the bike_racks feature class and add it to the current map.

  7. Use the same method to add the roads feature class to the map.

    These feature classes represent bicycle parking racks and roads within Washington, D.C.

    Next, you’ll review the coordinate systems of the two feature classes.

  8. In the Contents pane, right-click Map and click Properties.

    Open the Properties pane of the map.

  9. On the Map Properties: Map window, click Coordinate Systems.

    Click Coordinate Systems.

  10. Expand Layers, and expand the entries for the WGS 1984 and NAD 1983 StatePlane Maryland FIPS 1900 (US Feet) coordinate systems.

    Expand the two coordinate systems entries.

    The bike_racks feature class is in a geographic coordinate system named WGS 1984 while the road and boundary feature classes are in the projected State Plane coordinate system for Maryland, NAD 1983 StatePlane Maryland FIPS 1900 (US Feet).

    Your objective is to put all the feature classes in a dataset with the projected coordinate system.

  11. Click OK to close the Map Properties window.

    You have examined the geodatabase and identified the two coordinate systems used by the feature classes. Next, you will project one of the feature classes.

Project a feature class

Next you will project one of the feature classes and examine the parameters required for that tool.

  1. On the ribbon, click Analysis and in the Geoprocessing section, click Tools.

    Click Analysis and in the Geoprocessing section, click Tools.

    The Geoprocessing pane appears.

  2. In the Geoprocessing pane, click in the search box and type Project.
  3. In the search results, click Project (Data Management Tools).
  4. In the Project tool pane, for the Input Dataset or Feature Class parameter, choose bike_racks.
  5. For the Output Dataset or Feature Class name, click the browse button and browse to the Transportation geodatabase. Expand the geodatabase, and in the Name box, type bike_racks_sp. Click Save.
  6. For the Output Coordinate System, click the drop-down list and click roads.

    The Project tool with parameters set.

    Choosing roads sets the value for Output Coordinate System to the coordinate system of the roads feature class, the State Plane Maryland coordinate system.

    The Geographic Transformation parameter is set to WGS_1984_(ITRF00) To_NAD_1983, because the geographic coordinate systems of the input and the output are different.

    Note:

    A geographic transformation is necessary when the geographic coordinate systems of the input feature class and output feature class are different. When the geographic coordinate systems are identical, no list of values appears for this parameter. When a transformation is necessary, a drop-down list appears, based on the input and output geographic coordinate systems, and a default transformation is selected. You will rely on this default transformation in this lesson.

  7. Click Run.

    The Project tools runs, and the projected feature class is added to the active map.

    To prepare the data to be used in a network, you would need to repeat this process for every feature class in the geodatabase: check the coordinate system and decide whether you need to run the Project tool. Project the feature classes that must be projected. Copy the other feature classes without projecting them.

    Instead of repeating these steps manually, you will use Python code to automate the process.

  8. Close the Project tool.
  9. In the Catalog pane, right-click the bike_racks_sp feature class, click Delete, and click Yes to permanently delete the feature class.

    You are now ready to start the workflow using Python code.

Use Python to describe a feature class

The first step in the workflow is to examine the coordinate system of the feature classes. You will do this using Python code in the Python window.

  1. On the ribbon, click Analysis, and in the Geoprocessing section, click the drop-down arrow on the Python button, and click Python Window.

    Open the Python window.

  2. Click the prompt section at the bottom of the Python window, type the following code, and press Enter:

    desc = arcpy.da.Describe("bike_racks")

    Add code to describe the bike_racks feature class.

    When you press Enter, the code runs immediately. It doesn't print any information, but it creates a variable named desc and sets it equal to the result of running the Describe function on the bike_racks feature class.

    The Describe function returns a dictionary with the properties of the dataset. This gives you access to the spatial reference, among other properties.

  3. In the prompt section, add the following code and press Enter.

    sr = desc["spatialReference"]

    This sets the new variable named sr to the value stored at the SpatialReference key of the dictionary of dataset properties. The SpatialReference object contains all the relevant information about the coordinate system of the dataset. This allows you to check for specific properties.

  4. In the prompt section, add the following code and press Enter.

    print(sr.name)

    This prints the name of the spatial reference object.

    Print the name of the spatial reference object.

    Checking the coordinate system for each feature class in turn this way is a bit cumbersome, so you will use a list function to make a list and then process all the feature classes.

Make a list of feature classes and describe them

You can speed up the process of checking the coordinate systems of the feature classes by making a list of them and then using a loop structure in Python to process the list and describe each one.

  1. In the prompt section, add the following code and press Enter.

    fcs = arcpy.ListFeatureClasses()

    This creates a variable named fcs and sets it equal to the result of running the ListFeatureClasses function on the current workspace. You haven't set the workspace explicitly, but Transportation.gdb is the default workspace for this project. The function returns a list of the feature classes in Transportation.gdb.

  2. In the prompt section, add the following code and press Enter.

    print(fcs)

    The result is a Python list of feature class names. It is enclosed in square brackets, and the feature class names are Python strings, separated by commas.

    ['bus_lines', 'boundary', 'street_lights', 'roads', 'traffic_analysis_zones', 'bike_routes', 'bike_racks', 'parking_zones', 'intersections', 'station_entrances']

    Next, you'll use a for loop to process each item in the list.

  3. In the prompt section, add the following code:

    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        print(f"{fc}: {sr.name}")

    A for loop to process the list of feature classes

    The first line defines a for loop. It creates a temporary variable named fc that will be assigned the name of each feature class in the fcs list. The line ends with a colon to indicate that what follows is the code block that will run for each item in the list. The next three lines are indented by four spaces to indicate that they belong to the code block. The first line in the code block creates a variable named desc and sets it equal to the result of running the Describe function on the current feature class value stored in the fc variable. The second line creates the sr variable and sets it to the spatialReference object stored in desc. The third line prints a formatted string that contains the feature class name, a colon, and the spatial reference name.

    The code in this block repeats the process you did earlier to get the name of the spatial reference for the bike_racks feature class, but it does it on a variable that is set to each of the items in the list, so it processes and reports the results for all of the feature classes.

  4. Press Enter twice to run the for loop and its code block.

    Report the spatial reference for each feature class in the list.

    Half of the feature classes are in one coordinate system and half are in the other.

    The next step is to write code to create a geodatabase and to use the Project and Copy Features tools to bring the feature classes into the same dataset with a common, projected coordinate system. You will export the work you've done so far and use it as the basis for a script.

Create a script

Next, you will continue writing the code to automate this process as a script. You can test code in the Python window, but for longer scripts it is usually better to write them in a Python editor. You will export the code you have so far and continue working on it in IDLE, the default Python editor.

  1. Right-click in the transcript section of the Python window and click Save Transcript.

    Right-click in the Python window and save the transcript.

  2. In the Save Transcript window, browse to the PythonWorkflow folder where you extracted the data, name the transcript workflow_project.py, and click Save.

    This saves the transcript as a Python script file that you can open in a Python editor.

  3. Start Microsoft File Explorer and go to the PythonWorkflow folder.
  4. Right-click workflow_project.py and click Edit with IDLE (ArcGIS Pro).

    Right-click the workflow_project.py script and click Edit with IDLE (ArcGIS Pro).

    Note:
    If you also have ArcGIS Desktop 10.x (ArcMap) installed, the context menu will also include the shortcut Edit with IDLE. Do not use this shortcut since this does not open the correct version of Python.

    Note:
    If Edit with IDLE (ArcGIS Pro) is not visible in the context menu, click Start, expand ArcGIS, and click Python Command Prompt. In the Python Command Prompt window, type idle and press Enter. The IDLE (Python 3.9 Shell) window appears. Click File and click Open. Browse to and open the workflow_project.py file.

    The script opens in IDLE, the default editor for Python. The script includes all the code from the transcript section of the Python window, including any printed messages, which appear as comments with the hash character at the start of the line.

    The transcript opens in IDLE Python editor.

  5. In the IDLE editor window, remove all of the code before the fcs = arcpy.ListFeatureClasses() line.
  6. Remove all the comment lines.
  7. Remove the print(fcs) line.

    The following is the remaining code:

    fcs = arcpy.ListFeatureClasses()
    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        print(f"{fc}: {sr.name}")

    Next, you will add lines to import two libraries, set some variables, and set the workspace.

  8. Add a new line before the fcs = arcpy.ListFeatureClasses() line, and add the following lines at the beginning of the script.

    import arcpy
    import os

    The first line of code imports the ArcPy package to ensure the functionality of ArcPy is available in the script when it is run outside of ArcGIS Pro. The second line imports the os module, used to handle file paths.

  9. Add a new line after the first two lines, and add the following lines of code:
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    arcpy.env.workspace = os.path.join(mypath, gdb)

    The first line specifies the location of the data. If you extracted the PythonWorkflow folder to another location, you must edit this line to be the path on your computer. This value is assigned to a variable named mypath. This variable will be used to set the workspace, as well as for other tasks, such as creating a file geodatabase.

    A single forward slash (/) is used in the path instead of a single backslash (\). A single backslash in Python is used as an escape character and can have unintended consequences. Instead of one forward slash, you can also use the letter r for raw before the string (for example, r"C:\Lessons\PythonWorkflow") or use double backslashes (for example, "C:\\Lessons\\PythonWorkflow"). All three notations are considered correct and can be used interchangeably.

    The next line sets the variable gdb equal to the name of the geodatabase where the feature classes of interest are stored.

    The last line sets the workspace by combining the folder where the data resides (mypath) and the name of the geodatabase (gdb). The os.path.join() function is used to combine these two strings into a new string of the path for the workspace. It is recommended that you use os.path.join() to do this because it creates in robust path strings without the use of single backslashes (\). These are read by Python as escape characters and can result in errors.

    The following is the full script so far:

    import arcpy
    import os
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    fcs = arcpy.ListFeatureClasses()
    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        print(f"{fc}: {sr.name}")

    Script at first test point

    Now you can test your script to confirm that it works.

  10. Click File and click Save.

    This saves the changes you’ve made to the script. You can also use the keyboard shortcut Ctrl+S in IDLE to save your work.

  11. Click Run and click Run Module.

    Run Module to run the script code

    This runs the script. You can also use the keyboard shortcut F5 to run the script.

    The IDLE Shell window appears, and after a brief pause while the ArcPy module imports, the feature class names and spatial reference names are printed.

    Results of first test, printed names of feature classes and spatial references

    To complete the script to automate this workflow you will need to add the following capabilities: 1) create a geodatabase; 2) create a feature dataset; 3) copy the feature classes that are already projected; and 4) project the feature classes that are in a geographic coordinate system. You will write code for each element, test the code, and then continue with the next element.

Use code to create a geodatabase

The next step is to add code to your script to create the geodatabase. Since you may need to test the script multiple times, you will need to be able to overwrite previously created data. You will add an environment setting to the script to allow this.

  1. After the line that starts with arcpy.env.workspace, add a line and add the following code:

    arcpy.env.overwriteOutput = True

    Next, you will create variables to store the names of new geodatabase and the new feature dataset.

  2. After the gdb = "Transportation.gdb" line, add a line and add the following code:

    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"

    By using variables, you avoid having to repeat the names in the rest of the script. This makes your code more reusable. If you want to use a different name for the geodatabase or dataset, you only need to change it in one place in the script.

    Next, add code to create the geodatabase.

  3. After the line that starts with arcpy.env.overwriteOutput, add the following code:

    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)

    This line calls the Create File Geodatabase tool. In the parentheses, you specify that the first required parameter, the location for the new geodatabase, is set to the variable mypath, which contains the path value that you set. After a comma, you supply the other required parameter of the tool, the file geodatabase name. The variable new_gdb contains the name of the new geodatabase.

    The line also assigned the results of creating the geodatabase to a variable. The variable new_gdb_path contains the path and name of the newly created geodatabase. This makes it easier to refer to this new geodatabase in the script.

    Before you test the script, you will comment out some code that doesn’t need to be tested.

  4. Select all the lines of code after the new_gdb_path line.

    Select lines that do not need to be tested.

  5. Click Format and click Comment Out Region.

    Comment out lines.

    This adds two hash characters to the beginning of each of the selected lines of code. Python interprets lines that start with a hash sign as comments, so they will not run. You could delete these lines, but part of the code will be used again. By commenting out these lines, you can leave the code in the script for later use but prevent it from running.

    Some lines are commented out.

    The following is the code so far:

    import arcpy
    import os
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    arcpy.env.overwriteOutput = True
    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)
    ##fcs = arcpy.ListFeatureClasses()
    ##for fc in fcs:
    ##    desc = arcpy.da.Describe(fc)
    ##    sr = desc["spatialReference"]
    ##    print(f"{fc}: {sr.name}")

  6. Save and run the script.

    The IDLE Shell window restarts, and after a few moments, the input prompt, >>>, returns. The code does not currently have any working lines that print information to the shell, so it is hard to tell if the code worked. You will check in ArcGIS Pro.

  7. In ArcGIS Pro, in the Catalog pane, in the Folders section, right-click the PythonWorkflow folder, and click Refresh.

    Refresh the PythonWorkflow folder in the Catalog pane.

  8. Expand the PythonWorkflow folder.

    The new geodatabase is in the folder.

    The new geodatabase is in the folder. It is currently empty.

  9. Right-click Metro_Transport.gdb, click Delete, and click Yes to permanently delete the geodatabase.

    While you are testing a script, it is often helpful to delete outputs, so it easier to see whether or not the script is working.

    Another indicator you can use that a script is working is to add messages declaring what has happened. You can add print statements to your code to help you keep track of what is happening.

  10. In the IDLE Editor window, after the line that starts with new_gdb_path = arcpy.CreateFileGDB, add a new line and add the following code:

    print(f"The geodatabase {new_gdb} has been created.")

    Add a line to print a formatted string indicating the geodatabase was created.

    This print statement prints a formatted string that contains the value of the new_gdb variable. Print statements are not necessary for the script to run, but they help you keep track of what the script is doing. They can also be very helpful in debugging errors in long scripts. You can add multiple print statements indicating the status in the script at different points, and when you see each message, you know that the script has proceeded to that point. You can also use formatted strings to print the values of variables in your script; this can be very helpful in debugging errors.

  11. Save the script.

Use code to create a feature dataset

Next, you will create the feature dataset inside the new geodatabase. One defining property of a feature dataset is that all feature classes inside the feature dataset share the same coordinate system.

You will use the State Plane Maryland coordinate system for this dataset. While it is possible to use the coordinate system name when setting the coordinate system in Python, it is simpler to use a short code, known as the WKID, or well-known identifier.

  1. In ArcGIS Pro, in the Contents pane, right-click the roads layer and click Properties.
  2. On the Layer Properties pane, click the Source tab.

    Click the Source tab of the Layer Properties pane.

  3. Click Data Source to collapse the Data Source section.

    Collapse the Data Source section.

  4. Click Spatial Reference to expand it.

    Click Spatial Reference to expand the Spatial Reference section.

    The WKID code for this coordinate system is 2248.

    The WKID code is 2248.

  5. Click Cancel to close the Layer Properties pane.

    Now you will use this WKID code to set the spatial reference for the feature dataset.

  6. In IDLE, after the line that starts with print(f"The geodatabase, add the following lines of code:

    arcpy.CreateFeatureDataset_management(new_gdb_path, fds, 2248)
    print(f"The feature dataset {fds} has been created.")

    Lines to create the feature dataset and print a report of that have been added.

    The first line runs the Create Feature Dataset tool, giving it three required parameters. The first parameter is the location of the geodatabase where the feature dataset is created, the second is the name of the feature dataset, and the third is the WKID of the coordinate system for the dataset. The new_gdb_path variable includes the full path to the database. The name of the feature dataset was previously assigned to the fds variable.

    Another way to set the coordinate system is to provide the path to an existing feature class, for example, by giving the path to the roads feature class in the Transportation.gdb geodatabase.

    The second line prints a formatted string to indicate that the new dataset was created.

    The following is the full code:

    import arcpy
    import os
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    arcpy.env.overwriteOutput = True
    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)
    print(f"The geodatabase {new_gdb} has been created.")
    arcpy.CreateFeatureDataset_management(new_gdb_path, fds, 2248)
    print(f"The feature dataset {fds} has been created.")
    ##fcs = arcpy.ListFeatureClasses()
    ##for fc in fcs:
    ##    desc = arcpy.da.Describe(fc)
    ##    sr = desc["spatialReference"]
    ##    print(f"{fc}: {sr.name}")

  7. Save and run the code.

    The code runs, and after a few moments, the two status messages are printed to the IDLE shell.

    The code runs and the status is reported.

  8. In ArcGIS Pro, in the Catalog pane, right-click the PythonWorkflow folder and click Refresh.

    The Metro_Transport geodatabase was created.

  9. Expand the Metro_Transport geodatabase.

    The Metro_Network feature dataset was created.

  10. Delete the Metro_Transport geodatabase.

Use code to conditionally copy feature classes

Next, you will use some of the previously commented out code to list the feature classes in the Transportation.gdb geodatabase. You will add logic to it to check if the spatial reference WKID of each feature class is 2248, and code to copy the feature class to the new geodatabase when that condition is true.

  1. In IDLE, select the lines of code you commented out earlier.
  2. Click Format, and click Uncomment Region.

    Uncomment the code.

    Uncommenting the code removes the hash signs before each line, so the code will run instead of being interpreted as a comment.

    The code you’ve uncommented makes a list of feature classes in the current workspace, and then uses the description of each of the items in the list to extract the spatial reference. Now, instead of printing that information, you will add to the code to check the spatial reference value and either copy the feature class or project it.

    Both the Copy Features tool and the Project tool take an input feature class and produce an output feature class. While the names of the feature classes can be kept the same, the paths for the outputs will be different, because the new feature classes will be in a new geodatabase.

    The input feature classes are represented by the variable fc. The values of fc are feature class names derived from a list of feature classes in the current workspace.

    For example, the full path of one of the input feature classes is: C:\Lessons\PythonWorkflow\Transportation.gdb\roads

    Because the workspace is set, the feature class names, such as roads can be used directly in tools. The full path is not needed when working with feature classes in the current workspace. That’s why desc = arcpy.da.Describe(fc) or desc = arcpy.da.Describe("roads") works.

    However, you must give the output feature class parameters the full path for the new feature classes in the new workspace. This path can be constructed using os.path.join(), just like earlier in the script, where the environment was set.

  3. Select the line of code that starts with print(f"{fc}: and replace it with following line of code:

    new_fc = os.path.join(mypath, new_gdb, fds, fc)

    This line should be at the same indentation level, inside the for fc in fcs: loop code block.

    On this line, the new variable, new_fc, is set equal to the path created by joining together the folder where the data resides (mypath), the new geodatabase (new_gdb), and the new feature dataset (fds). The last part of the path is the name of the new feature class, which is the same as the input feature class (the value of the variable fc). This part of the path changes with every iteration of the loop over the list of feature classes.

    With the full path for the output feature classes created, you are ready to add code to decide whether to copy or project each feature class based on the coordinate system. In Python, you can test for different conditions using if statements and have different blocks of code run depending on whether or not a condition in the statement is true.

  4. After the new_fc = os.path.join line, at the same level of indentation (inside the for loop), add the following line of code:

    if sr.factoryCode == 2248:

    This code checks to see if the WKID of the feature class, stored on the sr object as its factoryCode value, matches the State Plane Maryland coordinate system WKID of 2248.

    It uses an if statement and an expression and ends with a colon to indicate that a code block follows that will run if the statement is true.

    The statement uses a double equals sign. In Python, a single equal sign is used to set a variable to a value, and a double equals sign is used to check for equality.

  5. Click at the end of this line of code and press Enter.

    This results in the correct indentation for the next line of code, indented four spaces relative to the if statement line. This is the start of a new code block that will run only if the sr.factoryCode is equal to the value 2248.

    With the full path for the output feature classes created and the test for the coordinate system satisfied, you can add code to copy the feature class.

  6. On the newly indented line, add the following lines of code:

    arcpy.CopyFeatures_management(fc, new_fc)
            print(f"The feature class {fc} has been copied.")

    The first line runs the Copy Features tool, copying the current feature class to the new geodatabase.

    The second line prints a formatted string to indicate that the new dataset was created.

    The following is the full code:

    import arcpy
    import os
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    arcpy.env.overwriteOutput = True
    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)
    print(f"The geodatabase {new_gdb} has been created.")
    arcpy.CreateFeatureDataset_management(new_gdb_path, fds, 2248)
    print(f"The feature dataset {fds} has been created.")
    fcs = arcpy.ListFeatureClasses()
    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        new_fc = os.path.join(mypath, new_gdb, fds, fc)
        if sr.factoryCode == 2248:
            arcpy.CopyFeatures_management(fc, new_fc)
            print(f"The feature class {fc} has been copied.")

    The logic to copy the feature class between geodatabases when the WKID is 2248 is added to the script

  7. Save and run the code.

    The matching feature classes are copied.

    The code runs. It creates the geodatabase and the feature dataset, and it copies the five layers that were in the State Plane Maryland coordinate system.

  8. In ArcGIS Pro, in the Catalog pane, refresh the PythonWorkflow folder.
  9. Refresh the Metro_Transport geodatabase and expand it.
  10. Refresh the Metro_Network feature dataset and expand it.

    The five feature classes are copied to the new geodatabase.

    The geodatabase and dataset contain the feature classes that match the coordinate system of the dataset.

Add code to conditionally project feature classes

The final step to complete the script is to add logic to use the Project tool to project the feature classes that are not in the State Plane Maryland coordinate system and write the results to the feature dataset in the new geodatabase.

  1. In IDLE, click at the end of the line of code that begins print(f"The feature class and press Enter.
  2. Press the Backspace key to reduce the indentation by one level.

    You will add an else statement, which must be at the same level of indentation as the previous if statement.

    An else statement is used to run a different code block when the if statement is false.

  3. On the new, less indented line, add the following lines of code:

    else:
            arcpy.Project_management(fc, new_fc, 2248)
            print(f"The feature class {fc} has been projected.")

    The if statement and else statements are at the same level of indentation.

    The else statement creates a logical branch with a code block that will run after the if statement is checked for the cases where it is not true. The logic is, if the WKID is 2248, copy the feature class, and if it is not, project the feature class.

    The second of these lines is indented four spaces because it belongs to the code block that runs in the else condition. The Project tool projects the input feature class to the State Plane Maryland coordinate system and the output feature class is stored in the new geodatabase. The parameters of the Project tool are the input feature class, the output feature class, and the output coordinate system (the WKID 2248 is used for this parameter).

    Note:
    There is a fourth parameter of the Project tool, which is an optional transformation. When you ran the Project tool earlier, you saw that a transformation is needed between the NAD 1983 geographic coordinate system and the WGS 1984 geographic coordinate system, but by default the appropriate transformation is selected when the tool is run. This means that there is no need to specify a transformation in the code here.

    Based on the earlier results from checking the coordinate system of all the feature classes, you know that the feature classes not already in the State Plane Maryland coordinate system are in one specific geographic coordinate system. However, there is no need to specify this specific coordinate system. By using an else statement, the Project tool is run for all feature classes where the if statement is false, regardless of the specific coordinate system.

    The following is the full code:

    import arcpy
    import os
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    arcpy.env.overwriteOutput = True
    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)
    print(f"The geodatabase {new_gdb} has been created.")
    arcpy.CreateFeatureDataset_management(new_gdb_path, fds, 2248)
    print(f"The feature dataset {fds} has been created.")
    fcs = arcpy.ListFeatureClasses()
    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        new_fc = os.path.join(mypath, new_gdb, fds, fc)
        if sr.factoryCode == 2248:
            arcpy.CopyFeatures_management(fc, new_fc)
            print(f"The feature class {fc} has been copied.")
        else:
            arcpy.Project_management(fc, new_fc, 2248)
            print(f"The feature class {fc} has been projected.")

    The full code for the script

  4. Save and run the script.

    The code runs. It creates the geodatabase and the feature dataset, copies the five layers that were in the State Plane Maryland coordinate system, and projects the five layers that were in the WGS84 coordinate system.

    Final code run results

  5. In ArcGIS Pro, in the Catalog pane, refresh the Metro_Network feature dataset.

    The dataset contains all of the feature classes, all in the correct coordinate system.

    Final geodatabase with all of the feature classes

    Your code is working, and at this point, you would be able to create the geometric network.

Add comments to the script

This is a relatively simple script, but it is recommended that you include comments in your code to make it easier to understand. Comments can be used to explain the purpose of the script and identify key steps. This will make it easier for others to understand your script and modify it for their own purpose. It will also make it easier for you to understand the code, if you leave it for a while and then need to come back to modify it.

Comments start with one or more hash characters. Comments can start at the beginning of a line or can be added at the end of a line of code.

  1. In IDLE, add a new line at the beginning of the script.
  2. Copy and paste the following comments on the new line:

    # Author: your name
    # Date: the date
    # Purpose: This script reads all the feature classes in a
    # geodatabase and copies them to a new feature dataset in
    # a new geodatabase. Feature classes not already in the
    # target coordinate system are projected.

  3. Edit the Author and Date lines to include your name and the current date.
  4. Before the import arcpy line, add two new lines, and on the second line, add the following comment:

    # Imports

    The blank line will not affect the code, and makes the code more legible. The comment identifies that this section imports libraries needed for the code. Imports are generally put together near the top of a script.

  5. Add two new lines after the import os line, and add the following comment:

    # Variables for paths, outputs, workspaces

    This comment identifies where these variables are first set.

  6. Add two new lines after the arcpy.env.overwriteOutput = True line, and add the following comment:

    # Create a new geodatabase and dataset

  7. Add two new lines before the fcs = arcpy.ListFeatureClasses() line, and add the following comment:

    # Create a list of feature classes in the workspace

  8. After the if sr.factoryCode == 2248: line, add the following comment on the same line:

     # WKID of target coordinate system

    You have added comments to explain the code.

    The following is the full code:

    # Author: your name
    # Date: the date
    # Purpose: This script reads all the feature classes in a
    # geodatabase and copies them to a new feature dataset in
    # a new geodatabase. Feature classes not already in the
    # target coordinate system are projected.
    
    # Imports
    import arcpy
    import os
    
    # Variables for paths, outputs, workspaces
    mypath = "C:/Lessons/PythonWorkflow"
    gdb = "Transportation.gdb"
    new_gdb = "Metro_Transport.gdb"
    fds = "Metro_Network"
    arcpy.env.workspace = os.path.join(mypath, gdb)
    arcpy.env.overwriteOutput = True
    
    # Create a new geodatabase and dataset
    new_gdb_path = arcpy.CreateFileGDB_management(mypath, new_gdb)
    print(f"The geodatabase {new_gdb} has been created.")
    arcpy.CreateFeatureDataset_management(new_gdb_path, fds, 2248)
    print(f"The feature dataset {fds} has been created.")
    
    # Create a list of feature classes in the workspace
    fcs = arcpy.ListFeatureClasses()
    for fc in fcs:
        desc = arcpy.da.Describe(fc)
        sr = desc["spatialReference"]
        new_fc = os.path.join(mypath, new_gdb, fds, fc)
        if sr.factoryCode == 2248: # WKID of target coordinate system
            arcpy.CopyFeatures_management(fc, new_fc)
            print(f"The feature class {fc} has been copied.")
        else:
            arcpy.Project_management(fc, new_fc, 2248)
            print(f"The feature class {fc} has been projected.")

    Final script with comments

  9. Save the script.

In this tutorial, you learned the following:

  • Python scripts can be used to automate repetitive tasks in GIS workflows.
  • ArcPy includes several functions to create lists of datasets.
  • By listing and describing datasets using Python code, you can create a detailed inventory of GIS datasets in a workspace. You can then decide to process each dataset differently based on its characteristics.
  • Careful manipulation of paths and file names is necessary to ensure correct outputs.

You may also be interested in Python Scripting for ArcGIS Pro and Advanced Python Scripting for ArcGIS Pro by Dr. Paul A. Zandbergen, published by Esri Press.