def polygons_in_zones(zone_fc, zone_field, polygons_of_interest, output_table, interest_selection_expr):
    old_workspace = arcpy.env.workspace
    arcpy.env.workspace = 'in_memory'
    arcpy.SetLogHistory(False)
    arcpy.env.outputCoordinateSystem = arcpy.SpatialReference(102039)
    selected_polys = 'selected_polys'
    # fixes some stupid ArcGIS thing with the interactive Python window
    if arcpy.Exists(selected_polys):
        arcpy.env.overwriteOutput = True

    arcpy.AddMessage('Copying/selecting polygon features...')
    if interest_selection_expr:
        arcpy.Select_analysis(polygons_of_interest, selected_polys, interest_selection_expr)
    else:
        arcpy.CopyFeatures_management(polygons_of_interest, selected_polys)

    # use tabulate intersection for the areas overlapping
    arcpy.AddMessage('Tabulating intersection between zones and polygons...')
    tab_table = arcpy.TabulateIntersection_analysis(zone_fc, zone_field, selected_polys,
                                        'tabulate_intersection_table')

    # area was calculated in map units which was m2 so convert to hectares
    arcpy.AddField_management(tab_table, 'Poly_Ha', 'DOUBLE')
    arcpy.CalculateField_management(tab_table, 'Poly_Ha', '!AREA!/10000', 'PYTHON')


    # just change the name of the percent field
    arcpy.AlterField_management(tab_table, 'PERCENTAGE', 'Poly_Pct')

    # Now just get the count as there is no other area metric anymore
    spjoin_fc = arcpy.SpatialJoin_analysis(zone_fc, selected_polys, 'spatial_join_output')
    arcpy.AlterField_management(spjoin_fc, 'Join_Count', 'Poly_n')

    # Add the density
    arcpy.AddField_management(spjoin_fc, 'Poly_nperha', 'DOUBLE')
    arcpy.CalculateField_management(spjoin_fc, 'Poly_nperha', '!Poly_n!/!shape.area@hectares!', 'PYTHON')

    arcpy.AddMessage('Refining output...')
    arcpy.JoinField_management(tab_table, zone_field, spjoin_fc, zone_field, ["Poly_n", 'Poly_nperha'])
    final_fields = ['Poly_Ha', 'Poly_Pct', 'Poly_n', 'Poly_nperha']

    # make output nice
    arcpy.env.overwriteOutput = False
    cu.one_in_one_out(tab_table, final_fields, zone_fc, zone_field, output_table)

    cu.redefine_nulls(output_table, final_fields, [0, 0, 0, 0])

    # clean up
    # can't delete all of in_memory because this function is meant to be called from another one that uses in_memory
    for item in [selected_polys, tab_table, spjoin_fc]:
        arcpy.Delete_management(item)
    arcpy.env.workspace = old_workspace

    arcpy.AddMessage('Polygons in zones tool complete.')
    arcpy.SetLogHistory(True)
def wetland_order(rivex, stream_area_fc, nwi, out_fc):
    arcpy.env.workspace = 'in_memory'
    arcpy.env.outputCoordinateSystem = arcpy.SpatialReference(102039)
    arcpy.env.extent = nwi

    # Buffer the wetland perimeters by 30 meters
    cu.multi_msg('Creating 30m wetland buffers...')
    arcpy.Buffer_analysis(nwi, "wetland_buffers", "30 meters", "OUTSIDE_ONLY")
    arcpy.env.extent = "wetland_buffers"

    cu.multi_msg('Preparing for river line and area merge...')
    arcpy.CopyFeatures_management(rivex, 'rivex_extent')
    arcpy.CopyFeatures_management(stream_area_fc, 'stream_area_extent')
    arcpy.MakeFeatureLayer_management('rivex_extent', 'rivex_lyr')
    arcpy.SelectLayerByLocation_management('rivex_lyr', 'COMPLETELY_WITHIN',
                                           stream_area_fc)
    arcpy.CopyFeatures_management('rivex_lyr', 'rivex_for_splitting')
    arcpy.SelectLayerByAttribute_management('rivex_lyr', 'SWITCH_SELECTION')
    arcpy.CopyFeatures_management('rivex_lyr', 'rivex_not_areas')
    split_strahler('stream_area_extent', 'rivex_for_splitting',
                   'stream_area_split')

    # areas TO lines
    arcpy.PolygonToLine_management('stream_area_split', 'streamarea_to_line',
                                   False)

    # Merge features together
    arcpy.Merge_management(['streamarea_to_line', 'rivex_not_areas'],
                           'merged_rivers', 'NO_TEST')

    # FOR THE LINE-BASED PORTION
    # Spatial join connected wetlands and streams
    ##################Field Maps########################
    fms = arcpy.FieldMappings()
    fm_strahlermax = arcpy.FieldMap()
    fm_strahlersum = arcpy.FieldMap()
    fm_lengthkm = arcpy.FieldMap()
    fm_wetid = arcpy.FieldMap()

    fm_strahlermax.addInputField('merged_rivers', "Strahler")
    fm_strahlersum.addInputField('merged_rivers', "Strahler")
    fm_lengthkm.addInputField('merged_rivers', "LengthKm")
    fm_wetid.addInputField("wetland_buffers", "WET_ID")

    fm_lengthkm.mergeRule = 'Sum'
    fm_strahlermax.mergeRule = 'Max'
    fm_strahlersum.mergeRule = 'Sum'

    lengthkm_name = fm_lengthkm.outputField
    lengthkm_name.name = 'StreamKm'
    lengthkm_name.aliasName = 'StreamKm'
    fm_lengthkm.outputField = lengthkm_name

    strahlermax_name = fm_strahlermax.outputField
    strahlermax_name.name = 'StrOrdMax'
    strahlermax_name.aliasName = 'StrOrdMax'
    fm_strahlermax.outputField = strahlermax_name

    strahlersum_name = fm_strahlersum.outputField
    strahlersum_name.name = 'StrOrdSum'
    strahlersum_name.aliasName = 'StrOrdSum'
    fm_strahlersum.outputField = strahlersum_name

    fms.addFieldMap(fm_strahlermax)
    fms.addFieldMap(fm_strahlersum)
    fms.addFieldMap(fm_lengthkm)
    fms.addFieldMap(fm_wetid)
    #####################################################

    arcpy.SpatialJoin_analysis("wetland_buffers", 'merged_rivers',
                               "wetland_spjoin_streams", '', '', fms)

    # Get the stream count from the join count
    cu.rename_field("wetland_spjoin_streams", 'Join_Count', "StreamCnt", True)

    # Join the new fields back to the original feature class based on WET_ID
    join_fields = ['StrOrdMax', 'StrOrdSum', 'StreamKm', 'StreamCnt']
    arcpy.CopyFeatures_management(nwi, out_fc)
    arcpy.JoinField_management(out_fc, 'WET_ID', 'wetland_spjoin_streams',
                               'WET_ID', join_fields)

    # Set these to 0 where there is no connection
    cu.redefine_nulls(out_fc, join_fields, [0, 0, 0, 0])

    # Classify VegType: 4 options based on class code in ATTRIBUTE field
    arcpy.AddField_management(out_fc, "VegType", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["ATTRIBUTE", "VegType"]) as cursor:
        for row in cursor:
            attr_abbv = row[0][:3]
            if attr_abbv == "PEM" or attr_abbv == "PAB":
                row[1] = "PEMorPAB"
            elif attr_abbv == "PFO":
                row[1] = "PFO"
            elif attr_abbv == "PSS":
                row[1] = "PSS"
            else:
                row[1] = "Other"
            cursor.updateRow(row)

    # Determine the regime from the letter code. Examples: PSS1E ---> E,
    #  PEM1/SS1Fb --> F
    class_codes = 'RB UB AB US ML EM SS FO'.split()
    regime_codes = 'A B C E F G H J K'.split()
    arcpy.AddField_management(out_fc, "Regime", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["ATTRIBUTE", "Regime"]) as cursor:
        for row in cursor:
            # All the wetlands are already palustrine, so if we remove the class
            # codes, any capital letters left besides the P in front
            # are the regime code
            # example codes: PEM1E, PSS1/EM1E, PEM1/5C, PUSA, PSSf
            # If you ever can figure out the regex for this instead, go ahead.
            code_value = row[0]
            regime_value = 'unknown'
            # this bit searches for the class codes and replaces them with nothing
            # this is necessary because meaning of A, B, E, F is context dependent
            for class_code in class_codes:
                if class_code in code_value:
                    code_value = code_value.replace(class_code, '')
            for char in code_value:
                if char in regime_codes:
                    regime_value = char
            row[1] = regime_value
            cursor.updateRow(row)

    # Calculate WetOrder from StrOrdSum
    arcpy.AddField_management(out_fc, "WetOrder", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["StrOrdSum", "WetOrder"]) as cursor:
        for row in cursor:
            if row[0] == 0:
                row[1] = "Isolated"
            elif row[0] == 1:
                row[1] = "Single"
            elif row[0] == None:
                row[1] = "Isolated"
            else:
                row[1] = "Connected"
            cursor.updateRow(row)
    arcpy.Delete_management('in_memory')
Beispiel #3
0
def connected_wetlands(lakes_fc, lake_id_field, wetlands_fc, out_table):
    env.workspace = 'in_memory'
    env.outputCoordinateSystem = arcpy.SpatialReference(102039)

    arcpy.Buffer_analysis(lakes_fc, 'lakes_30m', '30 meters')

    arcpy.FeatureToLine_management('lakes_30m', 'shorelines')

    # 3 selections for the wetlands types we want to look at
    openwater_exp = """"VegType" = 'PEMorPAB'"""
    forested_exp = """"VegType" = 'PFO'"""
    scrubshrub_exp = """"VegType" = 'PSS'"""
    other_exp = """"VegType" = 'Other'"""
    all_exp = ''

    selections = [
        all_exp, forested_exp, scrubshrub_exp, openwater_exp, other_exp
    ]
    temp_tables = [
        'AllWetlands', 'ForestedWetlands', 'ScrubShrubWetlands',
        'OpenWaterWetlands', 'OtherWetlands'
    ]

    # for each wetland type, get the count of intersection wetlands, and the length of the lake
    # shoreline that is within a wetland polygon
    for sel, temp_table in zip(selections, temp_tables):
        print("Creating temporary table for wetlands where {0}".format(sel))
        # this function adds the count and the area using the lake as the zone
        polygons_in_zones('lakes_30m',
                          lake_id_field,
                          wetlands_fc,
                          temp_table,
                          sel,
                          contrib_area=True)

        # make good field names now rather than later
        for f in new_fields:
            cu.rename_field(temp_table, f, f.replace('Poly', temp_table), True)

        # shoreline calculation
        # using the Shape_Length field so can't do this part in memory
        shoreline_gdb = cu.create_temp_GDB('shoreline')
        selected_wetlands = os.path.join(shoreline_gdb, 'wetlands')
        arcpy.Select_analysis(wetlands_fc, selected_wetlands, sel)
        intersect_output = os.path.join(shoreline_gdb, "intersect")
        arcpy.Intersect_analysis(['shorelines', selected_wetlands],
                                 intersect_output)
        arcpy.Statistics_analysis(intersect_output, 'intersect_stats',
                                  [['Shape_Length', 'SUM']], lake_id_field)
        cu.one_in_one_out('intersect_stats', ['SUM_Shape_Length'], lakes_fc,
                          lake_id_field, 'temp_shoreline_table')
        cu.redefine_nulls('temp_shoreline_table', ['SUM_Shape_Length'], [0])
        shoreline_field = temp_table + "_Shoreline_Km"
        arcpy.AddField_management('temp_shoreline_table', shoreline_field,
                                  'DOUBLE')
        arcpy.CalculateField_management('temp_shoreline_table',
                                        shoreline_field,
                                        '!SUM_Shape_Length!/1000', 'PYTHON')

        # join the shoreline value to the temp_table
        arcpy.JoinField_management(temp_table, lake_id_field,
                                   'temp_shoreline_table', lake_id_field,
                                   shoreline_field)

        # clean up shoreline intermediates
        for item in [shoreline_gdb, 'intersect_stats', 'temp_shoreline_table']:
            arcpy.Delete_management(item)

    # join em up and copy to final
    temp_tables.remove('AllWetlands')
    for t in temp_tables:
        try:
            arcpy.JoinField_management('AllWetlands', lake_id_field, t,
                                       lake_id_field)
        # sometimes there's no table if it was an empty selection
        except:
            empty_fields = [f.replace('Poly', t) for f in new_fields]
            for ef in empty_fields:
                arcpy.AddField_management('AllWetlands', ef, 'Double')
                arcpy.CalculateField_management('AllWetlands', ef, '0',
                                                'PYTHON')
            continue
    # remove all the extra zone fields, which have underscore in name
    drop_fields = [
        f.name
        for f in arcpy.ListFields('AllWetlands', 'Permanent_Identifier_*')
    ]
    for f in drop_fields:
        arcpy.DeleteField_management('AllWetlands', f)

    # remove all the overlapping metrics, which do not apply by definition
    fields = [f.name for f in arcpy.ListFields('AlLWetlands')]
    for f in fields:
        if 'Overlapping' in f:
            arcpy.DeleteField_management('AllWetlands', f)
    arcpy.CopyRows_management('AllWetlands', out_table)

    for item in ['AllWetlands'] + temp_tables:
        try:
            arcpy.Delete_management(item)
        except:
            continue
def connected_wetlands(lakes_fc, lake_id_field, wetlands_fc, out_table):
    env.workspace = 'in_memory'
    env.outputCoordinateSystem = arcpy.SpatialReference(102039)

    arcpy.Buffer_analysis(lakes_fc, 'lakes_30m', '30 meters')

    arcpy.FeatureToLine_management('lakes_30m', 'shorelines')

    # 3 selections for the wetlands types we want to look at
    openwater_exp = """"VegType" = 'PEMorPAB'"""
    forested_exp = """"VegType" = 'PFO'"""
    scrubshrub_exp = """"VegType" = 'PSS'"""
    other_exp = """"VegType" = 'Other'"""
    all_exp = ''


    selections = [all_exp, forested_exp, scrubshrub_exp, openwater_exp, other_exp]
    temp_tables = ['AllWetlands', 'ForestedWetlands', 'ScrubShrubWetlands', 'OpenWaterWetlands', 'OtherWetlands']

    # for each wetland type, get the count of intersection wetlands, and the length of the lake
    # shoreline that is within a wetland polygon
    for sel, temp_table in zip(selections, temp_tables):
        print("Creating temporary table for wetlands where {0}".format(sel))
        # this function adds the count and the area using the lake as the zone
        polygons_in_zones('lakes_30m', lake_id_field, wetlands_fc, temp_table, sel, contrib_area = True)

        # make good field names now rather than later
        for f in new_fields:
            cu.rename_field(temp_table, f, f.replace('Poly', temp_table), True)

        # shoreline calculation
        # using the Shape_Length field so can't do this part in memory
        shoreline_gdb = cu.create_temp_GDB('shoreline')
        selected_wetlands = os.path.join(shoreline_gdb, 'wetlands')
        arcpy.Select_analysis(wetlands_fc, selected_wetlands, sel)
        intersect_output = os.path.join(shoreline_gdb, "intersect")
        arcpy.Intersect_analysis(['shorelines', selected_wetlands], intersect_output)
        arcpy.Statistics_analysis(intersect_output, 'intersect_stats', [['Shape_Length', 'SUM']], lake_id_field)
        cu.one_in_one_out('intersect_stats', ['SUM_Shape_Length'], lakes_fc, lake_id_field, 'temp_shoreline_table')
        cu.redefine_nulls('temp_shoreline_table', ['SUM_Shape_Length'], [0])
        shoreline_field = temp_table + "_Shoreline_Km"
        arcpy.AddField_management('temp_shoreline_table', shoreline_field, 'DOUBLE')
        arcpy.CalculateField_management('temp_shoreline_table', shoreline_field, '!SUM_Shape_Length!/1000', 'PYTHON')

        # join the shoreline value to the temp_table
        arcpy.JoinField_management(temp_table, lake_id_field, 'temp_shoreline_table', lake_id_field, shoreline_field)

        # clean up shoreline intermediates
        for item in [shoreline_gdb, 'intersect_stats', 'temp_shoreline_table']:
            arcpy.Delete_management(item)

    # join em up and copy to final
    temp_tables.remove('AllWetlands')
    for t in temp_tables:
        try:
            arcpy.JoinField_management('AllWetlands', lake_id_field, t, lake_id_field)
        # sometimes there's no table if it was an empty selection
        except:
            empty_fields = [f.replace('Poly', t) for f in new_fields]
            for ef in empty_fields:
                arcpy.AddField_management('AllWetlands', ef, 'Double')
                arcpy.CalculateField_management('AllWetlands', ef, '0', 'PYTHON')
            continue
    # remove all the extra zone fields, which have underscore in name
    drop_fields = [f.name for f in arcpy.ListFields('AllWetlands', 'Permanent_Identifier_*')]
    for f in drop_fields:
        arcpy.DeleteField_management('AllWetlands', f)

    # remove all the overlapping metrics, which do not apply by definition
    fields = [f.name for f in arcpy.ListFields('AlLWetlands')]
    for f in fields:
        if 'Overlapping' in f:
            arcpy.DeleteField_management('AllWetlands', f)
    arcpy.CopyRows_management('AllWetlands', out_table)

    for item in ['AllWetlands'] + temp_tables:
        try:
            arcpy.Delete_management(item)
        except:
            continue
def line_density(zones, zonefield, lines, out_table, interest_selection_expr):
    # Make output folder
##    name = "LineDensity_" + os.path.splitext(os.path.basename(zones))[0]
##    outfolder = os.path.join(topoutfolder, name)
##    if not os.path.exists(outfolder):
##        os.mkdir(outfolder)

    # Environmental Settings
    ws = "in_memory"

    if interest_selection_expr:
        arcpy.MakeFeatureLayer_management(lines, "selected_lines", interest_selection_expr)
    else:
        arcpy.MakeFeatureLayer_management(lines, "selected_lines")

    arcpy.env.workspace = ws
    albers = arcpy.SpatialReference(102039)
    arcpy.env.outputCoordinateSystem = albers
    arcpy.env.extent = zones

    # Zones will be coerced to albers, have to check lines though
    arcpy.CopyFeatures_management(zones, "zones_temp")
    if arcpy.Describe(lines).spatialReference.factoryCode != albers.factoryCode:
        arcpy.AddError("Lines feature class does not have desired projection (Albers USGS). Re-project to factory code 102039 and try again.")
        sys.exit(1)

    # Add hectares field to zones
    arcpy.AddField_management("zones_temp", "ZoneAreaHa", "DOUBLE")
    arcpy.CalculateField_management("zones_temp", "ZoneAreaHa", "!shape.area@hectares!", "PYTHON")

    # Perform identity analysis to join fields and crack lines at polygon boundaries
    cu.multi_msg("Cracking lines at polygon boundaries...")
    arcpy.Identity_analysis("selected_lines", "zones_temp", "lines_identity")
    cu.multi_msg("Cracking lines complete.")

    # Recalculate lengths
    arcpy.AddField_management("lines_identity", "LengthM", "DOUBLE")
    arcpy.CalculateField_management("lines_identity", "LengthM", '!shape.length@meters!', "PYTHON")

    # Summarize statistics by zone
    arcpy.Statistics_analysis("lines_identity", "length_in_zone", "LengthM SUM", zonefield)


    # Join ZoneAreaHa to table
    arcpy.JoinField_management("length_in_zone", zonefield, "zones_temp" , zonefield, "ZoneAreaHa")

    # Delete rows in table with zero for zone area
##    with arcpy.da.UpdateCursor("length_in_zone", "ZoneAreaHa") as cursor:
##        for row in cursor:
##            if row[0] is None:
##                cursor.deleteRow()

    # Add Density field and calc
    arcpy.AddField_management("length_in_zone", "Density_MperHA", "DOUBLE",'','','','',"NULLABLE")
    exp = "!SUM_LengthM! / !ZONEAREAHA!"
    arcpy.CalculateField_management("length_in_zone", "Density_MperHA", exp, "PYTHON")

    cu.one_in_one_out("length_in_zone", ['SUM_LengthM', 'Density_MperHA'], zones, zonefield, out_table)
    cu.redefine_nulls(out_table, ['SUM_LengthM', 'Density_MperHA'], [0, 0])


##    # Join to the original table
##    keep_fields = ["ZoneID", "SUM_LengthM", "Density_MperHA"]
##    arcpy.JoinField_management('zones_temp', zonefield, "length_in_zone", zonefield, keep_fields[1:])
##
##    # Select only null records and change to 0
##    arcpy.MakeFeatureLayer_management('zones_temp', 'zones_temp_lyr')
##    arcpy.SelectLayerByAttribute_management('zones_temp_lyr', "NEW_SELECTION", '''"SUM_LengthM" is null''')
##    fields_to_calc = ["SUM_LengthM", "Density_MperHA"]
##    for f in fields_to_calc:
##        arcpy.CalculateField_management('zones_temp_lyr', f, 0, "PYTHON")
##
##    #Delete all the fields that aren't the ones I need
##    keep_fields = ["ZoneID", "SUM_LengthM", "Density_MperHA"]
##    all_fields = [f.name for f in arcpy.ListFields('zones_temp_lyr')]
##    for f in all_fields:
##        if f not in keep_fields:
##            try:
##                arcpy.DeleteField_management('zones_temp_lyr', f)
##            except:
##                continue
##    arcpy.SelectLayerByAttribute_management('zones_temp_lyr', 'CLEAR_SELECTION')
##
##    arcpy.CopyRows_management('zones_temp_lyr', out_table)

    for tempitem in ['zones_temp', 'lines_identity', 'length_in_zone']:
        arcpy.Delete_management(tempitem)

    return out_table
def polygons_in_zones(zone_fc, zone_field, polygons_of_interest, output_table,
                      interest_selection_expr):
    old_workspace = arcpy.env.workspace
    arcpy.env.workspace = 'in_memory'
    arcpy.SetLogHistory(False)
    arcpy.env.outputCoordinateSystem = arcpy.SpatialReference(102039)
    selected_polys = 'selected_polys'
    # fixes some stupid ArcGIS thing with the interactive Python window
    if arcpy.Exists(selected_polys):
        arcpy.env.overwriteOutput = True

    arcpy.AddMessage('Copying/selecting polygon features...')
    if interest_selection_expr:
        arcpy.Select_analysis(polygons_of_interest, selected_polys,
                              interest_selection_expr)
    else:
        arcpy.CopyFeatures_management(polygons_of_interest, selected_polys)

    # use tabulate intersection for the areas overlapping
    arcpy.AddMessage('Tabulating intersection between zones and polygons...')
    tab_table = arcpy.TabulateIntersection_analysis(
        zone_fc, zone_field, selected_polys, 'tabulate_intersection_table')

    # area was calculated in map units which was m2 so convert to hectares
    arcpy.AddField_management(tab_table, 'Poly_Ha', 'DOUBLE')
    arcpy.CalculateField_management(tab_table, 'Poly_Ha', '!AREA!/10000',
                                    'PYTHON')

    # just change the name of the percent field
    arcpy.AlterField_management(tab_table, 'PERCENTAGE', 'Poly_Pct')

    # Now just get the count as there is no other area metric anymore
    spjoin_fc = arcpy.SpatialJoin_analysis(zone_fc, selected_polys,
                                           'spatial_join_output')
    arcpy.AlterField_management(spjoin_fc, 'Join_Count', 'Poly_n')

    # Add the density
    arcpy.AddField_management(spjoin_fc, 'Poly_nperha', 'DOUBLE')
    arcpy.CalculateField_management(spjoin_fc, 'Poly_nperha',
                                    '!Poly_n!/!shape.area@hectares!', 'PYTHON')

    arcpy.AddMessage('Refining output...')
    arcpy.JoinField_management(tab_table, zone_field, spjoin_fc, zone_field,
                               ["Poly_n", 'Poly_nperha'])
    final_fields = ['Poly_Ha', 'Poly_Pct', 'Poly_n', 'Poly_nperha']

    # make output nice
    arcpy.env.overwriteOutput = False
    cu.one_in_one_out(tab_table, final_fields, zone_fc, zone_field,
                      output_table)

    cu.redefine_nulls(output_table, final_fields, [0, 0, 0, 0])

    # clean up
    # can't delete all of in_memory because this function is meant to be called from another one that uses in_memory
    for item in [selected_polys, tab_table, spjoin_fc]:
        arcpy.Delete_management(item)
    arcpy.env.workspace = old_workspace

    arcpy.AddMessage('Polygons in zones tool complete.')
    arcpy.SetLogHistory(True)
def wetland_order(rivex, stream_area_fc, nwi, out_fc):
    arcpy.env.workspace = 'in_memory'
    arcpy.env.outputCoordinateSystem = arcpy.SpatialReference(102039)
    arcpy.env.extent = nwi

    # Buffer the wetland perimeters by 30 meters
    cu.multi_msg('Creating 30m wetland buffers...')
    arcpy.Buffer_analysis(nwi, "wetland_buffers", "30 meters", "OUTSIDE_ONLY")
    arcpy.env.extent = "wetland_buffers"

    cu.multi_msg('Preparing for river line and area merge...')
    arcpy.CopyFeatures_management(rivex, 'rivex_extent')
    arcpy.CopyFeatures_management(stream_area_fc, 'stream_area_extent')
    arcpy.MakeFeatureLayer_management('rivex_extent', 'rivex_lyr')
    arcpy.SelectLayerByLocation_management('rivex_lyr', 'COMPLETELY_WITHIN', stream_area_fc)
    arcpy.CopyFeatures_management('rivex_lyr', 'rivex_for_splitting')
    arcpy.SelectLayerByAttribute_management('rivex_lyr', 'SWITCH_SELECTION')
    arcpy.CopyFeatures_management('rivex_lyr', 'rivex_not_areas')
    split_strahler('stream_area_extent', 'rivex_for_splitting', 'stream_area_split')

    # areas TO lines
    arcpy.PolygonToLine_management('stream_area_split', 'streamarea_to_line', False)

    # Merge features together
    arcpy.Merge_management(['streamarea_to_line', 'rivex_not_areas'], 'merged_rivers', 'NO_TEST')

    # FOR THE LINE-BASED PORTION
    # Spatial join connected wetlands and streams
    ##################Field Maps########################
    fms = arcpy.FieldMappings()
    fm_strahlermax = arcpy.FieldMap()
    fm_strahlersum = arcpy.FieldMap()
    fm_lengthkm = arcpy.FieldMap()
    fm_wetid = arcpy.FieldMap()

    fm_strahlermax.addInputField('merged_rivers', "Strahler")
    fm_strahlersum.addInputField('merged_rivers', "Strahler")
    fm_lengthkm.addInputField('merged_rivers', "LengthKm")
    fm_wetid.addInputField("wetland_buffers", "WET_ID")

    fm_lengthkm.mergeRule = 'Sum'
    fm_strahlermax.mergeRule = 'Max'
    fm_strahlersum.mergeRule = 'Sum'

    lengthkm_name = fm_lengthkm.outputField
    lengthkm_name.name = 'StreamKm'
    lengthkm_name.aliasName = 'StreamKm'
    fm_lengthkm.outputField = lengthkm_name

    strahlermax_name = fm_strahlermax.outputField
    strahlermax_name.name = 'StrOrdMax'
    strahlermax_name.aliasName = 'StrOrdMax'
    fm_strahlermax.outputField = strahlermax_name

    strahlersum_name = fm_strahlersum.outputField
    strahlersum_name.name = 'StrOrdSum'
    strahlersum_name.aliasName = 'StrOrdSum'
    fm_strahlersum.outputField = strahlersum_name

    fms.addFieldMap(fm_strahlermax)
    fms.addFieldMap(fm_strahlersum)
    fms.addFieldMap(fm_lengthkm)
    fms.addFieldMap(fm_wetid)
    #####################################################

    arcpy.SpatialJoin_analysis("wetland_buffers", 'merged_rivers', "wetland_spjoin_streams", '', '', fms)

    # Get the stream count from the join count
    cu.rename_field("wetland_spjoin_streams", 'Join_Count', "StreamCnt", True)

    # Join the new fields back to the original feature class based on WET_ID
    join_fields = ['StrOrdMax', 'StrOrdSum', 'StreamKm', 'StreamCnt']
    arcpy.CopyFeatures_management(nwi, out_fc)
    arcpy.JoinField_management(out_fc, 'WET_ID', 'wetland_spjoin_streams', 'WET_ID', join_fields)

    # Set these to 0 where there is no connection
    cu.redefine_nulls(out_fc, join_fields, [0,0,0,0])

    # Classify VegType: 4 options based on class code in ATTRIBUTE field
    arcpy.AddField_management(out_fc, "VegType", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["ATTRIBUTE", "VegType"]) as cursor:
        for row in cursor:
            attr_abbv = row[0][:3]
            if attr_abbv == "PEM" or attr_abbv == "PAB":
                row[1] = "PEMorPAB"
            elif attr_abbv == "PFO":
                row[1] = "PFO"
            elif attr_abbv == "PSS":
                row[1] = "PSS"
            else:
                row[1] = "Other"
            cursor.updateRow(row)

    # Determine the regime from the letter code. Examples: PSS1E ---> E,
    #  PEM1/SS1Fb --> F
    class_codes = 'RB UB AB US ML EM SS FO'.split()
    regime_codes = 'A B C E F G H J K'.split()
    arcpy.AddField_management(out_fc, "Regime", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["ATTRIBUTE", "Regime"]) as cursor:
        for row in cursor:
            # All the wetlands are already palustrine, so if we remove the class
            # codes, any capital letters left besides the P in front
            # are the regime code
            # example codes: PEM1E, PSS1/EM1E, PEM1/5C, PUSA, PSSf
            # If you ever can figure out the regex for this instead, go ahead.
            code_value = row[0]
            regime_value = 'unknown'
            # this bit searches for the class codes and replaces them with nothing
            # this is necessary because meaning of A, B, E, F is context dependent
            for class_code in class_codes:
                if class_code in code_value:
                    code_value = code_value.replace(class_code, '')
            for char in code_value:
                if char in regime_codes:
                    regime_value = char
            row[1] = regime_value
            cursor.updateRow(row)

    # Calculate WetOrder from StrOrdSum
    arcpy.AddField_management(out_fc,"WetOrder", "TEXT")
    with arcpy.da.UpdateCursor(out_fc, ["StrOrdSum", "WetOrder"]) as cursor:
        for row in cursor:
            if row[0] == 0:
                row[1] = "Isolated"
            elif row[0] == 1:
                row[1] = "Single"
            elif row[0] == None:
                row[1] = "Isolated"
            else:
                row[1] = "Connected"
            cursor.updateRow(row)
    arcpy.Delete_management('in_memory')
def polygons_in_zones(zone_fc,
                      zone_field,
                      polygons_of_interest,
                      output_table,
                      interest_selection_expr,
                      contrib_area=True):
    old_workspace = arcpy.env.workspace
    arcpy.env.workspace = 'in_memory'
    arcpy.env.outputCoordinateSystem = arcpy.SpatialReference(102039)

    temp_polyzones = cu.create_temp_GDB('temp_polyzones')
    selected_polys = os.path.join(temp_polyzones, 'selected_polys')
    cu.multi_msg('Copying/selecting polygon features...')
    if interest_selection_expr:
        arcpy.Select_analysis(polygons_of_interest, selected_polys,
                              interest_selection_expr)
    else:
        arcpy.CopyFeatures_management(polygons_of_interest, selected_polys)

    arcpy.AddField_management(selected_polys, 'POLYAREA_ha', 'DOUBLE')
    arcpy.CalculateField_management(selected_polys, 'POLYAREA_ha',
                                    '!shape.area@hectares!', 'PYTHON')

    # use tabulate intersection for the areas overlapping
    tab_table = 'tabulate_intersection_table'
    cu.multi_msg('Tabulating intersection between zones and polygons...')
    arcpy.TabulateIntersection_analysis(zone_fc, zone_field, selected_polys,
                                        tab_table)

    # area was calculated in map units which was m2 so convert to hectares
    arcpy.AddField_management(tab_table, 'Poly_Overlapping_AREA_ha', 'DOUBLE')
    arcpy.CalculateField_management(tab_table, 'Poly_Overlapping_AREA_ha',
                                    '!AREA!/10000', 'PYTHON')

    # just change the name of the percent field
    cu.rename_field(tab_table, 'PERCENTAGE', 'Poly_Overlapping_AREA_pct', True)
    spjoin_fc = 'spatial_join_output'

    # Spatial join for the count and contributing area
    fms = arcpy.FieldMappings()

    fm_zone_id = arcpy.FieldMap()
    fm_zone_id.addInputField(zone_fc, zone_field)

    fm_count = arcpy.FieldMap()
    fm_count.addInputField(selected_polys, 'POLYAREA_ha')
    count_name = fm_count.outputField
    count_name.name = 'Poly_Count'
    count_name.alias = 'Poly_Count'
    fm_count.outputField = count_name
    fm_count.mergeRule = 'Count'

    fm_contrib_area = arcpy.FieldMap()
    fm_contrib_area.addInputField(selected_polys, 'POLYAREA_ha')
    contrib_area_name = fm_contrib_area.outputField
    contrib_area_name.name = 'Poly_Contributing_AREA_ha'
    contrib_area_name.alias = 'Poly_Contributing_AREA_ha'
    fm_contrib_area.outputField = contrib_area_name
    fm_contrib_area.mergeRule = 'Sum'

    fms.addFieldMap(fm_zone_id)
    fms.addFieldMap(fm_count)
    fms.addFieldMap(fm_contrib_area)

    cu.multi_msg('Spatial join between zones and wetlands...')
    arcpy.SpatialJoin_analysis(zone_fc, selected_polys, spjoin_fc,
                               "JOIN_ONE_TO_ONE", "KEEP_ALL", fms, "INTERSECT")

    cu.multi_msg('Refining output...')
    arcpy.JoinField_management(tab_table, zone_field, spjoin_fc, zone_field,
                               ["Poly_Count", "Poly_Contributing_AREA_ha"])
    final_fields = [
        'Poly_Overlapping_AREA_ha', 'Poly_Overlapping_AREA_pct', 'Poly_Count',
        'Poly_Contributing_AREA_ha'
    ]

    # make output nice
    cu.one_in_one_out(tab_table, final_fields, zone_fc, zone_field,
                      output_table)
    cu.redefine_nulls(output_table, final_fields, [0, 0, 0, 0])

    # clean up
    for item in [selected_polys, tab_table, spjoin_fc]:
        arcpy.Delete_management(item)
    arcpy.Delete_management(temp_polyzones)
    arcpy.env.workspace = old_workspace

    cu.multi_msg('Polygons in zones tool complete.')
Beispiel #9
0
def line_density(zones, zonefield, lines, out_table, interest_selection_expr):
    # Make output folder
    ##    name = "LineDensity_" + os.path.splitext(os.path.basename(zones))[0]
    ##    outfolder = os.path.join(topoutfolder, name)
    ##    if not os.path.exists(outfolder):
    ##        os.mkdir(outfolder)

    # Environmental Settings
    ws = "in_memory"

    if interest_selection_expr:
        arcpy.MakeFeatureLayer_management(lines, "selected_lines",
                                          interest_selection_expr)
    else:
        arcpy.MakeFeatureLayer_management(lines, "selected_lines")

    arcpy.env.workspace = ws
    albers = arcpy.SpatialReference(102039)
    arcpy.env.outputCoordinateSystem = albers
    arcpy.env.extent = zones

    # Zones will be coerced to albers, have to check lines though
    arcpy.CopyFeatures_management(zones, "zones_temp")
    if arcpy.Describe(
            lines).spatialReference.factoryCode != albers.factoryCode:
        arcpy.AddError(
            "Lines feature class does not have desired projection (Albers USGS). Re-project to factory code 102039 and try again."
        )
        sys.exit(1)

    # Add hectares field to zones
    arcpy.AddField_management("zones_temp", "ZoneAreaHa", "DOUBLE")
    arcpy.CalculateField_management("zones_temp", "ZoneAreaHa",
                                    "!shape.area@hectares!", "PYTHON")

    # Perform identity analysis to join fields and crack lines at polygon boundaries
    cu.multi_msg("Cracking lines at polygon boundaries...")
    arcpy.Identity_analysis("selected_lines", "zones_temp", "lines_identity")
    cu.multi_msg("Cracking lines complete.")

    # Recalculate lengths
    arcpy.AddField_management("lines_identity", "LengthM", "DOUBLE")
    arcpy.CalculateField_management("lines_identity", "LengthM",
                                    '!shape.length@meters!', "PYTHON")

    # Summarize statistics by zone
    arcpy.Statistics_analysis("lines_identity", "length_in_zone",
                              "LengthM SUM", zonefield)

    # Join ZoneAreaHa to table
    arcpy.JoinField_management("length_in_zone", zonefield, "zones_temp",
                               zonefield, "ZoneAreaHa")

    # Delete rows in table with zero for zone area
    ##    with arcpy.da.UpdateCursor("length_in_zone", "ZoneAreaHa") as cursor:
    ##        for row in cursor:
    ##            if row[0] is None:
    ##                cursor.deleteRow()

    # Add Density field and calc
    arcpy.AddField_management("length_in_zone", "Density_MperHA", "DOUBLE", '',
                              '', '', '', "NULLABLE")
    exp = "!SUM_LengthM! / !ZONEAREAHA!"
    arcpy.CalculateField_management("length_in_zone", "Density_MperHA", exp,
                                    "PYTHON")

    cu.one_in_one_out("length_in_zone", ['SUM_LengthM', 'Density_MperHA'],
                      zones, zonefield, out_table)
    cu.redefine_nulls(out_table, ['SUM_LengthM', 'Density_MperHA'], [0, 0])

    ##    # Join to the original table
    ##    keep_fields = ["ZoneID", "SUM_LengthM", "Density_MperHA"]
    ##    arcpy.JoinField_management('zones_temp', zonefield, "length_in_zone", zonefield, keep_fields[1:])
    ##
    ##    # Select only null records and change to 0
    ##    arcpy.MakeFeatureLayer_management('zones_temp', 'zones_temp_lyr')
    ##    arcpy.SelectLayerByAttribute_management('zones_temp_lyr', "NEW_SELECTION", '''"SUM_LengthM" is null''')
    ##    fields_to_calc = ["SUM_LengthM", "Density_MperHA"]
    ##    for f in fields_to_calc:
    ##        arcpy.CalculateField_management('zones_temp_lyr', f, 0, "PYTHON")
    ##
    ##    #Delete all the fields that aren't the ones I need
    ##    keep_fields = ["ZoneID", "SUM_LengthM", "Density_MperHA"]
    ##    all_fields = [f.name for f in arcpy.ListFields('zones_temp_lyr')]
    ##    for f in all_fields:
    ##        if f not in keep_fields:
    ##            try:
    ##                arcpy.DeleteField_management('zones_temp_lyr', f)
    ##            except:
    ##                continue
    ##    arcpy.SelectLayerByAttribute_management('zones_temp_lyr', 'CLEAR_SELECTION')
    ##
    ##    arcpy.CopyRows_management('zones_temp_lyr', out_table)

    for tempitem in ['zones_temp', 'lines_identity', 'length_in_zone']:
        arcpy.Delete_management(tempitem)

    return out_table