• Arcgis-Tools_01字段处理


    前言

    文中脚本点此下载。

    CSV转DBF

    CSV文件为逗号分隔符文本文件,有时需转换为DBF文件。

    import os
    import arcpy
    
    arcpy.env.workspace = "c:/temp"
    # Copy each file with a .csv extension to a dBASE file
    for csv_file in arcpy.ListFiles("*.csv"):
        # Use splitext to set the output table name
        dbase_file = os.path.splitext(csv_file)[0] + ".dbf"
        arcpy.CopyRows_management(csv_file, dbase_file)
    

    获取字段信息

    用于获取所有字段的信息,包括字段名、类型、长度、精度、小数位数。

    # -*- coding: cp936 -*-
    import arcpy, os, csv
    
    # in_fc = arcpy.GetParameterAsText(0)
    # out_csv = arcpy.GetParameterAsText(1)
    
    in_fc = r""
    out_csv = r""
    
    header = [u"字段名", u"类型", u"长度", u"精度", u"小数位数"]
    rows = []
    try:
        for field in arcpy.ListFields(in_fc):
            row = [field.name, field.type, field.length, field.precision, field.scale]
            # 因列举字段信息获取到的字段类型和创建字段的字段类型并不一致,存在映射关系
            # 在此判断并转换后获得到的信息可以直接用于创建字段
            if row[1] == "Integer":
                row[1] = "LONG"
            elif row[1] == "SmallInteger":
                row[1] = "SHORT"
            print row
            rows.append(row)
        with open(out_csv, "wb") as f:
            f_csv = csv.writer(f)
            f_csv.writerow(header)
            f_csv.writerows(rows)
    except arcpy.ExecuteError:
        for msg in range(0, arcpy.GetMessageCount()):
            if arcpy.GetSeverity(msg) == 2:
                print(msg)
                arcpy.AddReturnMessage(msg)
    

    批量创建字段

    用提供的存储了字段名、类型、长度、精度、小数位数的CSV或TXT文件批量创建字段。

    使用CSV

    # -*- coding: cp936 -*-
    # 字段类型:SHORT,LONG,FLOAT,DOUBLE,TEXT
    # 字段顺序:字段名,类型,长度,精度,小数位数
    import arcpy, os
    
    # in_fc = arcpy.GetParameterAsText(0)
    # in_field_csv = arcpy.GetParameterAsText(1)
    
    in_fc = os.getcwd() + os.sep + "testAddFields.shp"
    in_field_csv = os.getcwd() + os.sep + "a.csv"
    
    try:
        with open(in_field_csv) as f:
            f.readline()
            lines = f.readlines()
            for line in lines:
                field = line.rstrip("
    ").split(",")
                print field
                if field[1].upper() in ["SINGLE", "FLOAT", "DOUBLE"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], field[3], field[4])
                elif field[1].upper() in ["SHORT", "LONG"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], field[2])
                elif field[1].upper() in ["STRING", "TEXT"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], "", "", field[2])
                elif field[1].upper() in ["OID", "GEOMETRY"]:
                    pass
                else:
                    arcpy.AddField_management(in_fc, field[0], field[1])
    except arcpy.ExecuteError:
        for msg in range(0, arcpy.GetMessageCount()):
            if arcpy.GetSeverity(msg) == 2:
                print(msg)
                arcpy.AddReturnMessage(msg)
    

    使用Txt

    # -*- coding: cp936 -*-
    # 字段类型:SHORT,LONG,FLOAT,DOUBLE,TEXT
    # 字段顺序:字段名,类型,长度,精度,小数位数
    # 要求输入TXT为从Excel直接粘贴的,首行不含字段信息,无空格
    
    import arcpy
    
    # in_fc = arcpy.GetParameterAsText(0)
    # in_field_txt = arcpy.GetParameterAsText(1)
    
    in_fc = r"C:UsersAdminDesktop	empNew_Shapefile(2).shp".decode("gb2312")
    in_field_txt = r"C:UsersAdminDesktopfield.txt".decode("gb2312")
    
    try:
        with open(in_field_txt) as f:
            f.readline()
            lines = f.readlines()
            for line in lines:
                field = line.rstrip("
    ").split("	")
                print(field)
                if field[1].upper() in ["SINGLE", "FLOAT", "DOUBLE"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], field[3], field[4])
                elif field[1].upper() in ["SHORT", "LONG"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], field[2])
                elif field[1].upper() in ["STRING", "TEXT"]:
                    arcpy.AddField_management(in_fc, field[0], field[1], "", "", field[2])
                elif field[1].upper() in ["OID", "GEOMETRY"]:
                    pass
                else:
                    arcpy.AddField_management(in_fc, field[0], field[1])
    except arcpy.ExecuteError:
        for msg in range(0, arcpy.GetMessageCount()):
            if arcpy.GetSeverity(msg) == 2:
                print(msg)
                arcpy.AddReturnMessage(msg)
    

    调整字段顺序

    经常会遇到字段顺序需要调整的情况,可直接使用合并工具,在字段映射里调整,还可调整输入字段和输出字段的名称、类型等属性。当存在较多字段需调整,字段映射不能拖动,可以先创建标准库,追加进去即可。

    删除多余字段

    在建库阶段,编辑的属性信息可能比标准库多一些辅助字段,就需要删除这些多余的字段。删除过程中若人工识别,费时费力且易出错。此脚本可与标准库字段名对比,并删除掉多余的字段。

    根据要素对比

    # -*- coding: cp936 -*-
    # 此脚本作用:对比两个要素字段名,删除多余的字段
    import arcpy
    
    # edited_feature = arcpy.GetParameterAsText(0)
    # default_feature = arcpy.GetParameterAsText(1)
    
    # 原始要素路径
    default_feature = r"C:UsersAdminDesktopTestQQ_P.shp"
    # 修改后的要素路径
    edited_feature = r"C:UsersAdminDesktopTestBQ_P.shp"
    
    # 列出原始和修改的所有字段
    default_fieldlist = arcpy.ListFields(default_feature)
    edited_fieldlist = arcpy.ListFields(edited_feature)
    
    # 创建字段名空列表
    default_fieldname_list = []
    edited_fieldname_list = []
    # 列出原始所有字段名
    for field in default_fieldlist:
        default_fieldname_list.append(field.name)
    # 列出修改后的字段名
    for field in edited_fieldlist:
        edited_fieldname_list.append(field.name)
    
    delete_fieldlist = []
    # 选出多余的字段名
    for fieldname in edited_fieldname_list:
        if fieldname not in default_fieldname_list:
            print(fieldname)
            arcpy.AddMessage(fieldname)
            delete_fieldlist.append(fieldname)
    if len(delete_fieldlist) > 0:
        arcpy.DeleteField_management(edited_feature, delete_fieldlist)
        print("删除完成,共删除了 " + str(len(delete_fieldlist)) + " 个字段!")
        arcpy.AddMessage("删除完成,共删除了 " + str(len(delete_fieldlist)) + " 个字段!")
    else:
        print("没有多余字段,无需删除!")
        arcpy.AddMessage("没有多余字段,无需删除!")
    

    根据字段名对比

    # -*- coding: cp936 -*-
    # 此脚本作用:对比两个要素字段名,删除多余的字段
    import arcpy
    
    default_fieldname = "XIANG,CUN,LIN_BAN,XIAO_BAN,MIAN_JI,STQWMC,LD_QS,TDSYQS,DI_LEI,LIN_ZHONG,QI_YUAN,SEN_LIN_LB,SHI_QUAN_D,GJGYL_BHDJ,G_CHENG_LB,LING_ZU,YU_BI_DU,YOU_SHI_SZ,BH_DJ,BHYY,BHND,BGYJ,GLLX"
    edited_feature = r"C:UsersAdminDesktop	est	est.shp"
    
    default_fieldname_list = default_fieldname.split(",")
    
    # 修改的所有字段
    edited_fieldlist = arcpy.ListFields(edited_feature)
    
    # 创建字段名空列表
    edited_fieldname_list = []
    
    # 列出修改后的字段名
    for field in edited_fieldlist:
        if field.name != "FID" and field.name != "Shape":
            edited_fieldname_list.append(field.name)
    
    delete_fieldlist = []
    # 选出多余的字段名
    for fieldname in edited_fieldname_list:
        if fieldname not in default_fieldname_list:
            print fieldname
            delete_fieldlist.append(fieldname)
    if len(delete_fieldlist) > 0:
        arcpy.DeleteField_management(edited_feature, delete_fieldlist)
        print "删除完成,共删除了 " + str(len(delete_fieldlist)) + " 个字段!"
    else:
        print "没有多余字段,无需删除!"
    

    注:此需求也算伪需求,实际过程中,我们只需追加到标准库即可,追加时方案类型选择NO_TEST,也可以使用此工具简单调整一下字段映射。

    添加名称字段

    在大量矢量合并中,合并完成的矢量可能就无法溯源(因其属性可能存在交叉,如不同矢量可能都出现了某个县),这时就需要在合并前的矢量中添加一个名称字段,将文件名称或者路径存储在里面。

    #   -*-  coding:cp936  -*-
    import arcpy, os
    
    # in_folder = arcpy.GetParameterAsText(0)
    ##  choose from [path,fileNameWithExtension,fileNameWithoutExtension]
    # fcName_type = arcpy.GetParameterAsText(1)
    
    in_folder = r"C:UsersAdminDesktopff"
    #   choose from [path,fileNameWithExtension,fileNameWithoutExtension]
    fcName_type = "path"
    
    walk = arcpy.da.Walk(in_folder)
    for dirpath, dirnames, filenames in walk:
        for filename in filenames:
            in_fc = os.path.join(dirpath, filename)
            print(in_fc)
            arcpy.AddMessage(in_fc)
            arcpy.AddField_management(in_fc, "fcName", "TEXT")
            if fcName_type == "fileNameWithExtension":
                value = '"{0}"'.format(filename.encode('utf-8'))
                arcpy.CalculateField_management(in_fc, "fcName", value)
            elif fcName_type == "fileNameWithoutExtension":
                value = '"{0}"'.format(os.path.splitext(filename)[0].encode('utf-8'))
                arcpy.CalculateField_management(in_fc, "fcName", value)
            elif fcName_type == "path":
                value = '"{0}"'.format(os.path.join(dirpath + os.sep + filename).encode('utf-8'))
                arcpy.CalculateField_management(in_fc, "fcName", value)
    

    注:默认名称字段名为fcName,使用工具请注意各要素是否存在此字段,防止出现覆盖现象。

    字段拼接

    对某个具有相同属性的字段,有时需使用固定的连接符将其连接。如获取某县各个乡镇的项目汇总,可按照乡镇分组,对项目字段进行拼接。

    # -*- coding: cp936 -*-
    import arcpy
    
    # 输入要素
    in_fc = arcpy.GetParameterAsText(0)
    # 分组字段
    fields = arcpy.GetParameterAsText(1)
    # 连接字段
    join_field = arcpy.GetParameterAsText(2)
    # 连接分隔符
    split_str = arcpy.GetParameterAsText(3)
    # 连接后填入的字段名
    joined_field = arcpy.GetParameterAsText(4)
    
    # in_fc=r"C:UsersAdminDesktop	empExport_Output.shp"
    # fields=r"XIAN;XIANG"
    # split_str="/"
    # join_field="CUN_NAME"
    # joined_field="AAAA"
    arcpy.AddWarning("注意:ArcMap10.1以下版本不可用,拼接字段默认去重,对中文字段如需排序先使用排序工具排序!")
    
    try:
        # 对字符串处理成为字段计算器表达式
        group_field_list = fields.split(";")
        expression_list = []
        for field in group_field_list:
            expression_list.append("[" + field + "]")
    
        # 创建辅助字段,并计算出分组字段组合值
        string_join = '&"-"&'
        expression = string_join.join(expression_list)
        print expression
        arcpy.AddField_management(in_fc, "UniqueId", "TEXT", "", "", 240)
        arcpy.CalculateField_management(in_fc, "UniqueId", expression, "VB")
    
        # 获取分组字段唯一值
        field_list = []
        with arcpy.da.SearchCursor(in_fc, "UniqueId") as s_cursor:
            for row in s_cursor:
                if row[0] not in field_list:
                    field_list.append(row[0])
    
        # 对每一分组进行字符串拼接
        for a_field in field_list:
            join_strlist = []
            selectStr = "UniqueId = " + "'" + a_field + "'"
            print selectStr
            arcpy.AddMessage(a_field)
            with arcpy.da.SearchCursor(in_fc, join_field, selectStr) as s_cursor:
                for row in s_cursor:
                    # 拼接默认只拼接不同值
                    if row[0] not in join_strlist:
                        join_strlist.append(row[0])
            # 对拼接列表重排序(不支持中文,如需要先使用工具进行排序)
            join_strlist.sort()
            # 将拼接列表转为字符串
            join_str = split_str.join(join_strlist)
            print join_str
            arcpy.AddMessage(join_str)
            # 更新拼接字段
            with arcpy.da.UpdateCursor(in_fc, joined_field, selectStr) as u_cursor:
                for row in u_cursor:
                    row[0] = join_str
                    u_cursor.updateRow(row)
        # 删除辅助字段
        arcpy.DeleteField_management(in_fc, "UniqueId")
    except:
        for msg in range(0, arcpy.GetMessageCount()):
            if arcpy.GetSeverity(msg) == 2:
                print(msg)
                arcpy.AddReturnMessage(msg)
    

    注:脚本采用10.1以后才有的 arcpy.da 中的游标函数,不支持10.0版本,字段拼接结果中文不支持排序,如需获取中文排序结果,提前使用排序工具将需要拼接的字段排序。

    小班平差

    在小班年度变化中,不仅要保持前后总面积一致,还需保证各项动态变化保持平衡。手动平差工作量大且易出错,可使用此脚本辅助处理。

    # -*- coding: cp936 -*-
    # 功能:对小班进行平差,平差依据前期小班面积
    # 注意:后期数据面积字段未发生变化;小班未进行合并;[Q_XIAO_BAN]字段本期保留;前期同行政级别下小班号唯一
    # 问题:若默认保留四位小数,细碎小班可能会存在面积小于1平方米,若不处理会出现逻辑检查面积未填的错误
    # 验证方法:若要验证脚本的正确性,将平差的数据按照“UID_BAN”字段融合统计面积字段,与前期挂接面积相等
    import arcpy, os
    
    # last_fc=arcpy.GetParameterAsText(0)
    # now_fc=arcpy.GetParameterAsText(1)
    
    # 前期矢量
    last_fc = r"C:UsersAdminDesktoplast.shp".decode('gb2312')
    # 后期矢量
    now_fc = r"C:UsersAdminDesktop
    ow.shp".decode('gb2312')
    arcpy.env.overwriteOutput = True
    arcpy.AddWarning("注意:ArcMap10.1以下版本不可用!")
    try:
        # 存放临时文件文件夹
        temp_folder = os.path.dirname(now_fc)
        # 临时图层,从前期提取的变化小班层
        temp_shp = temp_folder + r"	emp.shp"
        # 要素图层名称
        last_lyr = "last_lyr"
        now_lyr = "now_lyr"
        # 字段计算表达式
        last_expression = "[XIAN]&[XIANG]&[CUN]&[LIN_BAN]&[XIAO_BAN]"
        now_expression = "[XIAN]&[XIANG]&[CUN]&[LIN_BAN]&[Q_XIAO_BAN]"
        # 添加标识字段
        arcpy.AddField_management(last_fc, "UID_BAN", "TEXT", "", "", 200)
        arcpy.AddField_management(now_fc, "UID_BAN", "TEXT", "", "", 200)
        arcpy.CalculateField_management(last_fc, "UID_BAN", last_expression, "VB")
        arcpy.CalculateField_management(now_fc, "UID_BAN", now_expression, "VB")
    
        # 选出前期变化小班
        arcpy.MakeFeatureLayer_management(last_fc, last_lyr)
        arcpy.MakeFeatureLayer_management(now_fc, now_lyr)
        arcpy.SelectLayerByLocation_management(last_lyr, "ARE_IDENTICAL_TO", now_lyr, "", "NEW_SELECTION")
        arcpy.SelectLayerByAttribute_management(last_lyr, "SWITCH_SELECTION")
        arcpy.CopyFeatures_management(last_lyr, temp_shp)
        # 删除要素图层
        arcpy.Delete_management(last_lyr)
        arcpy.Delete_management(now_lyr)
        # 后期数据计算几何面积
        arcpy.AddField_management(now_fc, "SHPAREA", "DOUBLE", 13, 4)
        arcpy.CalculateField_management(now_fc, "SHPAREA", "!shape.area@hectares!", "PYTHON_9.3")
        # 定义平差前后期对应的小班数
        last_xiaoban_count = arcpy.GetCount_management(temp_shp)
        now_xiaoban_count = 0
        # 遍历前期变化小班,将前期小班面积平差
        with arcpy.da.SearchCursor(temp_shp, ["UID_BAN", "MIAN_JI"]) as last_s_cursor:
            for last_row in last_s_cursor:
                print last_row[0], last_row[1]
                sum_area = last_row[1]
                selectStr = "UID_BAN" + " = '" + last_row[0] + "'"
                sum_geo_area = 0
                sum_count = 0
                print selectStr
                arcpy.AddMessage(selectStr)
    
                # 获取原前期未变小班经过切割后计算几何面积和
                with arcpy.da.SearchCursor(now_fc, "SHPAREA", selectStr) as now_s_cursor:
                    for now_row in now_s_cursor:
                        sum_geo_area = sum_geo_area + now_row[0]
                        sum_count = sum_count + 1
    
                # 更新本期平差小班数计数
                now_xiaoban_count = now_xiaoban_count + sum_count
                print now_xiaoban_count
                arcpy.AddMessage(now_xiaoban_count)
    
                # 定义剩余面积
                now_rest_area = sum_area
    
                # 对切割的小班逐一平差
                with arcpy.da.UpdateCursor(now_fc, ["SHPAREA", "MIAN_JI"], selectStr) as now_u_cursor:
                    for now_row in now_u_cursor:
                        sum_count = sum_count - 1
                        print sum_count
                        arcpy.AddMessage(sum_count)
                        # 判断如果是最后一个小班,则等于剩余面积,否则按照权重计算
                        if sum_count == 0:
                            now_row[1] = now_rest_area
                        else:
                            # 此处可以定义小数位数
                            now_row[1] = round(now_row[0] * sum_area / sum_geo_area, 4)
                            now_rest_area = now_rest_area - now_row[1]
                        now_u_cursor.updateRow(now_row)
        # 删除添加的多余字段
        arcpy.DeleteField_management(last_fc, "UID_BAN")
        arcpy.DeleteField_management(now_fc, "UID_BAN")
        arcpy.DeleteField_management(now_fc, "SHPAREA")
        # 删除临时文件
        arcpy.Delete_management(temp_shp)
        print("平差完成,共对本期数据平差小班{0}个,对应原小班{1}个!".format(now_xiaoban_count, last_xiaoban_count))
        arcpy.AddMessage("平差完成,共对本期数据平差小班{0}个,对应原小班{1}个!".format(now_xiaoban_count, last_xiaoban_count))
    except:
        for msg in range(0, arcpy.GetMessageCount()):
            if arcpy.GetSeverity(msg) == 2:
                print(msg)
                arcpy.AddReturnMessage(msg)
    
  • 相关阅读:
    2331: [SCOI2011]地板 插头DP
    APIO2018 铜滚记
    2827: 千山鸟飞绝 非旋treap
    3682: Phorni 后缀平衡树 线段树
    4712: 洪水 基于链分治的动态DP
    20180507小测
    4923: [Lydsy1706月赛]K小值查询 平衡树 非旋转Treap
    5312: 冒险 线段树 复杂度分析
    5210: 最大连通子块和 动态DP 树链剖分
    4513: [Sdoi2016]储能表 数位DP
  • 原文地址:https://www.cnblogs.com/bigmonk/p/12497917.html
Copyright © 2020-2023  润新知