5

What I want to do is calculate travel times between points within a road network. I know there are options with GRASS (via v.net) and pgRouting (and possibly many more). I intent to stick to the standard QGIS network analysis though.

I studied all the necessary material in the Network Analysis Library (pyQGIS cookbook) and I am able to obtain the distance in metres for any two points in my network via the standard QgsDistanceArcProperter() and dijkstra's algorithm. What I am not capable of doing is creating a properter that uses a different cost, namely the travel time per segment using the information on speed from its attributes.

Using python QGis network analysis library to calculate short path based on speed and distance? did a good job in translating the speedproperter that is used in the RoadGraph plugin. I am not able to get neither of their properters to run though. QGIS is crashing, so far I couldn't figure out why.

Does anyone know of another already existing properter somewhere that works? Or can point me to something that might bring me one step farther?

EDIT:
It seems that with QGIS3.0 the whole network analysis is revised. Some methods get renamed (e.g. properter -> strategy).
The method is going to be QgsNetworkSpeedStrategy().
The constructor is explained here, can anyone help to translate that into a python class that I could implement within my QGIS 2.18 python script?

1
  • 1
    the answer you linked to (the translated copy of the roadgraph implementation) does look promising. When you say QGIS crashes, do you get a python error in the error logs, or a full-on crash (e.g. a segfault?). I can see some places in that code that could be prone to things like divide-by-zero errors, depending on your network geometry. Did you try ErnestScribblers approach, the second answer which seems to take this into account?
    – Steven Kay
    Dec 6, 2016 at 21:03

2 Answers 2

5
+50

Here's a short Properter which I'm working on that might provide part of the answer. It aims to modify shortest path calculations for a road network by excluding freeways (because I'm using it for cycling routes) and roads that haven't been built yet. In my road layer, these are CLASS_CODE 0 and 9.

The property() method calculates the weight allocated to the graph edges. In my case this is either infinity or the unmodified distance. But it could be a speed figure derived from distance.

The required_attributes() method has to return the direction field, and any other field used in the property() method.

In the shortest path function:

directionField = self.roadLayer.fieldNameIndex('DIR_CODE')
classCodeField = self.roadLayer.fieldNameIndex('CLASS_CODE') 

properter = MyProperter(directionField, classCodeField)

In the properter class:

# class for MyPropertyer
class MyProperter(QgsArcProperter):
def __init__(self, directionIndex, classCodeIndex):
    QgsArcProperter.__init__(self)
    self.directionIndex = directionIndex
    self.classCodeIndex = classCodeIndex

# returns cost of edge, set at infinity for freeways and proposed roads, otherwise distance
def property(self, distance, feature):
    expression = feature.attribute("CLASS_CODE") in (0, 9) # 0 is freeway, 9 is proposed road
    if expression:
        return float('inf')
    return distance

def requiredAttributes(self):
    # return the indices for (1) the direction attribute, and (2) any other attribute used in the property() method
    return [self.directionIndex, self.classCodeIndex] 
0
3

This is the properter that I put together from all the properter-examples that were posted. It works well. Note that the defaultSpeed is not used in my case (for peculiar reasons of my project), but its easy to just implement the if statement.
Be careful when you edit around too often when you instantiate the class, because I constantly added and deleted lines when I experimented, I messed up some indentations without noticing. And python is pretty strict about that. It took me then some time to figure out that this was the actual error (was not obvious from the error message for me).

class SpeedFieldProperter(QgsArcProperter):
    """
    (attributeIndex, defaultSpeed=2.71828, speedToDistanceFactor = 1000)
    SpeedProperter to factor in speed and distance to edge tavel time cost
    @attributeIndex - find it out through attributeIndex = your_layer.fieldNameIndex('the_name_of_the_layercolumn')
    @defaultSpeed - not used here
    @speedToDistanceFactor - factor to adjust speed units (e.g. km/h) to distance units (e.g. meters)
    if the speed attribute is in km/h and distance in meters, this should equal 1000
    """
    def __init__(self, attributeIndex, defaultSpeed = 50, speedToDistanceFactor = 1000):
        QgsArcProperter.__init__(self)
        self.AttributeIndex = attributeIndex
        self.DefaultSpeed = defaultSpeed
        self.SpeedToDistanceFactor = speedToDistanceFactor

    def property(self, distance, Feature):
        """
        returns the cost of the edge. In this case travel time.
        """
        attrs = Feature.attributes()
        speed = attrs[self.AttributeIndex]
        travel_time = distance / (speed * self.SpeedToDistanceFactor)
        return travel_time

    def requiredAttributes(self):
        """
        returns list of indices of feature attributes
        needed for cost calculation in property()
        """
        return [self.AttributeIndex]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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