2

My goal: Merging all line segments in a vector to a single feature.

My approach: QGIS module singlepartstomultipart

My problem: For larger numbers of features within the line vector, the module has a processing time of several hours or even makes QGIS crash.

My code:

processing.runalg('qgis:singlepartstomultipart', {"INPUT": vect_in, "FIELD": "DN", "OUTPUT": vect_out})

My question: Is there a different way for solving this?

My suggestion: I tried to run singlepartstomultipart on sets of 100 or 1000 features to then merge these again. However, this seems to be quite a detour and running singlepartstomultipart didn't work on the merged sets (see #? in the code below. This code is the implementation of my suggested detour solution):

# Open line layer
Lines = QgsVectorLayer(Lines, Lines, "ogr")

# Define layer extent
extent = Lines.extent()
xmin = extent.xMinimum()
xmax = extent.xMaximum()
ymin = extent.yMinimum()
ymax = extent.yMaximum()

# Initialize counter
j = 0

# Merge line segments in sets of 1000 features
i = int(round(float(Lines.featureCount()) / 1000))

while j < i:
    # Create temporary layer
    vl = QgsVectorLayer("LineString?crs=EPSG:4326", "temp_layer", "memory")
    vl.setCrs(Lines.crs())
    pr = vl.dataProvider()
    vl.startEditing()

    # Select block of 1000 features to be merged
    start = j * 1 + j * 1000
    end = (j + 1) * 1000

    # Copy features to temporary layer
    iter = Lines.getFeatures()
    for feature in iter:
        if feature.id() > start and feature.id() < end:
            pr.addFeatures([feature])
            vl.commitChanges()

    # Add layer to registry
    # Note: Layer needs to be added to the canvas in order to be usable in processing.runalg below (#unclear)
    QgsMapLayerRegistry.instance().addMapLayer(vl)

    # Merge line segments to one feature
    multipart = os.getcwd() + r"\1a_multipart" + str(j) +".shp"
    if not os.path.isfile(multipart):
        processing.runalg('qgis:singlepartstomultipart',
                          {"INPUT": vl, "FIELD": "DN", "OUTPUT": multipart})

    # Remove layer from registry
    QgsMapLayerRegistry.instance().removeMapLayer(vl.id())
    j += 1

# Merge created files
list = []
for file in os.listdir(data_dir):
    if '1a_multipart' in file and '.shp' in file:
        temp_lines = QgsVectorLayer(file, 'temp_lines', "ogr")
        list.append(file)
multipart_merge = os.getcwd() + r"\1b_multipart.shp"
if not os.path.isfile(multipart_merge):
    processing.runalg('qgis:mergevectorlayers', list, multipart_merge)

# Merge features in merged shapefiles
final_merge = QgsVectorLayer(multipart_merge,multipart_merge, "ogr")
multipart = os.getcwd() + r"\1c_multipart.shp"
if not os.path.isfile(multipart):

    #? This doesn't work so far
    processing.runalg('qgis:singlepartstomultipart',
                      {"INPUT": final_merge, "FIELD": "FID", "OUTPUT": multipart})
  • 1
    How does your last qgis:singlepartstomultipart not work? Does an error appear, does QGIS just crash? – Joseph Apr 28 '17 at 13:28
  • 1
    I retried and now I got the desired result with a processing time of almost 8 minutes. I think before QGIS crashed. Still, I am not convinced that my detour solution is the optimal one. I think there should be a more efficient way to solve this that I haven't thought of. – Sophie Crommelinck May 1 '17 at 8:25
  • Hmm you don't need to load a layer to canvas in order to use processing.runalg(), a path to the layer is good enough. You also defined the extents early but don't seem to be calling them in your script :) – Joseph May 3 '17 at 9:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.