Skip to content

Commit

Permalink
#2 Work in progress:
Browse files Browse the repository at this point in the history
-Repository organisation
-Parser correction
  • Loading branch information
FABallemand committed Jun 13, 2023
1 parent 2e02b48 commit f869177
Show file tree
Hide file tree
Showing 26 changed files with 370 additions and 3,009 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
tests/dev_tests/*

# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ Easy to use Python GPX library.

## References:

### Python XML Parsing:
### Implementation

#### Python XML Parsing:
- Real Python: [A roadmap to XML Parsers in Python](https://realpython.com/python-xml-parser/#learn-about-xml-parsers-in-pythons-standard-library)
- [xml.etree.ElementTree — The ElementTree XML API](https://docs.python.org/3/library/xml.etree.elementtree.html)
<!-- - https://python.doctor/page-xml-python-xpath -->

### Creating a Python Library
#### Map Projection
- Wikipedia: [Web Mercator projection](https://en.wikipedia.org/wiki/Web_Mercator_projection)

#### Creating a Python Library
- Medium: [How to create a Python library](https://medium.com/analytics-vidhya/how-to-create-a-python-library-7d5aea80cc3f)
- Towards Data Science: [Deep dive: Create and publish your first Python library](https://towardsdatascience.com/deep-dive-create-and-publish-your-first-python-library-f7f618719e14)

Expand Down
16 changes: 0 additions & 16 deletions dev_test.py

This file was deleted.

8 changes: 0 additions & 8 deletions ezGPX/gpx_elements/gpx.py

This file was deleted.

6 changes: 0 additions & 6 deletions ezGPX/gpx_elements/metadata.py

This file was deleted.

11 changes: 0 additions & 11 deletions ezGPX/gpx_elements/track_point.py

This file was deleted.

3 changes: 2 additions & 1 deletion ezGPX/__init__.py → ezgpx/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from .gpx_elements import *
from .gpx_parser import *
from .gpx_writer import *
from .gpx_writer import *
from .gpx import *
1 change: 1 addition & 0 deletions ezgpx/gpx/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .gpx import *
59 changes: 59 additions & 0 deletions ezgpx/gpx/gpx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from typing import *
import pandas as pd
import matplotlib.pyplot as plt

from ..gpx_elements import Gpx
from ..gpx_parser import Parser
from ..gpx_writer import Writer

class GPX():
"""
High level GPX object.
"""
def __init__(self, file_path: str):
self.file_path = file_path
self.parser = Parser(file_path)
self.gpx = self.parser.gpx
self.writer = Writer()

def to_string(self) -> str:
return self.writer.gpx_to_string(self.gpx)

def to_gpx(self, path: str):
self.writer.write(self.gpx, path)

def to_dataframe(self) -> pd.DataFrame:
"""
Convert GPX object to Pandas Dataframe.
Returns:
pd.DataFrame: Dataframe containing position data from GPX.
"""
return self.gpx.to_dataframe()

def plot(self, title: str = "Track", base_color: str = "#101010", start_stop: bool = False, elevation_color: bool = False, file_path: str = None,):

# Create dataframe containing data from the GPX file
gpx_df = self.to_dataframe()

# Visualize GPX file
plt.figure(figsize=(14, 8))
if elevation_color:
plt.scatter(gpx_df["longitude"], gpx_df["latitude"], c=gpx_df["elevation"])
else:
plt.scatter(gpx_df["longitude"], gpx_df["latitude"], color=base_color)

if start_stop:
plt.scatter(gpx_df["longitude"][0], gpx_df["latitude"][0], color="#00FF00")
plt.scatter(gpx_df["longitude"][len(gpx_df["longitude"])-1], gpx_df["latitude"][len(gpx_df["longitude"])-1], color="#FF0000")

plt.title(title, size=20)
plt.xticks([min(gpx_df["longitude"]), max(gpx_df["longitude"])])
plt.yticks([min(gpx_df["latitude"]), max(gpx_df["latitude"])])


if file_path is not None:
# Check path
plt.savefig(file_path)
else:
plt.show()
File renamed without changes.
32 changes: 32 additions & 0 deletions ezgpx/gpx_elements/gpx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pandas as pd

from .metadata import *
from .track import *

class Gpx():
"""
Gpx (gpx) element in GPX file.
"""

def __init__(self, metadata: Metadata = None, tracks: list[Track] = []):
self.metadata = metadata
self.tracks = tracks

def to_dataframe(self) -> pd.DataFrame:
"""
Convert Gpx element to Pandas Dataframe.
Returns:
pd.DataFrame: Dataframe containing position data from GPX.
"""
route_info = []
for track in self.tracks:
for segment in track.track_segments:
for point in segment.track_points:
route_info.append({
"latitude": point.latitude,
"longitude": point.longitude,
"elevation": point.elevation
})
df = pd.DataFrame(route_info)
return df
11 changes: 11 additions & 0 deletions ezgpx/gpx_elements/metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@


class Metadata():
"""
Metadata (metadata) element in GPX file.
"""

def __init__(self, link: str = "", link_text: str = "", time: str = ""):
self.link = link
self.link_text = link_text
self.time = time
3 changes: 3 additions & 0 deletions ezGPX/gpx_elements/track.py → ezgpx/gpx_elements/track.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from .track_segment import *

class Track():
"""
Track (trk) element in GPX file.
"""

def __init__(self, name: str = "", track_segments: list[TrackSegment] = []):
self.name = name
Expand Down
14 changes: 14 additions & 0 deletions ezgpx/gpx_elements/track_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from typing import *

class TrackPoint():
"""
Track point (trkpt) elevationment in GPX file.
"""

def __init__(self, latitude: float = None, longitude: float = None, elevation: float = None, time: str = None):
self.latitude: float = latitude
self.longitude: float = longitude
self.elevation: float = elevation
self.time: str = time


Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from .track_point import *

class TrackSegment():

"""
Track segment (trkseg) in GPX file.
"""

def __init__(self, track_points: list[TrackPoint] = []):
self.track_points = track_points
File renamed without changes.
92 changes: 48 additions & 44 deletions ezGPX/gpx_parser/parser.py → ezgpx/gpx_parser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,60 +3,27 @@

import xml.etree.ElementTree as ET

from ..gpx_elements import GPX, Metadata, Track, TrackSegment, TrackPoint
from ..gpx_elements import Gpx, Metadata, Track, TrackSegment, TrackPoint

class Parser():

def __init__(self, gpx_file: str = ""):
self.gpx_file = gpx_file
def __init__(self, file_path: str = ""):
self.file_path = file_path
self.gpx_tree = None
self.gpx_root = None
self.name_space = {"topo": "http://www.topografix.com/GPX/1/1"}
self.gpx = GPX()
self.gpx = Gpx()

if self.gpx_file != "":
if self.file_path != "":
self.parse()

def checkSchema(self):
def check_schema(self):
pass

def parse(self, gpx_file: str = ""):

# File
if gpx_file != "":
self.gpx_file = gpx_file
elif self.gpx_file == "":
logging.error("No GPX file to parse")
return

# Parse GPX file
try:
self.gpx_tree = ET.parse(self.gpx_file)
self.gpx_root = self.gpx_tree.getroot()
except:
logging.exception("Unable to parse GPX file")
raise

# Parse metadata
try:
self.parseMetadata()
except:
logging.exception("Unable to parse metadata in GPX file")
raise

# Parse tracks
try:
self.parseTracks()
except:
logging.exception("Unable to parse tracks in GPX file")
raise

logging.debug("Parsing complete")

def parseMetadata(self):
def parse_metadata(self):
pass

def parseTracks(self):
def parse_tracks(self):

# Tracks
tracks = self.gpx_root.findall("topo:trk", self.name_space)
Expand All @@ -65,7 +32,7 @@ def parseTracks(self):
segments = track.findall("topo:trkseg", self.name_space)

# Create new track
gpx_track = Track(name=name)
gpx_track = Track(name=name.text)

# Track segments
for segment in segments:
Expand All @@ -80,10 +47,47 @@ def parseTracks(self):
time = point.find("topo:time", self.name_space)

# Create new point
gpx_point = TrackPoint(point.get("lat"), point.get("lon"), elevation.text, time.text)
gpx_point = TrackPoint(float(point.get("lat")),
float(point.get("lon")),
float(elevation.text),
time.text)

gpx_segment.track_points.append(gpx_point)

gpx_track.track_segments.append(gpx_segment)

self.gpx.tracks.append(gpx_track)
self.gpx.tracks.append(gpx_track)

def parse(self, file_path: str = "") -> Gpx:

# File
if file_path != "":
self.file_path = file_path
elif self.file_path == "":
logging.error("No GPX file to parse")
return

# Parse GPX file
try:
self.gpx_tree = ET.parse(self.file_path)
self.gpx_root = self.gpx_tree.getroot()
except:
logging.exception("Unable to parse GPX file")
raise

# Parse metadata
try:
self.parse_metadata()
except:
logging.exception("Unable to parse metadata in GPX file")
raise

# Parse tracks
try:
self.parse_tracks()
except:
logging.exception("Unable to parse tracks in GPX file")
raise

logging.debug("Parsing complete")
return self.gpx
File renamed without changes.

0 comments on commit f869177

Please sign in to comment.