geo-activity-playground 1.9.3__tar.gz → 1.10.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 (182) hide show
  1. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/PKG-INFO +1 -1
  2. geo_activity_playground-1.10.0/geo_activity_playground/alembic/versions/10021d238ada_add_explorer_tile_bookmarks.py +32 -0
  3. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/datamodel.py +13 -0
  4. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/parametric_plot.py +16 -0
  5. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/explorer/tile_visits.py +5 -0
  6. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/directory.py +43 -3
  7. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/strava_checkout.py +11 -3
  8. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/explorer_blueprint.py +41 -4
  9. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/settings_blueprint.py +24 -0
  10. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/server-side-explorer.js +6 -1
  11. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/explorer/server-side.html.j2 +11 -0
  12. geo_activity_playground-1.10.0/geo_activity_playground/webui/templates/settings/cluster-bookmarks-new.html.j2 +29 -0
  13. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/pyproject.toml +1 -1
  14. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/LICENSE +0 -0
  15. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/__init__.py +0 -0
  16. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/__main__.py +0 -0
  17. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/README +0 -0
  18. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/env.py +0 -0
  19. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/script.py.mako +0 -0
  20. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/0f02b92c4f94_add_tag_color.py +0 -0
  21. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +0 -0
  22. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +0 -0
  23. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +0 -0
  24. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/85fe0348e8a2_add_time_series_uuid_field.py +0 -0
  25. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/93cc82ad1b60_add_parametricplotspec.py +0 -0
  26. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +0 -0
  27. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +0 -0
  28. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/da2cba03b71d_add_photos.py +0 -0
  29. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/dc8073871da7_add_plotspec_group_by.py +0 -0
  30. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +0 -0
  31. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/f2f50843be2d_make_all_fields_in_activity_nullable.py +0 -0
  32. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/alembic/versions/script.py.mako +0 -0
  33. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/__init__.py +0 -0
  34. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/activities.py +0 -0
  35. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/config.py +0 -0
  36. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/coordinates.py +0 -0
  37. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/copernicus_dem.py +0 -0
  38. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/enrichment.py +0 -0
  39. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/export.py +0 -0
  40. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/heart_rate.py +0 -0
  41. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/meta_search.py +0 -0
  42. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/missing_values.py +0 -0
  43. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/paths.py +0 -0
  44. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/photos.py +0 -0
  45. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/privacy_zones.py +0 -0
  46. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/raster_map.py +0 -0
  47. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/similarity.py +0 -0
  48. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/summary_stats.py +0 -0
  49. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/tasks.py +0 -0
  50. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_datamodel.py +0 -0
  51. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_meta_search.py +0 -0
  52. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_missing_values.py +0 -0
  53. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_pandas_timezone.py +0 -0
  54. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_summary_stats.py +0 -0
  55. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_tiles.py +0 -0
  56. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_time_zone_from_location.py +0 -0
  57. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_time_zone_import.py +0 -0
  58. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/test_timezone_sqlalchemy.py +0 -0
  59. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/tiles.py +0 -0
  60. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/core/time_conversion.py +0 -0
  61. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/explorer/__init__.py +0 -0
  62. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/explorer/grid_file.py +0 -0
  63. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/explorer/video.py +0 -0
  64. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/heatmap_video.py +0 -0
  65. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/__init__.py +0 -0
  66. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/activity_parsers.py +0 -0
  67. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/csv_parser.py +0 -0
  68. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/strava_api.py +0 -0
  69. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/test_csv_parser.py +0 -0
  70. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/test_directory.py +0 -0
  71. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/importers/test_strava_api.py +0 -0
  72. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/__init__.py +0 -0
  73. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/app.py +0 -0
  74. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/authenticator.py +0 -0
  75. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/__init__.py +0 -0
  76. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/activity_blueprint.py +0 -0
  77. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/auth_blueprint.py +0 -0
  78. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +0 -0
  79. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/calendar_blueprint.py +0 -0
  80. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/eddington_blueprints.py +0 -0
  81. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/entry_views.py +0 -0
  82. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/equipment_blueprint.py +0 -0
  83. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/export_blueprint.py +0 -0
  84. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py +0 -0
  85. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/heatmap_blueprint.py +0 -0
  86. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/photo_blueprint.py +0 -0
  87. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +0 -0
  88. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/search_blueprint.py +0 -0
  89. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/square_planner_blueprint.py +0 -0
  90. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/summary_blueprint.py +0 -0
  91. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/tile_blueprint.py +0 -0
  92. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/time_zone_fixer_blueprint.py +0 -0
  93. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/blueprints/upload_blueprint.py +0 -0
  94. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/columns.py +0 -0
  95. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/flasher.py +0 -0
  96. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/plot_util.py +0 -0
  97. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/search_util.py +0 -0
  98. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/activity-trim.js +0 -0
  99. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/bootstrap/bootstrap-dark-mode.js +0 -0
  100. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/bootstrap/bootstrap.bundle.min.js +0 -0
  101. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/bootstrap/bootstrap.min.css +0 -0
  102. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/android-chrome-192x192.png +0 -0
  103. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/android-chrome-512x512.png +0 -0
  104. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/apple-touch-icon.png +0 -0
  105. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/browserconfig.xml +0 -0
  106. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/favicon-16x16.png +0 -0
  107. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/favicon-32x32.png +0 -0
  108. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/favicon-48x48.png +0 -0
  109. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/favicon.ico +0 -0
  110. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/favicon.svg +0 -0
  111. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/mstile-150x150.png +0 -0
  112. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/site.webmanifest +0 -0
  113. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/web-app-manifest-192x192.png +0 -0
  114. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/favicons/web-app-manifest-512x512.png +0 -0
  115. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/images/layers-2x.png +0 -0
  116. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/images/layers.png +0 -0
  117. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
  118. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/images/marker-icon.png +0 -0
  119. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
  120. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/Leaflet.fullscreen.min.js +0 -0
  121. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/MarkerCluster.Default.css +0 -0
  122. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/MarkerCluster.css +0 -0
  123. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/fullscreen.png +0 -0
  124. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/fullscreen@2x.png +0 -0
  125. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/images/layers-2x.png +0 -0
  126. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/images/layers.png +0 -0
  127. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/leaflet.css +0 -0
  128. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/leaflet.fullscreen.css +0 -0
  129. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/leaflet.js +0 -0
  130. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/leaflet/leaflet.markercluster.js +0 -0
  131. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/table-sort.min.js +0 -0
  132. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/vega/vega-embed@6.js +0 -0
  133. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/vega/vega-lite@4.js +0 -0
  134. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/static/vega/vega@5.js +0 -0
  135. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/day.html.j2 +0 -0
  136. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/edit.html.j2 +0 -0
  137. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/lines.html.j2 +0 -0
  138. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/name.html.j2 +0 -0
  139. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/show.html.j2 +0 -0
  140. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/activity/trim.html.j2 +0 -0
  141. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/auth/index.html.j2 +0 -0
  142. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +0 -0
  143. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/calendar/index.html.j2 +0 -0
  144. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/calendar/month.html.j2 +0 -0
  145. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/eddington/distance.html.j2 +0 -0
  146. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +0 -0
  147. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +0 -0
  148. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/equipment/index.html.j2 +0 -0
  149. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/export/index.html.j2 +0 -0
  150. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/hall_of_fame/index.html.j2 +0 -0
  151. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/heatmap/index.html.j2 +0 -0
  152. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/home.html.j2 +0 -0
  153. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/page.html.j2 +0 -0
  154. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/photo/map.html.j2 +0 -0
  155. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/photo/new.html.j2 +0 -0
  156. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/plot-macros.html.j2 +0 -0
  157. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/plot_builder/edit.html.j2 +0 -0
  158. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/plot_builder/import-spec.html.j2 +0 -0
  159. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/plot_builder/index.html.j2 +0 -0
  160. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/search/index.html.j2 +0 -0
  161. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/search_form.html.j2 +0 -0
  162. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/admin-password.html.j2 +0 -0
  163. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/color-schemes.html.j2 +0 -0
  164. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/heart-rate.html.j2 +0 -0
  165. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/index.html.j2 +0 -0
  166. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +0 -0
  167. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +0 -0
  168. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/metadata-extraction.html.j2 +0 -0
  169. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/privacy-zones.html.j2 +0 -0
  170. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/segmentation.html.j2 +0 -0
  171. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/sharepic.html.j2 +0 -0
  172. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/strava.html.j2 +0 -0
  173. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/tags-edit.html.j2 +0 -0
  174. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/tags-list.html.j2 +0 -0
  175. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/tags-new.html.j2 +0 -0
  176. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/settings/tile-source.html.j2 +0 -0
  177. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/square_planner/index.html.j2 +0 -0
  178. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/summary/index.html.j2 +0 -0
  179. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/summary/vega-chart.html.j2 +0 -0
  180. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/time_zone_fixer/index.html.j2 +0 -0
  181. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/upload/index.html.j2 +0 -0
  182. {geo_activity_playground-1.9.3 → geo_activity_playground-1.10.0}/geo_activity_playground/webui/templates/upload/reload.html.j2 +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: geo-activity-playground
3
- Version: 1.9.3
3
+ Version: 1.10.0
4
4
  Summary: Analysis of geo data activities like rides, runs or hikes.
5
5
  License: MIT
6
6
  Author: Martin Ueding
@@ -0,0 +1,32 @@
1
+ from typing import Sequence
2
+ from typing import Union
3
+
4
+ import sqlalchemy as sa
5
+ from alembic import op
6
+
7
+
8
+ # revision identifiers, used by Alembic.
9
+ revision: str = "10021d238ada"
10
+ down_revision: Union[str, None] = "85fe0348e8a2"
11
+ branch_labels: Union[str, Sequence[str], None] = None
12
+ depends_on: Union[str, Sequence[str], None] = None
13
+
14
+
15
+ def upgrade() -> None:
16
+ # ### commands auto generated by Alembic - please adjust! ###
17
+ op.create_table(
18
+ "explorer_tile_bookmarks",
19
+ sa.Column("id", sa.Integer(), nullable=False),
20
+ sa.Column("name", sa.String(), nullable=False),
21
+ sa.Column("zoom", sa.Integer(), nullable=False),
22
+ sa.Column("tile_x", sa.Integer(), nullable=False),
23
+ sa.Column("tile_y", sa.Integer(), nullable=False),
24
+ sa.PrimaryKeyConstraint("id"),
25
+ )
26
+ # ### end Alembic commands ###
27
+
28
+
29
+ def downgrade() -> None:
30
+ # ### commands auto generated by Alembic - please adjust! ###
31
+ op.drop_table("explorer_tile_bookmarks")
32
+ # ### end Alembic commands ###
@@ -497,3 +497,16 @@ class Photo(DB.Model):
497
497
  @property
498
498
  def path(self) -> pathlib.Path:
499
499
  return pathlib.Path(self.filename)
500
+
501
+
502
+ class ExplorerTileBookmark(DB.Model):
503
+ __tablename__ = "explorer_tile_bookmarks"
504
+ id: Mapped[int] = mapped_column(primary_key=True)
505
+
506
+ name: Mapped[str] = mapped_column(sa.String, nullable=False)
507
+ zoom: Mapped[int] = mapped_column(sa.Integer, nullable=False)
508
+ tile_x: Mapped[int] = mapped_column(sa.Integer, nullable=False)
509
+ tile_y: Mapped[int] = mapped_column(sa.Integer, nullable=False)
510
+
511
+ def __str__(self) -> str:
512
+ return f"{self.name} ({self.tile_x}, {self.tile_y}) @ {self.zoom}"
@@ -66,8 +66,24 @@ GROUP_BY_VARIABLES = {
66
66
  VARIABLES_1 = {"": "", **DISCRETE_VARIABLES}
67
67
  VARIABLES_2 = {"": "", **DISCRETE_VARIABLES, **CONTINUOUS_VARIABLES}
68
68
 
69
+ RENAMES = {
70
+ "year(start):O": "year(start_local):O",
71
+ "yearquarter(start)": "yearquarter(start_local)",
72
+ "yearquartermonth(start)": "yearquartermonth(start_local)",
73
+ "yearmonth(start)": "yearmonth(start_local)",
74
+ "quarter(start)": "quarter(start_local)",
75
+ "quartermonth(start)": "quartermonth(start_local)",
76
+ "month(start)": "month(start_local)",
77
+ "date(start)": "date(start_local)",
78
+ "weekday(start)": "weekday(start_local)",
79
+ }
80
+
69
81
 
70
82
  def make_parametric_plot(df: pd.DataFrame, spec: PlotSpec) -> dict[str, str]:
83
+ # Update renamed fields.
84
+ for field in spec.FIELDS:
85
+ setattr(spec, field, RENAMES.get(getattr(spec, field), getattr(spec, field)))
86
+
71
87
  if spec.group_by:
72
88
  grouped = df.groupby(spec.group_by)
73
89
  else:
@@ -76,8 +76,13 @@ class TileHistoryRow(TypedDict):
76
76
  class TileEvolutionState:
77
77
  def __init__(self) -> None:
78
78
  self.num_neighbors: dict[tuple[int, int], int] = {}
79
+ "Mapping from tile to the number of its neighbors."
80
+
79
81
  self.memberships: dict[tuple[int, int], tuple[int, int]] = {}
82
+ "Mapping from tile to the representative tile."
80
83
  self.clusters: dict[tuple[int, int], list[tuple[int, int]]] = {}
84
+ "Mapping from representative tile to the list of all cluster members."
85
+
81
86
  self.cluster_evolution = pd.DataFrame()
82
87
  self.square_start = 0
83
88
  self.cluster_start = 0
@@ -1,3 +1,4 @@
1
+ import hashlib
1
2
  import logging
2
3
  import pathlib
3
4
  import re
@@ -51,6 +52,17 @@ def import_from_directory(
51
52
  is None
52
53
  ]
53
54
 
55
+ for activity in DB.session.scalars(
56
+ sqlalchemy.select(Activity).filter(
57
+ Activity.upstream_id.is_(sqlalchemy.null()),
58
+ Activity.path.is_not(sqlalchemy.null()),
59
+ )
60
+ ):
61
+ assert activity.path is not None
62
+ if pathlib.Path(activity.path).exists():
63
+ activity.upstream_id = file_sha256(pathlib.Path(activity.path))
64
+ DB.session.commit()
65
+
54
66
  for i, activity_path in enumerate(
55
67
  tqdm(paths_to_import, desc="Importing activity files", delay=0)
56
68
  ):
@@ -58,10 +70,24 @@ def import_from_directory(
58
70
  activity = DB.session.scalar(
59
71
  sqlalchemy.select(Activity).filter(Activity.path == str(activity_path))
60
72
  )
61
- if activity is None:
62
- import_from_file(
63
- activity_path, repository, tile_visit_accessor, config, i
73
+ if activity is not None:
74
+ continue
75
+
76
+ with_same_hash = DB.session.scalars(
77
+ sqlalchemy.select(Activity).filter(
78
+ Activity.upstream_id == file_sha256(activity_path)
64
79
  )
80
+ ).all()
81
+ if with_same_hash:
82
+ if len(with_same_hash) == 1:
83
+ continue
84
+ else:
85
+ logger.warning(
86
+ "The following activities are duplicates: "
87
+ + ", ".join(str(activity.id) for activity in with_same_hash)
88
+ )
89
+
90
+ import_from_file(activity_path, repository, tile_visit_accessor, config, i)
65
91
 
66
92
 
67
93
  def import_from_file(
@@ -87,6 +113,7 @@ def import_from_file(
87
113
  return
88
114
 
89
115
  activity.path = str(path)
116
+ activity.upstream_id = file_sha256(path)
90
117
  if activity.name is None:
91
118
  activity.name = path.name.removesuffix("".join(path.suffixes))
92
119
 
@@ -120,3 +147,16 @@ def _get_metadata_from_path(
120
147
  if m := re.search(regex, str(path.relative_to(ACTIVITY_DIR))):
121
148
  return m.groupdict()
122
149
  return {}
150
+
151
+
152
+ def file_sha256(filename: pathlib.Path) -> str:
153
+ """
154
+ Based on https://stackoverflow.com/a/44873382/653152.
155
+ """
156
+ h = hashlib.sha256(usedforsecurity=False)
157
+ b = bytearray(128 * 1024)
158
+ mv = memoryview(b)
159
+ with open(filename, "rb", buffering=0) as f:
160
+ while n := f.readinto(mv):
161
+ h.update(mv[:n])
162
+ return h.hexdigest()
@@ -19,8 +19,6 @@ from ..core.datamodel import get_or_make_equipment
19
19
  from ..core.datamodel import get_or_make_kind
20
20
  from ..core.enrichment import update_and_commit
21
21
  from ..core.paths import activity_extracted_meta_dir
22
- from ..core.tasks import get_state
23
- from ..core.tasks import set_state
24
22
  from ..core.tasks import work_tracker_path
25
23
  from ..core.tasks import WorkTracker
26
24
  from .activity_parsers import ActivityParseError
@@ -132,6 +130,11 @@ EXPECTED_COLUMNS = [
132
130
  "Average Grade Adjusted Pace",
133
131
  "Timer Time",
134
132
  "Total Cycles",
133
+ "Regeneration",
134
+ "Mit Haustier",
135
+ "Wettbewerb",
136
+ "Langer Lauf",
137
+ "Für einen guten Zweck",
135
138
  "Media",
136
139
  ]
137
140
 
@@ -161,7 +164,12 @@ def import_from_strava_checkout(config: Config) -> None:
161
164
  if header[0] == EXPECTED_COLUMNS[0]:
162
165
  dayfirst = False
163
166
  elif header[0] == "Aktivitäts-ID":
164
- header = EXPECTED_COLUMNS
167
+ new_header = list(EXPECTED_COLUMNS)
168
+ if len(new_header) > len(header):
169
+ new_header = new_header[: len(header)]
170
+ elif len(new_header) < len(header):
171
+ new_header += [f"Ignored_{i}" for i in range(len(header) - len(new_header))]
172
+ header = new_header
165
173
  dayfirst = True
166
174
  else:
167
175
  logger.error(
@@ -4,6 +4,7 @@ import hashlib
4
4
  import io
5
5
  import logging
6
6
  from collections.abc import Iterable
7
+ from typing import Any
7
8
  from typing import Optional
8
9
  from typing import Union
9
10
 
@@ -13,6 +14,7 @@ import matplotlib
13
14
  import matplotlib.pyplot as pl
14
15
  import numpy as np
15
16
  import pandas as pd
17
+ import sqlalchemy
16
18
  from flask import Blueprint
17
19
  from flask import flash
18
20
  from flask import redirect
@@ -26,6 +28,7 @@ from ...core.config import ConfigAccessor
26
28
  from ...core.coordinates import Bounds
27
29
  from ...core.datamodel import Activity
28
30
  from ...core.datamodel import DB
31
+ from ...core.datamodel import ExplorerTileBookmark
29
32
  from ...core.raster_map import ImageTransform
30
33
  from ...core.raster_map import OSM_TILE_SIZE
31
34
  from ...core.raster_map import TileGetter
@@ -237,6 +240,27 @@ def make_explorer_blueprint(
237
240
  medians["tile_x"], medians["tile_y"], zoom
238
241
  )
239
242
 
243
+ bookmarks: list[dict[str, Any]] = []
244
+ for bookmark in DB.session.scalars(
245
+ sqlalchemy.select(ExplorerTileBookmark).where(
246
+ ExplorerTileBookmark.zoom == zoom
247
+ )
248
+ ).all():
249
+ tile = (bookmark.tile_x, bookmark.tile_y)
250
+ representative = tile_evolution_state.memberships.get(tile, None)
251
+ if not representative:
252
+ continue
253
+ cluster = tile_evolution_state.clusters.get(representative, None)
254
+ if not cluster:
255
+ continue
256
+ bookmarks.append(
257
+ {
258
+ "name": bookmark.name,
259
+ "bbox": geojson_bounding_box_for_tile_collection(cluster, zoom),
260
+ "size": len(cluster),
261
+ }
262
+ )
263
+
240
264
  context = {
241
265
  "center": {
242
266
  "latitude": median_lat,
@@ -263,6 +287,7 @@ def make_explorer_blueprint(
263
287
  "square_y": tile_evolution_state.square_y,
264
288
  "square_size": tile_evolution_state.max_square_size,
265
289
  "max_cluster_size": max(map(len, tile_evolution_state.clusters.values())),
290
+ "bookmarks": bookmarks,
266
291
  }
267
292
  return render_template("explorer/server-side.html.j2", **context)
268
293
 
@@ -450,6 +475,12 @@ def make_explorer_blueprint(
450
475
  evolution_state.memberships.get(tile_xy, None), []
451
476
  )
452
477
  ),
478
+ "new_bookmark_url": url_for(
479
+ "settings.cluster_bookmark_new",
480
+ zoom=zoom,
481
+ tile_x=tile_xy[0],
482
+ tile_y=tile_xy[1],
483
+ ),
453
484
  }
454
485
  else:
455
486
  result = {}
@@ -462,10 +493,16 @@ def bounding_box_for_biggest_cluster(
462
493
  clusters: Iterable[list[tuple[int, int]]], zoom: int
463
494
  ) -> str:
464
495
  biggest_cluster = max(clusters, key=lambda members: len(members))
465
- min_x = min(x for x, y in biggest_cluster)
466
- max_x = max(x for x, y in biggest_cluster)
467
- min_y = min(y for x, y in biggest_cluster)
468
- max_y = max(y for x, y in biggest_cluster)
496
+ return geojson_bounding_box_for_tile_collection(biggest_cluster, zoom)
497
+
498
+
499
+ def geojson_bounding_box_for_tile_collection(
500
+ tiles: list[tuple[int, int]], zoom: int
501
+ ) -> str:
502
+ min_x = min(x for x, y in tiles)
503
+ max_x = max(x for x, y in tiles)
504
+ min_y = min(y for x, y in tiles)
505
+ max_y = max(y for x, y in tiles)
469
506
  lat_max, lon_min = get_tile_upper_left_lat_lon(min_x, min_y, zoom)
470
507
  lat_min, lon_max = get_tile_upper_left_lat_lon(max_x, max_y, zoom)
471
508
  return geojson.dumps(
@@ -18,6 +18,7 @@ from ...core.config import ConfigAccessor
18
18
  from ...core.datamodel import Activity
19
19
  from ...core.datamodel import DB
20
20
  from ...core.datamodel import Equipment
21
+ from ...core.datamodel import ExplorerTileBookmark
21
22
  from ...core.datamodel import Kind
22
23
  from ...core.datamodel import Tag
23
24
  from ...core.enrichment import update_and_commit
@@ -110,6 +111,29 @@ def make_settings_blueprint(
110
111
  )
111
112
  )
112
113
 
114
+ @blueprint.route("/cluster-bookmarks/new", methods=["GET", "POST"])
115
+ @needs_authentication(authenticator)
116
+ def cluster_bookmark_new():
117
+ if request.method == "POST":
118
+ bm = ExplorerTileBookmark(
119
+ name=request.form["name"],
120
+ zoom=int(request.form["zoom"]),
121
+ tile_x=int(request.form["tile_x"]),
122
+ tile_y=int(request.form["tile_y"]),
123
+ )
124
+ DB.session.add(bm)
125
+ DB.session.commit()
126
+ return redirect(
127
+ url_for("explorer.server_side", zoom=int(request.form["zoom"]))
128
+ )
129
+ else:
130
+ return render_template(
131
+ "settings/cluster-bookmarks-new.html.j2",
132
+ zoom=request.args["zoom"],
133
+ tile_x=request.args["tile_x"],
134
+ tile_y=request.args["tile_y"],
135
+ )
136
+
113
137
  @blueprint.route("/color-schemes", methods=["GET", "POST"])
114
138
  @needs_authentication(authenticator)
115
139
  def color_schemes():
@@ -84,6 +84,7 @@ map.on('click', e => {
84
84
  ]
85
85
  if (data.this_cluster_size) {
86
86
  lines.push(`<dt>This cluster size</dt><dd>${data.this_cluster_size}</dd>`)
87
+ lines.push(`<dt>Bookmark</dt><dd><a href="${data.new_bookmark_url}">Create cluster bookmark</a></dd>`)
87
88
  }
88
89
 
89
90
  L.popup()
@@ -97,4 +98,8 @@ map.on('click', e => {
97
98
  function downloadAs(suffix) {
98
99
  bounds = map.getBounds();
99
100
  window.location.href = `/explorer/${zoom}/${bounds.getNorth()}/${bounds.getEast()}/${bounds.getSouth()}/${bounds.getWest()}/${suffix}`
100
- }
101
+ }
102
+
103
+ function centerOn(bbox) {
104
+ map.fitBounds(L.geoJSON(bbox).getBounds())
105
+ }
@@ -24,6 +24,17 @@
24
24
  </div>
25
25
  </div>
26
26
 
27
+ {% if bookmarks %}
28
+ <div class="btn-group mb-3" role="group" aria-label="Cluster bookmarks">
29
+ <button type="button" class="btn btn-primary" onclick='centerOn({{ center.bbox | safe }})'>Biggest ({{
30
+ max_cluster_size }})</button>
31
+ {% for bookmark in bookmarks %}
32
+ <button type="button" class="btn btn-primary" onclick='centerOn({{ bookmark.bbox | safe }})'>{{ bookmark.name }} ({{
33
+ bookmark.size }})</button>
34
+ {% endfor %}
35
+ </div>
36
+ {% endif %}
37
+
27
38
  <div class="row mb-3">
28
39
  <div class="col">
29
40
  <div id="explorer-map" class="mb-1" style="height: 800px;"></div>
@@ -0,0 +1,29 @@
1
+ {% extends "page.html.j2" %}
2
+
3
+ {% block container %}
4
+
5
+ <h1 class="mb-3">Create Explorer Tile Cluster Bookmark</h1>
6
+
7
+ <form method="POST">
8
+ <div class="mb-3">
9
+ <label for="name" class="form-label">Name</label>
10
+ <input type="text" class="form-control" id="name" name="name" />
11
+ </div>
12
+ <div class="mb-3">
13
+ <label for="zoom" class="form-label">Zoom</label>
14
+ <input type="number" class="form-control" id="zoom" name="zoom" value="{{ zoom }}" />
15
+ </div>
16
+ <div class="mb-3">
17
+ <label for="tile_x" class="form-label">Tile X</label>
18
+ <input type="number" class="form-control" id="tile_x" name="tile_x" value="{{ tile_x }}" />
19
+ </div>
20
+ <div class="mb-3">
21
+ <label for="tile_y" class="form-label">Tile Y</label>
22
+ <input type="number" class="form-control" id="tile_y" name="tile_y" value="{{ tile_y }}" />
23
+ </div>
24
+
25
+ <button type="submit" class="btn btn-primary">Create</button>
26
+ </form>
27
+
28
+
29
+ {% endblock %}
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "geo-activity-playground"
3
- version = "1.9.3"
3
+ version = "1.10.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"