Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linting and formatting #33

Merged
merged 6 commits into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[flake8]
max-line-length = 88
17 changes: 17 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Lint

on: [push, pull_request, workflow_dispatch]

permissions:
contents: read

jobs:
lint:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.x"
- uses: pre-commit/[email protected]
49 changes: 49 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
repos:
- repo: https://github.com/asottile/pyupgrade
rev: v3.4.0
hooks:
- id: pyupgrade
args: [--py38-plus]

- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black

- repo: https://github.com/PyCQA/isort
rev: 5.12.0
hooks:
- id: isort

- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
additional_dependencies:
[flake8-2020, flake8-errmsg, flake8-implicit-str-concat]

- repo: https://github.com/pre-commit/pygrep-hooks
rev: v1.10.0
hooks:
- id: python-check-blanket-noqa
- id: python-no-log-warn

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: check-case-conflict
- id: check-merge-conflict
- id: check-json
- id: check-toml
- id: check-yaml
- id: end-of-file-fixer
- id: trailing-whitespace

- repo: https://github.com/pre-commit/mirrors-prettier
rev: v3.0.0-alpha.9-for-vscode
hooks:
- id: prettier
args: [--prose-wrap=always, --print-width=88]

ci:
autoupdate_schedule: quarterly
44 changes: 32 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# strava_py

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

This is a port of the [R strava package](https://github.com/marcusvolz/strava) to Python.
This is a port of the [R strava package](https://github.com/marcusvolz/strava) to
Python.

## Installation

Expand Down Expand Up @@ -29,7 +31,8 @@ stravavis --help

### Facets

A plot of activities as small multiples. The concept behind this plot was originally inspired by [Sisu](https://twitter.com/madewithsisu).
A plot of activities as small multiples. The concept behind this plot was originally
inspired by [Sisu](https://twitter.com/madewithsisu).

![facets](https://raw.githubusercontent.com/marcusvolz/strava_py/main/plots/facets001.png "Facets, showing activity outlines")

Expand All @@ -53,39 +56,56 @@ Elevation profiles superimposed.

### Calendar

Calendar heatmap showing daily activity distance, using the [calmap](https://pythonhosted.org/calmap/) package. Requires "activities.csv" from the bulk Strava export.
Calendar heatmap showing daily activity distance, using the
[calmap](https://pythonhosted.org/calmap/) package. Requires "activities.csv" from the
bulk Strava export.

![map](https://raw.githubusercontent.com/marcusvolz/strava_py/main/plots/calendar001.png "Calendar heatmap")

### Dumbbell plot

Activities shown as horizontal lines by time of day and day of year, facetted by year. Requires "activities.csv" from the bulk Strava export.
Activities shown as horizontal lines by time of day and day of year, facetted by year.
Requires "activities.csv" from the bulk Strava export.

![map](https://raw.githubusercontent.com/marcusvolz/strava_py/main/plots/dumbbell001.png "Dumbbell plot")

## 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:


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](https://www.strava.com/)
2. Select "[Settings](https://www.strava.com/settings/profile)" from the main drop-down menu at top right of the screen
3. Select "[My Account](https://www.strava.com/account)" from the navigation menu to the left of the screen.
4. Under the "[Download or Delete Your Account](https://www.strava.com/athlete/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.***
2. Select "[Settings](https://www.strava.com/settings/profile)" from the main drop-down
menu at top right of the screen
3. Select "[My Account](https://www.strava.com/account)" from the navigation menu to the
left of the screen.
4. Under the
"[Download or Delete Your Account](https://www.strava.com/athlete/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](https://github.com/dodo-saba/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).
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](https://github.com/dodo-saba/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).

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

Some plots use the "activities.csv" file from the Strava bulk export zip. For those plots, create an "activities" dataframe using the following function:
Some plots use the "activities.csv" file from the Strava bulk export zip. For those
plots, create an "activities" dataframe using the following function:

```python
activities = process_activities("<path to activities.csv file>")
Expand Down
19 changes: 10 additions & 9 deletions RELEASING.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ git clone https://github.com/marcusvolz/strava_py
cd strava_py
```

* [ ] (Optional) Create a distribution and release on **TestPyPI**:
- [ ] (Optional) Create a distribution and release on **TestPyPI**:

```bash
python -m pip install -U pip build keyring twine
Expand All @@ -30,13 +30,13 @@ python -m pip install -U -i https://test.pypi.org/simple/ stravavis
stravavis --help
```

* [ ] Tag with the version number:
- [ ] Tag with the version number:

```bash
git tag -a v0.0.1 -m "Release 0.0.1"
```

* [ ] Create a distribution and release on **live PyPI**:
- [ ] Create a distribution and release on **live PyPI**:

```bash
python -m pip install -U pip build keyring twine
Expand All @@ -45,21 +45,22 @@ python -m build
twine check --strict dist/* && twine upload -r pypi dist/*
```

* [ ] Check installation:
- [ ] Check installation:

```bash
python -m pip uninstall -y stravavis
python -m pip install -U stravavis
stravavis --help
```

* [ ] Push tag:
```bash
- [ ] Push tag:

```bash
git push --tags
```

* [ ] Create a new release: https://github.com/marcusvolz/strava_py/releases/new
- [ ] Create a new release: https://github.com/marcusvolz/strava_py/releases/new

* [ ] Click "Choose a tag" and select newest.
- [ ] Click "Choose a tag" and select newest.

* [ ] Click "Auto-generate release notes", amend as required and "Publish release".
- [ ] Click "Auto-generate release notes", amend as required and "Publish release".
2 changes: 2 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[tool.isort]
profile = "black"
44 changes: 33 additions & 11 deletions src/stravavis/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,57 @@ def main():
parser.add_argument(
"--lon_min",
type=float,
help="Minimum longitude for plot_map (values less than this are removed from the data)",
help="Minimum longitude for plot_map "
"(values less than this are removed from the data)",
)
parser.add_argument(
"--lon_max",
type=float,
help="Maximum longitude for plot_map (values greater than this are removed from the data)",
help="Maximum longitude for plot_map "
"(values greater than this are removed from the data)",
)
parser.add_argument(
"--lat_min",
type=float,
help="Minimum latitude for plot_map (values less than this are removed from the data)",
help="Minimum latitude for plot_map "
"(values less than this are removed from the data)",
)
parser.add_argument(
"--lat_max",
type=float,
help="Maximum latitude for plot_map (values greater than this are removed from the data)",
help="Maximum latitude for plot_map "
"(values greater than this are removed from the data)",
)
parser.add_argument(
"--bbox", help="Shortcut for comma-separated LON_MIN,LAT_MIN,LON_MAX,LAT_MAX"
)
parser.add_argument("--alpha", default=0.4, help="Line transparency. 0 = Fully transparent, 1 = No transparency")
parser.add_argument(
"--alpha",
default=0.4,
help="Line transparency. 0 = Fully transparent, 1 = No transparency",
)
parser.add_argument("--linewidth", default=0.4, help="Line width")
parser.add_argument("--activities_path", help="Path to activities.csv from Strava bulk export zip")
parser.add_argument("--year_min", help="The minimum year to use for the calendar heatmap.")
parser.add_argument("--year_max", help="The maximum year to use for the calendar heatmap.")
parser.add_argument("--max_dist", help="Maximum daily distance for the calendar heatmap; values above this will be capped.")
parser.add_argument(
"--activities_path", help="Path to activities.csv from Strava bulk export zip"
)
parser.add_argument(
"--year_min", help="The minimum year to use for the calendar heatmap."
)
parser.add_argument(
"--year_max", help="The maximum year to use for the calendar heatmap."
)
parser.add_argument(
"--max_dist",
help="Maximum daily distance for the calendar heatmap; "
"values above this will be capped.",
)
parser.add_argument("--fig_height", help="Figure height for the calendar heatmap.")
parser.add_argument("--fig_width", help="Figure width for the calendar heatmap.")
parser.add_argument("--local_timezone", help="Timezone for determining local times for activities. See pytz.all_timezones for a list of all timezones.")
parser.add_argument(
"--local_timezone",
help="Timezone for determining local times for activities. "
"See pytz.all_timezones for a list of all timezones.",
)
args = parser.parse_args()

# Expand "~" or "~user"
Expand Down Expand Up @@ -114,7 +136,7 @@ def main():
outfile = f"{args.output_prefix}-calendar.png"
plot_calendar(activities, output_file=outfile)
print(f"Saved to {outfile}")

print("Plotting dumbbell...")
outfile = f"{args.output_prefix}-dumbbell.png"
plot_dumbbell(activities, output_file=outfile)
Expand Down
37 changes: 21 additions & 16 deletions src/stravavis/plot_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,40 @@
import matplotlib.pyplot as plt
import pandas as pd


ACTIVITY_FORMAT = "%b %d, %Y, %H:%M:%S %p"

def plot_calendar(activities, year_min=None, year_max=None, max_dist=None,
fig_height = 15, fig_width = 9, output_file='calendar.png'):

def plot_calendar(
activities,
year_min=None,
year_max=None,
max_dist=None,
fig_height=15,
fig_width=9,
output_file="calendar.png",
):
# Create a new figure
plt.figure()

# Process data
activities["Activity Date"] = pd.to_datetime(
activities["Activity Date"], format=ACTIVITY_FORMAT
)
activities['date'] = activities['Activity Date'].dt.date
activities = activities.groupby(['date'])['Distance'].sum()
activities["date"] = activities["Activity Date"].dt.date
activities = activities.groupby(["date"])["Distance"].sum()
activities.index = pd.to_datetime(activities.index)
activities.clip(0, max_dist, inplace=True)

if year_min:
activities = activities[activities.index.year>=year_min]
activities = activities[activities.index.year >= year_min]

if year_max:
activities = activities[activities.index.year<=year_max]
activities = activities[activities.index.year <= year_max]

# Create heatmap
fig, ax = calmap.calendarplot(
data = activities
)

fig, ax = calmap.calendarplot(data=activities)

# Save plot
fig.set_figheight(fig_height)
fig.set_figwidth(fig_width)
fig.savefig(output_file, dpi = 600)
fig.savefig(output_file, dpi=600)
Loading