You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在QGIS Python脚本中通过迭代实现Shapefile裁剪

嘿,这个批量按ID匹配裁剪的需求我刚好处理过,给你两个靠谱的方案——先说说QGIS图形模型器里的迭代用法,再给你直接能用的Python脚本,都能搞定5000个要素的批量处理:

方案一:用QGIS图形模型器实现迭代裁剪

其实图形模型器里是有迭代功能的,只是藏在「迭代器」设置里,步骤如下:

  1. 打开图形模型器,先添加两个输入图层:Shapefile A(待裁剪图层)Shapefile B(裁剪要素图层)
  2. 添加「迭代行(按表格)」工具,选择Shapefile B作为输入表格,把迭代字段设为你的ID字段(比如ID)——这个工具会逐个取出B中每个ID对应的单要素。
  3. 添加「按属性选择」工具,输入图层选Shapefile A,设置选择表达式为"ID" = @current_row_value@current_row_value是迭代器输出的当前ID值,要确保A和B的ID字段名称一致,不一样的话改A的字段名或者表达式里的字段名)。
  4. 添加「裁剪」工具:输入图层选「按属性选择」的输出(也就是A中当前ID匹配的要素),裁剪图层选迭代器输出的B中当前ID的要素。
  5. 给裁剪工具设置输出路径时,可以用@current_row_value命名文件,比如裁剪结果_@current_row_value.shp,这样每个ID的结果单独保存;如果想合并成一个图层,最后加个「合并矢量图层」工具,把所有裁剪输出拉进去就行。
  6. 运行模型,它会自动遍历所有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

火山引擎 最新活动