主要是让不会arcgis的人也能按字段分割shp

文摘   2024-10-07 17:25   广东  

两周前看到一个朋友在后台的留言,

有个功能能不能开发一下,就是输入一个shp,按其中的某个字段分别导出shp。主要是让不会arcgis的人也能按字段分割shp了。

我把这个需求可以理解为,按照指定字段的指定记录值,生成新的矢量文件。

这个功能,在arcgis中是常常被使用的。依稀记得是要使用一个属性选择器吗,然后过滤得到我们想保存的矢量。

那如果通过代码的形式,实现这个功能呢?

今天我们就来浅略地说一说,具体操作可以看我开源的代码。

1 介绍

常见的矢量文件格式是shp格式,而shp格式通常由三个不同后缀的文件组合而成,结构如下:

属性信息由字段和各自的记录值组合而成,如下:

字段是唯一的,而记录值可以存在相同的值(可以重复)。


2 后端处理的代码

import os.pathfrom osgeo import ogr
ogr.UseExceptions() # 启用异常处理class Shp_split: def __init__(self, filename): self.filename = filename self.driver = ogr.GetDriverByName('ESRI Shapefile') self.datasource = self.driver.Open(filename, 0) # 0 means read-only self.get_field_name() self.layer = self.datasource.GetLayer() def get_field_name(self): ds = self.datasource layer = ds.GetLayer() layer_defn = layer.GetLayerDefn() field_contents = [] # 遍历所有的字段 for i in range(layer_defn.GetFieldCount()): fieldDefn = layer_defn.GetFieldDefn(i) field_contents.append(fieldDefn.GetName()) self.field = field_contents # 关闭数据源 ds = None
self.field_contents = field_contents def get_unique_values(self, field_name):
# 获取字段定义 layerDefn = self.layer.GetLayerDefn() fieldIndex = layerDefn.GetFieldIndex(field_name)
# 检查字段是否存在 if fieldIndex == -1: print("Field not found.") else: # 获取所有记录 values = [] for feature in self.layer: value = feature.GetFieldAsString(fieldIndex) if value is not None: values.append(value)
return values
def split_by_field(self, field_name, value):
# 打开输入的 Shapefile 数据源
data_source = self.datasource if data_source is None: print(f'Could not open {self.filename}') return
# 获取数据源中的第一层(通常一个 Shapefile 只有一层) layer = data_source.GetLayer() if layer is None: print(f'No layer found in {self.filename}') return
output_shp_file = os.path.splitext(os.path.basename(self.filename))[0] +'_'+ field_name + '_' +value +'.shp' outpath = os.path.join(os.path.dirname(os.path.abspath(self.filename)), "out") os.makedirs(outpath, exist_ok=True)
output_shp = os.path.join(outpath, output_shp_file) # 创建输出的 Shapefile 数据源 # if ogr.GetDriverByName('ESRI Shapefile').Exists(output_shp): # ogr.GetDriverByName('ESRI Shapefile').DeleteDataSource(output_shp) out_data_source = self.driver.CreateDataSource(output_shp) if out_data_source is None: print(f'Could not create {output_shp}') return
# 复制输入层的定义以创建输出层 out_layer = out_data_source.CreateLayer(output_shp.split('.')[0], geom_type=layer.GetGeomType()) for i in range(layer.GetLayerDefn().GetFieldCount()): field_defn = layer.GetLayerDefn().GetFieldDefn(i) out_layer.CreateField(field_defn)
# 设置过滤器 layer.SetAttributeFilter(f"{field_name} = '{value}'")
# 遍历并复制匹配的特征 feature = layer.GetNextFeature() while feature: out_feature = ogr.Feature(out_layer.GetLayerDefn()) out_feature.SetFrom(feature) out_layer.CreateFeature(out_feature) out_feature = None # 释放内存 feature = layer.GetNextFeature()
# 关闭数据源 data_source = None out_data_source = None
if __name__ == '__main__': file_path = r'D:\code\China_Provinces_1389.shp' splitter = Shp_split(file_path) field_name = 'LABEL_CHN' # Replace with the actual field name you want to use splitter.split_by_field(field_name)


3 使用

把上面的后端处理部分的代码,整合到rstool中,

最后,我录制了一个简单的使用视频,如下:

输入一个shp文件后,首先在该文件所在的文件夹,生成一个叫做out的文件夹。

接着安装用户选择的字段、选择的记录值,在out文件夹下生成新的shp矢量文件。

目前测试存在两个问题:

1.缺少空间参考文件的问题

2.中文记录值的问题(尽量使用英文就不会有问题)

4 下载

我把功能集成到rstool中,rstool是我写的针对地信、遥感数据处理的工具,其代码开源到github,有需要的朋友自行去github搜索rstool。

本次已将打包后的rstool上传到云盘,有需要的朋友在后台回复rstool获取下载链接。

rstool正在开发中,不定期更新,开源地址是https://github.com/ytkz11/rs-tool

欢迎来白嫖!有哪里不对劲的地方或建议可以在下方留言。


十一假期即将结束,在这七天的晚上,断断续续、修修补补开发了两个小功能。

第一个功能是从照片中提取GPS信息并创建Shapefile:

从照片中提取GPS信息并创建Shapefile(第三版)同时生成一个TXT文本

从照片中提取GPS信息并创建Shapefile(第二版)适用于无人机照片和手机照片

从照片中提取GPS信息并创建Shapefile(第一版)适用于无人机照片和手机照片

第二功能是本篇所介绍的:按照指定字段的指定记录值,生成新的矢量文件。


朋友们在使用这个工具的时候,你无论是运行这个工具成功或者失败,都可以在下方留言。

最后,预估十月份会很忙,不能做到每天都更新公众号。


remote sensing
一个专注于测绘、地信、遥感的公众号
 最新文章