geo-activity-playground 0.28.0__py3-none-any.whl → 0.29.0__py3-none-any.whl
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/core/config.py +3 -0
- geo_activity_playground/core/paths.py +10 -0
- geo_activity_playground/core/tasks.py +5 -4
- geo_activity_playground/explorer/tile_visits.py +41 -7
- geo_activity_playground/webui/activity/controller.py +22 -1
- geo_activity_playground/webui/activity/templates/activity/show.html.j2 +33 -0
- geo_activity_playground/webui/app.py +10 -20
- geo_activity_playground/webui/authenticator.py +0 -3
- geo_activity_playground/webui/entry_controller.py +8 -4
- geo_activity_playground/webui/explorer/controller.py +1 -0
- geo_activity_playground/webui/explorer/templates/explorer/index.html.j2 +2 -0
- geo_activity_playground/webui/heatmap/heatmap_controller.py +1 -0
- geo_activity_playground/webui/plot_util.py +9 -0
- geo_activity_playground/webui/search/blueprint.py +20 -0
- geo_activity_playground/webui/settings/blueprint.py +67 -0
- geo_activity_playground/webui/settings/templates/settings/color-schemes.html.j2 +33 -0
- geo_activity_playground/webui/settings/templates/settings/index.html.j2 +9 -0
- geo_activity_playground/webui/summary/blueprint.py +3 -2
- geo_activity_playground/webui/summary/controller.py +20 -13
- geo_activity_playground/webui/templates/home.html.j2 +1 -1
- geo_activity_playground/webui/templates/page.html.j2 +56 -28
- {geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/METADATA +3 -4
- {geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/RECORD +27 -25
- geo_activity_playground/webui/search_controller.py +0 -19
- /geo_activity_playground/webui/{templates/search.html.j2 → search/templates/search/index.html.j2} +0 -0
- {geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/LICENSE +0 -0
- {geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/WHEEL +0 -0
- {geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/entry_points.txt +0 -0
@@ -21,6 +21,8 @@ logger = logging.getLogger(__name__)
|
|
21
21
|
@dataclasses.dataclass
|
22
22
|
class Config:
|
23
23
|
birth_year: Optional[int] = None
|
24
|
+
color_scheme_for_counts: str = "viridis"
|
25
|
+
color_scheme_for_kind: str = "category10"
|
24
26
|
equipment_offsets: dict[str, float] = dataclasses.field(default_factory=dict)
|
25
27
|
explorer_zoom_levels: list[int] = dataclasses.field(
|
26
28
|
default_factory=lambda: [14, 17]
|
@@ -52,6 +54,7 @@ class ConfigAccessor:
|
|
52
54
|
return self._config
|
53
55
|
|
54
56
|
def save(self) -> None:
|
57
|
+
print(self._config)
|
55
58
|
with open(new_config_file(), "w") as f:
|
56
59
|
json.dump(
|
57
60
|
dataclasses.asdict(self._config),
|
@@ -1,6 +1,7 @@
|
|
1
1
|
"""
|
2
2
|
Paths within the playground and cache.
|
3
3
|
"""
|
4
|
+
import contextlib
|
4
5
|
import functools
|
5
6
|
import pathlib
|
6
7
|
import typing
|
@@ -24,6 +25,15 @@ def file_wrapper(path: pathlib.Path) -> typing.Callable[[], pathlib.Path]:
|
|
24
25
|
return wrapper
|
25
26
|
|
26
27
|
|
28
|
+
@contextlib.contextmanager
|
29
|
+
def atomic_open(path: pathlib.Path, mode: str):
|
30
|
+
temp_path = path.with_stem(path.stem + "-temp")
|
31
|
+
with open(temp_path, mode) as f:
|
32
|
+
yield f
|
33
|
+
path.unlink(missing_ok=True)
|
34
|
+
temp_path.rename(path)
|
35
|
+
|
36
|
+
|
27
37
|
_cache_dir = pathlib.Path("Cache")
|
28
38
|
|
29
39
|
_activity_dir = _cache_dir / "Activity"
|
@@ -8,6 +8,7 @@ from typing import Generic
|
|
8
8
|
from typing import Sequence
|
9
9
|
from typing import TypeVar
|
10
10
|
|
11
|
+
from geo_activity_playground.core.paths import atomic_open
|
11
12
|
from geo_activity_playground.core.paths import cache_dir
|
12
13
|
|
13
14
|
|
@@ -24,11 +25,8 @@ def stored_object(path: pathlib.Path, default):
|
|
24
25
|
|
25
26
|
yield payload
|
26
27
|
|
27
|
-
|
28
|
-
with open(temp_location, "wb") as f:
|
28
|
+
with atomic_open(path, "wb") as f:
|
29
29
|
pickle.dump(payload, f)
|
30
|
-
path.unlink(missing_ok=True)
|
31
|
-
temp_location.rename(path)
|
32
30
|
|
33
31
|
|
34
32
|
def work_tracker_path(name: str) -> pathlib.Path:
|
@@ -68,6 +66,9 @@ class WorkTracker:
|
|
68
66
|
def discard(self, id) -> None:
|
69
67
|
self._done.discard(id)
|
70
68
|
|
69
|
+
def reset(self) -> None:
|
70
|
+
self._done = set()
|
71
|
+
|
71
72
|
def close(self) -> None:
|
72
73
|
with open(self._path, "wb") as f:
|
73
74
|
pickle.dump(self._done, f)
|
@@ -14,6 +14,7 @@ from tqdm import tqdm
|
|
14
14
|
|
15
15
|
from geo_activity_playground.core.activities import ActivityRepository
|
16
16
|
from geo_activity_playground.core.config import Config
|
17
|
+
from geo_activity_playground.core.paths import atomic_open
|
17
18
|
from geo_activity_playground.core.paths import tiles_per_time_series
|
18
19
|
from geo_activity_playground.core.tasks import try_load_pickle
|
19
20
|
from geo_activity_playground.core.tasks import work_tracker_path
|
@@ -79,11 +80,12 @@ class TileVisitAccessor:
|
|
79
80
|
self.tile_state = make_tile_state()
|
80
81
|
# TODO: Reset work tracker
|
81
82
|
|
83
|
+
def reset(self) -> None:
|
84
|
+
self.tile_state = make_tile_state()
|
85
|
+
|
82
86
|
def save(self) -> None:
|
83
|
-
|
84
|
-
with open(tmp_path, "wb") as f:
|
87
|
+
with atomic_open(self.PATH, "wb") as f:
|
85
88
|
pickle.dump(self.tile_state, f)
|
86
|
-
tmp_path.rename(self.PATH)
|
87
89
|
|
88
90
|
|
89
91
|
def make_defaultdict_dict():
|
@@ -106,20 +108,52 @@ def make_tile_state() -> TileState:
|
|
106
108
|
return tile_state
|
107
109
|
|
108
110
|
|
111
|
+
def _consistency_check(
|
112
|
+
repository: ActivityRepository, tile_visit_accessor: TileVisitAccessor
|
113
|
+
) -> bool:
|
114
|
+
present_activity_ids = set(repository.get_activity_ids())
|
115
|
+
|
116
|
+
for zoom, activities_per_tile in tile_visit_accessor.tile_state[
|
117
|
+
"activities_per_tile"
|
118
|
+
].items():
|
119
|
+
for tile, tile_activity_ids in activities_per_tile.items():
|
120
|
+
deleted_activity_ids = tile_activity_ids - present_activity_ids
|
121
|
+
if deleted_activity_ids:
|
122
|
+
logger.info(f"Activities {deleted_activity_ids} have been deleted.")
|
123
|
+
return False
|
124
|
+
|
125
|
+
for zoom, tile_visits in tile_visit_accessor.tile_state["tile_visits"].items():
|
126
|
+
for tile, meta in tile_visits.items():
|
127
|
+
if meta["first_id"] not in present_activity_ids:
|
128
|
+
logger.info(f"Activity {meta['first_id']} have been deleted.")
|
129
|
+
return False
|
130
|
+
if meta["last_id"] not in present_activity_ids:
|
131
|
+
logger.info(f"Activity {meta['last_id']} have been deleted.")
|
132
|
+
return False
|
133
|
+
|
134
|
+
return True
|
135
|
+
|
136
|
+
|
109
137
|
def compute_tile_visits_new(
|
110
138
|
repository: ActivityRepository, tile_visit_accessor: TileVisitAccessor
|
111
139
|
) -> None:
|
112
140
|
work_tracker = WorkTracker(work_tracker_path("tile-state"))
|
141
|
+
|
142
|
+
if not _consistency_check(repository, tile_visit_accessor):
|
143
|
+
logger.warning("Need to recompute Explorer Tiles due to deleted activities.")
|
144
|
+
tile_visit_accessor.reset()
|
145
|
+
work_tracker.reset()
|
146
|
+
|
113
147
|
for activity_id in tqdm(
|
114
|
-
work_tracker.filter(repository.get_activity_ids()), desc="Tile visits
|
148
|
+
work_tracker.filter(repository.get_activity_ids()), desc="Tile visits"
|
115
149
|
):
|
116
|
-
|
150
|
+
_process_activity(repository, tile_visit_accessor.tile_state, activity_id)
|
117
151
|
work_tracker.mark_done(activity_id)
|
118
152
|
tile_visit_accessor.save()
|
119
153
|
work_tracker.close()
|
120
154
|
|
121
155
|
|
122
|
-
def
|
156
|
+
def _process_activity(
|
123
157
|
repository: ActivityRepository, tile_state: TileState, activity_id: int
|
124
158
|
) -> None:
|
125
159
|
activity = repository.get_activity_by_id(activity_id)
|
@@ -145,7 +179,7 @@ def do_tile_stuff(
|
|
145
179
|
zip(activity_tiles["tile_x"], activity_tiles["tile_y"]),
|
146
180
|
):
|
147
181
|
if activity["consider_for_achievements"]:
|
148
|
-
if tile not in
|
182
|
+
if tile not in tile_state["tile_visits"][zoom]:
|
149
183
|
new_tile_history_soa["activity_id"].append(activity_id)
|
150
184
|
new_tile_history_soa["time"].append(time)
|
151
185
|
new_tile_history_soa["tile_x"].append(tile[0])
|
@@ -12,6 +12,8 @@ import pandas as pd
|
|
12
12
|
from PIL import Image
|
13
13
|
from PIL import ImageDraw
|
14
14
|
|
15
|
+
from ...explorer.grid_file import make_grid_file_geojson
|
16
|
+
from ...explorer.grid_file import make_grid_points
|
15
17
|
from geo_activity_playground.core.activities import ActivityMeta
|
16
18
|
from geo_activity_playground.core.activities import ActivityRepository
|
17
19
|
from geo_activity_playground.core.activities import make_geojson_color_line
|
@@ -66,9 +68,27 @@ class ActivityController:
|
|
66
68
|
]
|
67
69
|
== activity["id"]
|
68
70
|
)
|
69
|
-
for zoom in
|
71
|
+
for zoom in sorted(self._config.explorer_zoom_levels)
|
70
72
|
}
|
71
73
|
|
74
|
+
new_tiles_geojson = {}
|
75
|
+
for zoom in sorted(self._config.explorer_zoom_levels):
|
76
|
+
new_tiles = self._tile_visit_accessor.tile_state["tile_history"][zoom].loc[
|
77
|
+
self._tile_visit_accessor.tile_state["tile_history"][zoom][
|
78
|
+
"activity_id"
|
79
|
+
]
|
80
|
+
== activity["id"]
|
81
|
+
]
|
82
|
+
if len(new_tiles):
|
83
|
+
points = make_grid_points(
|
84
|
+
(
|
85
|
+
(row["tile_x"], row["tile_y"])
|
86
|
+
for index, row in new_tiles.iterrows()
|
87
|
+
),
|
88
|
+
zoom,
|
89
|
+
)
|
90
|
+
new_tiles_geojson[zoom] = make_grid_file_geojson(points)
|
91
|
+
|
72
92
|
result = {
|
73
93
|
"activity": activity,
|
74
94
|
"line_json": line_json,
|
@@ -81,6 +101,7 @@ class ActivityController:
|
|
81
101
|
"date": activity["start"].date(),
|
82
102
|
"time": activity["start"].time(),
|
83
103
|
"new_tiles": new_tiles,
|
104
|
+
"new_tiles_geojson": new_tiles_geojson,
|
84
105
|
}
|
85
106
|
if (
|
86
107
|
heart_zones := _extract_heart_rate_zones(
|
@@ -136,6 +136,39 @@
|
|
136
136
|
<p>Not happy with the displayed data? <a href="{{ url_for('settings.sharepic') }}">Change share picture
|
137
137
|
settings</a>.</p>
|
138
138
|
|
139
|
+
{% if new_tiles_geojson %}
|
140
|
+
<h2>New explorer tiles</h2>
|
141
|
+
<p>With this activity you have explored new explorer tiles. The following maps show the new tiles on the respective zoom
|
142
|
+
levels.</p>
|
143
|
+
<script>
|
144
|
+
function add_map(id, geojson) {
|
145
|
+
let map = L.map(`map-${id}`, {
|
146
|
+
fullscreenControl: true
|
147
|
+
})
|
148
|
+
L.tileLayer('/tile/color/{z}/{x}/{y}.png', {
|
149
|
+
maxZoom: 19,
|
150
|
+
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
151
|
+
}).addTo(map)
|
152
|
+
|
153
|
+
let geojson_layer = L.geoJSON(geojson).addTo(map)
|
154
|
+
map.fitBounds(geojson_layer.getBounds())
|
155
|
+
return map
|
156
|
+
}
|
157
|
+
</script>
|
158
|
+
|
159
|
+
<div class="row mb-3">
|
160
|
+
{% for zoom, geojson in new_tiles_geojson.items() %}
|
161
|
+
<div class="col-md-6">
|
162
|
+
<h3>Zoom {{ zoom }}</h3>
|
163
|
+
<div id="map-{{ zoom }}" style="height: 300px; width: 100%;"></div>
|
164
|
+
<script>
|
165
|
+
let map{{ zoom }} = add_map("{{ zoom }}", {{ geojson | safe }})
|
166
|
+
</script>
|
167
|
+
</div>
|
168
|
+
{% endfor %}
|
169
|
+
</div>
|
170
|
+
{% endif %}
|
171
|
+
|
139
172
|
{% if similar_activites|length > 0 %}
|
140
173
|
<div class="row mb-3">
|
141
174
|
<div class="col">
|
@@ -5,7 +5,6 @@ import secrets
|
|
5
5
|
|
6
6
|
from flask import Flask
|
7
7
|
from flask import render_template
|
8
|
-
from flask import request
|
9
8
|
|
10
9
|
from ..core.activities import ActivityRepository
|
11
10
|
from ..explorer.tile_visits import TileVisitAccessor
|
@@ -16,31 +15,20 @@ from .entry_controller import EntryController
|
|
16
15
|
from .equipment.blueprint import make_equipment_blueprint
|
17
16
|
from .explorer.blueprint import make_explorer_blueprint
|
18
17
|
from .heatmap.blueprint import make_heatmap_blueprint
|
19
|
-
from .
|
18
|
+
from .search.blueprint import make_search_blueprint
|
20
19
|
from .square_planner.blueprint import make_square_planner_blueprint
|
21
20
|
from .summary.blueprint import make_summary_blueprint
|
22
21
|
from .tile.blueprint import make_tile_blueprint
|
23
22
|
from .upload.blueprint import make_upload_blueprint
|
23
|
+
from geo_activity_playground.core.config import Config
|
24
24
|
from geo_activity_playground.core.config import ConfigAccessor
|
25
25
|
from geo_activity_playground.webui.auth.blueprint import make_auth_blueprint
|
26
26
|
from geo_activity_playground.webui.authenticator import Authenticator
|
27
27
|
from geo_activity_playground.webui.settings.blueprint import make_settings_blueprint
|
28
28
|
|
29
29
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
@app.route("/search", methods=["POST"])
|
34
|
-
def search():
|
35
|
-
form_input = request.form
|
36
|
-
return render_template(
|
37
|
-
"search.html.j2",
|
38
|
-
**search_controller.render_search_results(form_input["name"])
|
39
|
-
)
|
40
|
-
|
41
|
-
|
42
|
-
def route_start(app: Flask, repository: ActivityRepository) -> None:
|
43
|
-
entry_controller = EntryController(repository)
|
30
|
+
def route_start(app: Flask, repository: ActivityRepository, config: Config) -> None:
|
31
|
+
entry_controller = EntryController(repository, config)
|
44
32
|
|
45
33
|
@app.route("/")
|
46
34
|
def index():
|
@@ -66,7 +54,6 @@ def web_ui_main(
|
|
66
54
|
host: str,
|
67
55
|
port: int,
|
68
56
|
) -> None:
|
69
|
-
|
70
57
|
repository.reload()
|
71
58
|
|
72
59
|
app = Flask(__name__)
|
@@ -75,8 +62,7 @@ def web_ui_main(
|
|
75
62
|
|
76
63
|
authenticator = Authenticator(config_accessor())
|
77
64
|
|
78
|
-
|
79
|
-
route_start(app, repository)
|
65
|
+
route_start(app, repository, config_accessor())
|
80
66
|
|
81
67
|
app.register_blueprint(make_auth_blueprint(authenticator), url_prefix="/auth")
|
82
68
|
|
@@ -111,7 +97,11 @@ def web_ui_main(
|
|
111
97
|
url_prefix="/square-planner",
|
112
98
|
)
|
113
99
|
app.register_blueprint(
|
114
|
-
|
100
|
+
make_search_blueprint(repository),
|
101
|
+
url_prefix="/search",
|
102
|
+
)
|
103
|
+
app.register_blueprint(
|
104
|
+
make_summary_blueprint(repository, config_accessor()),
|
115
105
|
url_prefix="/summary",
|
116
106
|
)
|
117
107
|
app.register_blueprint(make_tile_blueprint(), url_prefix="/tile")
|
@@ -14,9 +14,6 @@ class Authenticator:
|
|
14
14
|
self._config = config
|
15
15
|
|
16
16
|
def is_authenticated(self) -> bool:
|
17
|
-
print(
|
18
|
-
f"Password={self._config.upload_password}, Session={session.get('is_authenticated', False)}"
|
19
|
-
)
|
20
17
|
return not self._config.upload_password or session.get(
|
21
18
|
"is_authenticated", False
|
22
19
|
)
|
@@ -6,18 +6,22 @@ import pandas as pd
|
|
6
6
|
|
7
7
|
from geo_activity_playground.core.activities import ActivityRepository
|
8
8
|
from geo_activity_playground.core.activities import make_geojson_from_time_series
|
9
|
+
from geo_activity_playground.core.config import Config
|
10
|
+
from geo_activity_playground.webui.plot_util import make_kind_scale
|
9
11
|
|
10
12
|
|
11
13
|
class EntryController:
|
12
|
-
def __init__(self, repository: ActivityRepository) -> None:
|
14
|
+
def __init__(self, repository: ActivityRepository, config: Config) -> None:
|
13
15
|
self._repository = repository
|
16
|
+
self._config = config
|
14
17
|
|
15
18
|
def render(self) -> dict:
|
19
|
+
kind_scale = make_kind_scale(self._repository.meta, self._config)
|
16
20
|
result = {"latest_activities": []}
|
17
21
|
|
18
22
|
if len(self._repository):
|
19
23
|
result["distance_last_30_days_plot"] = distance_last_30_days_meta_plot(
|
20
|
-
self._repository.meta
|
24
|
+
self._repository.meta, kind_scale
|
21
25
|
)
|
22
26
|
|
23
27
|
for activity in itertools.islice(
|
@@ -33,7 +37,7 @@ class EntryController:
|
|
33
37
|
return result
|
34
38
|
|
35
39
|
|
36
|
-
def distance_last_30_days_meta_plot(meta: pd.DataFrame) -> str:
|
40
|
+
def distance_last_30_days_meta_plot(meta: pd.DataFrame, kind_scale: alt.Scale) -> str:
|
37
41
|
before_30_days = pd.to_datetime(
|
38
42
|
datetime.datetime.now() - datetime.timedelta(days=31)
|
39
43
|
)
|
@@ -48,7 +52,7 @@ def distance_last_30_days_meta_plot(meta: pd.DataFrame) -> str:
|
|
48
52
|
.encode(
|
49
53
|
alt.X("yearmonthdate(start)", title="Date"),
|
50
54
|
alt.Y("sum(distance_km)", title="Distance / km"),
|
51
|
-
alt.Color("kind", scale=
|
55
|
+
alt.Color("kind", scale=kind_scale, title="Kind"),
|
52
56
|
[
|
53
57
|
alt.Tooltip("yearmonthdate(start)", title="Date"),
|
54
58
|
alt.Tooltip("kind", title="Kind"),
|
@@ -48,6 +48,8 @@
|
|
48
48
|
function onEachFeature(feature, layer) {
|
49
49
|
if (feature.properties && feature.properties.first_visit) {
|
50
50
|
let lines = [
|
51
|
+
`<dt>Tile</dt>`,
|
52
|
+
`<dd>${feature.properties.tile}</dd>`,
|
51
53
|
`<dt>First visit</dt>`,
|
52
54
|
`<dd>${feature.properties.first_visit}</br><a href=/activity/${feature.properties.first_activity_id}>${feature.properties.first_activity_name}</a></dd>`,
|
53
55
|
`<dt>Last visit</dt>`,
|
@@ -123,6 +123,7 @@ class HeatmapController:
|
|
123
123
|
tile_counts += aim
|
124
124
|
tmp_path = tile_count_cache_path.with_suffix(".tmp.npy")
|
125
125
|
np.save(tmp_path, tile_counts)
|
126
|
+
tile_count_cache_path.unlink(missing_ok=True)
|
126
127
|
tmp_path.rename(tile_count_cache_path)
|
127
128
|
return tile_counts
|
128
129
|
|
@@ -0,0 +1,9 @@
|
|
1
|
+
import altair as alt
|
2
|
+
import pandas as pd
|
3
|
+
|
4
|
+
from geo_activity_playground.core.config import Config
|
5
|
+
|
6
|
+
|
7
|
+
def make_kind_scale(meta: pd.DataFrame, config: Config) -> alt.Scale:
|
8
|
+
kinds = sorted(meta["kind"].unique())
|
9
|
+
return alt.Scale(domain=kinds, scheme=config.color_scheme_for_kind)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
from flask import Blueprint
|
2
|
+
from flask import render_template
|
3
|
+
from flask import request
|
4
|
+
from flask import Response
|
5
|
+
|
6
|
+
from ...core.activities import ActivityRepository
|
7
|
+
|
8
|
+
|
9
|
+
def make_search_blueprint(repository: ActivityRepository) -> Blueprint:
|
10
|
+
blueprint = Blueprint("search", __name__, template_folder="templates")
|
11
|
+
|
12
|
+
@blueprint.route("/", methods=["POST"])
|
13
|
+
def index():
|
14
|
+
activities = []
|
15
|
+
for _, row in repository.meta.iterrows():
|
16
|
+
if request.form["name"] in row["name"]:
|
17
|
+
activities.append(row)
|
18
|
+
return render_template("search/index.html.j2", activities=activities)
|
19
|
+
|
20
|
+
return blueprint
|
@@ -42,6 +42,73 @@ def make_settings_blueprint(
|
|
42
42
|
**settings_controller.render_admin_password(),
|
43
43
|
)
|
44
44
|
|
45
|
+
@blueprint.route("/color-schemes", methods=["GET", "POST"])
|
46
|
+
@needs_authentication(authenticator)
|
47
|
+
def color_schemes():
|
48
|
+
if request.method == "POST":
|
49
|
+
config_accessor().color_scheme_for_counts = request.form[
|
50
|
+
"color_scheme_for_counts"
|
51
|
+
]
|
52
|
+
config_accessor().color_scheme_for_kind = request.form[
|
53
|
+
"color_scheme_for_kind"
|
54
|
+
]
|
55
|
+
config_accessor.save()
|
56
|
+
flash("Updated color schemes.", category="success")
|
57
|
+
return render_template(
|
58
|
+
"settings/color-schemes.html.j2",
|
59
|
+
color_scheme_for_counts=config_accessor().color_scheme_for_counts,
|
60
|
+
color_scheme_for_counts_avail=[
|
61
|
+
"viridis",
|
62
|
+
"magma",
|
63
|
+
"inferno",
|
64
|
+
"plasma",
|
65
|
+
"cividis",
|
66
|
+
"turbo",
|
67
|
+
"bluegreen",
|
68
|
+
"bluepurple",
|
69
|
+
"goldgreen",
|
70
|
+
"goldorange",
|
71
|
+
"goldred",
|
72
|
+
"greenblue",
|
73
|
+
"orangered",
|
74
|
+
"purplebluegreen",
|
75
|
+
"purpleblue",
|
76
|
+
"purplered",
|
77
|
+
"redpurple",
|
78
|
+
"yellowgreenblue",
|
79
|
+
"yellowgreen",
|
80
|
+
"yelloworangebrown",
|
81
|
+
"yelloworangered",
|
82
|
+
"darkblue",
|
83
|
+
"darkgold",
|
84
|
+
"darkgreen",
|
85
|
+
"darkmulti",
|
86
|
+
"darkred",
|
87
|
+
"lightgreyred",
|
88
|
+
"lightgreyteal",
|
89
|
+
"lightmulti",
|
90
|
+
"lightorange",
|
91
|
+
"lighttealblue",
|
92
|
+
],
|
93
|
+
color_scheme_for_kind=config_accessor().color_scheme_for_kind,
|
94
|
+
color_scheme_for_kind_avail=[
|
95
|
+
"accent",
|
96
|
+
"category10",
|
97
|
+
"category20",
|
98
|
+
"category20b",
|
99
|
+
"category20c",
|
100
|
+
"dark2",
|
101
|
+
"paired",
|
102
|
+
"pastel1",
|
103
|
+
"pastel2",
|
104
|
+
"set1",
|
105
|
+
"set2",
|
106
|
+
"set3",
|
107
|
+
"tableau10",
|
108
|
+
"tableau20",
|
109
|
+
],
|
110
|
+
)
|
111
|
+
|
45
112
|
@blueprint.route("/equipment-offsets", methods=["GET", "POST"])
|
46
113
|
@needs_authentication(authenticator)
|
47
114
|
def equipment_offsets():
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{% extends "page.html.j2" %}
|
2
|
+
|
3
|
+
{% block container %}
|
4
|
+
|
5
|
+
<h1 class="mb-3">Color Schemes for Plots</h1>
|
6
|
+
|
7
|
+
<p>Don't like color schemes in the plots? Have a look at the <a href="https://vega.github.io/vega/docs/schemes/"
|
8
|
+
target="_blank">colors schemes of Vega</a> and pick one that you like.</p>
|
9
|
+
|
10
|
+
<form method="POST">
|
11
|
+
<div class="mb-3">
|
12
|
+
<label class="form-label">Color scheme for activity kinds</label>
|
13
|
+
<select class="form-select" aria-label="Color scheme for activity kinds" name="color_scheme_for_kind">
|
14
|
+
{% for cs in color_scheme_for_kind_avail %}
|
15
|
+
<option {% if cs==color_scheme_for_kind %} selected {% endif %}>{{ cs }}</option>
|
16
|
+
{% endfor %}
|
17
|
+
</select>
|
18
|
+
</div>
|
19
|
+
|
20
|
+
<div class="mb-3">
|
21
|
+
<label class="form-label">Color scheme for heatmaps</label>
|
22
|
+
<select class="form-select" aria-label="Color scheme for heatmaps" name="color_scheme_for_counts">
|
23
|
+
{% for cs in color_scheme_for_counts_avail %}
|
24
|
+
<option {% if cs==color_scheme_for_counts %} selected {% endif %}>{{ cs }}</option>
|
25
|
+
{% endfor %}
|
26
|
+
</select>
|
27
|
+
</div>
|
28
|
+
|
29
|
+
<button type="submit" class="btn btn-primary">Save</button>
|
30
|
+
</form>
|
31
|
+
|
32
|
+
|
33
|
+
{% endblock %}
|
@@ -20,6 +20,15 @@
|
|
20
20
|
</div>
|
21
21
|
</div>
|
22
22
|
</div>
|
23
|
+
<div class="col">
|
24
|
+
<div class="card">
|
25
|
+
<div class="card-body">
|
26
|
+
<h5 class="card-title">Color schemes</h5>
|
27
|
+
<p class="card-text">Don't like the colors in the plots?</p>
|
28
|
+
<a href="{{ url_for('.color_schemes') }}" class="btn btn-primary">Set up color schemes</a>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
</div>
|
23
32
|
<div class="col">
|
24
33
|
<div class="card">
|
25
34
|
<div class="card-body">
|
@@ -3,10 +3,11 @@ from flask import render_template
|
|
3
3
|
|
4
4
|
from ...core.activities import ActivityRepository
|
5
5
|
from .controller import SummaryController
|
6
|
+
from geo_activity_playground.core.config import Config
|
6
7
|
|
7
8
|
|
8
|
-
def make_summary_blueprint(repository: ActivityRepository) -> Blueprint:
|
9
|
-
summary_controller = SummaryController(repository)
|
9
|
+
def make_summary_blueprint(repository: ActivityRepository, config: Config) -> Blueprint:
|
10
|
+
summary_controller = SummaryController(repository, config)
|
10
11
|
blueprint = Blueprint("summary", __name__, template_folder="templates")
|
11
12
|
|
12
13
|
@blueprint.route("/")
|
@@ -8,14 +8,18 @@ import pandas as pd
|
|
8
8
|
|
9
9
|
from geo_activity_playground.core.activities import ActivityRepository
|
10
10
|
from geo_activity_playground.core.activities import make_geojson_from_time_series
|
11
|
+
from geo_activity_playground.core.config import Config
|
12
|
+
from geo_activity_playground.webui.plot_util import make_kind_scale
|
11
13
|
|
12
14
|
|
13
15
|
class SummaryController:
|
14
|
-
def __init__(self, repository: ActivityRepository) -> None:
|
16
|
+
def __init__(self, repository: ActivityRepository, config: Config) -> None:
|
15
17
|
self._repository = repository
|
18
|
+
self._config = config
|
16
19
|
|
17
20
|
@functools.cache
|
18
21
|
def render(self) -> dict:
|
22
|
+
kind_scale = make_kind_scale(self._repository.meta, self._config)
|
19
23
|
df = embellished_activities(self._repository.meta)
|
20
24
|
df = df.loc[df["consider_for_achievements"]]
|
21
25
|
|
@@ -27,14 +31,14 @@ class SummaryController:
|
|
27
31
|
)
|
28
32
|
|
29
33
|
return {
|
30
|
-
"plot_distance_heatmap": plot_distance_heatmap(df),
|
31
|
-
"plot_monthly_distance": plot_monthly_distance(df),
|
32
|
-
"plot_yearly_distance": plot_yearly_distance(year_kind_total),
|
34
|
+
"plot_distance_heatmap": plot_distance_heatmap(df, self._config),
|
35
|
+
"plot_monthly_distance": plot_monthly_distance(df, kind_scale),
|
36
|
+
"plot_yearly_distance": plot_yearly_distance(year_kind_total, kind_scale),
|
33
37
|
"plot_year_cumulative": plot_year_cumulative(df),
|
34
38
|
"tabulate_year_kind_mean": tabulate_year_kind_mean(df)
|
35
39
|
.reset_index()
|
36
40
|
.to_dict(orient="split"),
|
37
|
-
"plot_weekly_distance": plot_weekly_distance(df),
|
41
|
+
"plot_weekly_distance": plot_weekly_distance(df, kind_scale),
|
38
42
|
"nominations": [
|
39
43
|
(
|
40
44
|
self._repository.get_activity_by_id(activity_id),
|
@@ -108,7 +112,7 @@ def embellished_activities(meta: pd.DataFrame) -> pd.DataFrame:
|
|
108
112
|
return df
|
109
113
|
|
110
114
|
|
111
|
-
def plot_distance_heatmap(meta: pd.DataFrame) -> str:
|
115
|
+
def plot_distance_heatmap(meta: pd.DataFrame, config: Config) -> str:
|
112
116
|
return (
|
113
117
|
alt.Chart(
|
114
118
|
meta.loc[
|
@@ -129,7 +133,10 @@ def plot_distance_heatmap(meta: pd.DataFrame) -> str:
|
|
129
133
|
scale=alt.Scale(reverse=True),
|
130
134
|
title="Year and month",
|
131
135
|
),
|
132
|
-
alt.Color(
|
136
|
+
alt.Color(
|
137
|
+
"sum(distance_km)",
|
138
|
+
scale=alt.Scale(scheme=config.color_scheme_for_counts),
|
139
|
+
),
|
133
140
|
[
|
134
141
|
alt.Tooltip("yearmonthdate(start)", title="Date"),
|
135
142
|
alt.Tooltip(
|
@@ -142,7 +149,7 @@ def plot_distance_heatmap(meta: pd.DataFrame) -> str:
|
|
142
149
|
)
|
143
150
|
|
144
151
|
|
145
|
-
def plot_monthly_distance(meta: pd.DataFrame) -> str:
|
152
|
+
def plot_monthly_distance(meta: pd.DataFrame, kind_scale: alt.Scale) -> str:
|
146
153
|
return (
|
147
154
|
alt.Chart(
|
148
155
|
meta.loc[
|
@@ -159,7 +166,7 @@ def plot_monthly_distance(meta: pd.DataFrame) -> str:
|
|
159
166
|
.encode(
|
160
167
|
alt.X("month(start)", title="Month"),
|
161
168
|
alt.Y("sum(distance_km)", title="Distance / km"),
|
162
|
-
alt.Color("kind", scale=
|
169
|
+
alt.Color("kind", scale=kind_scale, title="Kind"),
|
163
170
|
alt.Column("year(start):O", title="Year"),
|
164
171
|
)
|
165
172
|
.resolve_axis(x="independent")
|
@@ -167,14 +174,14 @@ def plot_monthly_distance(meta: pd.DataFrame) -> str:
|
|
167
174
|
)
|
168
175
|
|
169
176
|
|
170
|
-
def plot_yearly_distance(year_kind_total: pd.DataFrame) -> str:
|
177
|
+
def plot_yearly_distance(year_kind_total: pd.DataFrame, kind_scale: alt.Scale) -> str:
|
171
178
|
return (
|
172
179
|
alt.Chart(year_kind_total, title="Total Distance per Year")
|
173
180
|
.mark_bar()
|
174
181
|
.encode(
|
175
182
|
alt.X("year:O", title="Year"),
|
176
183
|
alt.Y("distance_km", title="Distance / km"),
|
177
|
-
alt.Color("kind", title="Kind"),
|
184
|
+
alt.Color("kind", scale=kind_scale, title="Kind"),
|
178
185
|
[
|
179
186
|
alt.Tooltip("year:O", title="Year"),
|
180
187
|
alt.Tooltip("kind", title="Kind"),
|
@@ -231,7 +238,7 @@ def tabulate_year_kind_mean(df: pd.DataFrame) -> pd.DataFrame:
|
|
231
238
|
return year_kind_mean_distance
|
232
239
|
|
233
240
|
|
234
|
-
def plot_weekly_distance(df: pd.DataFrame) -> str:
|
241
|
+
def plot_weekly_distance(df: pd.DataFrame, kind_scale: alt.Scale) -> str:
|
235
242
|
week_kind_total_distance = (
|
236
243
|
df[["year", "week", "kind", "distance_km"]]
|
237
244
|
.groupby(["year", "week", "kind"])
|
@@ -261,7 +268,7 @@ def plot_weekly_distance(df: pd.DataFrame) -> str:
|
|
261
268
|
.encode(
|
262
269
|
alt.X("year_week", title="Year and Week"),
|
263
270
|
alt.Y("distance_km", title="Distance / km"),
|
264
|
-
alt.Color("kind", title="Kind"),
|
271
|
+
alt.Color("kind", scale=kind_scale, title="Kind"),
|
265
272
|
[
|
266
273
|
alt.Tooltip("year_week", title="Year and Week"),
|
267
274
|
alt.Tooltip("kind", title="Kind"),
|
@@ -12,7 +12,7 @@
|
|
12
12
|
</div>
|
13
13
|
<div class="col-md-3">
|
14
14
|
<h2>Search activities</h2>
|
15
|
-
<form method="post" action="
|
15
|
+
<form method="post" action="{{ url_for('search.index') }}">
|
16
16
|
<input type="search" name="name" />
|
17
17
|
<input type="submit" class="button" />
|
18
18
|
</form>
|
@@ -62,42 +62,70 @@
|
|
62
62
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
63
63
|
|
64
64
|
{% if num_activities > 0 %}
|
65
|
-
<li class="nav-item">
|
66
|
-
<a class="nav-link"
|
67
|
-
|
68
|
-
|
69
|
-
|
65
|
+
<li class="nav-item dropdown">
|
66
|
+
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
67
|
+
aria-expanded="false">
|
68
|
+
Activities
|
69
|
+
</a>
|
70
|
+
<ul class="dropdown-menu">
|
71
|
+
<li><a class="dropdown-item" href="{{ url_for('calendar.index') }}">Calendar</a></li>
|
72
|
+
{# <li><a class="dropdown-item" href="{{ url_for('search.index') }}">Search</a></li> #}
|
73
|
+
</ul>
|
70
74
|
</li>
|
71
|
-
|
72
|
-
|
73
|
-
|
75
|
+
|
76
|
+
<li class="nav-item dropdown">
|
77
|
+
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
78
|
+
aria-expanded="false">
|
79
|
+
Statistics
|
80
|
+
</a>
|
81
|
+
<ul class="dropdown-menu">
|
82
|
+
<li><a class="dropdown-item" href="{{ url_for('summary.index') }}">Summary
|
83
|
+
Statistics</a>
|
84
|
+
</li>
|
85
|
+
<li><a class="dropdown-item" href="{{ url_for('eddington.index') }}">Eddington
|
86
|
+
Number</a>
|
87
|
+
</li>
|
88
|
+
<li><a class="dropdown-item" href="{{ url_for('equipment.index') }}">Equipment</a></li>
|
89
|
+
</ul>
|
74
90
|
</li>
|
75
|
-
|
76
|
-
|
77
|
-
|
91
|
+
|
92
|
+
<li class="nav-item dropdown">
|
93
|
+
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
94
|
+
aria-expanded="false">
|
95
|
+
Explorer
|
96
|
+
</a>
|
97
|
+
<ul class="dropdown-menu">
|
98
|
+
<li><a class="dropdown-item" href="{{ url_for('explorer.map', zoom=14) }}">Explorer
|
99
|
+
Tiles (Zoom 14)</a></li>
|
100
|
+
<li><a class="dropdown-item" href="{{ url_for('explorer.map', zoom=17) }}">Squadratinhos
|
101
|
+
(Zoom 17)</a></li>
|
102
|
+
</ul>
|
78
103
|
</li>
|
104
|
+
|
79
105
|
<li class="nav-item">
|
80
106
|
<a class="nav-link" aria-current="page" href="{{ url_for('heatmap.index') }}">Heatmap</a>
|
81
107
|
</li>
|
82
|
-
<li class="nav-item">
|
83
|
-
<a class="nav-link" aria-current="page"
|
84
|
-
href="{{ url_for('eddington.index') }}">Eddington</a>
|
85
|
-
</li>
|
86
|
-
<li class="nav-item">
|
87
|
-
<a class="nav-link" aria-current="page"
|
88
|
-
href="{{ url_for('equipment.index') }}">Equipment</a>
|
89
|
-
</li>
|
90
108
|
{% endif %}
|
91
|
-
<li class="nav-item">
|
92
|
-
<a class="nav-link" aria-current="page" href="{{ url_for('upload.index') }}">Upload</a>
|
93
|
-
</li>
|
94
|
-
<li class="nav-item">
|
95
|
-
<a class="nav-link" aria-current="page" href="{{ url_for('upload.reload') }}">Refresh</a>
|
96
|
-
</li>
|
97
|
-
<li class="nav-item">
|
98
|
-
<a class="nav-link" aria-current="page" href="{{ url_for('settings.index') }}">Settings</a>
|
99
|
-
</li>
|
100
109
|
|
110
|
+
<li class="nav-item dropdown">
|
111
|
+
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
|
112
|
+
aria-expanded="false">
|
113
|
+
Admin
|
114
|
+
</a>
|
115
|
+
<ul class="dropdown-menu">
|
116
|
+
<li><a class="dropdown-item" href="{{ url_for('upload.index') }}">Upload Activities</a>
|
117
|
+
</li>
|
118
|
+
<li><a class="dropdown-item" href="{{ url_for('upload.reload') }}">Scan New
|
119
|
+
Activities</a>
|
120
|
+
</li>
|
121
|
+
|
122
|
+
<li>
|
123
|
+
<hr class="dropdown-divider">
|
124
|
+
</li>
|
125
|
+
|
126
|
+
<li><a class="dropdown-item" href="{{ url_for('settings.index') }}">Settings</a></li>
|
127
|
+
</ul>
|
128
|
+
</li>
|
101
129
|
|
102
130
|
<li class="nav-item dropdown">
|
103
131
|
<button
|
{geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/METADATA
RENAMED
@@ -1,14 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: geo-activity-playground
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.29.0
|
4
4
|
Summary: Analysis of geo data activities like rides, runs or hikes.
|
5
5
|
License: MIT
|
6
6
|
Author: Martin Ueding
|
7
7
|
Author-email: mu@martin-ueding.de
|
8
|
-
Requires-Python: >=3.
|
8
|
+
Requires-Python: >=3.10,<3.13
|
9
9
|
Classifier: License :: OSI Approved :: MIT License
|
10
10
|
Classifier: Programming Language :: Python :: 3
|
11
|
-
Classifier: Programming Language :: Python :: 3.9
|
12
11
|
Classifier: Programming Language :: Python :: 3.10
|
13
12
|
Classifier: Programming Language :: Python :: 3.11
|
14
13
|
Classifier: Programming Language :: Python :: 3.12
|
@@ -30,7 +29,7 @@ Requires-Dist: python-dateutil (>=2.8.2,<3.0.0)
|
|
30
29
|
Requires-Dist: requests (>=2.28.1,<3.0.0)
|
31
30
|
Requires-Dist: scipy (>=1.8.1,<2.0.0)
|
32
31
|
Requires-Dist: shapely (>=2.0.5,<3.0.0)
|
33
|
-
Requires-Dist: stravalib (>=
|
32
|
+
Requires-Dist: stravalib (>=2.0,<3.0)
|
34
33
|
Requires-Dist: tcxreader (>=0.4.5,<0.5.0)
|
35
34
|
Requires-Dist: tomli (>=2.0.1,<3.0.0) ; python_version < "3.11"
|
36
35
|
Requires-Dist: tqdm (>=4.64.0,<5.0.0)
|
{geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/RECORD
RENAMED
@@ -2,22 +2,22 @@ geo_activity_playground/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
|
|
2
2
|
geo_activity_playground/__main__.py,sha256=MBZn9K1m3PofiPNTtpsSTVCyB_Gz95TjVP-nb9v_-JE,3989
|
3
3
|
geo_activity_playground/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
geo_activity_playground/core/activities.py,sha256=yDjf3aVOC3LvnAwAvQUl_e7S3NXq_vKgccq0hGuFdLI,6609
|
5
|
-
geo_activity_playground/core/config.py,sha256=
|
5
|
+
geo_activity_playground/core/config.py,sha256=DsjZhiq2BZs94rjd7zgt_KTZIjVfxfntiEQZhgq8NeA,4617
|
6
6
|
geo_activity_playground/core/coordinates.py,sha256=tDfr9mlXhK6E_MMIJ0vYWVCoH0Lq8uyuaqUgaa8i0jg,966
|
7
7
|
geo_activity_playground/core/enrichment.py,sha256=CwZhW-svgPAYbdx3n9kvKlTgcsiCaeuJfSRCC4JxX6g,7411
|
8
8
|
geo_activity_playground/core/heart_rate.py,sha256=IwMt58TpjOYqpAxtsj07zP2ttpN_J3GZeiv-qGhYyJc,1598
|
9
9
|
geo_activity_playground/core/heatmap.py,sha256=bRLQHzmTEsQbX8XWeg85x_lRGk272UoYRiCnoxZ5da0,4189
|
10
|
-
geo_activity_playground/core/paths.py,sha256=
|
10
|
+
geo_activity_playground/core/paths.py,sha256=BZYuIg1LVHjuWLKB0Iz6Cevlq-XSalpCes_ClFuXa0s,2410
|
11
11
|
geo_activity_playground/core/privacy_zones.py,sha256=4TumHsVUN1uW6RG3ArqTXDykPVipF98DCxVBe7YNdO8,512
|
12
12
|
geo_activity_playground/core/similarity.py,sha256=Jo8jRViuORCxdIGvyaflgsQhwu9S_jn10a450FRL18A,3159
|
13
|
-
geo_activity_playground/core/tasks.py,sha256=
|
13
|
+
geo_activity_playground/core/tasks.py,sha256=aMDBWJqp6ek2ao6G6Xa8GOSZbcQqXoWL74SGRowRPIk,2942
|
14
14
|
geo_activity_playground/core/test_tiles.py,sha256=zce1FxNfsSpOQt66jMehdQRVoNdl-oiFydx6iVBHZXM,764
|
15
15
|
geo_activity_playground/core/test_time_conversion.py,sha256=Sh6nZA3uCTOdZTZa3yOijtR0m74QtZu2mcWXsDNnyQI,984
|
16
16
|
geo_activity_playground/core/tiles.py,sha256=KpzD-h3kNzZ2ieLt6f2xHilSF3lHyfaEXPnrGvlIAz0,3379
|
17
17
|
geo_activity_playground/core/time_conversion.py,sha256=9J6aTlqJhWvsknQkoECNL-CIG-8BKs6ZatJJ9XJnTsg,367
|
18
18
|
geo_activity_playground/explorer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
geo_activity_playground/explorer/grid_file.py,sha256=k6j6KBEk2a2BY-onE8SV5TJsERGGyOrlY4as__meWpA,3304
|
20
|
-
geo_activity_playground/explorer/tile_visits.py,sha256=
|
20
|
+
geo_activity_playground/explorer/tile_visits.py,sha256=VaenegdPQ51vXxvn2oQXj8-3A7t8ihMhkgV8HpAqEuI,14133
|
21
21
|
geo_activity_playground/explorer/video.py,sha256=ROAmV9shfJyqTgnXVD41KFORiwnRgVpEWenIq4hMCRM,4389
|
22
22
|
geo_activity_playground/importers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
geo_activity_playground/importers/activity_parsers.py,sha256=m2SpvGlTZ8F3gG6YB24_ZFrlOAbtqbfWi-GIYspeUco,10593
|
@@ -31,15 +31,15 @@ geo_activity_playground/importers/test_strava_api.py,sha256=4vX7wDr1a9aRh8myxNrI
|
|
31
31
|
geo_activity_playground/webui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
32
32
|
geo_activity_playground/webui/activity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
33
|
geo_activity_playground/webui/activity/blueprint.py,sha256=upQzZa5sKApj_Fmu6PziFDboi7SBL5Zsi-tNSSNPlEE,1759
|
34
|
-
geo_activity_playground/webui/activity/controller.py,sha256=
|
34
|
+
geo_activity_playground/webui/activity/controller.py,sha256=PJIZ7pFqpUyWDrintnnlW6Hxj7DbdPswARozws6TE30,18861
|
35
35
|
geo_activity_playground/webui/activity/templates/activity/day.html.j2,sha256=r3qKl9uTzOko4R-ZzyYAZt1j61JSevYP4g0Yi06HHPg,2702
|
36
36
|
geo_activity_playground/webui/activity/templates/activity/lines.html.j2,sha256=5gB1aDjRgi_RventenRfC10_FtMT4ch_VuWvA9AMlBY,1121
|
37
37
|
geo_activity_playground/webui/activity/templates/activity/name.html.j2,sha256=RDLEt6ip8_ngmdLgaC5jg92Dk-F2umGwKkd8cWmvVko,2400
|
38
|
-
geo_activity_playground/webui/activity/templates/activity/show.html.j2,sha256=
|
39
|
-
geo_activity_playground/webui/app.py,sha256=
|
38
|
+
geo_activity_playground/webui/activity/templates/activity/show.html.j2,sha256=W77M1S7RQOGY3Vg9LRT5mFnefuMWUKKU1Vd-ZKxUoKg,6552
|
39
|
+
geo_activity_playground/webui/app.py,sha256=foON49jw8klBJ3GF70DDjgz-_KRDPFvC31_mScaqDXk,4255
|
40
40
|
geo_activity_playground/webui/auth/blueprint.py,sha256=Lx-ZvMnfHLC1CMre1xPQI3k_pCtQoZvgRhtmafULzoE,812
|
41
41
|
geo_activity_playground/webui/auth/templates/auth/index.html.j2,sha256=ILQ5HvTEYc3OrtOAIFt1VrqWorVD70V9DC342znmP70,579
|
42
|
-
geo_activity_playground/webui/authenticator.py,sha256=
|
42
|
+
geo_activity_playground/webui/authenticator.py,sha256=k278OEVuOfAmTGT4F2X4pqSTwwkK_FA87EIhAeysEqc,1416
|
43
43
|
geo_activity_playground/webui/calendar/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
44
44
|
geo_activity_playground/webui/calendar/blueprint.py,sha256=rlnhgU2DWAcdLMRq7m77NzrM_aDyp4s3kuuQHuzjHhg,782
|
45
45
|
geo_activity_playground/webui/calendar/controller.py,sha256=QpSAkR2s1sbLSu6P_fNNTccgGglOzEH2PIv1XwKxeVY,2778
|
@@ -49,26 +49,29 @@ geo_activity_playground/webui/eddington/__init__.py,sha256=47DEQpj8HBSa-_TImW-5J
|
|
49
49
|
geo_activity_playground/webui/eddington/blueprint.py,sha256=evIvueLfDWVTxJ9pRguqmZ9-Pybd2WmBRst_-7vX2QA,551
|
50
50
|
geo_activity_playground/webui/eddington/controller.py,sha256=ly7JSkSS79kO4CL_xugB62uRuuWKVqOjbN-pheelv94,2910
|
51
51
|
geo_activity_playground/webui/eddington/templates/eddington/index.html.j2,sha256=XHKeUymQMS5x00PLOVlg-nSRCz_jHB2pvD8QunULWJ4,1839
|
52
|
-
geo_activity_playground/webui/entry_controller.py,sha256=
|
52
|
+
geo_activity_playground/webui/entry_controller.py,sha256=kTEToBtR1T4l30cV3HkCK3KO2hVYfb22BSgcWLdLEXQ,2164
|
53
53
|
geo_activity_playground/webui/equipment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
54
54
|
geo_activity_playground/webui/equipment/blueprint.py,sha256=_NIhRJuJNbXpEd_nEPo01AqnUqPgo1vawFn7E3yoeng,636
|
55
55
|
geo_activity_playground/webui/equipment/controller.py,sha256=Sx9i2RCK7m4W6FgpDfRMewcH64VBQfUhHJdTSCwMqOU,4079
|
56
56
|
geo_activity_playground/webui/equipment/templates/equipment/index.html.j2,sha256=FEfxB4XwVYELAOdjVlSlprjJH_kLmE-pNWEEXdPqc6I,1778
|
57
57
|
geo_activity_playground/webui/explorer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
58
58
|
geo_activity_playground/webui/explorer/blueprint.py,sha256=EKnBs8llqT6Wy1uac18dF2epp3TebF9p3iGlSbj6Vl0,2337
|
59
|
-
geo_activity_playground/webui/explorer/controller.py,sha256
|
60
|
-
geo_activity_playground/webui/explorer/templates/explorer/index.html.j2,sha256=
|
59
|
+
geo_activity_playground/webui/explorer/controller.py,sha256=PAVyewO5ZY8BM1-EwtiqZuU-u63BJYuAKNNEDNutJkw,11669
|
60
|
+
geo_activity_playground/webui/explorer/templates/explorer/index.html.j2,sha256=u2htecx-XwINRiINHFN6EZDaRXVtiape1OCUZexTBU8,7049
|
61
61
|
geo_activity_playground/webui/heatmap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
62
62
|
geo_activity_playground/webui/heatmap/blueprint.py,sha256=bjQu-HL3QN5UpJ6tHOifhcLGlPr_hIKvaRu78md4JqM,1470
|
63
|
-
geo_activity_playground/webui/heatmap/heatmap_controller.py,sha256=
|
63
|
+
geo_activity_playground/webui/heatmap/heatmap_controller.py,sha256=Q17Ay8hbU5ZlUiz2a9S-ULWrnNGWQHvTTV3kDY5FhNc,7411
|
64
64
|
geo_activity_playground/webui/heatmap/templates/heatmap/index.html.j2,sha256=YLeu6P4djl8G4qAXR6DhetseqrbOodN7aN4coocknc4,1875
|
65
|
-
geo_activity_playground/webui/
|
66
|
-
geo_activity_playground/webui/
|
65
|
+
geo_activity_playground/webui/plot_util.py,sha256=pTTQoqOCkLVjkgOit7mbry28kMruZIL8amZozSzEpxQ,283
|
66
|
+
geo_activity_playground/webui/search/blueprint.py,sha256=b3TCIplY60MWE2_VsKHuoV1LAgNwd_T5ft5t0CKALFI,642
|
67
|
+
geo_activity_playground/webui/search/templates/search/index.html.j2,sha256=FvNRoDfUlSzXjM_tqZY_fDhuhUDgbPaY73q56gdvF1A,1130
|
68
|
+
geo_activity_playground/webui/settings/blueprint.py,sha256=u5VGzVoRRA9Am5WqC1VGod4L-k839_9qVlecKO9sRUE,7593
|
67
69
|
geo_activity_playground/webui/settings/controller.py,sha256=v14oKvI1QzWn0g41Sm4NA_g9q4SUVZ_bO9SUOZuPAaY,9121
|
68
70
|
geo_activity_playground/webui/settings/templates/settings/admin-password.html.j2,sha256=VYwddpObD1RpeTH5Dm4y7VtmT7kwURDCIjxyzJeq08c,495
|
71
|
+
geo_activity_playground/webui/settings/templates/settings/color-schemes.html.j2,sha256=CaFbYkkU1yGTOlAzGq97u3tVgS79RIo7PEmiVjuZiBc,1226
|
69
72
|
geo_activity_playground/webui/settings/templates/settings/equipment-offsets.html.j2,sha256=ltaYwFe8S8Mi72ddmIp1vwqlu8MEXXjBGfbpN2WBTC4,1728
|
70
73
|
geo_activity_playground/webui/settings/templates/settings/heart-rate.html.j2,sha256=UPT3MegRgSeff36lhCo0l3ZwhqNSIg5gM6h2s32GkCY,4255
|
71
|
-
geo_activity_playground/webui/settings/templates/settings/index.html.j2,sha256
|
74
|
+
geo_activity_playground/webui/settings/templates/settings/index.html.j2,sha256=-ZSlR6htaeMMOf4ISUSzWPu5BUhYODuAmcWPN0ZoBno,4443
|
72
75
|
geo_activity_playground/webui/settings/templates/settings/kinds-without-achievements.html.j2,sha256=IdUfXon1Pu8zX3NirKb28ypshLHOvZRpz2T4bJrzrak,1067
|
73
76
|
geo_activity_playground/webui/settings/templates/settings/metadata-extraction.html.j2,sha256=Ppa8O-zRJznbeCsF4YQj37_HM9nOW8fyTi66jvWvHmA,2285
|
74
77
|
geo_activity_playground/webui/settings/templates/settings/privacy-zones.html.j2,sha256=7BxFvCaVJOEqbImyK5vxCmhh-NGSFaRa9ARhqjZeYJ0,3093
|
@@ -91,12 +94,11 @@ geo_activity_playground/webui/static/mstile-150x150.png,sha256=j1ANUQJ1Xi1DR2sGq
|
|
91
94
|
geo_activity_playground/webui/static/safari-pinned-tab.svg,sha256=OzoEVGY0igWRXM1NiM3SRKugdICBN7aB_XuxaC3Mu9Q,8371
|
92
95
|
geo_activity_playground/webui/static/site.webmanifest,sha256=4vYxdPMpwTdB8EmOvHkkYcjZ8Yrci3pOwwY3o_VwACA,440
|
93
96
|
geo_activity_playground/webui/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
94
|
-
geo_activity_playground/webui/summary/blueprint.py,sha256=
|
95
|
-
geo_activity_playground/webui/summary/controller.py,sha256=
|
97
|
+
geo_activity_playground/webui/summary/blueprint.py,sha256=tfA2aPF19yKwkQOb5lPQBySoQYYhTn49Iuh0SYvsGP8,593
|
98
|
+
geo_activity_playground/webui/summary/controller.py,sha256=cWn5szA1o5Vjht0DyhRwBjmwqJryrLcmm4FUdmVpUoo,9443
|
96
99
|
geo_activity_playground/webui/summary/templates/summary/index.html.j2,sha256=rsII1eMY-xNugh8A9SecnEcDZqkEOWYIfiHAGroQYuM,4442
|
97
|
-
geo_activity_playground/webui/templates/home.html.j2,sha256=
|
98
|
-
geo_activity_playground/webui/templates/page.html.j2,sha256=
|
99
|
-
geo_activity_playground/webui/templates/search.html.j2,sha256=FvNRoDfUlSzXjM_tqZY_fDhuhUDgbPaY73q56gdvF1A,1130
|
100
|
+
geo_activity_playground/webui/templates/home.html.j2,sha256=eIPNyLHhUNVTITDbn6nR82-ZJA5Dp4SY41cZTjymZDU,2428
|
101
|
+
geo_activity_playground/webui/templates/page.html.j2,sha256=HN7s4i4kR3laMFkToktjwmTQiTHdrY3nqKcCVO9nKdA,11088
|
100
102
|
geo_activity_playground/webui/tile/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
101
103
|
geo_activity_playground/webui/tile/blueprint.py,sha256=cK0o2Z3BrLycgF9zw0F8s9qF-JaYDbF5Gog-GXDtUZ8,943
|
102
104
|
geo_activity_playground/webui/tile/controller.py,sha256=PISh4vKs27b-LxFfTARtr5RAwHFresA1Kw1MDcERSRU,1221
|
@@ -105,8 +107,8 @@ geo_activity_playground/webui/upload/blueprint.py,sha256=xX9scEmleN_dL03jfhWRh5y
|
|
105
107
|
geo_activity_playground/webui/upload/controller.py,sha256=disRtrlvPiqsIFt9UaAokgtRtXCvosg7bXkAnN_qaxk,4102
|
106
108
|
geo_activity_playground/webui/upload/templates/upload/index.html.j2,sha256=I1Ix8tDS3YBdi-HdaNfjkzYXVVCjfUTe5PFTnap1ydc,775
|
107
109
|
geo_activity_playground/webui/upload/templates/upload/reload.html.j2,sha256=YZWX5eDeNyqKJdQAywDBcU8DZBm22rRBbZqFjrFrCvQ,556
|
108
|
-
geo_activity_playground-0.
|
109
|
-
geo_activity_playground-0.
|
110
|
-
geo_activity_playground-0.
|
111
|
-
geo_activity_playground-0.
|
112
|
-
geo_activity_playground-0.
|
110
|
+
geo_activity_playground-0.29.0.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
|
111
|
+
geo_activity_playground-0.29.0.dist-info/METADATA,sha256=692u7MhLYbWTJR5OSwKqyS8sZDG3oq3TNZQyPIsHVlk,1612
|
112
|
+
geo_activity_playground-0.29.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
|
113
|
+
geo_activity_playground-0.29.0.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
|
114
|
+
geo_activity_playground-0.29.0.dist-info/RECORD,,
|
@@ -1,19 +0,0 @@
|
|
1
|
-
import logging
|
2
|
-
|
3
|
-
from ..core.activities import ActivityRepository
|
4
|
-
|
5
|
-
logger = logging.getLogger(__name__)
|
6
|
-
|
7
|
-
|
8
|
-
class SearchController:
|
9
|
-
def __init__(self, repository: ActivityRepository) -> None:
|
10
|
-
self._repository = repository
|
11
|
-
|
12
|
-
def render_search_results(self, name: str) -> dict:
|
13
|
-
logger.info(f"Searching for {name=}")
|
14
|
-
activities = []
|
15
|
-
for _, row in self._repository.meta.iterrows():
|
16
|
-
if name in row["name"]:
|
17
|
-
activities.append(row)
|
18
|
-
|
19
|
-
return {"activities": activities}
|
/geo_activity_playground/webui/{templates/search.html.j2 → search/templates/search/index.html.j2}
RENAMED
File without changes
|
{geo_activity_playground-0.28.0.dist-info → geo_activity_playground-0.29.0.dist-info}/LICENSE
RENAMED
File without changes
|
File without changes
|
File without changes
|