Create artistic visualisations with your exercise data (Python version)

Overview

strava_py

Create artistic visualisations with your exercise data (Python version).

This is a port of the R strava package to Python.

Examples

Facets

A plot of activities as small multiples. The concept behind this plot was originally inspired by Sisu.

facets

Map

A map of activities viewed in plan.

map

How to use

Bulk export from Strava

The process for downloading data is described on the Strava website here: [https://support.strava.com/hc/en-us/articles/216918437-Exporting-your-Data-and-Bulk-Export#Bulk], but in essence, do the following:

  1. Log in to Strava
  2. Select "Settings" from the main drop-down menu at top right of the screen
  3. Select "My Account" from the navigation menu to the left of the screen.
  4. Under the "Download or Delete Your Account" heading, click the "Get Started" button.
  5. Under the "Download Request", heading, click the "Request Your Archive" button. Don't click anything else on that page, i.e. particularly not the "Request Account Deletion" button.
  6. Wait for an email to be sent
  7. Click the link in email to download zipped folder containing activities
  8. Unzip files

Process the data

The main function for importing and processing activity files expects a path to a directory of unzipped GPX and / or FIT files. If required, the fit2gpx package provides useful tools for pre-processing bulk files exported from Strava, e.g. unzipping activity files (see Use Case 3: Strava Bulk Export Tools).

df = process_data(<path to folder with GPX and / or FIT files>)

Plot activities as small multiples

plot_facets(df, output_file = 'plot.png')

Plot activity map

plot_map(df, lon_min=None, lon_max= None, lat_min=None, lat_max=None,
             alpha=0.3, linewidth=0.3, output_file="map.png")
Comments
  • Getting:

    Getting: "gpxpy.gpx.GPXException: latitude is mandatory in None (got None)"

    Hey,

    I tried using the CLI tool but I'm getting this error: gpxpy.gpx.GPXException: latitude is mandatory in None (got None)

    I tried setting --lon_max, --lat_max to 180,90 and --lat_min, --lon_min to 0,0 but still getting the same error.

    Is this a problem with a specific .gpx file? And if so how can I find that one because the error doesn't show which file.

    Thanks

    opened by Alpha249 7
  • Starting cli.py gives error: ModuleNotFoundError: No module named 'stravavis'

    Starting cli.py gives error: ModuleNotFoundError: No module named 'stravavis'

    Thanks for the app, it looks quite nice. But as I'm a bit new to Python, I'm having trouble to get it started.

    I cloned the repo and tried from its root directory: [email protected] strava_py % python3 src/stravavis/cli.py /Users/jmizv/Downloads/gpx

    But I just got that error message:

    Traceback (most recent call last):
      File "/Users/jmizv/IdeaProjects/strava_py/src/stravavis/cli.py", line 91, in <module>
        main()
      File "/Users/jmizv/IdeaProjects/strava_py/src/stravavis/cli.py", line 41, in main
        from stravavis.plot_calendar import plot_calendar
    ModuleNotFoundError: No module named 'stravavis'
    [email protected] strava_py % 
    

    I'm probably missing something obvious but I don't see it. Could you, @marcusvolz, please give an advice?

    opened by jmizv 7
  • Add CLI as strava_py

    Add CLI as strava_py

    This PR adds a CLI for creating visualisations, and puts it into an installable package, ready for distributions via https://pypi.org so it can be installed using pip. (I can help with how to do that later!)

    First, I moved the strava_py directory into a src directory. This is commonly used for Python projects. The main benefits is to make sure when you're testing, you're testing against something that has been installed, and not something that happens to have the same directory name in your current dir. Much more:

    • https://packaging.python.org/en/latest/tutorials/packaging-projects/#a-simple-project
    • https://blog.ionelmc.ro/2014/05/25/python-packaging/
    • https://hynek.me/articles/testing-packaging/

    The way to install from source:

    pip install .
    

    Or if you're developing, -e means an editable install, so you can make changes to your local source tree and they're reflected in what's run:

    pip install -e .
    

    Then I went for strava_py as the CLI name (this can be changed):

    $ strava_py --help
    usage: strava_py [-h] [-o OUTPUT_FILE] path
    
    positional arguments:
      path                  Input path to folder with GPX and / or FIT files
    
    options:
      -h, --help            show this help message and exit
      -o OUTPUT_FILE, --output_file OUTPUT_FILE
                            Output PNG file (default: plot.png)
    

    Example run:

    $ strava_py /tmp/my_strava_activities
    Processing data...
    Processing: 6628958226.gpx
    Processing: 6626094662.gpx
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 142); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 162); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 203); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 249); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 285); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 326); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 351); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 397); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 443); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 487); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 531); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 575); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 619); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 663); adding dummy dev data...
      warnings.warn(msg)
    /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/fitdecode/reader.py:909: UserWarning: 'field "native_field_num" (idx #0) not found in message "field_description"' (local_mesg_num: 0; chunk_offset: 707); adding dummy dev data...
      warnings.warn(msg)
    Processing: 6678512291.fit
    Processing: 6619621876.gpx
    Processing: 6604948302.gpx
    Processing: 6860888905.fit
    Processing: 6678648994.fit
    Processing: 6676505895.fit
    Processing: 6810573487.fit
    Processing: 6623947053.gpx
    Processing: 6630963143.gpx
    Plotting facets...
    Saved to plot.png
    

    I'll also add a bunch of inline comments to explain what some things do, please feel free to ask more about any of this!

    opened by hugovk 3
  • Elevations

    Elevations

    @hugovk Thanks for reviewing these and for the recent PRs. This one just adds the elevations small multiples plot.

    I think I might have missed the suggested commits in your previous PRs, could you let me know if everything went through ok? Thanks!

    opened by marcusvolz 2
  • ValueError: All objects passed were None

    ValueError: All objects passed were None

    Hi, I have been trying to apply this package on my data pull from Strava but in the first step of processing data I'm getting this error of "ValueError: All objects passed were None" attaching a screenshot for reference. I tried to give address of either the activities or routes folder which has gpx files but still the error remains constant Screenshot 2022-12-25 at 16 03 22

    opened by shu3hamiitkgp 1
  • Fix squashed maps

    Fix squashed maps

    This is similar to https://github.com/marcusvolz/strava/issues/5.

    Here's the same GPX using main:

    strava-map

    Like https://stackoverflow.com/a/14457180/724176, rather than using latitude and longitude values, this uses a Mercator projection calculation to come up with x and y values instead.

    Dummy, unit map width and height values are used, as we don't know and don't need to know the final size as matplotlib will take care of that.

    And with this PR:

    strava-map

    Measuring performance:

    With main, on 2,946 GPX files (but commenting out some bits of cli.py to only run "Processing data..." and "Plotting map..."), it takes 11m45s on a Mac M1 16GB.

    With the PR it takes a comparable 11m43s, which is really good because the transform is done by Pandas so presumably in C.

    opened by hugovk 1
  • UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 379: character maps to <undefined>

    UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 379: character maps to

    When I execute stravavis against this single attached file (5670595833.gpx.txt, you need to remove the txt extension) it fails with the below error. I tend to add emojis to my strava activity titles so this is in my opinion the problem. Not sure if you could exclude this easily? The files are certainly not encoded with Cp1252.

    C:\Users\...>stravavis C:\Users\...
    Processing data...
    Processing ----------------------------------------   0% -:--:--
    multiprocessing.pool.RemoteTraceback:
    """
    Traceback (most recent call last):
      File "C:\Program Files\Python310\lib\multiprocessing\pool.py", line 125, in worker
        result = (True, func(*args, **kwds))
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\stravavis\process_data.py", line 13, in process_file
        return process_gpx(fpath)
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\stravavis\process_data.py", line 21, in process_gpx
        activity = gpxpy.parse(open(gpxfile))
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\gpxpy\__init__.py", line 37, in parse
        parser = mod_parser.GPXParser(xml_or_file)
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\gpxpy\parser.py", line 70, in __init__
        self.init(xml_or_file)
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\gpxpy\parser.py", line 82, in init
        text = xml_or_file.read() if hasattr(xml_or_file, 'read') else xml_or_file # type: ignore
      File "C:\Program Files\Python310\lib\encodings\cp1252.py", line 23, in decode
        return codecs.charmap_decode(input,self.errors,decoding_table)[0]
    UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 379: character maps to <undefined>
    """
    
    The above exception was the direct cause of the following exception:
    
    Traceback (most recent call last):
      File "C:\Program Files\Python310\lib\runpy.py", line 196, in _run_module_as_main
        return _run_code(code, main_globals, None,
      File "C:\Program Files\Python310\lib\runpy.py", line 86, in _run_code
        exec(code, run_globals)
      File "C:\Users\...\AppData\Roaming\Python\Python310\Scripts\stravavis.exe\__main__.py", line 7, in <module>
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\stravavis\cli.py", line 51, in main
        df = process_data(args.path)
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\stravavis\process_data.py", line 108, in process_data
        processed = list(it)
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\rich\progress.py", line 168, in track
        yield from progress.track(
      File "C:\Users\...\AppData\Roaming\Python\Python310\site-packages\rich\progress.py", line 1211, in track
        for value in sequence:
      File "C:\Program Files\Python310\lib\multiprocessing\pool.py", line 870, in next
        raise value
    UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 379: character maps to <undefined>
    

    5670595833.gpx.txt

    bug 
    opened by jmizv 1
  • Add --bbox CLI param as a shortcut

    Add --bbox CLI param as a shortcut

    It's a bit tedious to enter four params and values on the command line when creating a map:

    stravavis activities --lon_min 23.516665 --lat_min 60.000467 --lon_max 26.390877 --lat_max 61.360291

    This PR adds a --bbox shortcut for those, that takes a bounding box of comma-separated values of lon_min, lat_min, lon_max, lat_max:

    stravavis activities --bbox 23.516665,60.000467,26.390877,61.360291

    It's quite easy to find bounding boxes online, for example: http://bboxfinder.com/#60.000467,23.516665,61.360291,26.390877


    I also noticed that these lat/lon values are not actually passed from the CLI to the plotting function, and neither are alpha or linewidth, so let's fix that too :)


    Finally, bump some GitHub Actions versions for the CI.

    enhancement 
    opened by hugovk 1
  • Updated README: Add installation instructions and link directly to images

    Updated README: Add installation instructions and link directly to images

    Images are broken on PyPI:

    image

    Instead of linking to things like https://github.com/marcusvolz/strava_py/blob/main/plots/facets001.png, which is an HTML page showing the image, and which GitHub can apparently handle redirects to for the README, link directly to the image file, like https://raw.githubusercontent.com/marcusvolz/strava_py/main/plots/facets001.png

    This also adds installation instructions to the README.

    opened by hugovk 1
  • More progress bars for slow loops, and refactor

    More progress bars for slow loops, and refactor

    Also in Python we generally prefer to iterate over objects in a list (or tuple, or other so-called "iterable") rather than using an index of range(len(thing)).

    So for example, instead of:

    n = len(activities)
    for i in range(n):
        print(activities[i])
    

    This is more direct and readable:

    for activity in activities:
        print(activity)
    

    If we do need an index as well, enumerate is often used:

    for i, activity in enumerate(activities):
        print(i, activity)
    
    opened by hugovk 1
  • Use multiprocessing to speed up processing of input files

    Use multiprocessing to speed up processing of input files

    Use multiprocessing to speed up processing of input files, using the number of processes which matches the CPU count.

    On my old dual-core Mac, the processing step speeds up:

    • 601 files (all of 2021): 2m7s -> 1m20s
    • 2,629 files (my full Strava archive): 10m29s -> 5m9s

    Will be a larger gain for machines with more CPUs.

    multiprocessing needs a single worker function, this is the new process_file which decides which of process_gpx and process_fit to call. They also need to be top-level functions to work with multiprocessing.

    I also formatted the file using the popular Black autoformatter:

    python -m pip install -U black
    black . 
    

    I also fixed a bug when using an input path like ~/dir, it needs to expand ~ before checking it's a dir (and appending *).

    opened by hugovk 1
Releases(v0.1.0)
  • v0.1.0(Dec 30, 2022)

    What's Changed

    • Add --bbox CLI param as a shortcut by @hugovk in https://github.com/marcusvolz/strava_py/pull/18
    • Add support for Python 3.11 by @hugovk in https://github.com/marcusvolz/strava_py/pull/26
    • Catch exception to skip invalid file by @hugovk in https://github.com/marcusvolz/strava_py/pull/27
    • Fix encoding on Windows by @hugovk in https://github.com/marcusvolz/strava_py/pull/20
    • Fix squashed maps by @hugovk in https://github.com/marcusvolz/strava_py/pull/21
    • Fix README typo by @hugovk in https://github.com/marcusvolz/strava_py/pull/24

    Full Changelog: https://github.com/marcusvolz/strava_py/compare/v0.0.2...v0.1.0

    Source code(tar.gz)
    Source code(zip)
  • v0.0.2(Sep 1, 2022)

    What's Changed

    • Updated README: Add installation instructions and link directly to images by @hugovk in https://github.com/marcusvolz/strava_py/pull/17

    Full Changelog: https://github.com/marcusvolz/strava_py/compare/v0.0.1...v0.0.2

    Source code(tar.gz)
    Source code(zip)
  • v0.0.1(Sep 1, 2022)

    What's Changed

    • Add CLI as strava_py by @hugovk in https://github.com/marcusvolz/strava_py/pull/1
    • added plot_map by @marcusvolz in https://github.com/marcusvolz/strava_py/pull/2
    • Rename package and CLI program to stravavis by @hugovk in https://github.com/marcusvolz/strava_py/pull/3
    • Allow input path specification and show progress bar by @hugovk in https://github.com/marcusvolz/strava_py/pull/4
    • Elevations by @marcusvolz in https://github.com/marcusvolz/strava_py/pull/5
    • Test run on GitHub Actions by @hugovk in https://github.com/marcusvolz/strava_py/pull/6
    • Landscape by @marcusvolz in https://github.com/marcusvolz/strava_py/pull/8
    • Use multiprocessing to speed up processing of input files by @hugovk in https://github.com/marcusvolz/strava_py/pull/9
    • Calendar by @marcusvolz in https://github.com/marcusvolz/strava_py/pull/10
    • Fix local variable 'activities' referenced before assignment by @hugovk in https://github.com/marcusvolz/strava_py/pull/11
    • Fix ValueError with --activities_path by @hugovk in https://github.com/marcusvolz/strava_py/pull/12
    • Dumbbell by @marcusvolz in https://github.com/marcusvolz/strava_py/pull/13
    • Allow --activities_path to point to file or directory by @hugovk in https://github.com/marcusvolz/strava_py/pull/14
    • More progress bars for slow loops, and refactor by @hugovk in https://github.com/marcusvolz/strava_py/pull/15

    New Contributors

    • @hugovk made their first contribution in https://github.com/marcusvolz/strava_py/pull/1
    • @marcusvolz made their first contribution in https://github.com/marcusvolz/strava_py/pull/2

    Full Changelog: https://github.com/marcusvolz/strava_py/commits/v0.0.1

    Source code(tar.gz)
    Source code(zip)
Owner
Marcus Volz
Data visualisation | mathematical visualisation | 3D visualisation
Marcus Volz
PanGraphViewer -- show panenome graph in an easy way

PanGraphViewer -- show panenome graph in an easy way Table of Contents Versions and dependences Desktop-based panGraphViewer Library installation for

16 Dec 17, 2022
Some method of processing point cloud

Point-Cloud Some method of processing point cloud inversion the completion pointcloud to incomplete point cloud Some model of encoding point cloud to

Tan 1 Nov 19, 2021
Simple and fast histogramming in Python accelerated with OpenMP.

pygram11 Simple and fast histogramming in Python accelerated with OpenMP with help from pybind11. pygram11 provides functions for very fast histogram

Doug Davis 28 Dec 14, 2022
Generate visualizations of GitHub user and repository statistics using GitHub Actions.

GitHub Stats Visualization Generate visualizations of GitHub user and repository statistics using GitHub Actions. This project is currently a work-in-

Aditya Thakekar 1 Jan 11, 2022
Define fortify and autoplot functions to allow ggplot2 to handle some popular R packages.

ggfortify This package offers fortify and autoplot functions to allow automatic ggplot2 to visualize statistical result of popular R packages. Check o

Sinhrks 504 Dec 23, 2022
Massively parallel self-organizing maps: accelerate training on multicore CPUs, GPUs, and clusters

Somoclu Somoclu is a massively parallel implementation of self-organizing maps. It exploits multicore CPUs, it is able to rely on MPI for distributing

Peter Wittek 239 Nov 10, 2022
Plot and save the ground truth and predicted results of human 3.6 M and CMU mocap dataset.

Visualization-of-Human3.6M-Dataset Plot and save the ground truth and predicted results of human 3.6 M and CMU mocap dataset. human-motion-prediction

Gaurav Kumar Yadav 5 Nov 18, 2022
Streamlit-template - A streamlit app template based on streamlit-option-menu

streamlit-template A streamlit app template for geospatial applications based on

Qiusheng Wu 41 Dec 10, 2022
This is a small program that prints a user friendly, visual representation, of your current bsp tree

bspcq, q for query A bspc analyzer (utility for bspwm) This is a small program that prints a user friendly, visual representation, of your current bsp

nedia 9 Apr 24, 2022
Open-source demos hosted on Dash Gallery

Dash Sample Apps This repository hosts the code for over 100 open-source Dash apps written in Python or R. They can serve as a starting point for your

Plotly 2.7k Jan 07, 2023
Data Visualizations for the #30DayChartChallenge

The #30DayChartChallenge This repository contains all the charts made for the #30DayChartChallenge during the month of April. This project aims to exp

Isaac Arroyo 7 Sep 20, 2022
Splore - a simple graphical interface for scrolling through and exploring data sets of molecules

Scroll through and exPLORE molecule sets The splore framework aims to offer a si

3 Jun 18, 2022
Customizing Visual Styles in Plotly

Customizing Visual Styles in Plotly Code for a workshop originally developed for an Unconference session during the Outlier Conference hosted by Data

Data Design Dimension 9 Aug 03, 2022
Create artistic visualisations with your exercise data (Python version)

strava_py Create artistic visualisations with your exercise data (Python version). This is a port of the R strava package to Python. Examples Facets A

Marcus Volz 53 Dec 28, 2022
trade bot connected to binance API/ websocket.,, include dashboard in plotly dash to visualize trades and balances

Crypto trade bot 1. What it is Trading bot connected to Binance API. This project made for fun. So ... Do not use to trade live before you have backte

G 3 Oct 07, 2022
Python ts2vg package provides high-performance algorithm implementations to build visibility graphs from time series data.

ts2vg: Time series to visibility graphs The Python ts2vg package provides high-performance algorithm implementations to build visibility graphs from t

Carlos Bergillos 26 Dec 17, 2022
3D Vision functions with end-to-end support for deep learning developers, written in Ivy.

Ivy vision focuses predominantly on 3D vision, with functions for camera geometry, image projections, co-ordinate frame transformations, forward warping, inverse warping, optical flow, depth triangul

Ivy 61 Dec 29, 2022
Generate "Jupiter" plots for circular genomes

jupiter Generate "Jupiter" plots for circular genomes Description Python scripts to generate plots from ViennaRNA output. Written in "pidgin" python w

Robert Edgar 2 Nov 29, 2021
Bcc2telegraf: An integration that sends ebpf-based bcc histogram metrics to telegraf daemon

bcc2telegraf bcc2telegraf is an integration that sends ebpf-based bcc histogram

Peter Bobrov 2 Feb 17, 2022
Calendar heatmaps from Pandas time series data

Note: See MarvinT/calmap for the maintained version of the project. That is also the version that gets published to PyPI and it has received several f

Martijn Vermaat 195 Dec 22, 2022