Date post: | 16-Jul-2015 |
Category: |
Documents |
Upload: | elizabeth-mcdowell |
View: | 31 times |
Download: | 2 times |
E L I Z A B E T H M C D O W E L L
M E S A C O U N T Y G I S
PYTHON & THE CERR CHALLENGE PROCESS
COLORADO EMPLOYEE RESIDENCE REPORTS
• Local Government Severance Tax Fund
• Submitted by reporting parties (Marathon, Encana, etc…)
• A factor in allocating severance tax dollars to and within counties (Direct Distribution)
County Pool
• CERRs
• Mining & Well Permits
• Mineral Production
Sub County Pool
• CERRs
• Population
• Road Miles
DOLA Direct Distribution: Flowchart of Severance Tax Distributions
MESA COUNTY ALLOCATION
Direct Distribution Payment - 2014
$1,723,565.20
MESA COUNTY GIS
• Processes CERRs for municipalities
within Mesa County • City of Grand Junction
• City of Fruita
• Town of Palisade
• Town of De Beque
• Town of Collbran
• Include surrounding
Counties/Municipalities • Garfield County
• Town of Parachute
• Delta County
• Montrose County
• Grand County, UT
FOR 2013 REPORTING YEAR
• 237 CERRs (included addresses within Mesa County)
• 233 Companies
• 16,088 Total Employees
• 3,261 Employee Addresses within Mesa County
• 356 Not Challengeable
• 106 Invalid Addresses (Incl. PO Boxes, bad addresses)
• 879 Challenged Addresses
Jurisdiction Company Reported
Employees Post-Challenge
Employees Net Gain
City of Fruita 328 298 -30 City of Grand Junction 1769 1150 -619
Mesa County 994 1689 695 Town of Collbran 28 18 -10
Town of De Beque 56 45 -11
Town of Palisade 86 72 -14 Garfield County 4 0 -4
Town of Parachute 7 0 -7 TOTAL 3272 3272 0
+21%
APPLICATIONS USED
• Microsoft Excel
• Microsoft SQL Server Management Studio
• ESRI ArcMap 10.1
• PythonWin 2.7.2
WHY PYTHON?
• ESRI Marketing
• Online Python class
• Python based sessions at the ESRI Developer
Conference, March 2014
• Data Driven Pages enhanced with Python
CHALLENGE PROCESS OVERVIEW
1. Download / Prep CERRs
2. Geocode / Address Verification
3. Supporting Documentation
4. Submit Challenges on DOLA’s Website
SUPPORTING DOCUMENTATION
• In previous years supporting documentation was
created from Assessor’s Property Detail
• Individually created per challenge address
• For 2012 Reporting Year: >1000
• 2013 Reporting Year: 879 address challenges
DATA DRIVEN PAGE SETUP
• Input Layer
• Geocoded address = Page Name Field
• Use Page Definition
Query to only show the
active address on each page
• DDP Extent
• “Best Fit”
• 1500% Margin
Layout View
PYTHON SCRIPT COMPONENTS
• General Settings
• Map Document Variables
• Looping
• Map Layout / Dynamic Elements
• Export to PDF
Python script available on github: https://github.com/emcdowell/Python-CERR.git
GENERAL SETTINGS
• Import arcpy and os modules
• Allow script to overwrite outputs
arcpy.env.overwriteOutputs = True
• Script Parameters
• Used to select different input without having to change code
inputLayer = arcpy.GetParameterAsText(0)
• Set Directory Paths / Output PDF
MAP DOCUMENT VARIABLES
Set up map document variables mxd = arcpy.mapping.MapDocument(mxdpath)
ddp = mxd.dataDrivenPages
dataframes = arcpy.mapping.ListDataFrames(mxd, '')
actDataframe = arcpy.mapping.ListDataFrames(mxd, '')[0]
Define input table and temporary table variables inputTable = r'S:\IT\GIS\Liz\Python\CERR\Data\Python_CERR.gdb\MC_TAC_AgencyCodes'
tempTable = r'S:\IT\GIS\Liz\Python\CERR\Data\Python_CERR.gdb\tempTable'
Define field variables Link script to input layer
SCRIPT HAS MULTIPLE LOOPS
• Primary Loop:
• Loop through each page using page number for pgNum in range(1, ddp.pageCount + 1):
ddp.currentPageID = pgNum
• Secondary & Tertiary Loops:
• Script loops through scenarios within each page
• Search & Insert Cursors
• Layout element positioning
# Set variables to set data frame insets
reportedDistrict = ddp.pageRow.getValue(qMuni_County)
newDistrict = ddp.pageRow.getValue(qDistrict)
if reportedDistrict == 'City of Grand Junction':
lblGrandJunction.elementPositionX = 8.27
lblGrandJunction.elementPositionY = 2.63
lblFruita.elementPositionX = 10.0
lblCollbran.elementPositionX = 10.0
lblDebeque.elementPositionX = 10.0
lblPalisade.elementPositionX = 10.0
lblCounty.elementPositionX = 12.0
txtCounty.elementPositionX = 3.18
txtCounty.elementPositionY = 1.07
txtGrandJunction.elementPositionX = 10.0
txtFruita.elementPositionX = 10.0
txtCollbran.elementPositionX = 10.0
txtDebeque.elementPositionX = 10.0
txtPalisade.elementPositionX = 10.0
for frames in dataframes:
if frames.name == 'df_GJT':
frames.elementPositionX = 5.7
frames.elementPositionY = 0.5
elif frames.name == 'df_Address':
frames.elementPositionX = 0.2745
frames.elementPositionY = 2.9452
else:
frames.elementPositionX = 8.8
frames.elementPositionY = 0.7
elif reportedDistrict == ‘Mesa County’:
MAP LAYOUT ELEMENTS
• Each layout item MUST be uniquely named
• Size and Position Tab
• Element Name
• Create and do preliminary setup in ArcMap then
use Python to manipulate the element
SCALE BAR
# Set scale bar based on page extent
if actDataframe.scale < 4000:
scale1.elementPositionX = 0.33
scale1.elementPositionY = 2.98
scale2.elementPositionX = 11.6
scale3.elementPositionX = 11.6
scale4.elementPositionX = 11.6
elif 4001 <= actDataframe.scale <= 10000:
scale1.elementPositionX = 11.6
scale2.elementPositionX = 0.33
scale2.elementPositionY = 2.98
scale3.elementPositionX = 11.6
scale4.elementPositionX = 11.6
elif 10001 <= actDataframe.scale <= 20000:
scale1.elementPositionX = 11.6
scale2.elementPositionX = 11.6
scale3.elementPositionX = 0.33
scale3.elementPositionY = 2.98
scale4.elementPositionX = 11.6
elif actDataframe.scale > 20001:
scale1.elementPositionX = 11.6
scale2.elementPositionX = 11.6
scale3.elementPositionX = 11.6
scale4.elementPositionX = 0.33
scale4.elementPositionY = 2.98
• Create four scale bars in
ArcMap
• Set Division Value for each
• Determine placement on layout
• Use Python to change X,Y
location based on the scale of
the active data frame
Layout View
SEARCH & INSERT CURSORS
• Search Cursor
• Where input table field = page variable (TAC Code)
• Insert Cursor
• Populate temporary table with matching records
cursor = arcpy.da.SearchCursor(inputTable, ('TAC_Code', 'Year_', 'Agency_Name'), ''' "Year_" = 2013 ''')
insertcursor = arcpy.da.InsertCursor(tempTable, ('TAC_Code', 'Year_', 'Agency_Name'))
for row in cursor:
if row[0] == pgTAC:
insertcursor.insertRow(row)
del row
del insertcursor
del cursor
cursor = arcpy.da.SearchCursor(inputTable, ('TAC_Code', 'Year_', 'Agency_Name'), ''' "Year_" = 2013 ''')
insertcursor = arcpy.da.InsertCursor(tempTable, ('TAC_Code', 'Year_', 'Agency_Name'))
DYNAMIC TABLE
• List taxing authorities per challenge address • Verifies that a parcel is located inside or outside of municipal boundary
• Based on the number of rows in the table, script will adjust text size,
row height, grid line positioning
• ESRI Sample Code • DDPwithDynamicTablesAndGraphs_10.1_v1
#Set and clone cell text elements
cellTxt.fontSize = rowHeight / 0.0155 y = upperY - headerHeight rows = arcpy.SearchCursor("in_memory\sort1") for row in rows: x = upperX + 0.05 col1CellTxt = cellTxt.clone("_clone") col1CellTxt.text = row.getValue("Agency_Name") col1CellTxt.elementPositionX = x col1CellTxt.elementPositionY = y
col2CellTxt = cellTxt.clone("_clone") col2CellTxt.text = row.getValue("TAC_Code") col2CellTxt.elementPositionX = x + 2.3 col2CellTxt.elementPositionY = y y = y - rowHeight if col1CellTxt.elementWidth > 2: col1CellTxt.elementWidth = 2
EXPORT TO PDF
# Set Output PDF (Beginning of script)
pdfPath = outDir + r"\FinalMapBook.pdf"
if os.path.exists(pdfPath): # Check to see if file already exists, delete if it does
os.remove(pdfPath)
finalPdf = arcpy.mapping.PDFDocumentCreate(pdfPath)
…
# Name and export individual pages (Inside Loop through each page)
ddp.exportToPDF(pgLabel + ".pdf", "CURRENT")
finalPdf.appendPages(pgLabel + ".pdf")
…
# Commit Changes and delete variable references (Outside of loop)
finalPdf.saveAndClose()
del finalPdf
SAMPLE OUTPUT
THREE HOURS I WAS ABLE TO SPEND WORKING ON SOMETHING ELSE!
For batch size between 150 – 200 addresses
LINKS
• DDPwithDynamicTablesAndGraphs_10.1_v1
• Merge Excel Workbooks
• My full script
Questions?