前言
文中脚本点此下载。
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)