import arcpy
from arcpy import env
import xlrd, random, tempfile, shutil, os
"""
DESC:
本段代码用于处理两个图层间属性值关联汇总问题,
即把源图层的源属性值整合、汇总后填写目标图层的目标属性中。
至具体包括:
1、将与目标要素相交的源要素的指定字段值拼接为字符串填写至目标字段;
2、汇总与目标要素、源要素相交面积并汇总相交面积填写至目标字段;
3、分类汇总目标要素及源要素相交部分,填写至目标字段。
LOG:
[0315] 需要解决源、目的图层字段同名后地理处理重命名的问题
[0316] 已解决,编写__renameField对重名字段做重命名处理
"""
class FieldValueTransfer:
def __init__(self, workspace, xlsx_path):
env.workspace = workspace
env.overwriteOutput = True
self.xlsx_path = xlsx_path
self.temp_dir = tempfile.mkdtemp()
self.temp_gdb = os.path.join(self.temp_dir, "temp.gdb")
arcpy.CreateFileGDB_management(self.temp_dir, "temp.gdb")
def deleteTempDir(self):
"""
删除临时文件夹
"""
shutil.rmtree(self.temp_dir)
def __layerChecker(self, layer_name):
"""
检查图层是否存在
:param layer_name: 图层名
"""
if not arcpy.Exists(layer_name):
print "Layer " + layer_name + " not exists!"
return False
else:
return True
def __fieldCheck(self, layer_name, field_name):
"""
检查字段是否存在
:param layer_name: 图层名
:param field_name: 属性名
"""
fields_name_list = [f.name for f in arcpy.ListFields(layer_name)]
if field_name not in fields_name_list:
print "Field " + field_to + " not exists in Layer " + layer_name + "!"
return False
else:
return True
def __renameField(self, layer_name, field_name):
"""
如图层存在字段,对字段重命名
:param layer: 对比图层
:param field_name: 原属性名
"""
field_name_new = field_name
fields_name_list = [f.name for f in arcpy.ListFields(layer_name)]
if field_name_new not in fields_name_list:
return field_name_new
ext_list = ["_1", "2", "_13", "_14", "_15", "_16", "_17", "_18", "_19"]
generator_ext = (e for e in ext_list)
while True:
try:
ext = next(generator_ext)
field_name_new += ext
if field_name_new not in fields_name_list:
return field_name_new
except StopInteration:
break
return None
def sumupFieldValue(self, layer_to, field_to, layer_from, field_from):
"""
汇总相交要素属性,写入目标要素
:param layer_to: 写入属性值的图层名
:param field_to: 写入属性值的字段名
:param layer_from: 属性值的来源图层
"""
try:
if ((not self.__layerChecker(layer_to)) or
(not self.__layerChecker(layer_from)) or
(not self.__fieldCheck(layer_to, field_to)) or
(not self.__fieldCheck(layer_from, field_from))):
return
layer_name = "lyr" + str(random.random()*100000)
arcpy.MakeFeatureLayer_management(layer_from, layer_name)
with arcpy.da.UpdateCursor(layer_to, ("SHAPE@", field_to)) as updateCursor:
for row_to in updateCursor:
geometry_to = row_to[0]
arcpy.SelectLayerByLocation_management(layer_name, "INTERSECT", geometry_to)
field_value = ""
with arcpy.da.SearchCursor(layer_name, ("SHAPE@", field_from)) as searchCursor:
for row_from in searchCursor:
geometry_from = row_from[0]
if (not geometry_from and
not geometry_to and
geometry_to.touches(geometry_from)):
continue
if row_from[1] and len(str(row_from[1]).strip()) > 0 and (str(row_from[1]).strip() not in field_value):
field_value += (str(row_from[1]).strip() + unicode("、", "utf-8"))
if len(field_value) > 0:
field_value = field_value[0:-1]
row_to[1] = field_value
updateCursor.updateRow(row_to)
arcpy.Delete_management(layer_name)
except Exception as e:
print "--- sumupFieldValue ---"
print arcpy.GetMessages()
print e
def sumupIntersectArea(self, layer_to, field_to, layer_from):
"""
汇总相交图形面积
:param layer_to: 写入属性值的图层名
:param field_to: 写入属性值的字段名
:param layer_from: 属性值的来源图层
"""
try:
if ((not self.__layerChecker(layer_to)) or
(not self.__layerChecker(layer_from)) or
(not self.__fieldCheck(layer_to, field_to))):
return
output_name = self.temp_gdb + "/" + layer_to + "_" + layer_from + "_Intersect"
if not arcpy.Exists(output_name):
arcpy.Intersect_analysis([layer_to, layer_from], output_name, "ALL", "", "")
intable = output_name
outtable = output_name + "_Statistic"
statsFields = [["Shape_Area", "SUM"]]
casefield = "FID_" + layer_to
arcpy.Statistics_analysis(intable, outtable, statsFields, casefield)
with arcpy.da.SearchCursor(outtable, ("FID_" + layer_to, "SUM_Shape_Area")) as searchCursor:
for srow in searchCursor:
expression = "OBJECTID=" + str(srow[0])
with arcpy.da.UpdateCursor(layer_to, (field_to), where_clause = expression) as updateCursor:
for row_to in updateCursor:
row_to[0] = round(srow[1], 2)
updateCursor.updateRow(row_to)
except Exception as e:
print "--- sumupIntersectArea ---"
print arcpy.GetMessages()
print e
def classifyAndSumupIntersectArea(self, layer_to, field_to, layer_from, field_from):
"""
分类汇总相交图形面积
:param layer_to: 写入属性值的图层名
:param field_to: 写入属性值的字段名
:param layer_from: 属性值的来源图层
:param field_from: 属性值的来源字段
"""
try:
if ((not self.__layerChecker(layer_to)) or
(not self.__layerChecker(layer_from)) or
(not self.__fieldCheck(layer_to, field_to)) or
(not self.__fieldCheck(layer_from, field_from))):
return
output_name = self.temp_gdb + "/" + layer_to + "_" + layer_from + "_Intersect"
if not arcpy.Exists(output_name):
arcpy.Intersect_analysis([layer_to, layer_from], output_name, "ALL", "", "")
field_from = self.__renameField(layer_to, field_from)
if not field_from:
print "Field name " + field_from + " is duplicated in Layer " + layer_to
return
intable = output_name
outtable = output_name + "_Statistic"
statsFields = [["Shape_Area", "SUM"]]
casefield = ["FID_" + layer_to, field_from]
arcpy.Statistics_analysis(intable, outtable, statsFields, casefield)
field_value_dict = {}
with arcpy.da.SearchCursor(outtable, ("FID_" + layer_to, field_from, "SUM_Shape_Area")) as searchCursor:
for srow in searchCursor:
srow_fid = srow[0]
srow_field_name = srow[1]
srow_area = srow[2]
if srow_field_name is not None:
field_value = (srow_field_name + ": " + str(round(srow_area, 2)) + unicode("㎡、", "utf-8"))
else:
field_value = ("Null: " + str(round(srow_area, 2)) + unicode("㎡、", "utf-8"))
if str(srow_fid) not in field_value_dict:
field_value_dict[str(srow_fid)] = field_value
else:
field_value_dict[str(srow_fid)] += field_value
for key, val in field_value_dict.items():
expression = "OBJECTID=" + key
with arcpy.da.UpdateCursor(layer_to, (field_to), where_clause=expression) as updateCursor:
for urow in updateCursor:
urow[0] = val[0:-1]
updateCursor.updateRow(urow)
except Exception as e:
print "--- classifyAndSumupIntersectArea ---"
print arcpy.GetMessages()
print e
if __name__ == "__main__":
try:
workspace = unicode("C:/Users/may/Desktop/xxxxxx/xxxxxx.gdb", "utf-8")
xlsx_path = unicode("C:/Users/may/Desktop/xxxxxx/mapper/fieldMapper0316.xlsx", "utf-8")
fieldValueTransfer = FieldValueTransfer(workspace, xlsx_path)
workbook = xlrd.open_workbook(fieldValueTransfer.xlsx_path)
sheet = workbook.sheet_by_index(0)
rows = sheet.nrows
for i in range(1, rows):
layer_to = sheet.cell(i, 0).value
field_to = sheet.cell(i, 1).value
layer_from = sheet.cell(i, 2).value
field_from = sheet.cell(i, 3).value
_type = sheet.cell(i, 4).value
print "\n" + "*" * 20 + str(i) + "*" * 20
print layer_to, field_to, layer_from, field_from
if _type == 1.0:
fieldValueTransfer.sumupFieldValue(layer_to, field_to, layer_from, field_from)
elif _type == 2.0:
fieldValueTransfer.classifyAndSumupIntersectArea(layer_to, field_to, layer_from, field_from)
elif _type == 3.0:
fieldValueTransfer.sumupIntersectArea(layer_to, field_to, layer_from)
else:
continue
fieldValueTransfer.deleteTempDir()
print "Done!"
except Exception as e:
print e