Skip to content

Instantly share code, notes, and snippets.

@ClemRz
Last active October 1, 2018 17:48
Show Gist options
  • Save ClemRz/0e81a4e6a180b1b191cbca9e6d05c575 to your computer and use it in GitHub Desktop.
Save ClemRz/0e81a4e6a180b1b191cbca9e6d05c575 to your computer and use it in GitHub Desktop.
Removes inaccurate point from a GPS trace.

Filter a KML by HDOP value

Sometimes a trace KML file obtained from a GPS has some points with high HDOP value. Those are usually not accurate and can be omitted from the trace.

How to use this script

Then open a terminal and run:

python zFilterByHdop.py /path/to/your/file.kml

By default the HDOP threshold is set to 2. If you want to change that value you can use the option -d:

python zFilterByHdop.py /path/to/your/file.kml -d 2.3

For more help just run:

python zFilterByHdop.py -h

Resulting file

The output file is located in the same folder than the input one.

import xml.etree.ElementTree as etree
import re
import argparse
def inplace_change(filename, old_string, new_string, verbose):
with open(filename) as f:
s = f.read()
if (old_string not in s and verbose):
print '"{old_string}" not found in {filename}.'.format(**locals())
return
with open(filename, 'w') as f:
if (verbose):
print 'Changing "{old_string}" to "{new_string}" in {filename}'.format(**locals())
s = s.replace(old_string, new_string)
f.write(s)
def filter(max_hdop, filename, verbose):
ns = {"kml": "http://www.opengis.net/kml/2.2"}
outfile = filename.split(".")[0] + ".out." + filename.split(".")[1]
tree = etree.parse(filename)
root = tree.getroot()
track1 = root.find("kml:Document/kml:Folder[@id='Tracks']/kml:Folder[@id='track 1']", ns)
linestring = track1.find("kml:Placemark/kml:MultiGeometry/kml:LineString/kml:coordinates", ns)
linestringtxt = linestring.text
points = track1.find("kml:Folder[@id='track 1 points']", ns)
placemarks = points.findall("kml:Placemark", ns)
placemarks_count = len(placemarks)
removal_counter = 0
if (verbose):
print "Processing {} points".format(placemarks_count)
for placemark in placemarks:
description = placemark.find("kml:description", ns).text
hdop = float(re.search("<i>HDOP:</i> ([\d.]+)", description).group(1))
if hdop >= max_hdop:
coordinates = placemark.find("kml:Point/kml:coordinates", ns).text
coordlen = len(re.findall(coordinates, linestringtxt))
if coordlen > 1:
print "Could not process coordinates {} because they appear {} times. Please remove this point manually.".format(coordinates, coordlen)
else:
if (verbose):
print "Removing {} (HDOP: {} > {})".format(coordinates, hdop, str(max_hdop))
linestringtxt = linestringtxt.replace(coordinates + " ", "")
points.remove(placemark)
removal_counter += 1
linestring.text = linestringtxt
percent = 100 * float(removal_counter)/placemarks_count
print "Removed {} points of {} ({:<0.2f}%)".format(removal_counter, placemarks_count, percent)
print "Output file: {}".format(outfile)
tree.write(outfile, encoding="utf-8", xml_declaration=True)
inplace_change(outfile, "ns0:", "", verbose)
def get_options():
parser = argparse.ArgumentParser(prog='HdopFilter by ClemRz', description='Filter a KML file based on HDOP')
parser.add_argument('filename', help='The path to the KML file to filter')
parser.add_argument('-d', '--hdop', dest='hdop', default='2', help='The threshold HDOP value')
parser.add_argument('-v', '--verbose', dest='verbose', help='Enables verbose output', action='store_true')
return parser.parse_args()
def main():
options = get_options()
filter(float(options.hdop), options.filename, options.verbose)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment