在QGIS Python脚本中通过迭代实现Shapefile裁剪
嘿,这个批量按ID匹配裁剪的需求我刚好处理过,给你两个靠谱的方案——先说说QGIS图形模型器里的迭代用法,再给你直接能用的Python脚本,都能搞定5000个要素的批量处理:
方案一:用QGIS图形模型器实现迭代裁剪
其实图形模型器里是有迭代功能的,只是藏在「迭代器」设置里,步骤如下:
- 打开图形模型器,先添加两个输入图层:Shapefile A(待裁剪图层)和Shapefile B(裁剪要素图层)。
- 添加「迭代行(按表格)」工具,选择Shapefile B作为输入表格,把迭代字段设为你的ID字段(比如
ID)——这个工具会逐个取出B中每个ID对应的单要素。 - 添加「按属性选择」工具,输入图层选Shapefile A,设置选择表达式为
"ID" = @current_row_value(@current_row_value是迭代器输出的当前ID值,要确保A和B的ID字段名称一致,不一样的话改A的字段名或者表达式里的字段名)。 - 添加「裁剪」工具:输入图层选「按属性选择」的输出(也就是A中当前ID匹配的要素),裁剪图层选迭代器输出的B中当前ID的要素。
- 给裁剪工具设置输出路径时,可以用
@current_row_value命名文件,比如裁剪结果_@current_row_value.shp,这样每个ID的结果单独保存;如果想合并成一个图层,最后加个「合并矢量图层」工具,把所有裁剪输出拉进去就行。 - 运行模型,它会自动遍历所有ID,完成批量裁剪。
方案二:直接写Python脚本(更高效灵活)
如果觉得模型器迭代有点慢,或者需要自定义逻辑,直接写Python脚本会更顺手,核心思路是先把B的ID和对应几何存成字典,再遍历每个ID去A里匹配裁剪:
from qgis.core import ( QgsVectorLayer, QgsFeature, QgsGeometry, QgsVectorFileWriter, QgsFeatureRequest ) import processing # 替换成你的文件路径 shapefile_a = "/你的路径/ShapefileA.shp" shapefile_b = "/你的路径/ShapefileB.shp" output_dir = "/你的输出文件夹/" # 加载图层 layer_a = QgsVectorLayer(shapefile_a, "待裁剪图层", "ogr") layer_b = QgsVectorLayer(shapefile_b, "裁剪要素图层", "ogr") if not layer_a.isValid() or not layer_b.isValid(): print("图层加载失败!检查文件路径是否正确") else: # 假设两个图层的ID字段都叫"ID",不一样的话修改这里 id_field = "ID" # 把B的ID和对应几何存进字典,方便快速查找 b_id_geom_map = {} for feat in layer_b.getFeatures(): current_id = feat[id_field] b_id_geom_map[current_id] = feat.geometry() # 遍历每个ID进行裁剪 for target_id, clip_geom in b_id_geom_map.items(): # 在A中筛选对应ID的要素 request = QgsFeatureRequest().setFilterExpression(f'"{id_field}" = {target_id}') a_matched_features = [f for f in layer_a.getFeatures(request)] if not a_matched_features: print(f"未找到ID={target_id}的A要素,跳过") continue # 对每个匹配的A要素执行裁剪 clipped_results = [] for a_feat in a_matched_features: clipped_geometry = a_feat.geometry().intersection(clip_geom) if not clipped_geometry.isNull(): new_feat = QgsFeature(a_feat.fields()) new_feat.setGeometry(clipped_geometry) new_feat.setAttributes(a_feat.attributes()) clipped_results.append(new_feat) # 保存当前ID的裁剪结果 if clipped_results: output_path = f"{output_dir}/clipped_result_{target_id}.shp" write_status = QgsVectorFileWriter.writeAsVectorFormat( layer_a, output_path, "UTF-8", layer_a.crs(), "ESRI Shapefile", features=clipped_results ) if write_status == QgsVectorFileWriter.NoError: print(f"ID={target_id}的裁剪结果已保存:{output_path}") else: print(f"保存ID={target_id}结果时出错") # 可选:合并所有裁剪结果成一个图层 # output_files = [f"{output_dir}/clipped_result_{id}.shp" for id in b_id_geom_map.keys()] # processing.run("native:mergevectorlayers", { # "LAYERS": output_files, # "OUTPUT": f"{output_dir}/all_clipped_results.shp" # })
小提示:
- 确保两个图层的坐标参考系一致,不一致的话可以在脚本里加一步投影转换(用
processing.run("native:reprojectlayer")),把B转成A的CRS。 - 如果不需要单独保存每个ID的文件,也可以把所有裁剪结果放到同一个图层里再一次性保存,能节省磁盘空间。
内容的提问来源于stack exchange,提问作者SnoruntIce




