Skip to content

Commit aa73be8

Browse files
committed
#5 Work in progress:
-Plot with gmplot [ci skip]
1 parent 416a6b6 commit aa73be8

File tree

4 files changed

+140
-23
lines changed

4 files changed

+140
-23
lines changed

README.md

-8
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,6 @@ test_gpx.plot(start_stop=True, elevation_color=True)
2020

2121
## 📚 References:
2222

23-
### 🖥️ Implementation
24-
25-
#### 🏷️ XML
26-
- [GPX XML Schema](http://www.topografix.com/GPX/1/1/)
27-
28-
#### 🌏 Map Projection
29-
- Wikipedia: [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection)
30-
3123
### 🧭 Other Python GPX Library
3224
- [gpxpy](https://github.com/tkrajina/gpxpy)
3325

ezgpx/gpx/gpx.py

+74-13
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@
22
from datetime import datetime
33
import pandas as pd
44
from math import degrees
5+
56
import matplotlib.pyplot as plt
67

8+
import webbrowser
9+
import gmplot
10+
711
from ..gpx_elements import Gpx
812
from ..gpx_parser import Parser
913
from ..gpx_writer import Writer
@@ -20,18 +24,41 @@ def __init__(self, file_path: str):
2024
self.gpx: Gpx = self.parser.gpx
2125
self.writer: Writer = Writer(self.gpx, precisions=self.parser.precisions, time_format=self.parser.time_format)
2226

27+
def name(self) -> str:
28+
"""
29+
Return activity name.
30+
31+
Returns:
32+
str: Activity name.
33+
"""
34+
return self.gpx.name()
35+
2336
def nb_points(self) -> int:
2437
"""
25-
Compute the number of points in the GPX.
38+
Return the number of points in the GPX.
2639
2740
Returns:
2841
int: Number of points in the GPX.
2942
"""
30-
nb_pts = 0
31-
for track in self.gpx.tracks:
32-
for track_segment in track.trkseg:
33-
nb_pts += len(track_segment.trkpt)
34-
return nb_pts
43+
return self.gpx.nb_points()
44+
45+
def bounds(self) -> tuple[float, float, float, float]:
46+
"""
47+
Find minimum and maximum latitude and longitude.
48+
49+
Returns:
50+
tuple[float, float, float, float]: Min latitude, min longitude, max latitude, max longitude
51+
"""
52+
return self.gpx.bounds()
53+
54+
def center(self) -> tuple[float, float]:
55+
"""
56+
Return the coordinates of the center point.
57+
58+
Returns:
59+
tuple[float, float]: Latitude and longitude of the center point.
60+
"""
61+
return self.gpx.center()
3562

3663
def distance(self) -> float:
3764
"""
@@ -236,18 +263,18 @@ def simplify(self, tolerance: float = 2):
236263
epsilon = degrees(tolerance/EARTH_RADIUS)
237264
self.gpx.simplify(epsilon)
238265

239-
def plot(
266+
def matplotlib_plot(
240267
self,
241268
projection: str = None,
242269
title: str = "Track",
243270
base_color: str = "#101010",
244271
start_stop: bool = False,
245272
elevation_color: bool = False,
246-
duration: bool = None,
247-
distance: bool = None,
248-
ascent: bool = None,
249-
pace: bool = None,
250-
speed: bool = None,
273+
duration: bool = False,
274+
distance: bool = False,
275+
ascent: bool = False,
276+
pace: bool = False,
277+
speed: bool = False,
251278
file_path: str = None):
252279

253280
# Handle projection
@@ -304,4 +331,38 @@ def plot(
304331
# Check path
305332
plt.savefig(file_path)
306333
else:
307-
plt.show()
334+
plt.show()
335+
336+
def gmap_plot(
337+
self,
338+
title: str = None,
339+
base_color: str = "#110000",
340+
start_stop: str = False,
341+
zoom: float = 10.0,
342+
file_path: str = None,
343+
open: bool = True,
344+
scatter: bool = False,
345+
plot: bool = True):
346+
347+
# Convert to dataframe and compute center latitude and longitude
348+
test_gpx_df = self.to_dataframe()
349+
center_lat, center_lon = self.center()
350+
351+
# Create plotter
352+
map = gmplot.GoogleMapPlotter(center_lat, center_lon, zoom)
353+
354+
# Plot and save
355+
if title is not None:
356+
map.text(center_lat, center_lon, self.name(), color="#FFFFFF")
357+
if start_stop:
358+
map.scatter([self.gpx.tracks[0].trkseg[0].trkpt[0].lat], [self.gpx.tracks[0].trkseg[0].trkpt[0].lon], "#00FF00", size=5, marker=True)
359+
map.scatter([self.gpx.tracks[-1].trkseg[-1].trkpt[-1].lat], [self.gpx.tracks[-1].trkseg[-1].trkpt[-1].lat], "#FF0000", size=5, marker=True)
360+
if scatter:
361+
map.scatter(test_gpx_df["latitude"], test_gpx_df["longitude"], base_color, size=5, marker=False)
362+
if plot:
363+
map.plot(test_gpx_df["latitude"], test_gpx_df["longitude"], base_color, edge_width=2.5)
364+
map.draw(file_path)
365+
366+
# Open
367+
if open:
368+
webbrowser.open(file_path)

ezgpx/gpx_elements/gpx.py

+60
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,66 @@ def __init__(
6969
self.tracks: list[Track] = tracks
7070
self.extensions: Extensions = extensions
7171

72+
def name(self) -> str:
73+
"""
74+
Return activity name.
75+
76+
Returns:
77+
str: Activity name.
78+
"""
79+
return self.tracks[0].name
80+
81+
def nb_points(self) -> int:
82+
"""
83+
Compute the number of points in the GPX.
84+
85+
Returns:
86+
int: Number of points in the GPX.
87+
"""
88+
nb_pts = 0
89+
for track in self.tracks:
90+
for track_segment in track.trkseg:
91+
nb_pts += len(track_segment.trkpt)
92+
return nb_pts
93+
94+
def bounds(self) -> tuple[float, float, float, float]:
95+
"""
96+
Find minimum and maximum latitude and longitude.
97+
98+
Returns:
99+
tuple[float, float, float, float]: Min latitude, min longitude, max latitude, max longitude
100+
"""
101+
min_lat = self.tracks[0].trkseg[0].trkpt[0].lat
102+
min_lon = self.tracks[0].trkseg[0].trkpt[0].lon
103+
max_lat = min_lat
104+
max_lon = min_lon
105+
106+
for track in self.tracks:
107+
for track_segment in track.trkseg:
108+
for track_point in track_segment.trkpt:
109+
if track_point.lat < min_lat:
110+
min_lat = track_point.lat
111+
if track_point.lon < min_lon:
112+
min_lon = track_point.lon
113+
if track_point.lat > max_lat:
114+
max_lat = track_point.lat
115+
if track_point.lon > max_lon:
116+
max_lon = track_point.lon
117+
return min_lat, min_lon, max_lat, max_lon
118+
119+
120+
def center(self) -> tuple[float, float]:
121+
"""
122+
Compute the center coordinates of the track.
123+
124+
Returns:
125+
tuple[float, float]: Latitude and longitude of the center point.
126+
"""
127+
min_lat, min_lon, max_lat, max_lon = self.bounds()
128+
center_lat = min_lat + (max_lat - min_lat) / 2
129+
center_lon = min_lon + (max_lon - min_lon) / 2
130+
return center_lat, center_lon
131+
72132
def distance(self) -> float:
73133
"""
74134
Compute the total distance (meters) of the tracks contained in the Gpx element.

notes.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
### 🖥️ Implementation
44

5-
#### 💾 Python XML Parsing:
5+
#### 🏷️ XML
6+
- [GPX XML Schema](http://www.topografix.com/GPX/1/1/)
67
- Real Python: [A roadmap to XML Parsers in Python](https://realpython.com/python-xml-parser/#learn-about-xml-parsers-in-pythons-standard-library)
78
- [xml.etree.ElementTree — The ElementTree XML API](https://docs.python.org/3/library/xml.etree.elementtree.html)
89
- GeeksForGeeks: [Reading and Writing XML Files in Python](https://www.geeksforgeeks.org/reading-and-writing-xml-files-in-python/)
910

10-
#### 🌏 Map Projection
11+
#### 🌏 Map Plotting
12+
- [gmplot](https://github.com/gmplot/gmplot)
13+
- [OSMPythonTools](https://wiki.openstreetmap.org/wiki/OSMPythonTools)
14+
- - Towards Data Science: [Loading Data from OpenStreetMap with Python and the Overpass API](https://towardsdatascience.com/loading-data-from-openstreetmap-with-python-and-the-overpass-api-513882a27fd0)
1115
- Wikipedia: [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection)
1216

1317
#### 🗃️ Creating a Python Library

0 commit comments

Comments
 (0)