-
Notifications
You must be signed in to change notification settings - Fork 58
/
gps_class.py
95 lines (87 loc) · 3.85 KB
/
gps_class.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
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
class GPSVis(object):
"""
Class for GPS data visualization using pre-downloaded OSM map in image format.
"""
def __init__(self, data_path, map_path, points):
"""
:param data_path: Path to file containing GPS records.
:param map_path: Path to pre-downloaded OSM map in image format.
:param points: Upper-left, and lower-right GPS points of the map (lat1, lon1, lat2, lon2).
"""
self.data_path = data_path
self.points = points
self.map_path = map_path
self.result_image = Image
self.x_ticks = []
self.y_ticks = []
def plot_map(self, output='save', save_as='resultMap.png'):
"""
Method for plotting the map. You can choose to save it in file or to plot it.
:param output: Type 'plot' to show the map or 'save' to save it.
:param save_as: Name and type of the resulting image.
:return:
"""
self.get_ticks()
fig, axis1 = plt.subplots(figsize=(10, 10))
axis1.imshow(self.result_image)
axis1.set_xlabel('Longitude')
axis1.set_ylabel('Latitude')
axis1.set_xticklabels(self.x_ticks)
axis1.set_yticklabels(self.y_ticks)
axis1.grid()
if output == 'save':
plt.savefig(save_as)
else:
plt.show()
def create_image(self, color, width=2):
"""
Create the image that contains the original map and the GPS records.
:param color: Color of the GPS records.
:param width: Width of the drawn GPS records.
:return:
"""
data = pd.read_csv(self.data_path, names=['LATITUDE', 'LONGITUDE'], sep=',')
self.result_image = Image.open(self.map_path, 'r')
img_points = []
gps_data = tuple(zip(data['LATITUDE'].values, data['LONGITUDE'].values))
for d in gps_data:
x1, y1 = self.scale_to_img(d, (self.result_image.size[0], self.result_image.size[1]))
img_points.append((x1, y1))
draw = ImageDraw.Draw(self.result_image)
draw.line(img_points, fill=color, width=width)
def scale_to_img(self, lat_lon, h_w):
"""
Conversion from latitude and longitude to the image pixels.
It is used for drawing the GPS records on the map image.
:param lat_lon: GPS record to draw (lat1, lon1).
:param h_w: Size of the map image (w, h).
:return: Tuple containing x and y coordinates to draw on map image.
"""
# https://gamedev.stackexchange.com/questions/33441/how-to-convert-a-number-from-one-min-max-set-to-another-min-max-set/33445
old = (self.points[2], self.points[0])
new = (0, h_w[1])
y = ((lat_lon[0] - old[0]) * (new[1] - new[0]) / (old[1] - old[0])) + new[0]
old = (self.points[1], self.points[3])
new = (0, h_w[0])
x = ((lat_lon[1] - old[0]) * (new[1] - new[0]) / (old[1] - old[0])) + new[0]
# y must be reversed because the orientation of the image in the matplotlib.
# image - (0, 0) in upper left corner; coordinate system - (0, 0) in lower left corner
return int(x), h_w[1] - int(y)
def get_ticks(self):
"""
Generates custom ticks based on the GPS coordinates of the map for the matplotlib output.
:return:
"""
self.x_ticks = map(
lambda x: round(x, 4),
np.linspace(self.points[1], self.points[3], num=7))
y_ticks = map(
lambda x: round(x, 4),
np.linspace(self.points[2], self.points[0], num=8))
# Ticks must be reversed because the orientation of the image in the matplotlib.
# image - (0, 0) in upper left corner; coordinate system - (0, 0) in lower left corner
self.y_ticks = sorted(y_ticks, reverse=True)