Tackling Model Builder

Model Builder intimidates the hell out of me. I think once, a while back, I heard the words “python” and “script” and decided I’d never wander over yonder to them dark hills. So every process I do is done painstakingly by hand one-by-one until the final result is achieved…

For the most part, this has worked just fine for me. I’ve never had to be efficient about my workflow and no one has ever asked questions. So I slink around in my non-model-builder shame without exposure. This results in a lot of trash files, but it’s also resulted in knowing the functionality of these tools intimately well. I’ve always felt that learning something the hard way is the best way to learn… or at least that seems to be how I’ve stumbled through this life so far!

Now, though – I’m expected to know these things and the work load requires that many of my slow processes become more efficient and automated. So – I had to acquaint myself with model builder and I’ve been doing just that. I’m pretty happy that as of today, I’ve built my first complete tool and I’m really happy with the result.

The setup: We keep a layer that contains all our agency-owned lands by parcel/transaction. This layer really serves an internal purpose of tracking those transactions and then a secondary (but equal) purpose of keeping our boundaries up-to-date. Visually, though, it’s unpleasing. Likewise, the attribute table is full of fields that have no cartographic purpose and mean nothing to the public. The boundaries are also derived from various sources with various levels of accuracy, so slivers and gaps abound, yet legitimate inholdings should be preserved. We need to publish a clean, pretty layer for public use (as well as our own cartographic use) once a month.

Problem: Dissolve tool doesn’t cut it. It still leaves messy slivers. Aggregate takes care of this, but it totally wipes the attribute table. A spatial join can put Humpty Dumpty back together again, but it attaches ALL the attributes when we just want a couple. Some of the lands aren’t necessarily open to the public ( or part of a dataset that we ultimately want to publish), so there’s a query needed at some point to filter these. Maintaining separate datasets for each scenario sounds like a nightmare. Slivers need to be handled with care because we don’t want to exclude legitimate inholdings and make landowners angry at us.

Solution: I needed to build a tool that allows me to query what I’m interested in “dissolving”, dissolves it, takes care of slivers but MAINTAINS inholdings with aggregate, then spatially joins an interim layer from the original query to attach the park name. I’ve wrestled with this model for a couple weeks now. At once, I’m teaching myself how to use model builder and also have a practical end product. I finally got an output that is (mostly) what I’m looking for. Of course, this works on the assumption that your original layer is beautiful and organized. In our case – that is a work in progress (but close to being finished!)

The before and after:

An example of what the surveys layer looks like prior to processing. This is all part of one park, but composed of multiple acquisitions over the years.
“Dissolved” result – visually. Attribute table also cleaned up! Shows only the park name and none of the boring academic stuff for internal use.

 

 

 

 

 

 

 

 

 

This is what the layout looks like in model builder. Basically, I‘m so fancy:

Behold! My first model!

This is what the tool likes like when run from toolbox:

The simple prompt – showing SQL. Also pretty proud of my help text… yeaaaaa.

Lastly – here’s the fancy python script:

# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------------
# PrettyParkPolys.py
# Created on: 2017-07-05 16:14:40.00000
# (generated by ArcGIS/ModelBuilder)
# Usage: PrettyParkPolys 
# Description:
# This tool takes the surveys layer and dissolves them into nice, clean polygons. Then that output is spatially joined to re-assign their names.
# ---------------------------------------------------------------------------

# Set the necessary product code
# import arcinfo

# Import arcpy module
import arcpy

# Script arguments
Input_Features = arcpy.GetParameterAsText(0)

Output_Lands = arcpy.GetParameterAsText(1)

Expression = arcpy.GetParameterAsText(2)
if Expression == '#' or not Expression:
Expression = "Management = 'TDEC - TSP'" # provide a default value if unspecified

# Local variables:
Lands_Layer = "Lands_Layer"
Preserve_orthogonal_shape = "true"
Transfer_field_domain_descriptions = "false"
Maintain_fully_qualified_field_names = "true"
DissolveTest_Tbl = "E:\\TDEC\\ToolExperiment\\DissolveTest_Tbl"
Aggregated_Output = "E:\\TDEC\\ToolExperiment\\DissolveTest.shp"
Integrated_Aggregated_Output = Aggregated_Output
XY_Tolerance = "20 Feet"

# Process: Make Feature Layer
arcpy.MakeFeatureLayer_management(Input_Features, Lands_Layer, Expression, "", "OBJECTID OBJECTID VISIBLE NONE;Shape Shape HIDDEN NONE;PARK_MANGE PARK_MANGE HIDDEN NONE;DATE_ACQUI DATE_ACQUI HIDDEN NONE;BND_ORIGIN BND_ORIGIN HIDDEN NONE;TAG TAG HIDDEN NONE;SECOND_NA SECOND_NA HIDDEN NONE;UPDATE_ UPDATE_ HIDDEN NONE;UPDATE_DATE UPDATE_DATE HIDDEN NONE;COMMENT_ COMMENT_ HIDDEN NONE;OWNER OWNER HIDDEN NONE;PUBLIC_ PUBLIC_ HIDDEN NONE;TRANSACTION_NO_ TRANSACTION_NO_ HIDDEN NONE;REGION REGION HIDDEN NONE;DEEDACRES DEEDACRES HIDDEN NONE;Shape_Length Shape_Length HIDDEN NONE;Shape_Area Shape_Area HIDDEN NONE;Ownership Ownership HIDDEN NONE;Bndry_Origin Bndry_Origin HIDDEN NONE;Prim_Desig Prim_Desig HIDDEN NONE;Sec_Desig Sec_Desig HIDDEN NONE;Tert_Desig Tert_Desig HIDDEN NONE;Access Access VISIBLE NONE;Management Management HIDDEN NONE;APN APN HIDDEN NONE;PRIMARY PRIMARY VISIBLE NONE;Secondary Secondary VISIBLE NONE;Calc_Acres Calc_Acres VISIBLE NONE")

# Process: Aggregate Polygons
tempEnvironment0 = arcpy.env.transferDomains
arcpy.env.transferDomains = Transfer field domain descriptions
tempEnvironment1 = arcpy.env.qualifiedFieldNames
arcpy.env.qualifiedFieldNames = Maintain fully qualified field names
arcpy.AggregatePolygons_cartography(Lands_Layer, Aggregated_Output, "20 Meters", "0 SquareFeet", "0 SquareFeet", Preserve_orthogonal_shape, "", DissolveTest_Tbl)
arcpy.env.transferDomains = tempEnvironment0
arcpy.env.qualifiedFieldNames = tempEnvironment1

# Process: Integrate
arcpy.Integrate_management("E:\\TDEC\\ToolExperiment\\DissolveTest.shp #", XY_Tolerance)

# Process: Spatial Join
tempEnvironment0 = arcpy.env.qualifiedFieldNames
arcpy.env.qualifiedFieldNames = "true"
arcpy.SpatialJoin_analysis(Aggregated_Output, Lands_Layer, Output_Lands, "JOIN_ONE_TO_ONE", "KEEP_COMMON", "Id \"Id\" true true false 6 Long 0 6 ,First,#,E:\\TDEC\\ToolExperiment\\DissolveTest.shp,Id,-1,-1;Access \"Access\" true true false 50 Text 0 0 ,First,#,Lands_Layer,Access,-1,-1;PRIMARY \"PRIMARY\" true true false 70 Text 0 0 ,First,#,Lands_Layer,PRIMARY,-1,-1;Secondary \"Secondary\" true true false 70 Text 0 0 ,First,#,Lands_Layer,Secondary,-1,-1;Calc_Acres \"Calc_Acres\" true true false 8 Double 0 0 ,First,#,Lands_Layer,Calc_Acres,-1,-1", "INTERSECT", "20 Meters", "")
arcpy.env.qualifiedFieldNames = tempEnvironment0

Leave a Reply