I'm looking for help calculating the distance between a sequence of points that are in a single Shapefile in QGIS. Below is what my data look like and a blank distance column I've added to show how I'd like the distance to look. I want to know the distance between point 1 and 2, 2 and 3, etc. I'd like distance to be in meters or Km, but currently my Shapefile is in a projection whose units are decimal degrees.

ID  LAT         LON         TIME        DISTANCE
1   10.08527    124.59833   21:24:37    0
2   10.08523    124.59830   21:25:07    ?
3   10.08526    124.59832   21:25:37    ?
4   10.08526    124.59831   21:26:07    ?

A number of people have asked similar questions, but none quite get at what I want to do. This post is close, but this is in PostGIS, not QGIS Calculate distances between series of points in postgis

This post got me part of the way there, but since I'm new to QGIS the answer doesn't provide enough detail for me. For example, once I've installed the GRASS plugin, I think I need to save/import the Shapefile with my series of GPS points into GRASS so I can use the v.distance module, but I don't know how to do that. QGIS calculate distance of point along a line

Is the GRASS v.distance module the only way to go? Or is there a more straight forward way? If v.distance is the only way would someone be able to point me to or explain more step-by-step how to do this?

  • @underdark How can we do that in excel ? – user2207232 Mar 26 '13 at 22:53

I return to this issue because it is very similar to How do I find vector line bearing in QGIS or GRASS? and it can be solved with Python in the same way:

1) Haversine distance

One can find lots of scripts by searching Haversine distance with Python on the Internet and I choose one of them in Haversine Formula in Python (Bearing and Distance between two GPS points)

def haversine(lon1, lat1, lon2, lat2):
    Calculate the great circle distance between two points 
    on the earth (specified in decimal degrees)
    # convert decimal degrees to radians 
    lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2])
    # haversine formula 
    dlon = lon2 - lon1 
    dlat = lat2 - lat1 
    a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2
    c = 2 * math.asin(math.sqrt(a)) 
    km = 6367 * c
    return km

We have a series of lines (points) in the file that must be treated in pairs (point1 - point2) to calculate the distance. For this we will use a simple iterator from Most pythonic way to get the previous element

def offset(iterable):
    prev = None
    for elem in iterable:
        yield prev, elem
        prev = elem

Now it is possible to read the file (example of Kerrie) in pairs of lines/points

import csv
with open('testhavers.csv', 'rb') as f:
   reader = csv.DictReader(f)
   for  pair in offset(reader):
       print pair

 (None, {'LAT': '10.08527', 'LON': '124.59833', 'ID': '1', 'TIME': '21:24:37'})
 ({'LAT': '10.08527', 'LON': '124.59833', 'ID': '1', 'TIME': '21:24:37'},
 {'LAT':    '10.08523', 'LON': '124.59830', 'ID': '2', 'TIME': '21:25:07'})
 ({'LAT': '10.08523', 'LON': '124.59830', 'ID': '2', 'TIME': '21:25:07'}, 
 {'LAT': '10.08526', 'LON': '124.59832', 'ID': '3', 'TIME': '21:25:37'})
 ({'LAT': '10.08526', 'LON': '124.59832', 'ID': '3', 'TIME': '21:25:37'}, 
 {'LAT':    '10.08526', 'LON': '124.59831', 'ID': '4', 'TIME': '21:26:07'})

Then create a shapefile containing the original fields of the csv file and a new field for the distance with the Python modules Shapely and Fiona of Sean Gillies:

import fiona
from shapely.geometry import Point, mapping
# creation of the schema of the shapefile (geometry and fields)
schema = { 'geometry': 'Point', 'properties':{'ID': 'int', 'LAT':'float', 'LON':'float', 'TIME':'str','distance' : 'float'}}
# creation of the shapefile:
with fiona.collection("result.shp", "w", "ESRI Shapefile", schema) as output:
    # reading the csv file
    with open('testhavers.csv', 'rb') as f:
       reader = csv.DictReader(f)
       # we need here to eliminate the first pair of point with None
       for i, pair in enumerate(offset(reader)):
            if i == 0: (pair with None)
                # writing of the point geometry and the attributes
                point = Point(float(pair[1]['LON']), float(pair[1]['LAT']))
                dist = 0 # None
                output.write({'properties': {'ID':int(pair[1]['ID']),'LAT':float(pair[1]['LAT']),'LON':float(pair[1]['LON']), 'TIME':pair[1]['TIME'],'distance': dist},'geometry': mapping(point)})
                # writing of the point geometry and the attributes
                point = Point(float(pair[1]['LON']), float(pair[1]['LAT']))
                # Haversine distance between pairs of points
                dist = haversine(float(pair[0]['LON']), float(pair[0]['LAT']), float(pair[1]['LON']),float(pair[1]['LAT']))
                output.write({'properties': {'ID':int(pair[1]['ID']),'LAT':float(pair[1]['LAT']),'LON':float(pair[1]['LON']), 'TIME':pair[1]['TIME'],'distance': dist},'geometry': mapping(point)})

and the result: enter image description here

It is also possible to do it with PyQGIS but it is more complex than Fiona which uses simple dictionaries to create shapefiles.

You can use another function to calculate the Haversine distance (Why is law of cosines more preferable than haversine when calculating distance between two latitude-longitude points?) without any problem, only the distance calculation changes, not the process of creating the shapefile.

| improve this answer | |

If you're familiar with r, try using a combination of the 'sp' and 'dismo' package.

For example like this (assuming to have points with x,y coordinates):


data <- read.csv2(..) # Read in your data
coordinates(data) <- ~x+y # point them to your coordinates to make a spatialpoint layer
# Or like this:
Pointlayer <- SpatialPoints(cbind(data$x,data$y))

# then calculate your distance matrix your point sequence
d <- pointDistance(pp,longlat=F)

# Looks for example like this:
          [,1]     [,2]     [,3]     [,4]     [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
[1,]  0.000000       NA       NA       NA       NA   NA   NA   NA   NA    NA    NA    NA
[2,] 54.561891  0.00000       NA       NA       NA   NA   NA   NA   NA    NA    NA    NA
[3,] 25.000000 73.49830  0.00000       NA       NA   NA   NA   NA   NA    NA    NA    NA
[4,] 50.487622 43.93177 53.14132  0.00000       NA   NA   NA   NA   NA    NA    NA    NA
[5,]  4.123106 57.00877 26.30589 54.58938  0.00000   NA   NA   NA   NA    NA    NA    NA
[6,] 32.249031 37.21559 57.14018 60.30755 32.01562    0   NA   NA   NA    NA    NA    NA

#More information about the method in dismo package help
| improve this answer | |

Perhaps the distance matrix tool might help? It's under the Vector menu. For each point this will calculate the distance to each of the other points and store the result in a CSV file.

If you want the distances in metres I think it would make sense to transform your points from lat/lon to a projected shapefile (possibly UTM51 in your case) before using the tool.


| improve this answer | |

Use v.to.db in GRASS (e.g. via Sextante plugin) with option=length (line length).

Example of uploading line lengths (in meters) of each vector line to attribute table (fill the corresponding fields in the GUI):

v.to.db map=roads option=length type=line col=linelength units=me

| improve this answer | |

I find this problem is easiest to solve by working in a spreadsheet, don't use the gis. I found the work of Chris Veness to be very helpful -


If you scroll the the bottom paragraph, you will find links to two excel sheets, which are;



See also;

Why is law of cosines more preferable than haversine when calculating distance between two latitude-longitude points?

and you can search gis.se for haversine.


| improve this answer | |
  • Do you need help to get the data from the shapefile to the spreadsheet? – Willy Dec 16 '12 at 5:30

Your Answer

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

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