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

added plot_map #2

Merged
merged 1 commit into from
Feb 6, 2022
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
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ A plot of activities as small multiples. The concept behind this plot was origin

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

### Map

A map of activities viewed in plan.

![map](https://github.com/marcusvolz/strava_py/blob/main/plots/map001.png "A map of activities viewed in plan.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: remove full stop to match the facets alt text.

Suggested change
![map](https://github.com/marcusvolz/strava_py/blob/main/plots/map001.png "A map of activities viewed in plan.")
![map](https://github.com/marcusvolz/strava_py/blob/main/plots/map001.png "A map of activities viewed in plan")


## How to use

### Bulk export from Strava
Expand Down Expand Up @@ -38,3 +44,10 @@ df = process_data(<path to folder with GPX and / or FIT files>)
```python
plot_facets(df, output_file = 'plot.png')
```

### Plot activity map

```python
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")
```
Binary file added plots/map001.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions src/strava_py/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ def main():
parser.add_argument(
"-o", "--output_file", default="plot.png", help="Output PNG file"
)
parser.add_argument("lon_min", default=None, help="Minimum longitude for plot_map (values less than this are removed from the data)")
parser.add_argument("lon_max", default=None, help="Maximum longitude for plot_map (values greater than this are removed from the data)")
parser.add_argument("lat_min", default=None, help="Minimum latitude for plot_map (values less than this are removed from the data)")
parser.add_argument("lat_max", default=None, help="Maximum latitude for plot_map (values greater than this are removed from the data)")
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")
Comment on lines +12 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Include -- prefixes otherwise it complains about:

usage: strava_py [-h] [-o OUTPUT_FILE] path lon_min lon_max lat_min lat_max alpha linewidth
strava_py: error: the following arguments are required: lon_min, lon_max, lat_min, lat_max, alpha, linewidth
Suggested change
parser.add_argument("lon_min", default=None, help="Minimum longitude for plot_map (values less than this are removed from the data)")
parser.add_argument("lon_max", default=None, help="Maximum longitude for plot_map (values greater than this are removed from the data)")
parser.add_argument("lat_min", default=None, help="Minimum latitude for plot_map (values less than this are removed from the data)")
parser.add_argument("lat_max", default=None, help="Maximum latitude for plot_map (values greater than this are removed from the data)")
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("--lon_min", default=None, help="Minimum longitude for plot_map (values less than this are removed from the data)")
parser.add_argument("--lon_max", default=None, help="Maximum longitude for plot_map (values greater than this are removed from the data)")
parser.add_argument("--lat_min", default=None, help="Minimum latitude for plot_map (values less than this are removed from the data)")
parser.add_argument("--lat_max", default=None, help="Maximum latitude for plot_map (values greater than this are removed from the data)")
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")

args = parser.parse_args()

# Normally imports go at the top, but scientific libraries can be slow to import
# so let's validate arguments first
from strava_py.plot_map import plot_map
from strava_py.plot_facets import plot_facets
from strava_py.process_data import process_data
Comment on lines +22 to 24
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: alphabetical order helps as number of imports grows:

Suggested change
from strava_py.plot_map import plot_map
from strava_py.plot_facets import plot_facets
from strava_py.process_data import process_data
from strava_py.plot_facets import plot_facets
from strava_py.plot_map import plot_map
from strava_py.process_data import process_data


Expand All @@ -23,6 +30,10 @@ def main():
plot_facets(df, output_file=args.output_file)
print(f"Saved to {args.output_file}")

print("Plotting map...")
plot_facets(df, output_file=args.output_file)
print(f"Saved to {args.output_file}")
Comment on lines +34 to +35
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call plot_map and also pass the CLI args:

Suggested change
plot_facets(df, output_file=args.output_file)
print(f"Saved to {args.output_file}")
plot_map(
df,
lon_min=args.lon_min,
lon_max=args.lon_max,
lat_min=args.lat_min,
lat_max=args.lat_max,
alpha=args.alpha,
linewidth=args.linewidth,
output_file=args.output_file,
)
print(f"Saved to {args.output_file}")

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're also re-using args.output_file and therefore writing over the facets image.

Some options:

  • Remove the argument entirely
  • Add a second one for the map plot
  • Change the argument to be a prefix instead (e.g. strava), and we append -facets.png and -map.png

I think the third, as there may be more visualisations added soon, and it will be useful to be able to have different names for different runs (for example, I might generate output for each year of activities, or summer vs. winter).



if __name__ == "__main__":
main()
34 changes: 34 additions & 0 deletions src/strava_py/plot_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import matplotlib.pyplot as plt

def 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"):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults are 0.3 here and 0.4 for the CLI. Should they be the same?


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Turns out we need to explicitly create a new figure here and same place in plot_facets:

Suggested change
# Create a new figure
plt.figure()

Otherwise the map plot is like this -- a facet plot with the map in the last slot:

image

# Remove data outside the input ranges for lon / lat
if lon_min is not None:
df = df[df['lon'] >= lon_min]

if lon_max is not None:
df = df[df['lon'] <= lon_max]

if lat_min is not None:
df = df[df['lat'] >= lat_min]

if lat_max is not None:
df = df[df['lat'] <= lat_max]

# Create a list of activity names
activities = df['name'].unique()
n = len(activities)

# Plot activities one by one
for i in range(n):
X = df[df['name'] == activities[i]]['lon']
Y = df[df['name'] == activities[i]]['lat']
plt.plot(X, Y, color = 'black', alpha = alpha, linewidth = linewidth)

# Update plot aesthetics
plt.axis('off')
plt.axis('equal')
plt.margins(0)
plt.subplots_adjust(left = 0.05, right = 0.95, bottom = 0.05, top = 0.95)
plt.savefig(output_file, dpi = 600)