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.
Files changed (33) hide show
  1. geo_activity_playground/core/activities.py +12 -0
  2. geo_activity_playground/core/config.py +6 -2
  3. geo_activity_playground/core/enrichment.py +9 -0
  4. geo_activity_playground/core/meta_search.py +157 -0
  5. geo_activity_playground/core/summary_stats.py +30 -0
  6. geo_activity_playground/core/test_meta_search.py +100 -0
  7. geo_activity_playground/core/test_summary_stats.py +108 -0
  8. geo_activity_playground/webui/activity/controller.py +20 -0
  9. geo_activity_playground/webui/activity/templates/activity/day.html.j2 +3 -10
  10. geo_activity_playground/webui/activity/templates/activity/name.html.j2 +2 -0
  11. geo_activity_playground/webui/activity/templates/activity/show.html.j2 +17 -0
  12. geo_activity_playground/webui/app.py +27 -10
  13. geo_activity_playground/webui/eddington_blueprint.py +167 -58
  14. geo_activity_playground/webui/{equipment/controller.py → equipment_blueprint.py} +29 -42
  15. geo_activity_playground/webui/explorer/blueprint.py +4 -0
  16. geo_activity_playground/webui/heatmap/blueprint.py +10 -29
  17. geo_activity_playground/webui/heatmap/heatmap_controller.py +45 -103
  18. geo_activity_playground/webui/heatmap/templates/heatmap/index.html.j2 +5 -37
  19. geo_activity_playground/webui/search_blueprint.py +40 -71
  20. geo_activity_playground/webui/search_util.py +64 -0
  21. geo_activity_playground/webui/summary_blueprint.py +40 -39
  22. geo_activity_playground/webui/templates/eddington/index.html.j2 +73 -1
  23. geo_activity_playground/webui/{equipment/templates → templates}/equipment/index.html.j2 +3 -5
  24. geo_activity_playground/webui/templates/search/index.html.j2 +34 -87
  25. geo_activity_playground/webui/templates/search_form.html.j2 +116 -0
  26. geo_activity_playground/webui/templates/summary/index.html.j2 +5 -1
  27. {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/METADATA +1 -1
  28. {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/RECORD +31 -27
  29. geo_activity_playground/webui/equipment/__init__.py +0 -0
  30. geo_activity_playground/webui/equipment/blueprint.py +0 -16
  31. {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/LICENSE +0 -0
  32. {geo_activity_playground-0.36.2.dist-info → geo_activity_playground-0.38.0.dist-info}/WHEEL +0 -0
  33. {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 .equipment.blueprint import make_equipment_blueprint
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), url_prefix="/eddington"
104
+ make_eddington_blueprint(repository, search_query_history),
105
+ url_prefix="/eddington",
104
106
  )
105
107
  app.register_blueprint(
106
- make_equipment_blueprint(equipment_controller), url_prefix="/equipment"
108
+ make_equipment_blueprint(repository, config), url_prefix="/equipment"
107
109
  )
108
110
  app.register_blueprint(
109
- make_explorer_blueprint(explorer_controller), url_prefix="/explorer"
111
+ make_explorer_blueprint(explorer_controller, authenticator),
112
+ url_prefix="/explorer",
110
113
  )
111
114
  app.register_blueprint(
112
- make_heatmap_blueprint(repository, tile_visit_accessor, config_accessor()),
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(repository),
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), url_prefix="/summary"
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
- return {
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(repository: ActivityRepository) -> 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
- activities = repository.meta.loc[
16
- repository.meta["consider_for_achievements"]
17
- ].copy()
18
- activities["day"] = [start.date() for start in activities["start"]]
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
- sum_per_day = activities.groupby("day").apply(
21
- lambda group: int(sum(group["distance_km"])), include_groups=False
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
- counts = dict(zip(*np.unique(sorted(sum_per_day), return_counts=True)))
24
- eddington = pd.DataFrame(
25
- {"distance_km": d, "count": counts.get(d, 0)}
26
- for d in range(max(counts.keys()) + 1)
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
- eddington["total"] = eddington["count"][::-1].cumsum()[::-1]
29
- x = list(range(1, max(eddington["distance_km"]) + 1))
30
- en = eddington.loc[eddington["total"] >= eddington["distance_km"]][
31
- "distance_km"
32
- ].iloc[-1]
33
- eddington["missing"] = eddington["distance_km"] - eddington["total"]
34
-
35
- logarithmic_plot = (
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
- alt.Chart(
39
- eddington,
40
- height=500,
41
- width=1000,
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
- alt.Chart(pd.DataFrame({"distance_km": x, "total": x}))
65
- .mark_line(color="red")
66
- .encode(alt.X("distance_km"), alt.Y("total"))
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
- .interactive()
70
- .to_json(format="vega")
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
- return render_template(
73
- "eddington/index.html.j2",
74
- eddington_number=en,
75
- logarithmic_plot=logarithmic_plot,
76
- eddington_table=eddington.loc[
77
- (eddington["distance_km"] > en) & (eddington["distance_km"] <= en + 10)
78
- ].to_dict(orient="records"),
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 blueprint
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
- class EquipmentController:
9
- def __init__(self, repository: ActivityRepository, config: Config) -> None:
10
- self._repository = repository
11
- self._config = config
12
+ def make_equipment_blueprint(
13
+ repository: ActivityRepository, config: Config
14
+ ) -> Blueprint:
15
+ blueprint = Blueprint("equipment", __name__, template_folder="templates")
12
16
 
13
- def render(self) -> dict:
14
- kind_per_equipment = self._repository.meta.groupby("equipment").apply(
15
- lambda group: group.groupby("kind")
16
- .apply(lambda group2: sum(group2["distance_km"]), include_groups=False)
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.index:
42
- selection = self._repository.meta.loc[
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("kind", title="Kind"),
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
- for equipment, offset in self._config.equipment_offsets.items():
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.reset_index().to_dict(
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
  )