I have a shapefile of road volumes as polylines, and want to be able to show the sum of the volumes for polylines that are spatially the same/similar but are for travel in opposite directions. For e.g. one polyline for traffic travelling North may have a volume of 8000, while the equivalent polyline that is for traffic going South has a volume of 6000. I need to be able to locate each of these polylines and sum their volume values, and show this as a separate layer. Note that some polylines within the dataset are along one-way streets and therefore don't have an equivalent polyline that travels in the opposite direction.
I've been able to distinguish each line pair in the attribute table by generating the xmin and xmax, however I'm not keen on selecting each pair manually and calculating the sum of volumes given there are a few thousand. I've tried spatial join (MMQGIS plugin) and union in QGIS but haven't had any luck. I've also toyed with the QGIS Field Calculator a bit but I'm not very familiar with how to use some of the geometry commands for this type of analysis.
EDIT: as mentioned below, the code I suggest here is my first one, thus may be inefficient. I posted it in code-review SE, so whoever wishes might follow the post, to either correct the code, or to obtain a better, more-efficient version of it.
So this is my first PyQGIS code, which is aimed to do what you asked for, namely to find those pairs of lines (or roads) that share the same geometry, and sum the values of a chosen field (i.e. volume).
The output is a tmp. layer with 3 columns: ID, IDsub stand for FID of the features being merges, and ValueSum. Features with no other features with shared geometries, will get their original value in the ValueSum field, and -99 (i.e. no match) in the IDsub field.
Image of an output is below:
The code is attached as well. Feel free to modify it to your exact needs. Note that it may be in-efficient (for it is my fisrt code here), also make sure to define the path to your shapefile and the name of the field to be summed at the top.
path='D:/Documents/qgis/lines_same/Lines.shp' # Enter your SHP file path Val="Value" # Enter the field name you would like to summarize from PyQt4.QtCore import * layer = QgsVectorLayer(path,'Lines', 'ogr') tmp = QgsVectorLayer("LineString", "tmp_output", "memory") dp = tmp.dataProvider() tmp.startEditing() dp.addAttributes ( [ QgsField("ID", QVariant.Int), QgsField("IDsub", QVariant.Int), QgsField("ValueSum", QVariant.Int) ] ) iter = layer.getFeatures() for feature in iter: CreateVerify = 0 geom = feature.geometry() geom = geom.asPolyline() ID = feature.id() Value = feature[Val] iterSub = layer.getFeatures() for featureSub in iterSub: geomSub = featureSub.geometry() geomSub = geomSub.asPolyline() IDsub = featureSub.id() ValueSub = featureSub[Val] if (geom==geomSub and ID!=IDsub): CheckExist = tmp.getFeatures() Exist = 0 for exs in CheckExist: if (exs.geometry().asPolyline() == geom): Exist = Exist + 1 if (CreateVerify == 0 and Exist == 0): CreateVerify = 1 New = QgsFeature() New.setGeometry (QgsGeometry.fromPolyline(geom)) New.setAttributes([ID, IDsub, Value + ValueSub]) dp.addFeatures([ New ]) tmp.commitChanges() elif (Exist > 0): CreateVerify = 1 if (CreateVerify == 0): New = QgsFeature() New.setGeometry (QgsGeometry.fromPolyline(geom)) New.setAttributes([ID,-99, Value]) dp.addFeatures([ New ]) tmp.commitChanges() QgsMapLayerRegistry.instance().addMapLayer(tmp)
Just for completeness, I'd like to add another solution based on using spatial SQL queries. Suppose you have a roads layer in a Spatialite database, for example. I'll assume this roads table has a column 'id' and a columm 'volume'. To get those linestrings that are duplicates (end points are equal), together with the sum of the volumes you could do:
SELECT r1.id, r1.volume+r2.volume AS "Total volume" FROM roads AS r1, roads r2 WHERE r1.id<>r2.id AND StartPoint(r1.geometry) = EndPoint(r2.geometry) AND EndPoint(r1.geometry) = StartPoint(r2.geometry);
This is based on the end points of each linestring being exactly the same. But often computer (floating point) rounding errors, or digitizing mistakes leave end points slightly off. So a better option is to query for one endpoint to be within a buffer around the other line's endpoint. That would be (taking a 2 meter buffer):
SELECT r1.id, r1.volume+r2.volume AS "Total volume" FROM roads AS r1, roads r2 WHERE r1.id<>r2.id AND ST_Contains(ST_Buffer(EndPoint(r2.geometry),2), StartPoint(r1.geometry)) AND ST_Contains(ST_Buffer(StartPoint(r2.geometry),2), EndPoint(r1.geometry))
BTW, This only works if the linestrings are truely in opposite topological directions. If you have the two traffic directions digitized in the same line direction, the above won't work. The STartPoint of one of the duplicates must be at the EndPoint of it's duplicate pair. Hope that's clear…