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)
原文地址:https://www.cnblogs.com/bigmonk/p/12497917.html