geo-activity-playground 1.0.0__tar.gz → 1.1.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.
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/PKG-INFO +1 -1
- geo_activity_playground-1.1.0/geo_activity_playground/alembic/versions/dc8073871da7_add_plotspec_group_by.py +28 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/config.py +1 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/datamodel.py +9 -0
- geo_activity_playground-1.1.0/geo_activity_playground/core/parametric_plot.py +162 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/app.py +7 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/activity_blueprint.py +11 -10
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/auth_blueprint.py +3 -2
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +2 -1
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/calendar_blueprint.py +3 -2
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/eddington_blueprints.py +3 -2
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/entry_views.py +11 -11
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/equipment_blueprint.py +2 -1
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/explorer_blueprint.py +47 -13
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/export_blueprint.py +3 -2
- geo_activity_playground-1.1.0/geo_activity_playground/webui/blueprints/hall_of_fame_blueprint.py +79 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/plot_builder_blueprint.py +38 -19
- geo_activity_playground-1.1.0/geo_activity_playground/webui/blueprints/summary_blueprint.py +211 -0
- geo_activity_playground-1.1.0/geo_activity_playground/webui/columns.py +70 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/browserconfig.xml +1 -1
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/site.webmanifest +2 -2
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/server-side-explorer.js +7 -2
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/name.html.j2 +4 -4
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/show.html.j2 +8 -8
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/eddington/distance.html.j2 +3 -3
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +3 -3
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +3 -3
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/equipment/index.html.j2 +1 -1
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/explorer/server-side.html.j2 +5 -4
- geo_activity_playground-1.1.0/geo_activity_playground/webui/templates/hall_of_fame/index.html.j2 +58 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/home.html.j2 +1 -4
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/page.html.j2 +23 -37
- geo_activity_playground-1.1.0/geo_activity_playground/webui/templates/plot-macros.html.j2 +72 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/plot_builder/edit.html.j2 +12 -7
- geo_activity_playground-1.1.0/geo_activity_playground/webui/templates/plot_builder/import-spec.html.j2 +24 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/plot_builder/index.html.j2 +5 -0
- geo_activity_playground-1.1.0/geo_activity_playground/webui/templates/summary/index.html.j2 +50 -0
- geo_activity_playground-1.1.0/geo_activity_playground/webui/templates/summary/vega-chart.html.j2 +3 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/pyproject.toml +1 -1
- geo_activity_playground-1.0.0/geo_activity_playground/core/parametric_plot.py +0 -108
- geo_activity_playground-1.0.0/geo_activity_playground/webui/blueprints/summary_blueprint.py +0 -337
- geo_activity_playground-1.0.0/geo_activity_playground/webui/columns.py +0 -37
- geo_activity_playground-1.0.0/geo_activity_playground/webui/templates/summary/index.html.j2 +0 -257
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/LICENSE +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/__main__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/README +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/env.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/script.py.mako +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/0f02b92c4f94_add_tag_color.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/451e7836b53d_add_square_planner_bookmark.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/63d3b7f6f93c_initial_version.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/93cc82ad1b60_add_parametricplotspec.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/ab83b9d23127_add_upstream_id.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/b03491c593f6_add_crop_indices.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/da2cba03b71d_add_photos.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/e02e27876deb_add_square_planner_bookmark_name.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/alembic/versions/script.py.mako +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/activities.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/coordinates.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/enrichment.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/export.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/heart_rate.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/meta_search.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/missing_values.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/paths.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/privacy_zones.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/raster_map.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/similarity.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/summary_stats.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/tasks.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_datamodel.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_meta_search.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_missing_values.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_summary_stats.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_tiles.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/test_time_conversion.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/tiles.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/core/time_conversion.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/explorer/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/explorer/grid_file.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/explorer/tile_visits.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/explorer/video.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/heatmap_video.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/activity_parsers.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/csv_parser.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/directory.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/strava_api.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/strava_checkout.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/test_csv_parser.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/test_directory.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/importers/test_strava_api.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/authenticator.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/__init__.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/heatmap_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/photo_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/search_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/settings_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/square_planner_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/tile_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/blueprints/upload_blueprint.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/flasher.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/plot_util.py +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/search_util.py +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/bootstrap}/bootstrap-dark-mode.js +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/bootstrap}/bootstrap.bundle.min.js +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/bootstrap}/bootstrap.min.css +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/android-chrome-192x192.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/android-chrome-512x512.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/apple-touch-icon.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/favicon-16x16.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/favicon-32x32.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/favicon-48x48.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/favicon.ico +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/favicon.svg +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/mstile-150x150.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/web-app-manifest-192x192.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/favicons}/web-app-manifest-512x512.png +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/images/layers-2x.png +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/images/layers.png +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/images/marker-icon-2x.png +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/images/marker-icon.png +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/images/marker-shadow.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/Leaflet.fullscreen.min.js +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/MarkerCluster.Default.css +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/MarkerCluster.css +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/fullscreen.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/fullscreen@2x.png +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/leaflet.css +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/leaflet.fullscreen.css +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/leaflet.js +0 -0
- {geo_activity_playground-1.0.0/geo_activity_playground/webui/static → geo_activity_playground-1.1.0/geo_activity_playground/webui/static/leaflet}/leaflet.markercluster.js +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/static/table-sort.min.js +0 -0
- /geo_activity_playground-1.0.0/geo_activity_playground/webui/static/vega-embed@6 → /geo_activity_playground-1.1.0/geo_activity_playground/webui/static/vega/vega-embed@6.js +0 -0
- /geo_activity_playground-1.0.0/geo_activity_playground/webui/static/vega-lite@4 → /geo_activity_playground-1.1.0/geo_activity_playground/webui/static/vega/vega-lite@4.js +0 -0
- /geo_activity_playground-1.0.0/geo_activity_playground/webui/static/vega@5 → /geo_activity_playground-1.1.0/geo_activity_playground/webui/static/vega/vega@5.js +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/day.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/edit.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/lines.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/activity/trim.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/auth/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/calendar/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/calendar/month.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/export/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/heatmap/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/photo/map.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/photo/new.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/search/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/search_form.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/admin-password.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/color-schemes.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/heart-rate.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/manage-equipments.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/manage-kinds.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/metadata-extraction.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/privacy-zones.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/segmentation.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/sharepic.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/strava.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/tags-edit.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/tags-list.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/settings/tags-new.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/square_planner/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/upload/index.html.j2 +0 -0
- {geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/templates/upload/reload.html.j2 +0 -0
@@ -0,0 +1,28 @@
|
|
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 = "dc8073871da7"
|
10
|
+
down_revision: Union[str, None] = "0f02b92c4f94"
|
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
|
+
with op.batch_alter_table("plot_specs", schema=None) as batch_op:
|
18
|
+
batch_op.add_column(sa.Column("group_by", sa.String(), nullable=True))
|
19
|
+
|
20
|
+
# ### end Alembic commands ###
|
21
|
+
|
22
|
+
|
23
|
+
def downgrade() -> None:
|
24
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
25
|
+
with op.batch_alter_table("plot_specs", schema=None) as batch_op:
|
26
|
+
batch_op.drop_column("group_by")
|
27
|
+
|
28
|
+
# ### end Alembic commands ###
|
@@ -21,6 +21,7 @@ logger = logging.getLogger(__name__)
|
|
21
21
|
@dataclasses.dataclass
|
22
22
|
class Config:
|
23
23
|
birth_year: Optional[int] = None
|
24
|
+
cluster_color_strategy: str = "colorful_cluster"
|
24
25
|
color_scheme_for_counts: str = "teals"
|
25
26
|
color_scheme_for_kind: str = "category10"
|
26
27
|
color_scheme_for_heatmap: str = "hot"
|
@@ -231,6 +231,9 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
231
231
|
df = pd.DataFrame(rows)
|
232
232
|
# If the search yields only activities without time information, the dtype isn't derived correctly.
|
233
233
|
df["start"] = pd.to_datetime(df["start"])
|
234
|
+
# start = df["start"].to_list()
|
235
|
+
# random.shuffle(start)
|
236
|
+
# df["start"] = pd.Series(start)
|
234
237
|
df["elapsed_time"] = pd.to_timedelta(df["elapsed_time"])
|
235
238
|
|
236
239
|
if len(df):
|
@@ -251,8 +254,12 @@ def query_activity_meta(clauses: list = []) -> pd.DataFrame:
|
|
251
254
|
df["week"] = df["start"].dt.isocalendar().week
|
252
255
|
df["day_of_week"] = df["start"].dt.day_of_week
|
253
256
|
df["iso_year"] = df["start"].dt.isocalendar().year
|
257
|
+
df["iso_day"] = df["start"].dt.isocalendar().day
|
254
258
|
df["hours"] = df["elapsed_time"].dt.total_seconds() / 3_600
|
255
259
|
df["hours_moving"] = df["moving_time"].dt.total_seconds() / 3_600
|
260
|
+
df["iso_year_week"] = [
|
261
|
+
f"{year:04d}-{week:02d}" for year, week in zip(df["iso_year"], df["week"])
|
262
|
+
]
|
256
263
|
|
257
264
|
df.index = df["id"]
|
258
265
|
|
@@ -365,6 +372,7 @@ class PlotSpec(DB.Model):
|
|
365
372
|
opacity: Mapped[str] = mapped_column(sa.String, nullable=False, default="")
|
366
373
|
column: Mapped[str] = mapped_column(sa.String, nullable=False, default="")
|
367
374
|
facet: Mapped[str] = mapped_column(sa.String, nullable=False, default="")
|
375
|
+
group_by: Mapped[str] = mapped_column(sa.String, nullable=True, default="")
|
368
376
|
|
369
377
|
FIELDS = [
|
370
378
|
"name",
|
@@ -378,6 +386,7 @@ class PlotSpec(DB.Model):
|
|
378
386
|
"opacity",
|
379
387
|
"column",
|
380
388
|
"facet",
|
389
|
+
"group_by",
|
381
390
|
]
|
382
391
|
|
383
392
|
def __str__(self) -> str:
|
@@ -0,0 +1,162 @@
|
|
1
|
+
import altair as alt
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
from .datamodel import PlotSpec
|
5
|
+
|
6
|
+
|
7
|
+
MARKS = {
|
8
|
+
"point": "Point",
|
9
|
+
"circle": "Circle",
|
10
|
+
"area": "Area",
|
11
|
+
"bar": "Bar",
|
12
|
+
"rect": "Rectangle",
|
13
|
+
"line": "Line",
|
14
|
+
}
|
15
|
+
CONTINUOUS_VARIABLES = {
|
16
|
+
"distance_km": "Distance / km",
|
17
|
+
"distance_km_cumsum": "Cumulative Distance / km",
|
18
|
+
"sum(distance_km)": "Total distance / km",
|
19
|
+
"mean(distance_km)": "Average distance / km",
|
20
|
+
"start": "Date",
|
21
|
+
"hours": "Elapsed time / h",
|
22
|
+
"hours_moving": "Moving time / h",
|
23
|
+
"calories": "Energy / kcal",
|
24
|
+
"steps": "Steps",
|
25
|
+
"elevation_gain": "Elevation gain / m",
|
26
|
+
"start_elevation": "Start elevation / m",
|
27
|
+
"end_elevation": "End elevation / m",
|
28
|
+
"sum(elevation_gain)": "Total elevation gain / m",
|
29
|
+
"mean(elevation_gain)": "Average elevation gain / m",
|
30
|
+
"num_new_tiles_14": "New tiles 14",
|
31
|
+
"num_new_tiles_14": "New tiles 17",
|
32
|
+
"average_speed_moving_kmh": "Average moving speed / km/h",
|
33
|
+
"average_speed_elapsed_kmh": "Average elapsed speed / km/h",
|
34
|
+
"start_latitude": "Start latitude / °",
|
35
|
+
"start_longitude": "Start longitude / °",
|
36
|
+
"end_latitude": "End latitude / °",
|
37
|
+
"end_longitude": "End longitude / °",
|
38
|
+
}
|
39
|
+
DISCRETE_VARIABLES = {
|
40
|
+
"equipment": "Equipment",
|
41
|
+
"kind": "Activity kind",
|
42
|
+
"consider_for_achievements": "Consider for achievements",
|
43
|
+
"year(start):O": "Year",
|
44
|
+
"iso_year:O": "ISO Year",
|
45
|
+
"yearquarter(start)": "Year, Quarter",
|
46
|
+
"yearquartermonth(start)": "Year, Quarter, Month",
|
47
|
+
"yearmonth(start)": "Year, Month",
|
48
|
+
"quarter(start)": "Quarter",
|
49
|
+
"quartermonth(start)": "Quarter, Month",
|
50
|
+
"month(start)": "Month",
|
51
|
+
"week:O": "ISO Week",
|
52
|
+
"date(start)": "Day of month",
|
53
|
+
"weekday(start)": "Day of week",
|
54
|
+
"iso_day:O": "ISO Day",
|
55
|
+
}
|
56
|
+
GROUP_BY_VARIABLES = {
|
57
|
+
"": "(no grouping)",
|
58
|
+
"equipment": "Equipment",
|
59
|
+
"kind": "Activity kind",
|
60
|
+
"consider_for_achievements": "Consider for achievements",
|
61
|
+
"year": "Year",
|
62
|
+
"iso_year": "ISO Year",
|
63
|
+
"week": "ISO Week",
|
64
|
+
}
|
65
|
+
|
66
|
+
VARIABLES_1 = {"": "", **DISCRETE_VARIABLES}
|
67
|
+
VARIABLES_2 = {"": "", **DISCRETE_VARIABLES, **CONTINUOUS_VARIABLES}
|
68
|
+
|
69
|
+
|
70
|
+
def make_parametric_plot(df: pd.DataFrame, spec: PlotSpec) -> dict[str, str]:
|
71
|
+
if spec.group_by:
|
72
|
+
grouped = df.groupby(spec.group_by)
|
73
|
+
else:
|
74
|
+
grouped = [("", df)]
|
75
|
+
|
76
|
+
chart_groups = {}
|
77
|
+
for key, group in grouped:
|
78
|
+
chart = alt.Chart(group)
|
79
|
+
|
80
|
+
match spec.mark:
|
81
|
+
case "point":
|
82
|
+
chart = chart.mark_point()
|
83
|
+
case "circle":
|
84
|
+
chart = chart.mark_circle()
|
85
|
+
case "area":
|
86
|
+
chart = chart.mark_area()
|
87
|
+
case "bar":
|
88
|
+
chart = chart.mark_bar()
|
89
|
+
case "rect":
|
90
|
+
chart = chart.mark_rect()
|
91
|
+
case "line":
|
92
|
+
chart = chart.mark_line()
|
93
|
+
case _:
|
94
|
+
raise ValueError()
|
95
|
+
|
96
|
+
if spec.mark in ["area", "line"]:
|
97
|
+
group_by_variables = [
|
98
|
+
var.split(":")[0]
|
99
|
+
for var in [
|
100
|
+
spec.color,
|
101
|
+
spec.shape,
|
102
|
+
spec.size,
|
103
|
+
spec.opacity,
|
104
|
+
spec.row,
|
105
|
+
spec.column,
|
106
|
+
spec.facet,
|
107
|
+
]
|
108
|
+
if var
|
109
|
+
]
|
110
|
+
for column in ["distance_km"]:
|
111
|
+
group[column + "_cumsum"] = (
|
112
|
+
group[group_by_variables + [column]]
|
113
|
+
.groupby(group_by_variables)
|
114
|
+
.cumsum()
|
115
|
+
)
|
116
|
+
|
117
|
+
encodings = [
|
118
|
+
(
|
119
|
+
alt.X(spec.x, type="ordinal", title=VARIABLES_2[spec.x])
|
120
|
+
if spec.mark == "rect"
|
121
|
+
else alt.X(spec.x, title=VARIABLES_2[spec.x])
|
122
|
+
),
|
123
|
+
(
|
124
|
+
alt.Y(spec.y, type="ordinal", title=VARIABLES_2[spec.y])
|
125
|
+
if spec.mark == "rect"
|
126
|
+
else alt.Y(spec.y, title=VARIABLES_2[spec.y])
|
127
|
+
),
|
128
|
+
]
|
129
|
+
tooltips = [
|
130
|
+
alt.Tooltip(spec.x, title=VARIABLES_2[spec.x]),
|
131
|
+
alt.Tooltip(spec.y, title=VARIABLES_2[spec.y]),
|
132
|
+
]
|
133
|
+
|
134
|
+
if spec.color:
|
135
|
+
encodings.append(alt.Color(spec.color, title=VARIABLES_2[spec.color]))
|
136
|
+
tooltips.append(alt.Tooltip(spec.color, title=VARIABLES_2[spec.color]))
|
137
|
+
if spec.shape:
|
138
|
+
encodings.append(alt.Shape(spec.shape, title=VARIABLES_2[spec.shape]))
|
139
|
+
tooltips.append(alt.Tooltip(spec.shape, title=VARIABLES_2[spec.shape]))
|
140
|
+
if spec.size:
|
141
|
+
encodings.append(alt.Size(spec.size, title=VARIABLES_2[spec.size]))
|
142
|
+
tooltips.append(alt.Tooltip(spec.size, title=VARIABLES_2[spec.size]))
|
143
|
+
if spec.opacity:
|
144
|
+
encodings.append(alt.Opacity(spec.opacity, title=VARIABLES_2[spec.opacity]))
|
145
|
+
tooltips.append(alt.Tooltip(spec.opacity, title=VARIABLES_2[spec.opacity]))
|
146
|
+
if spec.row:
|
147
|
+
encodings.append(alt.Row(spec.row, title=VARIABLES_2[spec.row]))
|
148
|
+
tooltips.append(alt.Tooltip(spec.row, title=VARIABLES_2[spec.row]))
|
149
|
+
if spec.column:
|
150
|
+
encodings.append(alt.Column(spec.column, title=VARIABLES_2[spec.column]))
|
151
|
+
tooltips.append(alt.Tooltip(spec.column, title=VARIABLES_2[spec.column]))
|
152
|
+
if spec.facet:
|
153
|
+
encodings.append(
|
154
|
+
alt.Facet(spec.facet, columns=3, title=VARIABLES_2[spec.facet])
|
155
|
+
)
|
156
|
+
tooltips.append(alt.Tooltip(spec.facet, title=VARIABLES_2[spec.facet]))
|
157
|
+
|
158
|
+
key = str(int(key) if isinstance(key, float) else key)
|
159
|
+
chart_groups[key] = (
|
160
|
+
chart.encode(*encodings, tooltips).interactive().to_json(format="vega")
|
161
|
+
)
|
162
|
+
return chart_groups
|
{geo_activity_playground-1.0.0 → geo_activity_playground-1.1.0}/geo_activity_playground/webui/app.py
RENAMED
@@ -7,6 +7,7 @@ import pathlib
|
|
7
7
|
import secrets
|
8
8
|
import shutil
|
9
9
|
import urllib.parse
|
10
|
+
import uuid
|
10
11
|
|
11
12
|
import pandas as pd
|
12
13
|
import sqlalchemy
|
@@ -39,6 +40,7 @@ from .blueprints.entry_views import register_entry_views
|
|
39
40
|
from .blueprints.equipment_blueprint import make_equipment_blueprint
|
40
41
|
from .blueprints.explorer_blueprint import make_explorer_blueprint
|
41
42
|
from .blueprints.export_blueprint import make_export_blueprint
|
43
|
+
from .blueprints.hall_of_fame_blueprint import make_hall_of_fame_blueprint
|
42
44
|
from .blueprints.heatmap_blueprint import make_heatmap_blueprint
|
43
45
|
from .blueprints.photo_blueprint import make_photo_blueprint
|
44
46
|
from .blueprints.plot_builder_blueprint import make_plot_builder_blueprint
|
@@ -112,6 +114,10 @@ def web_ui_main(
|
|
112
114
|
else:
|
113
115
|
return value.strftime("%Y-%m-%d %H:%M")
|
114
116
|
|
117
|
+
@app.template_global("unique_id")
|
118
|
+
def unique_id():
|
119
|
+
return f"id-{uuid.uuid4()}"
|
120
|
+
|
115
121
|
@app.template_filter()
|
116
122
|
def td(v: datetime.timedelta):
|
117
123
|
if pd.isna(v):
|
@@ -162,6 +168,7 @@ def web_ui_main(
|
|
162
168
|
image_transforms,
|
163
169
|
),
|
164
170
|
"/export": make_export_blueprint(authenticator),
|
171
|
+
"/hall-of-fame": make_hall_of_fame_blueprint(repository, search_query_history),
|
165
172
|
"/heatmap": make_heatmap_blueprint(
|
166
173
|
repository, tile_visit_accessor, config_accessor(), search_query_history
|
167
174
|
),
|
@@ -18,6 +18,7 @@ from flask import render_template
|
|
18
18
|
from flask import request
|
19
19
|
from flask import Response
|
20
20
|
from flask import url_for
|
21
|
+
from flask.typing import ResponseReturnValue
|
21
22
|
from PIL import Image
|
22
23
|
from PIL import ImageDraw
|
23
24
|
|
@@ -59,7 +60,7 @@ def make_activity_blueprint(
|
|
59
60
|
blueprint = Blueprint("activity", __name__, template_folder="templates")
|
60
61
|
|
61
62
|
@blueprint.route("/all")
|
62
|
-
def all():
|
63
|
+
def all() -> ResponseReturnValue:
|
63
64
|
cmap = matplotlib.colormaps["Dark2"]
|
64
65
|
fc = geojson.FeatureCollection(
|
65
66
|
features=[
|
@@ -93,7 +94,7 @@ def make_activity_blueprint(
|
|
93
94
|
return render_template("activity/lines.html.j2", **context)
|
94
95
|
|
95
96
|
@blueprint.route("/<int:id>")
|
96
|
-
def show(id: str):
|
97
|
+
def show(id: str) -> ResponseReturnValue:
|
97
98
|
activity = repository.get_activity_by_id(id)
|
98
99
|
|
99
100
|
time_series = repository.get_time_series(id)
|
@@ -189,7 +190,7 @@ def make_activity_blueprint(
|
|
189
190
|
return render_template("activity/show.html.j2", **context)
|
190
191
|
|
191
192
|
@blueprint.route("/<int:id>/sharepic.png")
|
192
|
-
def sharepic(id: int):
|
193
|
+
def sharepic(id: int) -> ResponseReturnValue:
|
193
194
|
activity = repository.get_activity_by_id(id)
|
194
195
|
time_series = repository.get_time_series(id)
|
195
196
|
for coordinates in config.privacy_zones.values():
|
@@ -205,7 +206,7 @@ def make_activity_blueprint(
|
|
205
206
|
)
|
206
207
|
|
207
208
|
@blueprint.route("/day/<int:year>/<int:month>/<int:day>")
|
208
|
-
def day(year: int, month: int, day: int):
|
209
|
+
def day(year: int, month: int, day: int) -> ResponseReturnValue:
|
209
210
|
meta = repository.meta
|
210
211
|
selection = meta["start"].dt.date == datetime.date(year, month, day)
|
211
212
|
activities_that_day = meta.loc[selection]
|
@@ -256,7 +257,7 @@ def make_activity_blueprint(
|
|
256
257
|
)
|
257
258
|
|
258
259
|
@blueprint.route("/day-sharepic/<int:year>/<int:month>/<int:day>/sharepic.png")
|
259
|
-
def day_sharepic(year: int, month: int, day: int):
|
260
|
+
def day_sharepic(year: int, month: int, day: int) -> ResponseReturnValue:
|
260
261
|
meta = repository.meta
|
261
262
|
selection = meta["start"].dt.date == datetime.date(year, month, day)
|
262
263
|
activities_that_day = meta.loc[selection]
|
@@ -273,7 +274,7 @@ def make_activity_blueprint(
|
|
273
274
|
)
|
274
275
|
|
275
276
|
@blueprint.route("/name/<name>")
|
276
|
-
def name(name: str):
|
277
|
+
def name(name: str) -> ResponseReturnValue:
|
277
278
|
meta = repository.meta
|
278
279
|
selection = meta["name"] == name
|
279
280
|
activities_with_name = meta.loc[selection]
|
@@ -324,7 +325,7 @@ def make_activity_blueprint(
|
|
324
325
|
|
325
326
|
@blueprint.route("/edit/<id>", methods=["GET", "POST"])
|
326
327
|
@needs_authentication(authenticator)
|
327
|
-
def edit(id: str):
|
328
|
+
def edit(id: str) -> ResponseReturnValue:
|
328
329
|
activity = DB.session.get(Activity, int(id))
|
329
330
|
if activity is None:
|
330
331
|
abort(404)
|
@@ -365,7 +366,7 @@ def make_activity_blueprint(
|
|
365
366
|
|
366
367
|
@blueprint.route("/trim/<id>", methods=["GET", "POST"])
|
367
368
|
@needs_authentication(authenticator)
|
368
|
-
def trim(id: str):
|
369
|
+
def trim(id: str) -> ResponseReturnValue:
|
369
370
|
activity = DB.session.get(Activity, int(id))
|
370
371
|
if activity is None:
|
371
372
|
abort(404)
|
@@ -434,7 +435,7 @@ def make_activity_blueprint(
|
|
434
435
|
|
435
436
|
@blueprint.route("/delete/<id>")
|
436
437
|
@needs_authentication(authenticator)
|
437
|
-
def delete(id: int):
|
438
|
+
def delete(id: int) -> ResponseReturnValue:
|
438
439
|
activity = DB.session.get_one(Activity, id)
|
439
440
|
activity.delete_data()
|
440
441
|
DB.session.delete(activity)
|
@@ -443,7 +444,7 @@ def make_activity_blueprint(
|
|
443
444
|
|
444
445
|
@blueprint.route("/download-original/<id>")
|
445
446
|
@needs_authentication(authenticator)
|
446
|
-
def download_original(id: int):
|
447
|
+
def download_original(id: int) -> ResponseReturnValue:
|
447
448
|
activity = DB.session.get_one(Activity, id)
|
448
449
|
path = pathlib.Path(activity.path)
|
449
450
|
with open(path) as f:
|
@@ -3,6 +3,7 @@ from flask import redirect
|
|
3
3
|
from flask import render_template
|
4
4
|
from flask import request
|
5
5
|
from flask import url_for
|
6
|
+
from flask.typing import ResponseReturnValue
|
6
7
|
|
7
8
|
from ..authenticator import Authenticator
|
8
9
|
|
@@ -11,7 +12,7 @@ def make_auth_blueprint(authenticator: Authenticator) -> Blueprint:
|
|
11
12
|
blueprint = Blueprint("auth", __name__, template_folder="templates")
|
12
13
|
|
13
14
|
@blueprint.route("/", methods=["GET", "POST"])
|
14
|
-
def index():
|
15
|
+
def index() -> ResponseReturnValue:
|
15
16
|
if request.method == "POST":
|
16
17
|
authenticator.authenticate(request.form["password"])
|
17
18
|
if redirect_to := request.form["redirect"]:
|
@@ -23,7 +24,7 @@ def make_auth_blueprint(authenticator: Authenticator) -> Blueprint:
|
|
23
24
|
)
|
24
25
|
|
25
26
|
@blueprint.route("/logout")
|
26
|
-
def logout():
|
27
|
+
def logout() -> ResponseReturnValue:
|
27
28
|
authenticator.logout()
|
28
29
|
return redirect(url_for(".index"))
|
29
30
|
|
@@ -2,6 +2,7 @@ import altair as alt
|
|
2
2
|
import pandas as pd
|
3
3
|
from flask import Blueprint
|
4
4
|
from flask import render_template
|
5
|
+
from flask.typing import ResponseReturnValue
|
5
6
|
|
6
7
|
from ..columns import column_distance
|
7
8
|
from ..columns import column_elevation_gain
|
@@ -12,7 +13,7 @@ def make_bubble_chart_blueprint(repository) -> Blueprint:
|
|
12
13
|
blueprint = Blueprint("bubble_chart", __name__, template_folder="templates")
|
13
14
|
|
14
15
|
@blueprint.route("/", endpoint="index")
|
15
|
-
def bubble_chart():
|
16
|
+
def bubble_chart() -> ResponseReturnValue:
|
16
17
|
activities = repository.meta
|
17
18
|
|
18
19
|
# Ensure 'activity_id' exists in the activities DataFrame
|
@@ -5,6 +5,7 @@ import pandas as pd
|
|
5
5
|
import sqlalchemy
|
6
6
|
from flask import Blueprint
|
7
7
|
from flask import render_template
|
8
|
+
from flask.typing import ResponseReturnValue
|
8
9
|
|
9
10
|
from ...core.activities import ActivityRepository
|
10
11
|
from ...core.datamodel import Activity
|
@@ -15,7 +16,7 @@ def make_calendar_blueprint(repository: ActivityRepository) -> Blueprint:
|
|
15
16
|
blueprint = Blueprint("calendar", __name__, template_folder="templates")
|
16
17
|
|
17
18
|
@blueprint.route("/")
|
18
|
-
def index():
|
19
|
+
def index() -> ResponseReturnValue:
|
19
20
|
data = DB.session.execute(
|
20
21
|
sqlalchemy.select(Activity.start, Activity.distance_km)
|
21
22
|
).all()
|
@@ -49,7 +50,7 @@ def make_calendar_blueprint(repository: ActivityRepository) -> Blueprint:
|
|
49
50
|
return render_template("calendar/index.html.j2", **context)
|
50
51
|
|
51
52
|
@blueprint.route("/<int:year>/<int:month>")
|
52
|
-
def month(year: int, month: int):
|
53
|
+
def month(year: int, month: int) -> ResponseReturnValue:
|
53
54
|
meta = repository.meta
|
54
55
|
|
55
56
|
filtered = meta.loc[
|
@@ -8,6 +8,7 @@ from flask import Blueprint
|
|
8
8
|
from flask import render_template
|
9
9
|
from flask import Request
|
10
10
|
from flask import request
|
11
|
+
from flask.typing import ResponseReturnValue
|
11
12
|
|
12
13
|
from ...core.activities import ActivityRepository
|
13
14
|
from ...core.meta_search import apply_search_query
|
@@ -24,7 +25,7 @@ def register_eddington_blueprint(
|
|
24
25
|
blueprint = Blueprint("eddington", __name__, template_folder="templates")
|
25
26
|
|
26
27
|
@blueprint.route("/")
|
27
|
-
def distance():
|
28
|
+
def distance() -> ResponseReturnValue:
|
28
29
|
return _render_eddington_template(
|
29
30
|
repository,
|
30
31
|
request,
|
@@ -35,7 +36,7 @@ def register_eddington_blueprint(
|
|
35
36
|
)
|
36
37
|
|
37
38
|
@blueprint.route("/elevation_gain")
|
38
|
-
def elevation_gain():
|
39
|
+
def elevation_gain() -> ResponseReturnValue:
|
39
40
|
return _render_eddington_template(
|
40
41
|
repository,
|
41
42
|
request,
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import collections
|
2
2
|
import datetime
|
3
|
+
from typing import Any
|
3
4
|
|
4
5
|
import altair as alt
|
5
6
|
import flask
|
@@ -7,6 +8,7 @@ import pandas as pd
|
|
7
8
|
import sqlalchemy
|
8
9
|
from flask import render_template
|
9
10
|
from flask import Response
|
11
|
+
from flask.typing import ResponseReturnValue
|
10
12
|
|
11
13
|
from ...core.activities import ActivityRepository
|
12
14
|
from ...core.activities import make_geojson_from_time_series
|
@@ -16,6 +18,7 @@ from ...core.datamodel import DB
|
|
16
18
|
from ..columns import column_distance
|
17
19
|
from ..columns import column_elevation_gain
|
18
20
|
from ..columns import ColumnDescription
|
21
|
+
from ..columns import META_COLUMNS
|
19
22
|
from ..plot_util import make_kind_scale
|
20
23
|
|
21
24
|
|
@@ -23,19 +26,16 @@ def register_entry_views(
|
|
23
26
|
app: flask.Flask, repository: ActivityRepository, config: Config
|
24
27
|
) -> None:
|
25
28
|
@app.route("/")
|
26
|
-
def index() ->
|
27
|
-
context = {"latest_activities": []}
|
29
|
+
def index() -> ResponseReturnValue:
|
30
|
+
context: dict[str, Any] = {"latest_activities": []}
|
31
|
+
df = repository.meta
|
28
32
|
|
29
33
|
if len(repository):
|
30
|
-
kind_scale = make_kind_scale(
|
31
|
-
context["
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if config.reliable_elevation_measurements:
|
36
|
-
context["elevation_gain_last_30_days_plot"] = _last_30_days_meta_plot(
|
37
|
-
repository.meta, kind_scale, column_elevation_gain
|
38
|
-
)
|
34
|
+
kind_scale = make_kind_scale(df, config)
|
35
|
+
context["last_30_days_plot"] = {
|
36
|
+
column.display_name: _last_30_days_meta_plot(df, kind_scale, column)
|
37
|
+
for column in META_COLUMNS
|
38
|
+
}
|
39
39
|
|
40
40
|
context["latest_activities"] = collections.defaultdict(list)
|
41
41
|
for activity in DB.session.scalars(
|
@@ -2,6 +2,7 @@ import altair as alt
|
|
2
2
|
import pandas as pd
|
3
3
|
from flask import Blueprint
|
4
4
|
from flask import render_template
|
5
|
+
from flask.typing import ResponseReturnValue
|
5
6
|
|
6
7
|
from ...core.activities import ActivityRepository
|
7
8
|
from ...core.config import Config
|
@@ -15,7 +16,7 @@ def make_equipment_blueprint(
|
|
15
16
|
blueprint = Blueprint("equipment", __name__, template_folder="templates")
|
16
17
|
|
17
18
|
@blueprint.route("/")
|
18
|
-
def index():
|
19
|
+
def index() -> ResponseReturnValue:
|
19
20
|
equipment_summary = get_equipment_use_table(
|
20
21
|
repository.meta, config.equipment_offsets
|
21
22
|
)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import abc
|
2
2
|
import datetime
|
3
|
+
import hashlib
|
3
4
|
import io
|
4
5
|
import itertools
|
5
6
|
import logging
|
@@ -21,6 +22,7 @@ from flask import render_template
|
|
21
22
|
from flask import request
|
22
23
|
from flask import Response
|
23
24
|
from flask import url_for
|
25
|
+
from flask.typing import ResponseReturnValue
|
24
26
|
|
25
27
|
from ...core.activities import ActivityRepository
|
26
28
|
from ...core.config import ConfigAccessor
|
@@ -62,7 +64,7 @@ class ColorStrategy(abc.ABC):
|
|
62
64
|
pass
|
63
65
|
|
64
66
|
|
65
|
-
class
|
67
|
+
class MaxClusterColorStrategy(ColorStrategy):
|
66
68
|
def __init__(self, evolution_state, tile_visits):
|
67
69
|
self.evolution_state = evolution_state
|
68
70
|
self.tile_visits = tile_visits
|
@@ -84,6 +86,31 @@ class ClusterColorStrategy(ColorStrategy):
|
|
84
86
|
return grayscale
|
85
87
|
|
86
88
|
|
89
|
+
class ColorfulClusterColorStrategy(ColorStrategy):
|
90
|
+
def __init__(self, evolution_state: TileEvolutionState, tile_visits):
|
91
|
+
self.evolution_state = evolution_state
|
92
|
+
self.tile_visits = tile_visits
|
93
|
+
self.max_cluster_members = max(
|
94
|
+
evolution_state.clusters.values(),
|
95
|
+
key=len,
|
96
|
+
)
|
97
|
+
self._cmap = matplotlib.colormaps["hsv"]
|
98
|
+
|
99
|
+
def color_image(
|
100
|
+
self, tile_xy: tuple[int, int], grayscale: np.ndarray
|
101
|
+
) -> np.ndarray:
|
102
|
+
if tile_xy in self.evolution_state.memberships:
|
103
|
+
cluster_id = self.evolution_state.memberships[tile_xy]
|
104
|
+
m = hashlib.sha256()
|
105
|
+
m.update(str(cluster_id).encode())
|
106
|
+
d = int(m.hexdigest(), base=16) / (256.0**m.digest_size)
|
107
|
+
return blend_color(grayscale, np.array([[self._cmap(d)[:3]]]), 0.3)
|
108
|
+
elif tile_xy in self.tile_visits:
|
109
|
+
return blend_color(grayscale, 0.0, 0.3)
|
110
|
+
else:
|
111
|
+
return grayscale
|
112
|
+
|
113
|
+
|
87
114
|
class VisitTimeColorStrategy(ColorStrategy):
|
88
115
|
def __init__(self, tile_visits, use_first=True):
|
89
116
|
self.tile_visits = tile_visits
|
@@ -133,7 +160,7 @@ def make_explorer_blueprint(
|
|
133
160
|
|
134
161
|
@blueprint.route("/enable-zoom-level/<int:zoom>")
|
135
162
|
@needs_authentication(authenticator)
|
136
|
-
def enable_zoom_level(zoom: int):
|
163
|
+
def enable_zoom_level(zoom: int) -> ResponseReturnValue:
|
137
164
|
if 0 <= zoom <= 19:
|
138
165
|
config_accessor().explorer_zoom_levels.append(zoom)
|
139
166
|
config_accessor().explorer_zoom_levels.sort()
|
@@ -145,11 +172,11 @@ def make_explorer_blueprint(
|
|
145
172
|
return redirect(url_for(".map", zoom=zoom))
|
146
173
|
|
147
174
|
@blueprint.route(
|
148
|
-
"/<int:zoom>/<float:north>/<float:east>/<float:south>/<float:west>/
|
175
|
+
"/<int:zoom>/<float:north>/<float:east>/<float:south>/<float:west>/missing.<suffix>"
|
149
176
|
)
|
150
|
-
def
|
177
|
+
def download_missing(
|
151
178
|
zoom: int, north: float, east: float, south: float, west: float, suffix: str
|
152
|
-
):
|
179
|
+
) -> ResponseReturnValue:
|
153
180
|
x1, y1 = compute_tile(north, west, zoom)
|
154
181
|
x2, y2 = compute_tile(south, east, zoom)
|
155
182
|
tile_bounds = Bounds(x1, y1, x2 + 2, y2 + 2)
|
@@ -170,11 +197,11 @@ def make_explorer_blueprint(
|
|
170
197
|
)
|
171
198
|
|
172
199
|
@blueprint.route(
|
173
|
-
"/<int:zoom>/<float:north>/<float:east>/<float:south>/<float:west>/
|
200
|
+
"/<int:zoom>/<float:north>/<float:east>/<float:south>/<float:west>/explored.<suffix>"
|
174
201
|
)
|
175
|
-
def
|
202
|
+
def download_explored(
|
176
203
|
zoom: int, north: float, east: float, south: float, west: float, suffix: str
|
177
|
-
):
|
204
|
+
) -> ResponseReturnValue:
|
178
205
|
x1, y1 = compute_tile(north, west, zoom)
|
179
206
|
x2, y2 = compute_tile(south, east, zoom)
|
180
207
|
tile_bounds = Bounds(x1, y1, x2 + 2, y2 + 2)
|
@@ -197,7 +224,7 @@ def make_explorer_blueprint(
|
|
197
224
|
)
|
198
225
|
|
199
226
|
@blueprint.route("/<int:zoom>/server-side")
|
200
|
-
def server_side(zoom: int):
|
227
|
+
def server_side(zoom: int) -> ResponseReturnValue:
|
201
228
|
if zoom not in config_accessor().explorer_zoom_levels:
|
202
229
|
return {"zoom_level_not_generated": zoom}
|
203
230
|
|
@@ -239,7 +266,7 @@ def make_explorer_blueprint(
|
|
239
266
|
return render_template("explorer/server-side.html.j2", **context)
|
240
267
|
|
241
268
|
@blueprint.route("/<int:zoom>/tile/<int:z>/<int:x>/<int:y>.png")
|
242
|
-
def tile(zoom: int, z: int, x: int, y: int) ->
|
269
|
+
def tile(zoom: int, z: int, x: int, y: int) -> ResponseReturnValue:
|
243
270
|
tile_visits = tile_visit_accessor.tile_state["tile_visits"][zoom]
|
244
271
|
evolution_state = tile_visit_accessor.tile_state["evolution_state"][zoom]
|
245
272
|
|
@@ -248,9 +275,16 @@ def make_explorer_blueprint(
|
|
248
275
|
square_line_width = 3
|
249
276
|
square_color = np.array([[[228, 26, 28]]]) / 256
|
250
277
|
|
251
|
-
|
252
|
-
|
253
|
-
|
278
|
+
color_strategy_name = request.args.get("color_strategy", "colorful_cluster")
|
279
|
+
if color_strategy_name == "default":
|
280
|
+
color_strategy_name = config_accessor().cluster_color_strategy
|
281
|
+
match color_strategy_name:
|
282
|
+
case "max_cluster":
|
283
|
+
color_strategy = MaxClusterColorStrategy(evolution_state, tile_visits)
|
284
|
+
case "colorful_cluster":
|
285
|
+
color_strategy = ColorfulClusterColorStrategy(
|
286
|
+
evolution_state, tile_visits
|
287
|
+
)
|
254
288
|
case "first":
|
255
289
|
color_strategy = VisitTimeColorStrategy(tile_visits, use_first=True)
|
256
290
|
case "last":
|