WordPress.com



Final Python Script ProjectGEOGRAPHY 375 Spring 2017American River CollegeRicardo A. Contrerasricontremph@Summary.My employer, the Substance Abuse, Prevention and Control Office or SAPC (a program within the Los Angeles County Department of Public Health, or LAC-DPH), expects to see an expansion in the State of California Medi-Cal beneficiary population (adults with incomes up to 138% of the Federal Poverty Level, or FPL) who will become eligible for publicly-funded substance use disorder (SUD) treatment services. All substance use disorder treatment will be funded under the State of California Drug Medi-Cal Organized Delivery System (DMC-ODS) Waiver as of July 1st, 2017. This State waver is, in turn, part of the U.S. Affordable Care Act (ACA) that will pay for and provide DMC-ODS beneficiaries expanded health care services, including SUD treatment benefits. (Source: Centers for Medicare and Medicaid Services or CMS, 2017. ) In order to plan for the greatest coverage demand under the future expansion of SUD treatment services, it is necessary to identify communities where people ‘in need’ of SUD services are ‘concentrated.’ According to State of California Department of Health Care Services guidelines, it is estimated that between12% and 13% of adults living at or below the 138 % Federal poverty Level (FPL) are also in need of SUD treatment services (Source: State of California Department of Health Care Services, 2016. )Due to the reasons described above, one of the research activities my employer is expected to pursue is monitoring SUD-related treatment accessibility, availability, and any service gaps among DMC-ODS eligible populations. For health service delivery planning purposes, LAC-DPH SAPC uses eight service planning areas (SPA) that are, in turn, based on census tracts, for demographic and rate calculations, where their underlying population counts (e.g., people < 18 years of age, adults) is important to be considered. Given the previous context, it became an opportunity for this author to demonstrate his newly acquired Python Script programming skills by writing a Python script that automates the creation of SPA-related hot spot maps to highlight where the DMC-ODS SUD eligible populations may be statistically clustered (or statistically dispersed), by census tract. This author utilized the Update Cursor, Make Feature Layer, Select Layer By Location, Hot Spots Stats Routine, Search Cursor and Export to pdf Routines to automate the production of the eight SPA-based Hot Spot maps. An added bonus was to find out whether the census tracts are either clustered or dispersed in each SPA region of the Los Angeles County area. Purpose.The purpose of this Python Script for ArcGIS project is to help automate some basic geoprocessing steps to generate eight SPA-based, fixed distance band hot spot analysis maps that represent census tract clusters where DMC-ODS, SUD treatment eligible populations are more likely to be located (‘concentrated) in Los Angeles County. The hot spot maps identify census tracts where 13% of Adult Medi-Cal beneficiaries (e.g., SUD treatment beneficiaries) can be either clustered or dispersed, having applied the Getis-Ord Gi* statistic test that searches for statistically-significant clusters. This test is based on z scores that identify the statistical significance of clustering for any specific distance (Source: ESRI Developer Network or EDN. ) ‘These maps can then be used for future publicly funded SUD treatment provider site allocation expansion purposes, if deemed useful. 3. Description of the geoprocessing tasks.My description in this document is intended to provide the overall picture about the geoprocessing tasks I employed for this project. Please refer to the Power Point presentation associated to this summary for additional script details. This Python Script project uses three script files (A, B, C). Part A uses the update cursor to update a field, ‘FPL138_15pc,’ with the estimated number of adults eligible for DMC-ODS SUD treatment services -- this value should be 13% of adults living at or below the 138 FPL in each census tract. The data source file for this project is the 2015 estimated number of adults living at or below 138% FPL (LAC_FPL138_2015), available internally through my employer (the Los Angeles County Department of Public Health.) I saved all input and output GIS features in a file geodatabase, LayerTemplates.gdb.Part A. Update new field and generate eight new SPA layers.I created a new field that would hold the estimated 13% value, ‘FPL138_15pc,’ in the table of attributes for the LAC_FPL138_2015 layer. To update this field, I used the estimated total number of adults living at or below the 138 FPL (‘t_138_15’ variable) within each census tract and applied the following formula:Estimated number of adults living at or below the 138 FPL * 0.13I accomplished this by defining my feature class and fields to be used, after which I defined the update cursor routine to calculate the new 13% counts into the ‘FPL138_15pc’ field:# Set my current workspace:print "Setting my current workspace"arcpy.env.workspace = "C:\\PythonCourse_FinalPrjt"outpath = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb"FPL138fc = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb\\LACounty_GIS\\LAC_FPL138_2015"fields = ['t_138_15','FPL138_15pc']I also defined my generic SPA layers that I would use during the MakeFeatureLayer_management routine in Part A of the script. Here are the eight generic layers, available to me through my employer’s GIS data repository:SPA1 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA1_generic"SPA2 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA2_generic"SPA3 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA3_generic"SPA4 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA4_generic"SPA5 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA5_generic"SPA6 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA6_generic"SPA7 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA7_generic"SPA8 = "C:\PythonCourse_FinalPrjt\LayerTemplates.gdb\LACounty_GIS\SPA8_generic"My update cursor is:FPL138fc = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb\\LACounty_GIS\\LAC_FPL138_2015"fields = ['t_138_15','FPL138_15pc']for row in cursor:# Update the FPL138_pc field inside the FPL138fc feature to show the calculated number of # adults living at or below the 138% FPL who are in need of substance abuse treatment. row[1] = row[0] * 0.13 cursor.updateRow(row)Next, I extracted features to eight new feature classes (SPA 1 through SPA 8) based on their spatial relationship between the FPL138fc (this feature class represents the entire County of Los Angeles census tract layer) and each of the SPAx_generic layers. The purpose of using the SelectLayerByLocation routine was to select census tracts that had their center inside each of the eight generic SPA polygons (SPAx_generic) and export the selected features into eight (8) new feature classes using the arcpy.CopyFeatures_management routine. In the end, I expected to generate eight new SPA layers, each containing a subset of census tracts with their SPA-related updated FPL138_pc field (the field holding the 13% DMC-ODS eligible population estimated value.Part of the script is shown, for SPA 1 only: # First, check total number of census tracts in FPL138fc feature class (Hint: N = 2,345) result = arcpy.GetCount_management(FPL138fc) print "Number of features in entire feature class " + FPL138fc + " : " + str(result) if arcpy.Exists("FPL138fc_lyr"): arcpy.Delete_management("FPL138fc_lyr") # First, let's generate the new feature layers (FPL138fc_lyr and SPA1_lyr) that will serve as our SelectLayerByLocation templates: arcpy.MakeFeatureLayer_management(FPL138fc, "FPL138fc_lyr") # Next, select SPA-specific census tracts from the "FPL138fc_lyr" and export them out into new SPAx_out layers. # Generating SPA 1 related census tract selection. if arcpy.Exists("SPA1_lyr"): arcpy.Delete_management("SPA1_lyr") arcpy.MakeFeatureLayer_management(SPA1, "SPA1_lyr") # Select all census tracts which have their centroid within the SPA 1 generic polygon (SPA1_generic): print "Generating census tract selection by their SPA 1 location" arcpy.SelectLayerByLocation_management("FPL138fc_lyr", "HAVE_THEIR_CENTER_IN", "SPA1_lyr", 0, "NEW_SELECTION") num_cts = arcpy.GetCount_management("FPL138fc_lyr") print "Number of selected census tracts in SPA 1: " + str(num_cts) # Write the selected features to a new feature class (e.g., SPA1_out). First, check to see if the feature exists, if so, delete it. if arcpy.Exists(SPA1_out): arcpy.Delete_management(SPA1_out) arcpy.CopyFeatures_management("FPL138fc_lyr", SPA1_out) print "Copied selected features from the FPL138fc_lyr to " + SPA1_out # Now, let's print the record number or count in the new feature layer generated with the query: result = arcpy.GetCount_management(SPA1_out) print "Census tract count in SPA1_out after applying \ SelectLayerByLocation/SelectLayerByAttribute: "+ str(result)This resulted in generating eight new GIS feature classes, SPA1_out through SPA8_out, that hold the updated 'FPL138_15pc' field. This field, in each derived SPA layer, is the count field needed for Part B of my Python scripts.Part B. Conduct Fixed Distance Band Hot Spot Analysis for each SPA region.Based on previous hot spot analysis testing this author had conducted at work, distance values (in feet) selected for the eight SPA-based fixed distance band hot spot analyses are as follow:Table 1. Fixed Distance Band Values.SPA 1 = 10 miles (52,800 feet)SPA 2 = 3 miles (15,840 feet)SPA 3 = 3 miles (15,840 feet)SPA 4 = 1.5 miles (7,920 feet)SPA 5 = 5 miles (26,400 feet)SPA 6 = 2 miles (10,560 feet)SPA 7 = 2 miles (10,560 feet)SPA 8 = 2.5 miles (13,200 feet)Note: I had established ‘benchmark’ distance values by running the optimized hot spot analysis tool found under the ArcGIS Toolbox, Spatial Statistics, Mapping Clusters, Optimized Hot Spot Analysis Tool ahead of time. It does not require the user to ‘feed’ any distance value as the tool itself will find what that optimized distance is for each region, depending on the size of the region. However, after running the optimized hot spot analysis tests, this author changed the distance values eventually used in the arcpy.HotSpots_stats routine (Fixed Distance Band method). The fixed distance band values, in miles and feet, are represented in Table 1 (see Page 4). To learn more about hot spot analysis methods, please refer to ESRI’s Modeling spatial relationships page at Part B, the workspace was defined, along with the data out path.# Setting my current workspace:print "Setting my current workspace"arcpy.env.workspace = "C:\\PythonCourse_FinalPrjt"outpath = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb"# Define SPA output layers(SPAx_out) that contain the estimated 138% Federal Poverty Level # (FPL) count field. This count is based on State of California Drug-Medical (DMC) program # eligibility criterium that uses a 13% segment of all persons living at or below 138% FPL as # representing adult individuals more likely to be in need of substance abuse treatment (e.g., alcohol # and drugs) in a community. For this project, community is defined as populations located in # census tracts within each Service Planning Area (SPA). Updating a new field (FPL138_15pc) # using the UpdateCursor and applying the SelectByLocation Routine was accomplished in PART # A of this Python Script project.SPA1_out = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb\\LACounty_GIS\\SPA1_out"A partial segment of the Hot Spot script is shown here, for SPA 1 region only. Please note the use of ‘FIXED_DISTANCE_BAND’ for the conceptualization of spatial relationships within the HotSpots Routine in the script: # SPA 1 Fixed Distance Analysis# Please note distances used in the script are in U.S. feet (distance units of the projected coordinate# system, NAD_1983_StatePlane_California_V_FIPS_0405_Feet). The arcpy.HotSpots_stats # Routine is used for each SPA-specific hot spot analysis. print "Started Hot Spot Analysis (Getis Ord Gi*), Fixed Distance Method, 10 mile, for SPA 1" # Define variables needed to run the Hot Spot Analysis in SPA 1 area. FPL138_15pc = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb\\LACounty_GIS\\SPA1_out.FPL138_15pc" SPA1_FxdDist_10Mile = "C:\\PythonCourse_FinalPrjt\\LayerTemplates.gdb\\Hot_Spots\\SPA1_FxdDist_10Mile" Results_Field = "GiZScore" Probability_Field = "GiPValue" Source_ID = "SOURCE_ID" # Process: Hot Spot Analysis (Getis-Ord Gi*) arcpy.HotSpots_stats(SPA1_out, "FPL138_15pc", SPA1_FxdDist_10Mile,\ "FIXED_DISTANCE_BAND", "EUCLIDEAN_DISTANCE", "NONE", "52800", "", "", "NO_FDR") print "Finished Hot Spot Analysis (Getis Ord Gi*), Fixed Distance Method, 10 mile, for SPA 1"Part C. Automating pdf map production for Hot Spot Analyses of Eight Service Planning Area regions in Los Angeles County.This Python script works on a customized mxd map template I created before writing this part of the Python script. It applies the mapping module routine to generate customized .pdf map files, each for each of the eight SPA hot spots generated in Part B of this script project. A picture of this starting template can be seen here:36581219The main task of this last script section is to zoom-in on each of the eight SPA regions and generate a specific SPA map (eight in total). It is also supposed to auto-arrange the position of city and SPA labels so that the relative position of these text elements does not “compete’ with the one region being zoomed-in. In order to accomplish this task, this author adapted our course instructor’s mapping module script to meet this Python Script project needs. Here are some specific examples of what the Python Script accomplished in Part C.After importing the arcpy.mapping module, I defined my workspace as follows:# Setting my current workspace: print "Setting my current workspace" datapath = 'C:\\PythonCourse_FinalPrjt\\' mappath = datapath + 'MyData\\Maps\\' mxd = MapDocument(datapath + 'Python_FinalPrjt.mxd') # Gettting my list of data frames. I am using a single data frame for this project. # [0] indicates the first (or only one data frame, which I labeled "DataFrame_SPAs") dataframe = ListDataFrames(mxd, "DataFrame_SPAs") [0]I used the code line “For loop” to go through all SPA layers in my Table of Contents:for TOCLayer in TOCLayers: print 'Layer Name ' + str(TOCLayer.name) #if SPALayer.longName == 'Detail Map\SPAs': print 'Longname ' + str(TOCLayer.longName)I added two layers (City_Group.lyr, SPA_Labels.lyr) to my data frame (‘AddLayer’) and auto-arranged each:dataLayer = Layer(datapath + 'MyData\City_Group.lyr') AddLayer(dataframe, dataLayer, 'AUTO_ARRANGE') legend = ListLayoutElements(mxd, 'LEGEND_ELEMENT', 'Legend') [0]dataLayer2 = Layer(datapath + 'MyData\SPA_Labels.lyr') AddLayer(dataframe, dataLayer2, 'AUTO_ARRANGE') legend = ListLayoutElements(mxd, 'LEGEND_ELEMENT', 'Legend') [0]After running these line codes, I followed our course Python Script template for the mapping module by adding a search cursor on the SPALayer:field_name = ["SPA_NAME"] with arcpy.da.SearchCursor(SPALayer, field_name) as SPArows: # Create a for loop that will help the Search Cursor go through each row in the column # referenced above (field_name = ["SPA_NAME"]) of the SPA layer. for SPArow in SPArows: # According to Mr. Jennings's template, indentation is necessary to loop over # the individual rows of the cursor. # Set a variable to the SPA's NAME field so it holds the actual variable name. SPAName = SPArow[0] # remember, a Python list index is used to obtain the value for a # row and column where column is the "SPA_NAME" field # (proxied by 'field_name' form line 64 above) # Must generate a query variable that uses the SPA name variable. query = """"SPA_NAME" = '""" + SPAName + """'""" # Must assign the SPA Layer's definition Query property to the query variable. SPALayer.definitionQuery = query # Set the data frame's extent property to the layer's extent using the getExtent() method. # NOTE: dataframe is already defined. dataframe.extent = SPALayer.getExtent() # Set the dataframe's scale propety to dataframe.scale * 1.1 (10%) # Please note: dataframe was defined already. dataframe.scale = dataframe.scale * 1.1 # Add a 10% buffer to the extentImmediately after setting the dataframe extent and scale, I also created a query variable that used the SPA name variable. Please note: these SPA names, taken from the variable “SPA_NAME” in the table of attributes on the SPA layer, are used to name each SPA-based pdf map generated in the ExportToPDF routine. query = """"SPA_NAME" = '""" + SPAName + """'""" # Must assign the SPA Layer's definition Query property to the query variable. SPALayer.definitionQuery = query # Next, set the data frame's extent property to the layer's extent using the getExtent() # method. NOTE: dataframe is already defined. dataframe.extent = SPALayer.getExtent() # Set the dataframe's scale propety to dataframe.scale * 1.1. Please note: dataframe was # defined already. dataframe.scale = dataframe.scale * 1.1 # Add a 10% buffer to the extentFinally, Part C of the Python Script ends by checking if the eight SPA-based pdf maps exist. To delete and update any existing pdf file, I used the Delete.management routine before using the ExportToPDF routine to create the final .pdf map files. if arcpy.Exists(mappath + SPAName + '_map.pdf'): arcpy.Delete_management(mappath + SPAName + '_map.pdf') # Use the ExportToPDF routine to export the map ExportToPDF(mxd, mappath + SPAName + '_map.pdf') print 'Created ' + SPAName + '_map.pdf'Summary of any difficulties/issues and how they were resolved.Indentation. Most of the difficulties encountered were related to script indentation. Being new to Python Scripting, and even after reading our textbooks and listening to Mr. Jenning’s recorded lectures for appropriate tips, this author still encountered errors due to improper indentation. The way to fix improper indentation was to focus on the Python Shell error and looking for the improper indentation on the code line specified by it. Wrong double quote use.Exercise caution identifying when you need to use double quotes to signify an object you are referring to in your script is a “layer” and when it is a feature class (no double quotes are needed). Data Availability.Although not a real issue in this project, it is advised to plan ahead before starting any Python Script and identify all data sources that will be needed in different sections of your script. In this Python project’s case, this author had access to the 2015 estimated 138% Federal Poverty counts, by census tract, for Los Angeles County. Additionally, this author had access to all eight ‘generic’ SPA-specific GIS layers that were needed by the SelectByLocation.management routine to select census tracts from the main poverty layer (FPL138fc_lyr) that contained the updated 13% poverty count field ('FPL138_15pc') for each census tract row. Map Template Set Up.The mapping module used in this Python Script project manipulates map elements similarly to the way Data Driven Pages works. Being familiar, to some extent, with the latter, helps raise awareness of ways in which the map template will be represented in the final pdf output. Hence, this author recommends setting up the map template and adding layout elements ahead of time. Test your mapping module output and see how things are placed. In this project, removing the city boundary layer from the map legend items ensured that this layer would not show up twice in each of the pdf maps. The reason was that the city boundary layer would be added to the map template through the AddLayer routine in the script (Part C). The same applied to the SPA labels layer, as it would be added to the map template by an AddLayer routine as well. Bibliographic and Data References.Centers for Medicare and Medicaid Services or CMS (2017). Affordable Care Act. of California Department of Health Care Services (2016). Drug Medi-Cal Organized Delivery System Waiver presentation. Developer Network. Pro. page. Modeling spatial relationships. , Nathan (2016). A Python Primer for ArcGIS, Workbooks 1, 2 & 3. San Bernardino, California.Jennings, Nathan (2017). Python Script lesson templates for update and search cursors, and mapping module, Geography 375, Spring 2017. American River College, Sacramento, California.Los Angeles County Internal Services Department (ISD), Urban Research Unit. GIS layer for estimated number of adult persons living at or below the 138 % Federal Poverty Level in 2015; generic service planning area (SPA) layers for Los Angeles County. ................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download