前言
最近需要用ArcGIS统计面内点的数量,搜索了一下,官方提供的工具为空间连接,挺好用,但是有一个缺点,一次只能计算一个点要素类,多个点要素类需要重复操作,比较繁琐。搜索一番网上没有较完美的解决方案,刚好最近在研究Arcpy,开始手搓轮子。
实现思路
Arcpy实现判定相交我想到的有两个方法,一个是官方的按位置选择图层,一个是遍历图层用Arcpy的Geometry类中的contains判定相交,此处使用的是前者,Arcpy调用官方工具也十分简单,在具体工具的运行键右边有个向下拉的部分,点击后选择复制成Python代码即可。
踩过的坑
新添加的图层无法使用SelectLayerByLocation
根据官方介绍,需要使用MakeFeatureLayer创建要素图层
MakeFeatureLayer后编辑字段会影响源要素属性
先CopyFeatures_management将要素类复制到数据库,再使用MakeFeatureLayer创建要素图层,操作完成之后不需要重新导出
组内要素的处理问题
.split("\\")[-1]
从路径提取中的文件名
要素类行数获取
int(arcpy.management.GetCount("目标要素")[0])
成品代码
注释很详细,看不懂翻翻官方手册就行
# -*- coding: utf-8 -*-
"""
Tool: 统计
Source Name: <File name>
Version: Arcgis Pro 2.8
Author: Chao
Usage: <Command syntax>
Required Arguments: <point_parameter>
<surface_parameter>
Optional Arguments: <point_parameter2>
<point_parameter3>
Description: 统计面内多个点要素类的点数量
"""
import arcpy
def ScriptTool(point_parameter, surface_parameter, result_parameter):
true_result_parameter = result_parameter
# 根据绝对路径提取文件名
result_parameter = result_parameter.split("\\")[-1]
# 复制图层并添加到图层列表,不使用MakeFeatureLayer将无法使用SelectLayerByLocation,不copy直接创建图层要素修改时源要素会变化
arcpy.CopyFeatures_management(surface_parameter, true_result_parameter)
arcpy.management.MakeFeatureLayer(true_result_parameter, result_parameter)
# 获取面文件行数,用于计算进度
task_total_num = int(arcpy.management.GetCount(surface_parameter)[0])
# 添加进度条
arcpy.SetProgressor("step", f"即将开始任务,共计{task_total_num}个面",0, task_total_num , 1)
# 将点文件文本切割为列表
point_list = point_parameter.split(";")
# 获取面要素已有字段
fieldList = arcpy.ListFields(result_parameter)
field_name_List = []
for field in fieldList:
field_name_List.append(field.name)
for point_name in point_list:
# 处理需要添加的字段
if "\\" in point_name:
point_name_str = point_name.split("\\")[-1]
else:
point_name_str = point_name
# 判断是否包含该字段,没有则添加
if point_name_str not in field_name_List:
# 添加字段
arcpy.management.AddField(result_parameter, point_name_str, "LONG", None, None, None, point_name_str,
"NULLABLE","NON_REQUIRED",'')
# 添加游标,用于遍历面要素
updateCursor = arcpy.UpdateCursor(result_parameter)
task_num = 1
for row in updateCursor:
OBJECTID = row.getValue("OBJECTID")
# 选择面要素的一个面,通过按位置选择工具选出与其相交的点要素
arcpy.management.SelectLayerByAttribute(result_parameter, "NEW_SELECTION", f"OBJECTID = {OBJECTID}", None)
arcpy.management.SelectLayerByLocation(point_parameter, "INTERSECT", result_parameter, None, "NEW_SELECTION",
"NOT_INVERT")
# 修改进度条显示文字
arcpy.SetProgressorLabel(f"开始统计面,当前第{task_num}/{task_total_num}个面")
# 修改进度条进度,向后跳动一个间隔数
arcpy.SetProgressorPosition()
for point_name in point_list:
num = int(arcpy.management.GetCount(point_name)[0])
if "\\" in point_name:
point_name_str = point_name.split("\\")[-1]
else:
point_name_str = point_name
# 为所选字段赋值
arcpy.management.CalculateField(result_parameter, point_name_str, str(num), "PYTHON3", '', "TEXT",
"NO_ENFORCE_DOMAINS")
task_num = task_num + 1
# 清除选择的要素
arcpy.management.SelectLayerByAttribute(result_parameter, "CLEAR_SELECTION")
for point_name in point_list:
arcpy.management.SelectLayerByAttribute(point_name, "CLEAR_SELECTION")
arcpy.SetProgressorLabel(f"统计完成")
return
if __name__ == '__main__':
# 获取脚本输入信息
# Getpoint_parameterAsText-将输入要素转换为文本,多选要素中间";"相隔
surface_parameter = arcpy.GetParameterAsText(0)
point_parameter = arcpy.GetParameterAsText(1)
result_parameter = arcpy.GetParameterAsText(2)
ScriptTool(point_parameter, surface_parameter,result_parameter)
脚本参数设置,如图
最后
工具实现的面内多点要素类的统计,统计信息以字段的形式储存在输出要素类中,另外实现了进度条信息的可视化。第二种实现方法在面和点的数量较少的时候运行估计会快些,暂时还没造轮子,留个坑。
补充第二种(contains)方法
脚本属性设置同第一种方法
# -*- coding: utf-8 -*-
"""
Tool: 统计
Source Name: <File name>
Version: Arcgis Pro 2.8
Author: Chao
Usage: <Command syntax>
Required Arguments: <point_parameter>
<surface_parameter>
Optional Arguments: <point_parameter2>
<point_parameter3>
Description: 统计面内多个点要素类的点数量
"""
import arcpy
def ScriptTool(point_parameter, surface_parameter, result_parameter):
true_result_parameter = result_parameter
# 根据绝对路径提取文件名
result_parameter = result_parameter.split("\\")[-1]
# 复制图层并添加到图层列表,不使用MakeFeatureLayer将无法使用SelectLayerByLocation,不copy直接创建图层要素修改时源要素会变化
arcpy.CopyFeatures_management(surface_parameter, true_result_parameter)
arcpy.management.MakeFeatureLayer(true_result_parameter, result_parameter)
# 获取面文件行数,用于计算进度
task_total_num = int(arcpy.management.GetCount(surface_parameter)[0])
# 添加进度条
arcpy.SetProgressor("step", f"即将开始任务,共计{task_total_num}个面",0, task_total_num , 1)
# 将点文件文本切割为列表
point_list = point_parameter.split(";")
# 获取面要素已有字段
fieldList = arcpy.ListFields(result_parameter)
field_name_List = []
for field in fieldList:
field_name_List.append(field.name)
for point_name in point_list:
# 处理需要添加的字段
if "\\" in point_name:
point_name_str = point_name.split("\\")[-1]
else:
point_name_str = point_name
# 判断是否包含该字段,没有则添加
if point_name_str not in field_name_List:
# 添加字段
arcpy.management.AddField(result_parameter, point_name_str, "LONG", None, None, None, point_name_str,
"NULLABLE","NON_REQUIRED",'')
# 添加游标,用于遍历面要素
updateCursor = arcpy.UpdateCursor(result_parameter)
task_num = 1
for row in updateCursor:
surface_geometry = row.shape
# 修改进度条显示文字
arcpy.SetProgressorLabel(f"开始统计面,当前第{task_num}/{task_total_num}个面")
# 修改进度条进度,向后跳动一个间隔数
arcpy.SetProgressorPosition()
for point_name in point_list:
pointCursor = arcpy.UpdateCursor(point_name)
num = 0
for point_row in pointCursor:
point_geometry =point_row.shape
## 判断点是否在面内
if (surface_geometry.contains(point_geometry)):
num = num + 1
if "\\" in point_name:
point_name_str = point_name.split("\\")[-1]
else:
point_name_str = point_name
# 为所选字段赋值
row.setValue(point_name_str, str(num))
updateCursor.updateRow(row)
del pointCursor
task_num = task_num + 1
arcpy.SetProgressorLabel(f"统计完成")
return
if __name__ == '__main__':
# 获取脚本输入信息
# Getpoint_parameterAsText-将输入要素转换为文本,多选要素中间";"相隔
surface_parameter = arcpy.GetParameterAsText(0)
point_parameter = arcpy.GetParameterAsText(1)
result_parameter = arcpy.GetParameterAsText(2)
ScriptTool(point_parameter, surface_parameter,result_parameter)
8 条评论
文章的确不错啊https://www.cscnn.com/
想想你的文章写的特别好https://www.ea55.com/
看的我热血沸腾啊https://www.237fa.com/
看的我热血沸腾啊
博主真是太厉害了!!!
xmsibf93051TO-感谢作者的精彩分享,让我对XX领域有了更深入的了解。www.well-techmachine.cn/tags/16.html/
你好,之前网站的文章不同步过来吗
没备份