gpx-player 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Yury Kirienko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ recursive-include schema *.xsd
2
+ include *.html *.js
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: gpx-player
3
+ Version: 0.1.0
4
+ Summary: Visualise & animate GPX race tracks.
5
+ Author: Yury Kirienko
6
+ License: MIT License
7
+
8
+ Copyright (c) 2023 Yury Kirienko
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: folium
32
+ Requires-Dist: jinja2
33
+ Requires-Dist: matplotlib
34
+ Requires-Dist: pytz
35
+ Requires-Dist: lxml
36
+ Requires-Dist: numpy
37
+ Requires-Dist: gpxpy
38
+ Dynamic: license-file
39
+
40
+ # gpx-player
41
+ ## GPX Race Visualizer
42
+
43
+ GPX Race Visualizer is a Python script to visualize the progression of multiple GPS tracks (e.g., from a race) on a 2D map.
44
+ It takes as input one or more GPX files and creates an animation showing the movement of each track over time.
45
+ This is a simple, open-source alternative to features like Strava's Flyby, which require an account and can have privacy issues.
46
+
47
+ ### Modes
48
+ The player supports two modes:
49
+ #### 1. "Video" mode
50
+ Produce an `MP4` or a `GIF` file showing how the situation developed.
51
+ For sailing races, it also calculates the distance covered after the 'start' signal and the current speed.
52
+ ##### Example:
53
+ ![Example output](example.gif "Example of the script output")
54
+
55
+ #### 2. Map mode
56
+ Displays the track on OpenSeaMap.
57
+ You can see the full tracks with colour-coded speeds,
58
+ and you can 'play' the tracks and see the markers move around the map.
59
+
60
+ #### Example:
61
+ Since GitHub Markdown doesn't allow embedding HTML,
62
+ you can see an [interactive example](https://kirienko.github.io/static/GinSul-2024.html) here.
63
+
64
+ Screenshot:
65
+ [![OPS Example](./example_osm.png)](https://kirienko.github.io/static/GinSul-2024.html)
66
+ ## Installation
67
+
68
+ Clone the repository and install the required dependencies with pip:
69
+
70
+ ```bash
71
+ git clone https://github.com/kirienko/gpx-player.git
72
+ cd gpx-player
73
+ pip install -r requirements.txt
74
+ ```
75
+
76
+ ## Usage
77
+ To run the script producing `mp4`, pass one or more GPX file paths as command-line arguments:
78
+ ```bash
79
+ python main.py example-data/track1.gpx example-data/track2.gpx
80
+ ```
81
+ To get a sea map, run the `openseamap.py`:
82
+ ```bash
83
+ python openseamap.py --title 'Gin Sul Regatta 2024' --names Alex Yury Richard \
84
+ --files example-data/osm-demo-Alex.gpx example-data/osm-demo-Richard.gpx \
85
+ example-data/osm-demo-Yury.gpx
86
+ ```
87
+
88
+ A more sophisticated example, that produced a video above:
89
+ ```bash
90
+ python main.py example-data/track1.gpx example-data/track2.gpx example-data/track3.gpx \
91
+ --start 2023-07-01T10:53:00+0000 \
92
+ --names "Mr. Pommeroy" "Miss Sophie" "Sir Toby²" \
93
+ --title "Elbe-Damm Regatta (01.07.2023), Race 1" \
94
+ --race_start 2023-07-01T10:58:00+0000 --marks example-data/marks.txt -g
95
+ ```
96
+ ### Additional parameters:
97
+ * `--title` or `-t`: The title of the video
98
+ * `--start` or `-s`: start time in the format `2023-06-30T12:53:00+0200`, all points _before_ that will not be plotted
99
+ * `--end` or `-e`: end time in the format `2023-06-30T13:53:00+0200`, all points _after_ that will not be plotted
100
+ * `--names` or `-n`: names of the participants (otherwise the file names will be used in the legend)
101
+ * `--race_start`, `-r`: Race start time in the format `YYYY-MM-DDTHH:MM:SS%z`, e.g. `2023-07-01T12:29:00+0200`
102
+ * `--names` or `-n`: Names of the participants
103
+ * `--marks`or`-m`: The file with the static marks to put onto the map. One pair of coordinates per line, see below.
104
+ * `--gif` or `-g`: Save as GIF moving picture instead of MP4
105
+ * `--timezone` or `-tz`: Local timezone to use for processing timestamps, e.g. `America/Los_Angeles`, see [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (default: `Europe/Berlin`).
106
+
107
+ ## Marks
108
+ The script also supports visualizing predefined marks on the map, which can be useful for events like sailing regattas.
109
+ The marks are defined as a list of (latitude, longitude) tuples in a separate text file and can be added to the script as follows:
110
+ ```
111
+ 53.542484632728, 9.801163896918299
112
+ 53.542997846049374, 9.80611324310303
113
+ 53.54823800356785, 9.812614917755129
114
+ 53.54921647691311, 9.807373881340029
115
+ 53.54508251196638, 9.80433225631714
116
+ ```
117
+
118
+ ## Getting GPX Files
119
+
120
+ GPX files can be obtained from several GPS-tracking services:
121
+ * Strava: Go to the activity page and click on the wrench icon. Then select "Export GPX".
122
+ * Garmin Connect: Open the activity, go to the gear icon and select "Export to GPX".
123
+ * Endomondo: From the workout page, click the three-dot menu icon and select "Export". Then choose "GPX".
124
+
125
+ ## GPX Validation
126
+
127
+ For the `gpx-player` to work properly, it needs the correct GPX files.
128
+ You can verify that you are inputting the correct file by using the special validator
129
+ included in this package.
130
+
131
+ The `validator.py` script is a command-line utility and module for validating GPX files.
132
+ It checks for XML schema conformance and timestamp consistency,
133
+ supporting both strict and lenient modes.
134
+ Errors are raised as `GPXValidationError` which can be caught in Python code.
135
+ To run as a CLI tool, use:
136
+ ```bash
137
+ python validator.py path/to/yourfile.gpx --strict
138
+ ```
139
+
140
+ The `--strict` parameter is optional. In most cases you do not need it,
141
+ because files that strictly correspond to the GPX schema are rare.
142
+ For example, almost all modern files contain coordinates, elevations and time stamps
143
+ with more decimal places than originally planned.
144
+
145
+ Also, to better understand your GPX file, you can use the `gpxinfo` console command
146
+ that comes with `gpxpy`. If you are already using the player, you have it:
147
+
148
+ ```bash
149
+ $ gpxinfo example-data/osm_track1.gpx
150
+ File: example-data/osm_track1.gpx
151
+ Waypoints: 0
152
+ Routes: 0
153
+ Length 2D: 9.621km
154
+ Length 3D: 9.648km
155
+ Moving time: 01:05:22
156
+ Stopped time: n/a
157
+ Max speed: 3.12m/s = 11.22km/h
158
+ Avg speed: 2.46m/s = 8.85km/h
159
+ Total uphill: 97.20m
160
+ Total downhill: 98.40m
161
+ Started: 2024-07-24 15:59:05+00:00
162
+ Ended: 2024-07-24 17:04:27+00:00
163
+ Points: 776
164
+ Avg distance between points: 12.40m
165
+
166
+ ```
167
+
168
+ ## Support
169
+ Now you can buy me a coffee to encourage further development!
170
+
171
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/kirienko)
@@ -0,0 +1,132 @@
1
+ # gpx-player
2
+ ## GPX Race Visualizer
3
+
4
+ GPX Race Visualizer is a Python script to visualize the progression of multiple GPS tracks (e.g., from a race) on a 2D map.
5
+ It takes as input one or more GPX files and creates an animation showing the movement of each track over time.
6
+ This is a simple, open-source alternative to features like Strava's Flyby, which require an account and can have privacy issues.
7
+
8
+ ### Modes
9
+ The player supports two modes:
10
+ #### 1. "Video" mode
11
+ Produce an `MP4` or a `GIF` file showing how the situation developed.
12
+ For sailing races, it also calculates the distance covered after the 'start' signal and the current speed.
13
+ ##### Example:
14
+ ![Example output](example.gif "Example of the script output")
15
+
16
+ #### 2. Map mode
17
+ Displays the track on OpenSeaMap.
18
+ You can see the full tracks with colour-coded speeds,
19
+ and you can 'play' the tracks and see the markers move around the map.
20
+
21
+ #### Example:
22
+ Since GitHub Markdown doesn't allow embedding HTML,
23
+ you can see an [interactive example](https://kirienko.github.io/static/GinSul-2024.html) here.
24
+
25
+ Screenshot:
26
+ [![OPS Example](./example_osm.png)](https://kirienko.github.io/static/GinSul-2024.html)
27
+ ## Installation
28
+
29
+ Clone the repository and install the required dependencies with pip:
30
+
31
+ ```bash
32
+ git clone https://github.com/kirienko/gpx-player.git
33
+ cd gpx-player
34
+ pip install -r requirements.txt
35
+ ```
36
+
37
+ ## Usage
38
+ To run the script producing `mp4`, pass one or more GPX file paths as command-line arguments:
39
+ ```bash
40
+ python main.py example-data/track1.gpx example-data/track2.gpx
41
+ ```
42
+ To get a sea map, run the `openseamap.py`:
43
+ ```bash
44
+ python openseamap.py --title 'Gin Sul Regatta 2024' --names Alex Yury Richard \
45
+ --files example-data/osm-demo-Alex.gpx example-data/osm-demo-Richard.gpx \
46
+ example-data/osm-demo-Yury.gpx
47
+ ```
48
+
49
+ A more sophisticated example, that produced a video above:
50
+ ```bash
51
+ python main.py example-data/track1.gpx example-data/track2.gpx example-data/track3.gpx \
52
+ --start 2023-07-01T10:53:00+0000 \
53
+ --names "Mr. Pommeroy" "Miss Sophie" "Sir Toby²" \
54
+ --title "Elbe-Damm Regatta (01.07.2023), Race 1" \
55
+ --race_start 2023-07-01T10:58:00+0000 --marks example-data/marks.txt -g
56
+ ```
57
+ ### Additional parameters:
58
+ * `--title` or `-t`: The title of the video
59
+ * `--start` or `-s`: start time in the format `2023-06-30T12:53:00+0200`, all points _before_ that will not be plotted
60
+ * `--end` or `-e`: end time in the format `2023-06-30T13:53:00+0200`, all points _after_ that will not be plotted
61
+ * `--names` or `-n`: names of the participants (otherwise the file names will be used in the legend)
62
+ * `--race_start`, `-r`: Race start time in the format `YYYY-MM-DDTHH:MM:SS%z`, e.g. `2023-07-01T12:29:00+0200`
63
+ * `--names` or `-n`: Names of the participants
64
+ * `--marks`or`-m`: The file with the static marks to put onto the map. One pair of coordinates per line, see below.
65
+ * `--gif` or `-g`: Save as GIF moving picture instead of MP4
66
+ * `--timezone` or `-tz`: Local timezone to use for processing timestamps, e.g. `America/Los_Angeles`, see [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (default: `Europe/Berlin`).
67
+
68
+ ## Marks
69
+ The script also supports visualizing predefined marks on the map, which can be useful for events like sailing regattas.
70
+ The marks are defined as a list of (latitude, longitude) tuples in a separate text file and can be added to the script as follows:
71
+ ```
72
+ 53.542484632728, 9.801163896918299
73
+ 53.542997846049374, 9.80611324310303
74
+ 53.54823800356785, 9.812614917755129
75
+ 53.54921647691311, 9.807373881340029
76
+ 53.54508251196638, 9.80433225631714
77
+ ```
78
+
79
+ ## Getting GPX Files
80
+
81
+ GPX files can be obtained from several GPS-tracking services:
82
+ * Strava: Go to the activity page and click on the wrench icon. Then select "Export GPX".
83
+ * Garmin Connect: Open the activity, go to the gear icon and select "Export to GPX".
84
+ * Endomondo: From the workout page, click the three-dot menu icon and select "Export". Then choose "GPX".
85
+
86
+ ## GPX Validation
87
+
88
+ For the `gpx-player` to work properly, it needs the correct GPX files.
89
+ You can verify that you are inputting the correct file by using the special validator
90
+ included in this package.
91
+
92
+ The `validator.py` script is a command-line utility and module for validating GPX files.
93
+ It checks for XML schema conformance and timestamp consistency,
94
+ supporting both strict and lenient modes.
95
+ Errors are raised as `GPXValidationError` which can be caught in Python code.
96
+ To run as a CLI tool, use:
97
+ ```bash
98
+ python validator.py path/to/yourfile.gpx --strict
99
+ ```
100
+
101
+ The `--strict` parameter is optional. In most cases you do not need it,
102
+ because files that strictly correspond to the GPX schema are rare.
103
+ For example, almost all modern files contain coordinates, elevations and time stamps
104
+ with more decimal places than originally planned.
105
+
106
+ Also, to better understand your GPX file, you can use the `gpxinfo` console command
107
+ that comes with `gpxpy`. If you are already using the player, you have it:
108
+
109
+ ```bash
110
+ $ gpxinfo example-data/osm_track1.gpx
111
+ File: example-data/osm_track1.gpx
112
+ Waypoints: 0
113
+ Routes: 0
114
+ Length 2D: 9.621km
115
+ Length 3D: 9.648km
116
+ Moving time: 01:05:22
117
+ Stopped time: n/a
118
+ Max speed: 3.12m/s = 11.22km/h
119
+ Avg speed: 2.46m/s = 8.85km/h
120
+ Total uphill: 97.20m
121
+ Total downhill: 98.40m
122
+ Started: 2024-07-24 15:59:05+00:00
123
+ Ended: 2024-07-24 17:04:27+00:00
124
+ Points: 776
125
+ Avg distance between points: 12.40m
126
+
127
+ ```
128
+
129
+ ## Support
130
+ Now you can buy me a coffee to encourage further development!
131
+
132
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/kirienko)
@@ -0,0 +1,145 @@
1
+ // Global variables to track play/pause state and the interval ID
2
+ let isPlaying = false;
3
+ let playbackInterval;
4
+
5
+ document.addEventListener('DOMContentLoaded', () => {
6
+ const slider = createSlider();
7
+ const timeLegend = createTimeLegend(slider);
8
+
9
+ document.body.appendChild(slider);
10
+ document.body.appendChild(timeLegend);
11
+
12
+ // Access the Folium-initialized map using the dynamically generated map_id
13
+ const map = window[map_id];
14
+
15
+ const trackMarkers = initializeTrackMarkers(map);
16
+
17
+ slider.addEventListener('input', () => {
18
+ updateTrackMarkers(slider, trackMarkers);
19
+ updateTimeDisplay(slider, timeLegend);
20
+ });
21
+
22
+ // Initialize with the first timestamp
23
+ slider.dispatchEvent(new Event('input'));
24
+ });
25
+
26
+ function createSlider() {
27
+ const slider = document.createElement('input');
28
+ slider.type = 'range';
29
+ slider.min = 0;
30
+ slider.max = 1000;
31
+ slider.value = 0;
32
+ Object.assign(slider.style, {
33
+ position: 'fixed',
34
+ bottom: '20px',
35
+ left: '50%',
36
+ transform: 'translateX(-50%)',
37
+ width: '80%',
38
+ zIndex: 1000,
39
+ });
40
+ return slider;
41
+ }
42
+
43
+ function createTimeLegend(slider) {
44
+ const timeLegend = document.createElement('div');
45
+ Object.assign(timeLegend.style, {
46
+ position: 'fixed',
47
+ bottom: '50px',
48
+ right: '10px',
49
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
50
+ padding: '5px',
51
+ border: '1px solid white',
52
+ borderRadius: '5px',
53
+ zIndex: 1000,
54
+ color: 'white',
55
+ display: 'flex',
56
+ flexDirection: 'column',
57
+ alignItems: 'center',
58
+ });
59
+
60
+ const timeDisplay = document.createElement('div');
61
+ timeDisplay.style.marginBottom = '2px';
62
+ timeLegend.appendChild(timeDisplay);
63
+
64
+ const playPauseButton = document.createElement('button');
65
+ playPauseButton.innerHTML = '⏯️'; // Play/Pause icon
66
+ playPauseButton.style.marginTop = '5px';
67
+ playPauseButton.addEventListener('click', () => togglePlayPause(slider, playPauseButton));
68
+
69
+ timeLegend.appendChild(playPauseButton);
70
+
71
+ timeLegend.timeDisplay = timeDisplay;
72
+
73
+ return timeLegend;
74
+ }
75
+
76
+ function initializeTrackMarkers(map) {
77
+ const colors = ['red', 'green', 'blue', 'orange', 'purple', 'brown', 'pink', 'yellow', 'cyan', 'magenta'];
78
+ return gpx_points_data.map((track, index) => {
79
+ const color = colors[index % colors.length];
80
+ const marker = L.circleMarker([track[0].lat, track[0].lon], {
81
+ radius: 4,
82
+ color: color,
83
+ fillColor: color,
84
+ fillOpacity: 0.5
85
+ }).addTo(map);
86
+ return marker;
87
+ });
88
+ }
89
+
90
+ function updateTrackMarkers(slider, trackMarkers) {
91
+ const timeIndex = Math.floor(slider.value / 1000 * (gpx_timestamps.length - 1));
92
+ const currentTime = new Date(gpx_timestamps[timeIndex]).getTime();
93
+
94
+ trackMarkers.forEach((marker, trackIndex) => {
95
+ const track = gpx_points_data[trackIndex];
96
+ let closestPoint = track[0];
97
+ for (let i = 1; i < track.length; i++) {
98
+ const pointTime = new Date(track[i].time).getTime();
99
+ if (pointTime <= currentTime) {
100
+ closestPoint = track[i];
101
+ } else {
102
+ break;
103
+ }
104
+ }
105
+ marker.setLatLng([closestPoint.lat, closestPoint.lon]);
106
+ });
107
+ }
108
+
109
+ function updateTimeDisplay(slider, timeLegend) {
110
+ const timeIndex = Math.floor(slider.value / 1000 * (gpx_timestamps.length - 1));
111
+ const currentTime = new Date(gpx_timestamps[timeIndex]).getTime();
112
+ timeLegend.timeDisplay.innerHTML = `${new Date(currentTime).toUTCString()}`;
113
+ }
114
+
115
+ function updateSlider(slider) {
116
+ if (parseInt(slider.value) < parseInt(slider.max)) {
117
+ slider.value = parseInt(slider.value) + 1;
118
+ slider.dispatchEvent(new Event('input'));
119
+ } else {
120
+ // Slider has reached the maximum value
121
+ clearInterval(playbackInterval);
122
+ isPlaying = false;
123
+ resetPlayPauseButton();
124
+ }
125
+ }
126
+
127
+ function togglePlayPause(slider, playPauseButton) {
128
+ if (isPlaying) {
129
+ clearInterval(playbackInterval);
130
+ resetPlayPauseButton();
131
+ isPlaying = false; // Ensure isPlaying is set to false when paused
132
+ } else {
133
+ playbackInterval = setInterval(() => updateSlider(slider), 100);
134
+ playPauseButton.style.backgroundColor = 'gray';
135
+ playPauseButton.innerHTML = '⏸️';
136
+ isPlaying = true; // Set isPlaying to true when playback starts
137
+ }
138
+ }
139
+
140
+ function resetPlayPauseButton() {
141
+ const playPauseButton = document.querySelector('button');
142
+ playPauseButton.style.backgroundColor = '';
143
+ playPauseButton.innerHTML = '⏯️';
144
+ }
145
+
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: gpx-player
3
+ Version: 0.1.0
4
+ Summary: Visualise & animate GPX race tracks.
5
+ Author: Yury Kirienko
6
+ License: MIT License
7
+
8
+ Copyright (c) 2023 Yury Kirienko
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: folium
32
+ Requires-Dist: jinja2
33
+ Requires-Dist: matplotlib
34
+ Requires-Dist: pytz
35
+ Requires-Dist: lxml
36
+ Requires-Dist: numpy
37
+ Requires-Dist: gpxpy
38
+ Dynamic: license-file
39
+
40
+ # gpx-player
41
+ ## GPX Race Visualizer
42
+
43
+ GPX Race Visualizer is a Python script to visualize the progression of multiple GPS tracks (e.g., from a race) on a 2D map.
44
+ It takes as input one or more GPX files and creates an animation showing the movement of each track over time.
45
+ This is a simple, open-source alternative to features like Strava's Flyby, which require an account and can have privacy issues.
46
+
47
+ ### Modes
48
+ The player supports two modes:
49
+ #### 1. "Video" mode
50
+ Produce an `MP4` or a `GIF` file showing how the situation developed.
51
+ For sailing races, it also calculates the distance covered after the 'start' signal and the current speed.
52
+ ##### Example:
53
+ ![Example output](example.gif "Example of the script output")
54
+
55
+ #### 2. Map mode
56
+ Displays the track on OpenSeaMap.
57
+ You can see the full tracks with colour-coded speeds,
58
+ and you can 'play' the tracks and see the markers move around the map.
59
+
60
+ #### Example:
61
+ Since GitHub Markdown doesn't allow embedding HTML,
62
+ you can see an [interactive example](https://kirienko.github.io/static/GinSul-2024.html) here.
63
+
64
+ Screenshot:
65
+ [![OPS Example](./example_osm.png)](https://kirienko.github.io/static/GinSul-2024.html)
66
+ ## Installation
67
+
68
+ Clone the repository and install the required dependencies with pip:
69
+
70
+ ```bash
71
+ git clone https://github.com/kirienko/gpx-player.git
72
+ cd gpx-player
73
+ pip install -r requirements.txt
74
+ ```
75
+
76
+ ## Usage
77
+ To run the script producing `mp4`, pass one or more GPX file paths as command-line arguments:
78
+ ```bash
79
+ python main.py example-data/track1.gpx example-data/track2.gpx
80
+ ```
81
+ To get a sea map, run the `openseamap.py`:
82
+ ```bash
83
+ python openseamap.py --title 'Gin Sul Regatta 2024' --names Alex Yury Richard \
84
+ --files example-data/osm-demo-Alex.gpx example-data/osm-demo-Richard.gpx \
85
+ example-data/osm-demo-Yury.gpx
86
+ ```
87
+
88
+ A more sophisticated example, that produced a video above:
89
+ ```bash
90
+ python main.py example-data/track1.gpx example-data/track2.gpx example-data/track3.gpx \
91
+ --start 2023-07-01T10:53:00+0000 \
92
+ --names "Mr. Pommeroy" "Miss Sophie" "Sir Toby²" \
93
+ --title "Elbe-Damm Regatta (01.07.2023), Race 1" \
94
+ --race_start 2023-07-01T10:58:00+0000 --marks example-data/marks.txt -g
95
+ ```
96
+ ### Additional parameters:
97
+ * `--title` or `-t`: The title of the video
98
+ * `--start` or `-s`: start time in the format `2023-06-30T12:53:00+0200`, all points _before_ that will not be plotted
99
+ * `--end` or `-e`: end time in the format `2023-06-30T13:53:00+0200`, all points _after_ that will not be plotted
100
+ * `--names` or `-n`: names of the participants (otherwise the file names will be used in the legend)
101
+ * `--race_start`, `-r`: Race start time in the format `YYYY-MM-DDTHH:MM:SS%z`, e.g. `2023-07-01T12:29:00+0200`
102
+ * `--names` or `-n`: Names of the participants
103
+ * `--marks`or`-m`: The file with the static marks to put onto the map. One pair of coordinates per line, see below.
104
+ * `--gif` or `-g`: Save as GIF moving picture instead of MP4
105
+ * `--timezone` or `-tz`: Local timezone to use for processing timestamps, e.g. `America/Los_Angeles`, see [here](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) (default: `Europe/Berlin`).
106
+
107
+ ## Marks
108
+ The script also supports visualizing predefined marks on the map, which can be useful for events like sailing regattas.
109
+ The marks are defined as a list of (latitude, longitude) tuples in a separate text file and can be added to the script as follows:
110
+ ```
111
+ 53.542484632728, 9.801163896918299
112
+ 53.542997846049374, 9.80611324310303
113
+ 53.54823800356785, 9.812614917755129
114
+ 53.54921647691311, 9.807373881340029
115
+ 53.54508251196638, 9.80433225631714
116
+ ```
117
+
118
+ ## Getting GPX Files
119
+
120
+ GPX files can be obtained from several GPS-tracking services:
121
+ * Strava: Go to the activity page and click on the wrench icon. Then select "Export GPX".
122
+ * Garmin Connect: Open the activity, go to the gear icon and select "Export to GPX".
123
+ * Endomondo: From the workout page, click the three-dot menu icon and select "Export". Then choose "GPX".
124
+
125
+ ## GPX Validation
126
+
127
+ For the `gpx-player` to work properly, it needs the correct GPX files.
128
+ You can verify that you are inputting the correct file by using the special validator
129
+ included in this package.
130
+
131
+ The `validator.py` script is a command-line utility and module for validating GPX files.
132
+ It checks for XML schema conformance and timestamp consistency,
133
+ supporting both strict and lenient modes.
134
+ Errors are raised as `GPXValidationError` which can be caught in Python code.
135
+ To run as a CLI tool, use:
136
+ ```bash
137
+ python validator.py path/to/yourfile.gpx --strict
138
+ ```
139
+
140
+ The `--strict` parameter is optional. In most cases you do not need it,
141
+ because files that strictly correspond to the GPX schema are rare.
142
+ For example, almost all modern files contain coordinates, elevations and time stamps
143
+ with more decimal places than originally planned.
144
+
145
+ Also, to better understand your GPX file, you can use the `gpxinfo` console command
146
+ that comes with `gpxpy`. If you are already using the player, you have it:
147
+
148
+ ```bash
149
+ $ gpxinfo example-data/osm_track1.gpx
150
+ File: example-data/osm_track1.gpx
151
+ Waypoints: 0
152
+ Routes: 0
153
+ Length 2D: 9.621km
154
+ Length 3D: 9.648km
155
+ Moving time: 01:05:22
156
+ Stopped time: n/a
157
+ Max speed: 3.12m/s = 11.22km/h
158
+ Avg speed: 2.46m/s = 8.85km/h
159
+ Total uphill: 97.20m
160
+ Total downhill: 98.40m
161
+ Started: 2024-07-24 15:59:05+00:00
162
+ Ended: 2024-07-24 17:04:27+00:00
163
+ Points: 776
164
+ Avg distance between points: 12.40m
165
+
166
+ ```
167
+
168
+ ## Support
169
+ Now you can buy me a coffee to encourage further development!
170
+
171
+ [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/kirienko)
@@ -0,0 +1,24 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ animate_tracks.js
5
+ gpx_utils.py
6
+ header_template.html
7
+ legend.js
8
+ main.py
9
+ openseamap.py
10
+ pyproject.toml
11
+ speed_legend_template.html
12
+ utils.py
13
+ validator.py
14
+ gpx_player.egg-info/PKG-INFO
15
+ gpx_player.egg-info/SOURCES.txt
16
+ gpx_player.egg-info/dependency_links.txt
17
+ gpx_player.egg-info/entry_points.txt
18
+ gpx_player.egg-info/requires.txt
19
+ gpx_player.egg-info/top_level.txt
20
+ schema/gpx_1.0.xsd
21
+ schema/gpx_1.1.xsd
22
+ tests/test_openseamap.py
23
+ tests/test_utils.py
24
+ tests/test_validation.py
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ gpx-player = main:main
3
+ gpx-validate = validator:main
@@ -0,0 +1,7 @@
1
+ folium
2
+ jinja2
3
+ matplotlib
4
+ pytz
5
+ lxml
6
+ numpy
7
+ gpxpy