Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ strava
*.pyc
*.osm
*.pkl
.DS_Store
.env
29 changes: 25 additions & 4 deletions download.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
activities_url = "https://www.strava.com/athlete/training_activities"
gpx_url = "https://www.strava.com/activities/{id}/export_gpx"
activity_txt = "activities.txt"
skipped_txt = "skipped.txt"
rogue_txt = "rogue.txt"


def get_activity_ids(sess, current_list=None):
Expand Down Expand Up @@ -71,10 +73,24 @@ def get_activity_ids(sess, current_list=None):
if not os.path.exists(args.output_dir):
os.mkdir(args.output_dir)


old_skipped = []
skipped_file = os.path.join(args.output_dir, skipped_txt)
if os.path.exists(skipped_file):
with open(skipped_file, "r") as f:
old_skipped.extend([l.strip() for l in f.readlines()])

rogue = []
rogue_file = os.path.join(args.output_dir, rogue_txt)
if os.path.exists(rogue_file):
with open(rogue_file, "r") as f:
rogue.extend([l.strip() for l in f.readlines()])

email = input("email> ")
password = getpass.getpass("password> ")

skipped = []

with requests.session() as sess:
page = sess.get(login_url)
html = lxml.html.fromstring(page.text)
Expand All @@ -97,7 +113,12 @@ def get_activity_ids(sess, current_list=None):
for count, identifier in enumerate(activity_ids, 1):
if count % 20 == 0:
print(f"({count}/{len(activity_ids)})")

if identifier in old_skipped:
print(">> data doesn't look like gpx, skipping")
continue
if identifier in rogue:
print(">>> data is rogue, skipping")
continue
output = os.path.join(args.output_dir, f"{identifier}.gpx")
if not os.path.exists(output):
print(f"downloading activity {identifier} to {output}")
Expand All @@ -115,7 +136,7 @@ def get_activity_ids(sess, current_list=None):
print("found an existing gpx file, exiting")
sys.exit(0)

fname = os.path.join(args.output_dir, "skipped.txt")
print(f"writing skipped activity list to {fname}")
with open(fname, "w") as f:

print(f"writing skipped activity list to {skipped_file}")
with open(skipped_file, "a") as f:
f.write("\n".join(skipped))
9 changes: 5 additions & 4 deletions draw.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
import osm

# TODO: move to argparse
use_osm = True
osm_color = "salmon"
osm_line_width = .1
osm_alpha = .5


def plot(data, background_color, line_width, line_color, line_alpha, dpi, label=0):
def plot(data, background_color, line_width, line_color, line_alpha, dpi, use_osm, label=0):
if line_color.startswith("cmap:"):
use_cmap = True
max_elev = max([max(d["elevs"]) for d in data])
Expand Down Expand Up @@ -156,6 +155,8 @@ def add_shared_args(parser):
help="if defined only include this activity type")
parser.add_argument("--gpx-dir", default="strava",
help="directory with gpx files")
parser.add_argument("--use-osm", default=False, action="store_true",
help="overlay heatmap on top of OpenStreetMap")
Copy link
Owner

Choose a reason for hiding this comment

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

+1



parser = ArgumentParser()
Expand All @@ -179,7 +180,7 @@ def add_shared_args(parser):

args = parser.parse_args()

plot_keys = ["background_color", "line_color", "line_width", "line_alpha", "dpi"]
plot_keys = ["background_color", "line_color", "line_width", "line_alpha", "dpi", "use_osm"]
plot_args = {k: getattr(args, k) for k in plot_keys}

cache_path = os.path.join(args.gpx_dir, "cache.pkl")
Expand Down Expand Up @@ -216,7 +217,7 @@ def add_shared_args(parser):
coords = np.array([[np.average(d["lats"][0]), np.average(d["lons"][0])] for d in data])

if args.type == "cluster":
cluster = DBSCAN(eps=args.radius, min_samples=10)
cluster = DBSCAN(eps=args.radius, min_samples=args.min_cluster_size)
Copy link
Owner

Choose a reason for hiding this comment

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

+1

cluster.fit(coords)
n_clusters = np.max(cluster.labels_) + 1
centroids = [np.mean(coords[cluster.labels_ == l], axis=0) for l in range(n_clusters)]
Expand Down
48 changes: 48 additions & 0 deletions rogue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#!/usr/bin/env python3
from glob import glob
from gpxpy import parse
from math import atan2, cos, radians, sin, sqrt
import multiprocessing
import os

def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = radians(lat2-lat1)
dlon = radians(lon2-lon1)
a = sin(dlat/2) * sin(dlat/2) + cos(radians(lat1)) \
* cos(radians(lat2)) * sin(dlon/2) * sin(dlon/2)
c = 2 * atan2(sqrt(a), sqrt(1-a))
d = radius * c
return d


def disjointed(filename, max_jump=1):
gpx_file = open(filename, 'r')
gpx = parse(gpx_file)
for i in range(len(gpx.tracks[0].segments[0].points)-1):
p1 = gpx.tracks[0].segments[0].points[i]
p2 = gpx.tracks[0].segments[0].points[i+1]
d = distance((p1.latitude, p1.longitude), (p2.latitude, p2.longitude))
if d > max_jump:
return filename
return None


def main():
files = glob("strava/*.gpx")
p = multiprocessing.Pool(multiprocessing.cpu_count())
results = p.map(disjointed, files)
bad = [r for r in results if r]
if len(bad) > 0:
with open("strava/rogue.txt", "a") as f:
for b in bad:
print(f"deleting {b}")
os.remove(b)
i = b.split(".")[0].split("/")[1]
f.write(f"\n{i}")
os.remove("strava/cache.pkl")

if __name__ == '__main__':
main()