1

I am working with a road network, where I extracted only the three main road types. In the next step, I would like to union all Linestrings based on their road type and connectivity. That means that I have a gdf of thousands of Linestrings right now but want to end up with only six Linestrings (see image below).

So, red, green and blue are the three road types and therefore cannot be unioned together. On top of that 3, 4, 5, and 6 are the same type but are not connected to each other but with another class.

I looked into dissolved but the problem here is that it ignores connectivity. On the other side, unary_union looks suitable but only returns shapely geometries which I would have to transform back into a gdf (as far as I'm concerned?). Any idea how to approach this problem?

Road Network

I found this code for an QGIS Add-on ([https://gis.stackexchange.com/questions/228267/merging-adjacent-lines-in-qgis#][3]). I could make the first block running (see in the very bottom) but struggle with the second block since I get a bunch of AttributeErrors and don't know how to translate them into pandas.

##Lines=vector line

from qgis.core import *

def find_adjacent(selected_ids): # for finding adjacent features
    outlist = []
    outinds = []
    outset = set()
    for j, l in enumerate(selected_ids):
        as_set = set(l)
        inds = []
        for k in outset.copy():
            if outlist[k] & as_set:
                outset.remove(k)
                as_set |= outlist[k]
                inds.extend(outinds[k])
        outset.add(j)
        outlist.append(as_set)
        outinds.append(inds + [j])
    outinds = [outinds[j] for j in outset]
    del outset, outlist
    result = [[selected_ids[j] for j in k] for k in outinds]
    return result


layer = processing.getObject(Lines)
crs = layer.crs().toWkt()

# Create the output layer
outLayer = QgsVectorLayer('Linestring?crs='+ crs, 'snapped' , 'memory')
prov = outLayer.dataProvider()
fields = layer.pendingFields()
prov.addAttributes(fields)
outLayer.updateFields()

already_processed = []
for feat in layer.getFeatures():
    attrs = feat.attributes()
    geom = feat.geometry()
    curr_id = feat["ID"]
    if curr_id not in already_processed:
        query = '"ID" = %s' % (curr_id)
        selection = layer.getFeatures(QgsFeatureRequest().setFilterExpression(query))
        selected_ids = [k.geometry().asPolyline() for k in selection]
        adjacent_feats = find_adjacent(selected_ids)
        for f in adjacent_feats:
            first = True
            for x in xrange(0, len(f)):
                geom = (QgsGeometry.fromPolyline([QgsPoint(w) for w in f[x]]))
                if first:
                    outFeat = QgsFeature()
                    outFeat.setGeometry(geom)
                    outGeom = outFeat.geometry()
                    first = False
                else:
                    outGeom = outGeom.combine(geom)
            outFeat.setAttributes(attrs)
            outFeat.setGeometry(outGeom)
            prov.addFeatures([outFeat])
        already_processed.append(curr_id)
    else:
        continue

# Add the layer to the Layers panel
QgsMapLayerRegistry.instance().addMapLayer(outLayer)

First block using pandas:

def find_adjacent(line): # for finding adjacent features
    outlist = []
    outinds = []
    outset = set()
    for j, l in line.iteritems():
        as_set = set(line.astype(str))
        inds = []
        for k in outset.copy():
            if outlist[k] & as_set:
                outset.remove(k)
                as_set |= outlist[k]
                inds.extend(outinds[k])
        outset.add(j)
        outlist.append(as_set)
        outinds.append(inds + [j])
    outinds = [outinds[j] for j in outset]
    del outset, outlist
    result = [[line[j] for j in k] for k in outinds]
    return result

lines = find_adjacent(trunk.geometry)
2
  • Is what you are showing the sum of your data, or is it an example taken from a much larger dataset?
    – Hornbydd
    Commented Aug 23, 2022 at 11:24
  • That's the sum of my data. I also have another unfiltered gdf, but I intend to work with the gdf that is shown in the image.
    – Danny
    Commented Aug 23, 2022 at 11:34

1 Answer 1

0

The quickest solution is to manually select up the different groups of roads and label them, so all the lines that make up group 5 you tag as 5 in a field you had created. That will literally be a 3 minute job. Then dissolve on that group. In ArcMap/ArcGIS Pro you would use the Dissolve tool, I'm sure QGIS has an equivalent if you use that. This would all be done in less than 5 minutes.

2
  • Thanks for your answer. I realized that I should have been more specific in my question. I'd like to do this in Python, since I want to automate this process as part of a whole automated assessment tool.
    – Danny
    Commented Aug 23, 2022 at 12:57
  • Assuming your groups are not connected to other groups then you need some sort of network tracing solution, you probably want to be looking at networkx in that case.
    – Hornbydd
    Commented Aug 23, 2022 at 13:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.