geo-activity-playground 0.36.2__py3-none-any.whl → 0.38.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/activities.py +12 -0
- geo_activity_playground/core/config.py +6 -2
- geo_activity_playground/core/enrichment.py +9 -0
- geo_activity_playground/core/meta_search.py +157 -0
- geo_activity_playground/core/summary_stats.py +30 -0
- geo_activity_playground/core/test_meta_search.py +100 -0
- geo_activity_playground/core/test_summary_stats.py +108 -0
- geo_activity_playground/webui/activity/controller.py +20 -0
- geo_activity_playground/webui/activity/templates/activity/day.html.j2 +3 -10
- geo_activity_playground/webui/activity/templates/activity/name.html.j2 +2 -0
- geo_activity_playground/webui/activity/templates/activity/show.html.j2 +17 -0
- geo_activity_playground/webui/app.py +27 -10
- geo_activity_playground/webui/eddington_blueprint.py +167 -58
- geo_activity_playground/webui/{equipment/controller.py → equipment_blueprint.py} +29 -42
- geo_activity_playground/webui/explorer/blueprint.py +4 -0
- geo_activity_playground/webui/heatmap/blueprint.py +10 -29
- geo_activity_playground/webui/heatmap/heatmap_controller.py +45 -103
- geo_activity_playground/webui/heatmap/templates/heatmap/index.html.j2 +5 -37
- geo_activity_playground/webui/search_blueprint.py +40 -71
- geo_activity_playground/webui/search_util.py +64 -0
- geo_activity_playground/webui/summary_blueprint.py +40 -39
- geo_activity_playground/webui/templates/eddington/index.html.j2 +73 -1
- geo_activity_playground/webui/{equipment/templates → templates}/equipment/index.html.j2 +3 -5
- geo_activity_playground/webui/templates/search/index.html.j2 +34 -87
- geo_activity_playground/webui/templates/search_form.html.j2 +116 -0
- geo_activity_playground/webui/templates/summary/index.html.j2 +5 -1
- {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/METADATA +1 -1
- {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/RECORD +31 -27
- geo_activity_playground/webui/equipment/__init__.py +0 -0
- geo_activity_playground/webui/equipment/blueprint.py +0 -16
- {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/LICENSE +0 -0
- {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/WHEEL +0 -0
- {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/entry_points.txt +0 -0
@@ -8,6 +8,7 @@ import urllib.parse
|
|
8
8
|
|
9
9
|
from flask import Flask
|
10
10
|
from flask import render_template
|
11
|
+
from flask import request
|
11
12
|
|
12
13
|
from ..core.activities import ActivityRepository
|
13
14
|
from ..core.config import Config
|
@@ -21,8 +22,7 @@ from .calendar.blueprint import make_calendar_blueprint
|
|
21
22
|
from .calendar.controller import CalendarController
|
22
23
|
from .eddington_blueprint import make_eddington_blueprint
|
23
24
|
from .entry_controller import EntryController
|
24
|
-
from .
|
25
|
-
from .equipment.controller import EquipmentController
|
25
|
+
from .equipment_blueprint import make_equipment_blueprint
|
26
26
|
from .explorer.blueprint import make_explorer_blueprint
|
27
27
|
from .explorer.controller import ExplorerController
|
28
28
|
from .heatmap.blueprint import make_heatmap_blueprint
|
@@ -32,6 +32,7 @@ from .square_planner_blueprint import make_square_planner_blueprint
|
|
32
32
|
from .summary_blueprint import make_summary_blueprint
|
33
33
|
from .tile_blueprint import make_tile_blueprint
|
34
34
|
from .upload_blueprint import make_upload_blueprint
|
35
|
+
from geo_activity_playground.webui.search_util import SearchQueryHistory
|
35
36
|
|
36
37
|
|
37
38
|
def route_start(app: Flask, repository: ActivityRepository, config: Config) -> None:
|
@@ -80,11 +81,11 @@ def web_ui_main(
|
|
80
81
|
return f"{h}:{m:02d}:{s:02d}"
|
81
82
|
|
82
83
|
authenticator = Authenticator(config_accessor())
|
84
|
+
search_query_history = SearchQueryHistory(config_accessor, authenticator)
|
83
85
|
|
84
86
|
config = config_accessor()
|
85
87
|
activity_controller = ActivityController(repository, tile_visit_accessor, config)
|
86
88
|
calendar_controller = CalendarController(repository)
|
87
|
-
equipment_controller = EquipmentController(repository, config)
|
88
89
|
explorer_controller = ExplorerController(
|
89
90
|
repository, tile_visit_accessor, config_accessor
|
90
91
|
)
|
@@ -100,16 +101,20 @@ def web_ui_main(
|
|
100
101
|
make_calendar_blueprint(calendar_controller), url_prefix="/calendar"
|
101
102
|
)
|
102
103
|
app.register_blueprint(
|
103
|
-
make_eddington_blueprint(repository),
|
104
|
+
make_eddington_blueprint(repository, search_query_history),
|
105
|
+
url_prefix="/eddington",
|
104
106
|
)
|
105
107
|
app.register_blueprint(
|
106
|
-
make_equipment_blueprint(
|
108
|
+
make_equipment_blueprint(repository, config), url_prefix="/equipment"
|
107
109
|
)
|
108
110
|
app.register_blueprint(
|
109
|
-
make_explorer_blueprint(explorer_controller),
|
111
|
+
make_explorer_blueprint(explorer_controller, authenticator),
|
112
|
+
url_prefix="/explorer",
|
110
113
|
)
|
111
114
|
app.register_blueprint(
|
112
|
-
make_heatmap_blueprint(
|
115
|
+
make_heatmap_blueprint(
|
116
|
+
repository, tile_visit_accessor, config_accessor(), search_query_history
|
117
|
+
),
|
113
118
|
url_prefix="/heatmap",
|
114
119
|
)
|
115
120
|
app.register_blueprint(
|
@@ -121,11 +126,14 @@ def web_ui_main(
|
|
121
126
|
url_prefix="/square-planner",
|
122
127
|
)
|
123
128
|
app.register_blueprint(
|
124
|
-
make_search_blueprint(
|
129
|
+
make_search_blueprint(
|
130
|
+
repository, search_query_history, authenticator, config_accessor
|
131
|
+
),
|
125
132
|
url_prefix="/search",
|
126
133
|
)
|
127
134
|
app.register_blueprint(
|
128
|
-
make_summary_blueprint(repository, config),
|
135
|
+
make_summary_blueprint(repository, config, search_query_history),
|
136
|
+
url_prefix="/summary",
|
129
137
|
)
|
130
138
|
|
131
139
|
app.register_blueprint(make_tile_blueprint(config), url_prefix="/tile")
|
@@ -146,11 +154,20 @@ def web_ui_main(
|
|
146
154
|
|
147
155
|
@app.context_processor
|
148
156
|
def inject_global_variables() -> dict:
|
149
|
-
|
157
|
+
variables = {
|
150
158
|
"version": _try_get_version(),
|
151
159
|
"num_activities": len(repository),
|
152
160
|
"map_tile_attribution": config_accessor().map_tile_attribution,
|
161
|
+
"search_query_favorites": search_query_history.prepare_favorites(),
|
162
|
+
"search_query_last": search_query_history.prepare_last(),
|
163
|
+
"request_url": urllib.parse.quote_plus(request.url),
|
153
164
|
}
|
165
|
+
if len(repository):
|
166
|
+
variables["equipments_avail"] = sorted(
|
167
|
+
repository.meta["equipment"].unique()
|
168
|
+
)
|
169
|
+
variables["kinds_avail"] = sorted(repository.meta["kind"].unique())
|
170
|
+
return variables
|
154
171
|
|
155
172
|
app.run(host=host, port=port)
|
156
173
|
|
@@ -1,81 +1,190 @@
|
|
1
|
+
import datetime
|
2
|
+
|
1
3
|
import altair as alt
|
2
4
|
import numpy as np
|
3
5
|
import pandas as pd
|
4
6
|
from flask import Blueprint
|
5
7
|
from flask import render_template
|
8
|
+
from flask import request
|
6
9
|
|
7
10
|
from geo_activity_playground.core.activities import ActivityRepository
|
11
|
+
from geo_activity_playground.core.meta_search import apply_search_query
|
12
|
+
from geo_activity_playground.webui.search_util import search_query_from_form
|
13
|
+
from geo_activity_playground.webui.search_util import SearchQueryHistory
|
8
14
|
|
9
15
|
|
10
|
-
def make_eddington_blueprint(
|
16
|
+
def make_eddington_blueprint(
|
17
|
+
repository: ActivityRepository, search_query_history: SearchQueryHistory
|
18
|
+
) -> Blueprint:
|
11
19
|
blueprint = Blueprint("eddington", __name__, template_folder="templates")
|
12
20
|
|
13
21
|
@blueprint.route("/")
|
14
22
|
def index():
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
23
|
+
query = search_query_from_form(request.args)
|
24
|
+
search_query_history.register_query(query)
|
25
|
+
activities = (
|
26
|
+
apply_search_query(repository.meta, query)
|
27
|
+
.dropna(subset=["start", "distance_km"])
|
28
|
+
.copy()
|
29
|
+
)
|
19
30
|
|
20
|
-
|
21
|
-
|
31
|
+
activities["year"] = [start.year for start in activities["start"]]
|
32
|
+
activities["date"] = [start.date() for start in activities["start"]]
|
33
|
+
activities["isoyear"] = [
|
34
|
+
start.isocalendar().year for start in activities["start"]
|
35
|
+
]
|
36
|
+
activities["isoweek"] = [
|
37
|
+
start.isocalendar().week for start in activities["start"]
|
38
|
+
]
|
39
|
+
|
40
|
+
en_per_day, eddington_df_per_day = _get_distances_per_group(
|
41
|
+
activities.groupby("date")
|
42
|
+
)
|
43
|
+
en_per_week, eddington_df_per_week = _get_distances_per_group(
|
44
|
+
activities.groupby(["isoyear", "isoweek"])
|
22
45
|
)
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
46
|
+
|
47
|
+
return render_template(
|
48
|
+
"eddington/index.html.j2",
|
49
|
+
eddington_number=en_per_day,
|
50
|
+
logarithmic_plot=_make_eddington_plot(
|
51
|
+
eddington_df_per_day, en_per_day, "Days"
|
52
|
+
),
|
53
|
+
eddington_per_week=en_per_week,
|
54
|
+
eddington_per_week_plot=_make_eddington_plot(
|
55
|
+
eddington_df_per_week, en_per_week, "Weeks"
|
56
|
+
),
|
57
|
+
eddington_table=eddington_df_per_day.loc[
|
58
|
+
(eddington_df_per_day["distance_km"] > en_per_day)
|
59
|
+
& (eddington_df_per_day["distance_km"] <= en_per_day + 10)
|
60
|
+
].to_dict(orient="records"),
|
61
|
+
eddington_table_weeks=eddington_df_per_week.loc[
|
62
|
+
(eddington_df_per_week["distance_km"] > en_per_week)
|
63
|
+
& (eddington_df_per_week["distance_km"] <= en_per_week + 10)
|
64
|
+
].to_dict(orient="records"),
|
65
|
+
query=query.to_jinja(),
|
66
|
+
yearly_eddington=_get_yearly_eddington(activities),
|
67
|
+
eddington_number_history_plot=_get_eddington_number_history(activities),
|
27
68
|
)
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
69
|
+
|
70
|
+
return blueprint
|
71
|
+
|
72
|
+
|
73
|
+
def _get_distances_per_group(grouped) -> tuple[int, pd.DataFrame]:
|
74
|
+
sum_per_group = grouped.apply(
|
75
|
+
lambda group: int(sum(group["distance_km"])), include_groups=False
|
76
|
+
)
|
77
|
+
counts = dict(zip(*np.unique(sorted(sum_per_group), return_counts=True)))
|
78
|
+
eddington = pd.DataFrame(
|
79
|
+
{"distance_km": d, "count": counts.get(d, 0)}
|
80
|
+
for d in range(max(counts.keys()) + 1)
|
81
|
+
)
|
82
|
+
eddington["total"] = eddington["count"][::-1].cumsum()[::-1]
|
83
|
+
en = eddington.loc[eddington["total"] >= eddington["distance_km"]][
|
84
|
+
"distance_km"
|
85
|
+
].iloc[-1]
|
86
|
+
eddington["missing"] = eddington["distance_km"] - eddington["total"]
|
87
|
+
return en, eddington
|
88
|
+
|
89
|
+
|
90
|
+
def _make_eddington_plot(eddington_df: pd.DataFrame, en: int, interval: str) -> dict:
|
91
|
+
x = list(range(1, max(eddington_df["distance_km"]) + 1))
|
92
|
+
return (
|
93
|
+
(
|
36
94
|
(
|
37
|
-
(
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
title=f"Eddington Number {en}",
|
43
|
-
)
|
44
|
-
.mark_area(interpolate="step")
|
45
|
-
.encode(
|
46
|
-
alt.X(
|
47
|
-
"distance_km",
|
48
|
-
scale=alt.Scale(domainMin=0),
|
49
|
-
title="Distance / km",
|
50
|
-
),
|
51
|
-
alt.Y(
|
52
|
-
"total",
|
53
|
-
scale=alt.Scale(domainMax=en + 10),
|
54
|
-
title="Days exceeding distance",
|
55
|
-
),
|
56
|
-
[
|
57
|
-
alt.Tooltip("distance_km", title="Distance / km"),
|
58
|
-
alt.Tooltip("total", title="Days exceeding distance"),
|
59
|
-
alt.Tooltip("missing", title="Days missing for next"),
|
60
|
-
],
|
61
|
-
)
|
95
|
+
alt.Chart(
|
96
|
+
eddington_df,
|
97
|
+
height=500,
|
98
|
+
width=800,
|
99
|
+
title=f"Eddington Number {en}",
|
62
100
|
)
|
63
|
-
|
64
|
-
|
65
|
-
.
|
66
|
-
|
101
|
+
.mark_area(interpolate="step")
|
102
|
+
.encode(
|
103
|
+
alt.X(
|
104
|
+
"distance_km",
|
105
|
+
scale=alt.Scale(domainMin=0),
|
106
|
+
title="Distance / km",
|
107
|
+
),
|
108
|
+
alt.Y(
|
109
|
+
"total",
|
110
|
+
scale=alt.Scale(domainMax=en + 10),
|
111
|
+
title=f"{interval} exceeding distance",
|
112
|
+
),
|
113
|
+
[
|
114
|
+
alt.Tooltip("distance_km", title="Distance / km"),
|
115
|
+
alt.Tooltip("total", title=f"{interval} exceeding distance"),
|
116
|
+
alt.Tooltip("missing", title=f"{interval} missing for next"),
|
117
|
+
],
|
67
118
|
)
|
68
119
|
)
|
69
|
-
|
70
|
-
|
120
|
+
+ (
|
121
|
+
alt.Chart(pd.DataFrame({"distance_km": x, "total": x}))
|
122
|
+
.mark_line(color="red")
|
123
|
+
.encode(alt.X("distance_km"), alt.Y("total"))
|
124
|
+
)
|
71
125
|
)
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
126
|
+
.interactive(bind_x=False)
|
127
|
+
.to_json(format="vega")
|
128
|
+
)
|
129
|
+
|
130
|
+
|
131
|
+
def _get_eddington_number(distances: pd.Series) -> int:
|
132
|
+
if len(distances) == 1:
|
133
|
+
if distances.iloc[0] >= 1:
|
134
|
+
return 1
|
135
|
+
else:
|
136
|
+
0
|
137
|
+
|
138
|
+
sorted_distances = sorted(distances, reverse=True)
|
139
|
+
for en, distance in enumerate(sorted_distances, 1):
|
140
|
+
if distance < en:
|
141
|
+
return en - 1
|
142
|
+
|
143
|
+
|
144
|
+
def _get_yearly_eddington(meta: pd.DataFrame) -> dict[int, int]:
|
145
|
+
meta = meta.dropna(subset=["start", "distance_km"]).copy()
|
146
|
+
meta["year"] = [start.year for start in meta["start"]]
|
147
|
+
meta["date"] = [start.date() for start in meta["start"]]
|
148
|
+
|
149
|
+
yearly_eddington = meta.groupby("year").apply(
|
150
|
+
lambda group: _get_eddington_number(
|
151
|
+
group.groupby("date").apply(
|
152
|
+
lambda group2: int(group2["distance_km"].sum()), include_groups=False
|
153
|
+
)
|
154
|
+
),
|
155
|
+
include_groups=False,
|
156
|
+
)
|
157
|
+
return yearly_eddington.to_dict()
|
158
|
+
|
159
|
+
|
160
|
+
def _get_eddington_number_history(meta: pd.DataFrame) -> dict:
|
161
|
+
|
162
|
+
daily_distances = meta.groupby("date").apply(
|
163
|
+
lambda group2: int(group2["distance_km"].sum()), include_groups=False
|
164
|
+
)
|
165
|
+
|
166
|
+
eddington_number_history = {"date": [], "eddington_number": []}
|
167
|
+
top_days = []
|
168
|
+
for date, distance in daily_distances.items():
|
169
|
+
if len(top_days) == 0:
|
170
|
+
top_days.append(distance)
|
171
|
+
else:
|
172
|
+
if distance >= top_days[0]:
|
173
|
+
top_days.append(distance)
|
174
|
+
top_days.sort()
|
175
|
+
while top_days[0] < len(top_days):
|
176
|
+
top_days.pop(0)
|
177
|
+
eddington_number_history["date"].append(
|
178
|
+
datetime.datetime.combine(date, datetime.datetime.min.time())
|
79
179
|
)
|
180
|
+
eddington_number_history["eddington_number"].append(len(top_days))
|
181
|
+
history = pd.DataFrame(eddington_number_history)
|
80
182
|
|
81
|
-
return
|
183
|
+
return (
|
184
|
+
alt.Chart(history)
|
185
|
+
.mark_line(interpolate="step-after")
|
186
|
+
.encode(
|
187
|
+
alt.X("date", title="Date"),
|
188
|
+
alt.Y("eddington_number", title="Eddington number"),
|
189
|
+
)
|
190
|
+
).to_json(format="vega")
|
@@ -1,47 +1,28 @@
|
|
1
1
|
import altair as alt
|
2
2
|
import pandas as pd
|
3
|
+
from flask import Blueprint
|
4
|
+
from flask import render_template
|
3
5
|
|
4
6
|
from geo_activity_playground.core.activities import ActivityRepository
|
5
7
|
from geo_activity_playground.core.config import Config
|
8
|
+
from geo_activity_playground.core.summary_stats import get_equipment_use_table
|
9
|
+
from geo_activity_playground.webui.plot_util import make_kind_scale
|
6
10
|
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
+
def make_equipment_blueprint(
|
13
|
+
repository: ActivityRepository, config: Config
|
14
|
+
) -> Blueprint:
|
15
|
+
blueprint = Blueprint("equipment", __name__, template_folder="templates")
|
12
16
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
.
|
17
|
-
.idxmax(),
|
18
|
-
include_groups=False,
|
17
|
+
@blueprint.route("/")
|
18
|
+
def index():
|
19
|
+
equipment_summary = get_equipment_use_table(
|
20
|
+
repository.meta, config.equipment_offsets
|
19
21
|
)
|
20
22
|
|
21
|
-
equipment_summary = (
|
22
|
-
self._repository.meta.groupby("equipment")
|
23
|
-
.apply(
|
24
|
-
lambda group: pd.Series(
|
25
|
-
{
|
26
|
-
"total_distance_km": group["distance_km"].sum(),
|
27
|
-
"first_use": group["start"].iloc[0],
|
28
|
-
"last_use": group["start"].iloc[-1],
|
29
|
-
},
|
30
|
-
),
|
31
|
-
include_groups=False,
|
32
|
-
)
|
33
|
-
.sort_values("last_use", ascending=False)
|
34
|
-
)
|
35
|
-
|
36
|
-
equipment_summary["primarily_used_for"] = None
|
37
|
-
for equipment, kind in kind_per_equipment.items():
|
38
|
-
equipment_summary.loc[equipment, "primarily_used_for"] = kind
|
39
|
-
|
40
23
|
equipment_variables = {}
|
41
|
-
for equipment in equipment_summary
|
42
|
-
selection =
|
43
|
-
self._repository.meta["equipment"] == equipment
|
44
|
-
]
|
24
|
+
for equipment in equipment_summary["equipment"]:
|
25
|
+
selection = repository.meta.loc[repository.meta["equipment"] == equipment]
|
45
26
|
total_distances = pd.DataFrame(
|
46
27
|
{
|
47
28
|
"time": selection["start"],
|
@@ -75,6 +56,11 @@ class EquipmentController:
|
|
75
56
|
.encode(
|
76
57
|
alt.X("year(start):O", title="Year"),
|
77
58
|
alt.Y("sum(distance_km)", title="Distance / km"),
|
59
|
+
alt.Color(
|
60
|
+
"kind",
|
61
|
+
scale=make_kind_scale(repository.meta, config),
|
62
|
+
title="Kind",
|
63
|
+
),
|
78
64
|
)
|
79
65
|
.to_json(format="vega")
|
80
66
|
)
|
@@ -87,7 +73,10 @@ class EquipmentController:
|
|
87
73
|
)
|
88
74
|
.mark_bar()
|
89
75
|
.encode(
|
90
|
-
alt.X(
|
76
|
+
alt.X(
|
77
|
+
"kind",
|
78
|
+
title="Kind",
|
79
|
+
),
|
91
80
|
alt.Y("sum(distance_km)", title="Distance / km"),
|
92
81
|
)
|
93
82
|
.to_json(format="vega")
|
@@ -102,13 +91,11 @@ class EquipmentController:
|
|
102
91
|
"usages_plot_id": f"usages_plot_{hash(equipment)}",
|
103
92
|
}
|
104
93
|
|
105
|
-
|
106
|
-
if equipment in equipment_summary.index:
|
107
|
-
equipment_summary.loc[equipment, "total_distance_km"] += offset
|
108
|
-
|
109
|
-
return {
|
94
|
+
variables = {
|
110
95
|
"equipment_variables": equipment_variables,
|
111
|
-
"equipment_summary": equipment_summary.
|
112
|
-
orient="records"
|
113
|
-
),
|
96
|
+
"equipment_summary": equipment_summary.to_dict(orient="records"),
|
114
97
|
}
|
98
|
+
|
99
|
+
return render_template("equipment/index.html.j2", **variables)
|
100
|
+
|
101
|
+
return blueprint
|
@@ -4,11 +4,14 @@ from flask import render_template
|
|
4
4
|
from flask import Response
|
5
5
|
from flask import url_for
|
6
6
|
|
7
|
+
from geo_activity_playground.webui.authenticator import Authenticator
|
8
|
+
from geo_activity_playground.webui.authenticator import needs_authentication
|
7
9
|
from geo_activity_playground.webui.explorer.controller import ExplorerController
|
8
10
|
|
9
11
|
|
10
12
|
def make_explorer_blueprint(
|
11
13
|
explorer_controller: ExplorerController,
|
14
|
+
authenticator: Authenticator,
|
12
15
|
) -> Blueprint:
|
13
16
|
blueprint = Blueprint("explorer", __name__, template_folder="templates")
|
14
17
|
|
@@ -19,6 +22,7 @@ def make_explorer_blueprint(
|
|
19
22
|
)
|
20
23
|
|
21
24
|
@blueprint.route("/enable-zoom-level/<zoom>")
|
25
|
+
@needs_authentication(authenticator)
|
22
26
|
def enable_zoom_level(zoom: str):
|
23
27
|
explorer_controller.enable_zoom_level(int(zoom))
|
24
28
|
return redirect(url_for(".map", zoom=zoom))
|
@@ -8,42 +8,32 @@ from geo_activity_playground.core.activities import ActivityRepository
|
|
8
8
|
from geo_activity_playground.core.config import Config
|
9
9
|
from geo_activity_playground.explorer.tile_visits import TileVisitAccessor
|
10
10
|
from geo_activity_playground.webui.heatmap.heatmap_controller import HeatmapController
|
11
|
+
from geo_activity_playground.webui.search_util import search_query_from_form
|
12
|
+
from geo_activity_playground.webui.search_util import SearchQueryHistory
|
11
13
|
|
12
14
|
|
13
15
|
def make_heatmap_blueprint(
|
14
16
|
repository: ActivityRepository,
|
15
17
|
tile_visit_accessor: TileVisitAccessor,
|
16
18
|
config: Config,
|
19
|
+
search_query_history: SearchQueryHistory,
|
17
20
|
) -> Blueprint:
|
18
21
|
heatmap_controller = HeatmapController(repository, tile_visit_accessor, config)
|
19
22
|
blueprint = Blueprint("heatmap", __name__, template_folder="templates")
|
20
23
|
|
21
24
|
@blueprint.route("/")
|
22
25
|
def index():
|
26
|
+
query = search_query_from_form(request.args)
|
27
|
+
search_query_history.register_query(query)
|
23
28
|
return render_template(
|
24
|
-
"heatmap/index.html.j2",
|
25
|
-
**heatmap_controller.render(
|
26
|
-
[int(k) for k in request.args.getlist("kind")],
|
27
|
-
request.args.get(
|
28
|
-
"date-start", type=dateutil.parser.parse, default=None
|
29
|
-
),
|
30
|
-
request.args.get("date-end", type=dateutil.parser.parse, default=None),
|
31
|
-
)
|
29
|
+
"heatmap/index.html.j2", **heatmap_controller.render(query)
|
32
30
|
)
|
33
31
|
|
34
32
|
@blueprint.route("/tile/<int:z>/<int:x>/<int:y>.png")
|
35
33
|
def tile(x: int, y: int, z: int):
|
34
|
+
query = search_query_from_form(request.args)
|
36
35
|
return Response(
|
37
|
-
heatmap_controller.render_tile(
|
38
|
-
x,
|
39
|
-
y,
|
40
|
-
z,
|
41
|
-
[int(k) for k in request.args.getlist("kind")],
|
42
|
-
request.args.get(
|
43
|
-
"date-start", type=dateutil.parser.parse, default=None
|
44
|
-
),
|
45
|
-
request.args.get("date-end", type=dateutil.parser.parse, default=None),
|
46
|
-
),
|
36
|
+
heatmap_controller.render_tile(x, y, z, query),
|
47
37
|
mimetype="image/png",
|
48
38
|
)
|
49
39
|
|
@@ -51,18 +41,9 @@ def make_heatmap_blueprint(
|
|
51
41
|
"/download/<float:north>/<float:east>/<float:south>/<float:west>/heatmap.png"
|
52
42
|
)
|
53
43
|
def download(north: float, east: float, south: float, west: float):
|
44
|
+
query = search_query_from_form(request.args)
|
54
45
|
return Response(
|
55
|
-
heatmap_controller.download_heatmap(
|
56
|
-
north,
|
57
|
-
east,
|
58
|
-
south,
|
59
|
-
west,
|
60
|
-
[int(k) for k in request.args.getlist("kind")],
|
61
|
-
request.args.get(
|
62
|
-
"date-start", type=dateutil.parser.parse, default=None
|
63
|
-
),
|
64
|
-
request.args.get("date-end", type=dateutil.parser.parse, default=None),
|
65
|
-
),
|
46
|
+
heatmap_controller.download_heatmap(north, east, south, west, query),
|
66
47
|
mimetype="image/png",
|
67
48
|
headers={"Content-disposition": 'attachment; filename="heatmap.png"'},
|
68
49
|
)
|