flopp / gpxtrackposter Goto Github PK
View Code? Open in Web Editor NEWCreate a visually appealing poster from your GPX tracks
License: MIT License
Create a visually appealing poster from your GPX tracks
License: MIT License
create_poster --gpx-dir "gpx/" --track-color '#5599ff' --track-color2 '#ffd732' --output "/tmp/GPXPOSTER.svg" --title 2019-2020 --athlete Bob --type github --language fr_FR --year 2019-2020 --circular-rings; done;
Colors are not used in github. I use these colors for heatmap and circular. As you can see, there is too much yellow in github:
(by the way, thanks a lot for gpxtrackposter ♥)
works until 2cf9558
breaks starting with 7842d42
(env) mpo@mpo-home:~/projects/flopp-GPX$ ./create_poster.py --type grid --gpx-dir "mytracks" --year 2017 --title "Running"Traceback (most recent call last):
File "./create_poster.py", line 11, in <module>
from src import track_loader
File "/home/mpo/projects/flopp-GPX/src/track_loader.py", line 31, in <module>
class TrackLoader:
File "/home/mpo/projects/flopp-GPX/src/track_loader.py", line 156, in TrackLoader
def __list_gpx_files(base_dir: str) -> typing.Generator[str]:
File "/usr/lib/python3.6/typing.py", line 682, in inner
return func(*args, **kwds)
File "/usr/lib/python3.6/typing.py", line 1130, in __getitem__
_check_generic(self, params)
File "/usr/lib/python3.6/typing.py", line 662, in _check_generic
("many" if alen > elen else "few", repr(cls), alen, elen))
TypeError: Too few parameters for typing.Generator; actual 1, expected 3
e.g.
create_poster.py --highlight "foo.gpx" --highlight "bar.gpx" --highlight-color "#FF0000" ...
Getting an error when I run the following command:
create_poster --type grid --title "Strava Routes" --athlete "NAME"
I am running the command from a directory that contains all my .gpx files. Any idea why this is happening?
This is the error (it prints one time in terminal for each .gpx file):
Error while loading /Users/../Downloads/export_54211749/activities/5138491472.gpx: Something went wrong when loading GPX.
Regardless if i use a fixed or relative path as --gpx-dir or double or single quotes, i seem to rund into the No tracks found problem. Is there a certain format expected from the GPX files? Mine gets exported as:
<gpx version="1.1" creator=" " xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
Hi, can someone help me getting this to run in native windows? All dependecies and venv work, but if i pass a gpx dir (that confirmed works on linux) i get the above error.The error is in track.py:76 except Exception as e: # raise TrackLoadError("Something went wrong when loading GPX.") from e
Sadly that doesn't tell me much.
If i remove the exception, I end up with an assertion error in create_poster-script.py:11, in <module> load_entry_point('gpxtrackposter==0.1', 'console_scripts', 'create_poster')()
I'm not familiar with all that build framework around that script so any help or pointers would be appreciated, because i think it's not an issue with the script itself or gpxpy.
Hello @flopp,
I would highly appreciate it if the outdated name "master" for the main branch could be renamed to "main".
Since 1st of October 2020 for all new projects the default name is "main".
I know that it seems to be a useless effort, but I think it is also an important statement these days.
Cheers,
LT.
I can define title with --title option but default title can't be translated
The recent update for activity type filtering causes the import of GPX files without a "type" to fail. I am using this software to import GPX tracks from ForeFlight which have no type field in the track. Reverting to the prior commit solves the problem as does adding a type field to GPX file manually.
Thanks!
As already stated in #7, the heatmap is kind of useless if the track collection is wide spread. Still, I'm a big fan of having a look at my complete route net.
My current solution is to reduce line widths by hand, e.g.
for line in scaled_lines:
d.add(d.polyline(points=line, stroke=color, stroke_opacity=0.02, fill='none', stroke_width=0.5, stroke_linejoin='round', stroke_linecap='round'))
for line in scaled_lines:
d.add(d.polyline(points=line, stroke=color, stroke_opacity=0.05, fill='none', stroke_width=0.2, stroke_linejoin='round', stroke_linecap='round'))
for line in scaled_lines:
d.add(d.polyline(points=line, stroke=color, fill='none', stroke_width=0.05, stroke_linejoin='round', stroke_linecap='round'))
for line in scaled_lines_special:
d.add(d.polyline(points=line, stroke=color_special, fill='none', stroke_width=0.05, stroke_linejoin='round', stroke_linecap='round'))
That is: 0.02, 0.5
and 0.05, 0.2
instead of 0.1, 5.0
and 0.2, 2.0
(for ~2.600 activities from Sweden till the Alps). A high resolution image is required, but it works.
Maybe it's possible to automatically calculate line widths based on d_y
and d_x
. We could define limits for the values (e.g. both version from above as upper and lower limit respectively).
last thing I think that could be added in translation file : ":"
In french, always as example, we use " :" (there is a nbsp)
(thank you very much for your reactivity on my issues reports and pull request, that's great and pleasant)
I've updated the stock strava.json
with my info from https://www.strava.com/settings/api, akin to
{
"client_id": "12345",
"client_secret": "somerandomcharacters",
"refresh_token": "morerandomcharacters",
}
Then I run create_poster --from-strava strava.json --year 2023
, but the process fails with an error in stravalib.
The error is stravalib.exc.AccessUnauthorized: Unauthorized: Authorization Error: [{'resource': 'AccessToken', 'field': 'activity:read_permission', 'code': 'missing'}]
.
On the Strava API page I also see an 'Access Token' for my account, do I have to enter that somewhere, too?
pip install
doesn't install locale
folder into lib/python3.8/site-packages/gpxtrackposter/
.
Depending on the heatmap's size, it may be nice to see at least some basic map in the background.
I have a first working solution with laufhannes@ebb0823 and laufhannes/staticmaplite@3758e11, but that's not perfect. The main part within this repo is to calculate lat/lng bounds of the visible part. Afterwards, a static map is requested, saved locally and inserted. (Without saving it locally, inkscape is not able to embed the image when converting to png)
The staticmaplite repo is written in php, but it should be possible to transform it into python. Using Google Maps Static may even be better (but requires an API key; in general free for non-commercial and low traffic apps), as it's possible to individually style the map. I created one first try for such a style at snazzy maps.
If using Google Maps, calculation of the required zoom level and cropping the image (or calculating the exact size) has to be done within this repo.
As this testing has been done in my local runalyze-environment, the example is decorated with our brandings ;)
And I guess this needs some additional padding within the draw area to not let tracks touch the border.
create_poster --output "/tmp/gpx_circular_test.svg" --athlete Anthony --year 2019 --type circular --special-distance 10 --special-distance2 15 --circular-rings
Everything is blue…
How should I use --special-distance argument? Is that a bug or a lack of understanding?
When I use --special colored some tracks are in yellow as expected
Month names are printed in the nominative case for all languages except Russian, where it should be январь
instead of января
in the example bellow, compare:
That's caused by:
$ python
>>> from datetime import datetime
>>> import locale
>>> locale.setlocale(locale.LC_ALL, 'ru_RU.UTF-8')
'ru_RU.UTF-8'
>>> datetime.today().strftime('%B')
'сентября'
Like GitHub poster when mouse hover, the title show.
Works if there is one file in the directory.
Doesn't work, there are 3 files in the directory.
create_poster --type circular
Creating poster of type circular with 2 tracks and storing it in file poster.svg...
Traceback (most recent call last):
File "/home/user/.local/bin/create_poster", line 10, in
sys.exit(main())
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/cli.py", line 277, in main
p.draw(drawers[args.type], args.output)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/poster.py", line 169, in draw
self._draw_tracks(d, XY(self.width - 20, self.height - 30 - 30), XY(10, 30))
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/poster.py", line 194, in _draw_tracks
self.tracks_drawer.draw(d, g, size, offset)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/circular_drawer.py", line 103, in draw
self._draw_year(dr, g_year, sub_size, offset + margin + cell_size * XY(x, y), year)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/circular_drawer.py", line 174, in _draw_year
key_times_list = utils.make_key_times(year_count)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/utils.py", line 121, in make_key_times
s = list(takewhile(lambda n: n < 1, itercount(0, 1 / year_count)))
ZeroDivisionError: division by zero
create_poster --type github
Creating poster of type github with 2 tracks and storing it in file poster.svg...
Traceback (most recent call last):
File "/home/user/.local/bin/create_poster", line 10, in
sys.exit(main())
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/cli.py", line 277, in main
p.draw(drawers[args.type], args.output)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/poster.py", line 169, in draw
self._draw_tracks(d, XY(self.width - 20, self.height - 30 - 30), XY(10, 30))
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/poster.py", line 194, in _draw_tracks
self.tracks_drawer.draw(d, g, size, offset)
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/github_drawer.py", line 44, in draw
year_length_str = utils.format_float(self.poster.m2u(year_length))
File "/home/user/.local/lib/python3.8/site-packages/gpxtrackposter/poster.py", line 175, in m2u
return m.m_as(Units().km)
File "/home/user/.local/lib/python3.8/site-packages/pint/quantity.py", line 533, in m_as
return self.to(units).magnitude
File "/home/user/.local/lib/python3.8/site-packages/pint/quantity.py", line 741, in to
magnitude = self._convert_magnitude_not_inplace(other, *contexts, **ctx_kwargs)
File "/home/user/.local/lib/python3.8/site-packages/pint/quantity.py", line 690, in _convert_magnitude_not_inplace
return self._REGISTRY.convert(self._magnitude, self._units, other)
File "/home/user/.local/lib/python3.8/site-packages/pint/registry.py", line 1036, in convert
return self._convert(value, src, dst, inplace)
File "/home/user/.local/lib/python3.8/site-packages/pint/registry.py", line 1951, in _convert
return super()._convert(value, src, dst, inplace)
File "/home/user/.local/lib/python3.8/site-packages/pint/registry.py", line 1558, in _convert
return super()._convert(value, src, dst, inplace)
File "/home/user/.local/lib/python3.8/site-packages/pint/registry.py", line 1069, in _convert
raise DimensionalityError(src, dst, src_dim, dst_dim)
pint.errors.DimensionalityError: Cannot convert from 'dimensionless' (dimensionless) to 'kilometer' ([length])
n/a
to avoid problems such as #78
Using gettext
Generating raw *.pot file
pygettext3 -d gpxposter src/*.py
paramter --language <lang_code>
Eg. `--language de_DE
Fallback is English
Current work at: https://github.com/mipapo/GpxTrackPoster
I would prefer if "Runs" would be renamed to "Number" to have a more general naming
If you want I can add the translation to https://translate.runalyze.com/ so that everyone can easily add new languages
I generated different workouts. All workouts with a distance of less than one kilometer are skipped
No tracks found.
Many workouts can be less than 1km, such as walking or swimming.
Please add support for tracks with a distance of less than 1km.
numbers are always displayed in english way "1234.5"
Could be great if we can choose numbers display with --language. In french, for exemple, we write "1 234,5"
something like
import locale
locale.setlocale(locale.LC_ALL, 'fr_FR.UTF-8')
'{0:n}'.format(1234.5)
?
n/a
Add circular layout:
I try to generate a poster with some gpx files extracted from my garmin account.
I have downloaded the files using the proposed python script garmin-connect-export.
Now, I get the following error:
Traceback (most recent call last):
File "~/GpxTrackPoster/venv/bin/create_poster", line 8, in <module>
sys.exit(main())
File "~/GpxTrackPoster/venv/lib/python3.7/site-packages/gpxtrackposter/cli.py", line 217, in main
tracks = loader.load_tracks(args.gpx_dir)
File "~/GpxTrackPoster/venv/lib/python3.7/site-packages/gpxtrackposter/track_loader.py", line 114, in load_tracks
return self._filter_and_merge_tracks(tracks)
File "~/GpxTrackPoster/venv/lib/python3.7/site-packages/gpxtrackposter/track_loader.py", line 169, in _filter_and_merge_tracks
tracks = self._merge_tracks(tracks)
File "~/GpxTrackPoster/venv/lib/python3.7/site-packages/gpxtrackposter/track_loader.py", line 176, in _merge_tracks
tracks = sorted(tracks, key=lambda t1: t1.start_time())
TypeError: can't compare offset-naive and offset-aware datetimes
Is something wrong with my gpx files?
As said, they all come from the same source.
Thanks in advance,
LT.
Decided to try tackling #7 by using DBSCAN to cluster the (center points of the) tracks, then only create the heatmap for the first cluster. The code is very messy right now -- just a PoC to see if I could get it work -- and I'm not an expert on clustering algorithms, but it seems to be working well enough for me. Without customizing the heatmap center/radius, my heatmap was gibberish. Adding in the clustering, I get this nice result:
If anyone wants to give it a try, it's in my fork -- I'd love to hear feedback/if it works for data other than mine. I've included a new requirements file, requirements-with-cluster.txt
. The only changes are to heatmap_drawer.py
, where I've added a new variable _cluster
, which can be toggled on or off. You can tweak the eps
parameter of DBSCAN to get different cluster sizes -- I'd imagine a cyclist doing 200 mile rides might need this set differently than a runner.
Edit: These changes are now present in this branch of my fork, but nost master.
The longer the distance the more intensive the color of that day
(Just looking at the posters all the time and wanna leave some ideas for peple who wanna contribute to this great repository ;) )
Consider about time zones when Calendar poster or GitHub poster?
Because we can get time zone from the GPX ( lat, lon can get the time zone)
Hello,
Would you consider adding tox / pex support instead of Makefile ?
Regards
Add a Strava import function (via stravalib
).
It may be enough to fetch the activities overview which contains the actual activity tracks as stripped down "summary polylines".
Dear,
I'm not very skilled in programming, but did my best to try to understand this.
After a long time I managed to clone repository and set it up. However i keep returning the error: "AttributeError: module 'pint' has no attribute 'quantity'. Did you mean: 'Quantity'?". And not getting any output.
I tried my best to see where it went wrong, but couldnt find it.
If you could help me that would be wonderful.
Note: i cloned repository in visual study code, then set it up with "source venv\Scripts\activate.bat" instead of "source venv/bin/activate" then created a folder in the repository with all my gpx files retrieved from strava
Add bbox option (--bbox COORDS1;COORDS2
) to restrict the extent of the heatmap poster.
Rationale: if there are some tracks in your collection that are far away from the other tracks (e.g. runs during vacation), the heatmap poster becomes useless.
Hi there, can we get an option to show all years? Or more than one year at a time?
I would like to combine several years at a time on the grid and heatmaps at least (might be tougher on the calendar and circular modes).
First of all, thanks for your work on this project ,it's great. #_#.
but when i cloned this project ,and run my own dataset, bug happened to me, it reported:
python create_poster.py --type grid --gpx-dir "data" --year 2018 --title "Running" --athlete "youth" --special 1.gpx --special 2.gpx --special 3.gpx
objc[6009]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[6008]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
objc[6009]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
objc[6008]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug.
objc[6007]: +[__NSPlaceholderDictionary initialize] may have been in progress in another thread when fork() was called.
Traceback (most recent call last):
File "create_poster.py", line 165, in <module>
main()
File "create_poster.py", line 142, in main
tracks = loader.load_tracks(args.gpx_dir)
File "/Users/youth/project/GpxTrackPoster/gpxtrackposter/track_loader.py", line 92, in load_tracks
loaded_tracks = self._load_tracks(remaining_file_names)
File "/Users/youth/project/GpxTrackPoster/gpxtrackposter/track_loader.py", line 148, in _load_tracks
t = future.result()
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/concurrent/futures/_base.py", line 425, in result
return self.__get_result()
File "/usr/local/Cellar/python/3.6.4_4/Frameworks/Python.framework/Versions/3.6/lib/python3.6/concurrent/futures/_base.py", line 384, in __get_result
raise self._exception
concurrent.futures.process.BrokenProcessPool: A process in the process pool was terminated abruptly while the future was running or pending.
I don't have any idea where the bug fires.
Thanks ;)
I guess this issue exists since 3e297b8 / #82.
I'm not sure how the unit handling in python works, but in this part max_length
is in km
if provided as cli argument and in m
otherwise. In my example, the division distance / max_length
gives 0.00028... kilometer / meter
, but it's 0.28... dimensionless
when using distance.to_base_units() / max_length.to_base_units()
.
min_length = length_range.lower()
max_length = length_range.upper()
if self._max_distance:
max_length = self._max_distance
assert min_length is not None
assert max_length is not None
ring_distance = self._determine_ring_distance(max_length)
if ring_distance is None:
return
distance = ring_distance
while distance < max_length:
radius = radius_range.interpolate((distance / max_length).magnitude)
Not sure if there are more lines where this fails (or did I somehow misconfigured my units?).
when drawing heatmap with several years, separate each year in layers could be great (same scale, can enable or disable easily in svg editor…)
As I mentioned in #82
You can see my test_svg file in my test repo
Parameter to switch between
I think the default one should be metric unit
Can we add this feature?
Add a link of svg file that user can select value or type value in form.
Add a generate button that can generate the svg file to show in the broswer.
I think flask is enough when click the button then cli side will generate the svg
is that possible to add an option to choose font?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.