-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathgetLineFromGpsPoints.py
110 lines (88 loc) · 4.07 KB
/
getLineFromGpsPoints.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import folium
import pandas as pd, numpy as np, matplotlib.pyplot as plt
import random
from numpy import sin,cos,arctan2,sqrt,pi
from shapely.geometry import MultiPoint
from sklearn.cluster import DBSCAN
from geopy.distance import great_circle
####################################
## functions below are taken (and modified a bit) from blog post published by Geoff Boeing
## http://geoffboeing.com/2014/08/clustering-to-reduce-spatial-data-set-size/
####################################
def getDbScanClustersCenters(df, epsInKm, minObjects):
clusters = getDbScanClusters(df, epsInKm, minObjects)
return getClustersCenters(clusters)
def getDbScanClusters(df, epsInKm, minObjects):
coords = df.as_matrix()
kms_per_radian = 6371.0088
epsilon = epsInKm / kms_per_radian
db = DBSCAN(eps=epsilon, min_samples=minObjects, algorithm='ball_tree', metric='haversine').fit(np.radians(coords))
cluster_labels = db.labels_
print('Number of clusters: {}'.format(len(set(cluster_labels))))
return pd.Series([coords[cluster_labels == n] for n in range(len(set(cluster_labels)) - 1)])
def get_centermost_point(cluster):
centroid = (MultiPoint(cluster).centroid.x, MultiPoint(cluster).centroid.y)
centermost_point = min(cluster, key=lambda point: great_circle(point, centroid).m)
return centermost_point
def getClustersCenters(clusters):
centermost_points = clusters.map(get_centermost_point)
lats, lons = zip(*centermost_points)
return pd.DataFrame({'lon':lons, 'lat':lats}).values.tolist()
####################################
def drawPointsOnMap(superMap, points, color, radiusSize):
print('Drawing {} points on map'.format(len(points)))
for point in points:
folium.CircleMarker(point, radius = radiusSize, fill_color = color, color = color).add_to(superMap)
def getDistanceBetweenPoints(point1, point2):
lon1 = point1[1] * pi / 180.0
lon2 = point2[1] * pi / 180.0
lat1 = point1[0] * pi / 180.0
lat2 = point2[0] * pi / 180.0
# haversine formula #### Same, but atan2 named arctan2 in numpy
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2.0))**2
c = 2.0 * arctan2(sqrt(a), sqrt(1.0-a))
km = 6371.0 * c
return km
def getEndPoint(points):
pointsForFindingLineEnd = list(points)
currentPoint = random.choice(pointsForFindingLineEnd)
pointsForFindingLineEnd.remove(currentPoint)
while(len(pointsForFindingLineEnd) > 0):
nextPoint = None
distanceToNextPoint = float("inf")
for point in pointsForFindingLineEnd:
distance = getDistanceBetweenPoints(point, currentPoint)
if (distance < distanceToNextPoint):
nextPoint = point
distanceToNextPoint= distance
pointsForFindingLineEnd.remove(nextPoint)
currentPoint = nextPoint
return currentPoint
def getLineFromPoints(points, startingPoint):
linePoints = list(points)
currentPoint = startingPoint
line = []
while(len(linePoints) > 0):
nextPoint = None
distanceToNextPoint = float("inf")
for point in linePoints:
distance = getDistanceBetweenPoints(point,currentPoint)
if (distance < distanceToNextPoint):
nextPoint = point
distanceToNextPoint= distance
linePoints.remove(nextPoint)
currentPoint = nextPoint
line.append(currentPoint)
return line
df = pd.read_csv('locations.csv', index_col = False, header=0)
superMap = folium.Map(location=[51.107885, 17.038538], zoom_start=14, tiles='OpenStreetMap')
drawPointsOnMap(superMap, df.values, '#3186cc', 20)
clustersCenters = getDbScanClustersCenters(df, 0.03, 10)
drawPointsOnMap(superMap, clustersCenters, '#ff0000', 30)
endPoint = getEndPoint(clustersCenters)
drawPointsOnMap(superMap, [endPoint], '#ff0000', 100)
line = getLineFromPoints(clustersCenters, endPoint)
superMap.add_children(folium.PolyLine(locations = line, weight = 10, color="#d63b3b"))
superMap.save('map.html')