geo-activity-playground 0.33.4__tar.gz → 0.34.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/PKG-INFO +1 -1
  2. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/strava_checkout.py +8 -2
  3. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/blueprint.py +7 -0
  4. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/controller.py +85 -15
  5. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/templates/activity/day.html.j2 +5 -1
  6. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/equipment/controller.py +1 -1
  7. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/summary/controller.py +11 -10
  8. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/pyproject.toml +1 -1
  9. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/LICENSE +0 -0
  10. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/__init__.py +0 -0
  11. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/__main__.py +0 -0
  12. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/__init__.py +0 -0
  13. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/activities.py +0 -0
  14. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/config.py +0 -0
  15. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/coordinates.py +0 -0
  16. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/enrichment.py +0 -0
  17. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/heart_rate.py +0 -0
  18. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/heatmap.py +0 -0
  19. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/paths.py +0 -0
  20. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/privacy_zones.py +0 -0
  21. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/similarity.py +0 -0
  22. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/tasks.py +0 -0
  23. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/test_tiles.py +0 -0
  24. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/test_time_conversion.py +0 -0
  25. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/tiles.py +0 -0
  26. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/core/time_conversion.py +0 -0
  27. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/explorer/__init__.py +0 -0
  28. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/explorer/grid_file.py +0 -0
  29. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/explorer/tile_visits.py +0 -0
  30. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/explorer/video.py +0 -0
  31. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/__init__.py +0 -0
  32. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/activity_parsers.py +0 -0
  33. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/csv_parser.py +0 -0
  34. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/directory.py +0 -0
  35. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/strava_api.py +0 -0
  36. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/test_csv_parser.py +0 -0
  37. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/test_directory.py +0 -0
  38. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/importers/test_strava_api.py +0 -0
  39. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/__init__.py +0 -0
  40. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/__init__.py +0 -0
  41. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/templates/activity/edit.html.j2 +0 -0
  42. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/templates/activity/lines.html.j2 +0 -0
  43. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/templates/activity/name.html.j2 +0 -0
  44. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/activity/templates/activity/show.html.j2 +0 -0
  45. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/app.py +0 -0
  46. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/auth/blueprint.py +0 -0
  47. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/auth/templates/auth/index.html.j2 +0 -0
  48. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/authenticator.py +0 -0
  49. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/calendar/__init__.py +0 -0
  50. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/calendar/blueprint.py +0 -0
  51. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/calendar/controller.py +0 -0
  52. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/calendar/templates/calendar/index.html.j2 +0 -0
  53. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/calendar/templates/calendar/month.html.j2 +0 -0
  54. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/eddington/__init__.py +0 -0
  55. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/eddington/blueprint.py +0 -0
  56. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/eddington/controller.py +0 -0
  57. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/eddington/templates/eddington/index.html.j2 +0 -0
  58. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/entry_controller.py +0 -0
  59. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/equipment/__init__.py +0 -0
  60. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/equipment/blueprint.py +0 -0
  61. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/equipment/templates/equipment/index.html.j2 +0 -0
  62. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/explorer/__init__.py +0 -0
  63. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/explorer/blueprint.py +0 -0
  64. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/explorer/controller.py +0 -0
  65. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/explorer/templates/explorer/index.html.j2 +0 -0
  66. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/heatmap/__init__.py +0 -0
  67. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/heatmap/blueprint.py +0 -0
  68. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/heatmap/heatmap_controller.py +0 -0
  69. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/heatmap/templates/heatmap/index.html.j2 +0 -0
  70. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/plot_util.py +0 -0
  71. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/search/blueprint.py +0 -0
  72. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/search/templates/search/index.html.j2 +0 -0
  73. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/blueprint.py +0 -0
  74. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/controller.py +0 -0
  75. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/admin-password.html.j2 +0 -0
  76. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/color-schemes.html.j2 +0 -0
  77. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2 +0 -0
  78. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/heart-rate.html.j2 +0 -0
  79. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/index.html.j2 +0 -0
  80. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/kind-renames.html.j2 +0 -0
  81. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2 +0 -0
  82. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/metadata-extraction.html.j2 +0 -0
  83. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/privacy-zones.html.j2 +0 -0
  84. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/segmentation.html.j2 +0 -0
  85. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/sharepic.html.j2 +0 -0
  86. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/settings/templates/settings/strava.html.j2 +0 -0
  87. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/square_planner/__init__.py +0 -0
  88. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/square_planner/blueprint.py +0 -0
  89. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/square_planner/controller.py +0 -0
  90. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/square_planner/templates/square_planner/index.html.j2 +0 -0
  91. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/android-chrome-192x192.png +0 -0
  92. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/android-chrome-512x512.png +0 -0
  93. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/apple-touch-icon.png +0 -0
  94. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/bootstrap-dark-mode.js +0 -0
  95. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/browserconfig.xml +0 -0
  96. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/favicon-16x16.png +0 -0
  97. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/favicon-32x32.png +0 -0
  98. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/favicon-48x48.png +0 -0
  99. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/favicon.ico +0 -0
  100. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/favicon.svg +0 -0
  101. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/mstile-150x150.png +0 -0
  102. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/site.webmanifest +0 -0
  103. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/web-app-manifest-192x192.png +0 -0
  104. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/static/web-app-manifest-512x512.png +0 -0
  105. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/summary/__init__.py +0 -0
  106. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/summary/blueprint.py +0 -0
  107. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/summary/templates/summary/index.html.j2 +0 -0
  108. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/templates/home.html.j2 +0 -0
  109. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/templates/page.html.j2 +0 -0
  110. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/templates/upload/index.html.j2 +0 -0
  111. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/templates/upload/reload.html.j2 +0 -0
  112. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/tile/__init__.py +0 -0
  113. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/tile/blueprint.py +0 -0
  114. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/tile/controller.py +0 -0
  115. {geo_activity_playground-0.33.4 → geo_activity_playground-0.34.0}/geo_activity_playground/webui/upload_blueprint.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geo-activity-playground
3
- Version: 0.33.4
3
+ Version: 0.34.0
4
4
  Summary: Analysis of geo data activities like rides, runs or hikes.
5
5
  License: MIT
6
6
  Author: Martin Ueding
@@ -146,7 +146,7 @@ def float_with_comma_or_period(x: str) -> Optional[float]:
146
146
 
147
147
  def import_from_strava_checkout() -> None:
148
148
  checkout_path = pathlib.Path("Strava Export")
149
- with open(checkout_path / "activities.csv") as f:
149
+ with open(checkout_path / "activities.csv", encoding="utf-8") as f:
150
150
  rows = parse_csv(f.read())
151
151
  header = rows[0]
152
152
 
@@ -159,9 +159,15 @@ def import_from_strava_checkout() -> None:
159
159
 
160
160
  if header[0] == EXPECTED_COLUMNS[0]:
161
161
  dayfirst = False
162
- if header[0] == "Aktivitäts-ID":
162
+ elif header[0] == "Aktivitäts-ID":
163
163
  header = EXPECTED_COLUMNS
164
164
  dayfirst = True
165
+ else:
166
+ logger.error(
167
+ f"You are trying to import a Strava checkout where the `activities.csv` contains an unexpected header format. In order to import this, we need to map these to the English ones. Unfortunately Strava often changes the number of columns. This means that the program needs to be updated to match the new Strava export format. Please go to https://github.com/martin-ueding/geo-activity-playground/issues and open a new issue and share the following output in the ticket:"
168
+ )
169
+ print(header)
170
+ sys.exit(1)
165
171
 
166
172
  table = {
167
173
  header[i]: [rows[r][i] for r in range(1, len(rows))] for i in range(len(header))
@@ -55,6 +55,13 @@ def make_activity_blueprint(
55
55
  **activity_controller.render_day(int(year), int(month), int(day)),
56
56
  )
57
57
 
58
+ @blueprint.route("/day-sharepic/<year>/<month>/<day>/sharepic.png")
59
+ def day_sharepic(year: str, month: str, day: str):
60
+ return Response(
61
+ activity_controller.render_day_sharepic(int(year), int(month), int(day)),
62
+ mimetype="image/png",
63
+ )
64
+
58
65
  @blueprint.route("/name/<name>")
59
66
  def name(name: str):
60
67
  return render_template(
@@ -170,8 +170,24 @@ class ActivityController:
170
170
  "date": datetime.date(year, month, day).isoformat(),
171
171
  "total_distance": activities_that_day["distance_km"].sum(),
172
172
  "total_elapsed_time": activities_that_day["elapsed_time"].sum(),
173
+ "day": day,
174
+ "month": month,
175
+ "year": year,
173
176
  }
174
177
 
178
+ def render_day_sharepic(self, year: int, month: int, day: int) -> bytes:
179
+ meta = self._repository.meta
180
+ selection = meta["start"].dt.date == datetime.date(year, month, day)
181
+ activities_that_day = meta.loc[selection]
182
+
183
+ time_series = [
184
+ self._repository.get_time_series(activity_id)
185
+ for activity_id in activities_that_day["id"]
186
+ ]
187
+ assert len(activities_that_day) > 0
188
+ assert len(time_series) > 0
189
+ return (make_day_sharepic(activities_that_day, time_series, self._config),)
190
+
175
191
  def render_all(self) -> dict:
176
192
  cmap = matplotlib.colormaps["Dark2"]
177
193
  fc = geojson.FeatureCollection(
@@ -452,14 +468,10 @@ def pixels_in_bounds(bounds: PixelBounds) -> int:
452
468
  return (bounds.x_max - bounds.x_min) * (bounds.y_max - bounds.y_min)
453
469
 
454
470
 
455
- def make_sharepic(
456
- activity: ActivityMeta,
457
- time_series: pd.DataFrame,
458
- sharepic_suppressed_fields: list[str],
459
- config: Config,
460
- ) -> bytes:
461
- tile_x = time_series["x"]
462
- tile_y = time_series["y"]
471
+ def make_sharepic_base(time_series_list: list[pd.DataFrame], config: Config):
472
+ all_time_series = pd.concat(time_series_list)
473
+ tile_x = all_time_series["x"]
474
+ tile_y = all_time_series["y"]
463
475
  tile_width = tile_x.max() - tile_x.min()
464
476
  tile_height = tile_y.max() - tile_y.min()
465
477
 
@@ -495,16 +507,32 @@ def make_sharepic(
495
507
  img = Image.fromarray((background * 255).astype("uint8"), "RGB")
496
508
  draw = ImageDraw.Draw(img, mode="RGBA")
497
509
 
498
- for _, group in time_series.groupby("segment_id"):
499
- yx = list(
500
- zip(
501
- (tile_xz - tile_xz_center[0]) * OSM_TILE_SIZE + target_width / 2,
502
- (tile_yz - tile_xz_center[1]) * OSM_TILE_SIZE + target_map_height / 2,
510
+ for time_series in time_series_list:
511
+ for _, group in time_series.groupby("segment_id"):
512
+ yx = list(
513
+ zip(
514
+ (tile_xz - tile_xz_center[0]) * OSM_TILE_SIZE + target_width / 2,
515
+ (tile_yz - tile_xz_center[1]) * OSM_TILE_SIZE
516
+ + target_map_height / 2,
517
+ )
503
518
  )
504
- )
505
519
 
506
- draw.line(yx, fill="red", width=4)
520
+ draw.line(yx, fill="red", width=4)
521
+
522
+ return img
523
+
507
524
 
525
+ def make_sharepic(
526
+ activity: ActivityMeta,
527
+ time_series: pd.DataFrame,
528
+ sharepic_suppressed_fields: list[str],
529
+ config: Config,
530
+ ) -> bytes:
531
+ footer_height = 100
532
+
533
+ img = make_sharepic_base([time_series], config)
534
+
535
+ draw = ImageDraw.Draw(img, mode="RGBA")
508
536
  draw.rectangle(
509
537
  [0, img.height - footer_height, img.width, img.height], fill=(0, 0, 0, 180)
510
538
  )
@@ -545,6 +573,48 @@ def make_sharepic(
545
573
  return bytes(f.getbuffer())
546
574
 
547
575
 
576
+ def make_day_sharepic(
577
+ activities: pd.DataFrame,
578
+ time_series_list: list[pd.DataFrame],
579
+ config: Config,
580
+ ) -> bytes:
581
+ footer_height = 100
582
+
583
+ img = make_sharepic_base(time_series_list, config)
584
+
585
+ draw = ImageDraw.Draw(img, mode="RGBA")
586
+ draw.rectangle(
587
+ [0, img.height - footer_height, img.width, img.height], fill=(0, 0, 0, 180)
588
+ )
589
+
590
+ date = activities.iloc[0]["start"].date()
591
+ distance_km = activities["distance_km"].sum()
592
+ elapsed_time: pd.Timedelta = activities["elapsed_time"].sum()
593
+ elapsed_time = elapsed_time.round("s")
594
+
595
+ facts = {
596
+ "date": f"{date}",
597
+ "distance_km": f"{distance_km:.1f} km",
598
+ "elapsed_time": re.sub(r"^0 days ", "", f"{elapsed_time}"),
599
+ }
600
+
601
+ draw.text(
602
+ (35, img.height - footer_height + 10),
603
+ " ".join(facts.values()),
604
+ font_size=20,
605
+ )
606
+
607
+ draw.text(
608
+ (img.width - 250, img.height - 20),
609
+ "Map: © Open Street Map Contributors",
610
+ font_size=14,
611
+ )
612
+
613
+ f = io.BytesIO()
614
+ img.save(f, format="png")
615
+ return bytes(f.getbuffer())
616
+
617
+
548
618
  def _extract_heart_rate_zones(
549
619
  time_series: pd.DataFrame, heart_rate_zone_computer: HeartRateZoneComputer
550
620
  ) -> Optional[pd.DataFrame]:
@@ -30,7 +30,7 @@
30
30
  <ol>
31
31
  {% for activity in activities %}
32
32
  <li><span style="color: {{ activity['color'] }};">█</span> <a
33
- href="{{ url_for('activity.show', id=activity.id) }}">{{
33
+ href="{{ url_for('.show', id=activity.id) }}">{{
34
34
  activity.name }}</a></li>
35
35
  {% endfor %}
36
36
  </ol>
@@ -80,4 +80,8 @@
80
80
  </div>
81
81
  </div>
82
82
 
83
+ <h2>Share picture</h2>
84
+
85
+ <p><img src="{{ url_for('.day_sharepic', year=year, month=month, day=day) }}" /></p>
86
+
83
87
  {% endblock %}
@@ -87,7 +87,7 @@ class EquipmentController:
87
87
  )
88
88
  .mark_bar()
89
89
  .encode(
90
- alt.X("kind", title="Year"),
90
+ alt.X("kind", title="Kind"),
91
91
  alt.Y("sum(distance_km)", title="Distance / km"),
92
92
  )
93
93
  .to_json(format="vega")
@@ -105,6 +105,7 @@ def embellished_activities(meta: pd.DataFrame) -> pd.DataFrame:
105
105
  df["month"] = [start.month for start in df["start"]]
106
106
  df["day"] = [start.day for start in df["start"]]
107
107
  df["week"] = [start.isocalendar().week for start in df["start"]]
108
+ df["iso_year"] = [start.isocalendar().year for start in df["start"]]
108
109
  df["hours"] = [
109
110
  elapsed_time.total_seconds() / 3600 for elapsed_time in df["elapsed_time"]
110
111
  ]
@@ -188,8 +189,8 @@ def plot_yearly_distance(year_kind_total: pd.DataFrame, kind_scale: alt.Scale) -
188
189
 
189
190
  def plot_year_cumulative(df: pd.DataFrame) -> str:
190
191
  year_cumulative = (
191
- df[["year", "week", "distance_km"]]
192
- .groupby("year")
192
+ df[["iso_year", "week", "distance_km"]]
193
+ .groupby("iso_year")
193
194
  .apply(
194
195
  lambda group: pd.DataFrame(
195
196
  {"week": group["week"], "distance_km": group["distance_km"].cumsum()}
@@ -205,10 +206,10 @@ def plot_year_cumulative(df: pd.DataFrame) -> str:
205
206
  .encode(
206
207
  alt.X("week", title="Week"),
207
208
  alt.Y("distance_km", title="Distance / km"),
208
- alt.Color("year:N", title="Year"),
209
+ alt.Color("iso_year:N", title="Year"),
209
210
  [
210
211
  alt.Tooltip("week", title="Week"),
211
- alt.Tooltip("year:N", title="Year"),
212
+ alt.Tooltip("iso_year:N", title="Year"),
212
213
  alt.Tooltip("distance_km", title="Distance / km"),
213
214
  ],
214
215
  )
@@ -234,26 +235,26 @@ def tabulate_year_kind_mean(df: pd.DataFrame) -> pd.DataFrame:
234
235
 
235
236
  def plot_weekly_distance(df: pd.DataFrame, kind_scale: alt.Scale) -> str:
236
237
  week_kind_total_distance = (
237
- df[["year", "week", "kind", "distance_km"]]
238
- .groupby(["year", "week", "kind"])
238
+ df[["iso_year", "week", "kind", "distance_km"]]
239
+ .groupby(["iso_year", "week", "kind"])
239
240
  .sum()
240
241
  .reset_index()
241
242
  )
242
243
  week_kind_total_distance["year_week"] = [
243
244
  f"{year}-{week:02d}"
244
245
  for year, week in zip(
245
- week_kind_total_distance["year"], week_kind_total_distance["week"]
246
+ week_kind_total_distance["iso_year"], week_kind_total_distance["week"]
246
247
  )
247
248
  ]
248
249
 
249
- last_year = week_kind_total_distance["year"].iloc[-1]
250
+ last_year = week_kind_total_distance["iso_year"].iloc[-1]
250
251
  last_week = week_kind_total_distance["week"].iloc[-1]
251
252
 
252
253
  return (
253
254
  alt.Chart(
254
255
  week_kind_total_distance.loc[
255
- (week_kind_total_distance["year"] == last_year)
256
- | (week_kind_total_distance["year"] == last_year - 1)
256
+ (week_kind_total_distance["iso_year"] == last_year)
257
+ | (week_kind_total_distance["iso_year"] == last_year - 1)
257
258
  & (week_kind_total_distance["week"] >= last_week)
258
259
  ],
259
260
  title="Weekly Distance",
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "geo-activity-playground"
3
- version = "0.33.4"
3
+ version = "0.34.0"
4
4
  description = "Analysis of geo data activities like rides, runs or hikes."
5
5
  authors = ["Martin Ueding <mu@martin-ueding.de>"]
6
6
  license = "MIT"