geo-activity-playground 0.40.1__py3-none-any.whl → 0.41.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 (28) hide show
  1. geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +70 -0
  2. geo_activity_playground/alembic/versions/script.py.mako +0 -6
  3. geo_activity_playground/core/activities.py +17 -30
  4. geo_activity_playground/core/datamodel.py +81 -0
  5. geo_activity_playground/webui/app.py +6 -2
  6. geo_activity_playground/webui/blueprints/activity_blueprint.py +20 -3
  7. geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +50 -25
  8. geo_activity_playground/webui/blueprints/calendar_blueprint.py +12 -4
  9. geo_activity_playground/webui/blueprints/eddington_blueprints.py +253 -0
  10. geo_activity_playground/webui/blueprints/entry_views.py +30 -15
  11. geo_activity_playground/webui/blueprints/explorer_blueprint.py +83 -9
  12. geo_activity_playground/webui/blueprints/summary_blueprint.py +102 -42
  13. geo_activity_playground/webui/columns.py +37 -0
  14. geo_activity_playground/webui/templates/activity/show.html.j2 +15 -4
  15. geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +24 -8
  16. geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +150 -0
  17. geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +150 -0
  18. geo_activity_playground/webui/templates/explorer/server-side.html.j2 +72 -0
  19. geo_activity_playground/webui/templates/home.html.j2 +14 -5
  20. geo_activity_playground/webui/templates/page.html.j2 +10 -1
  21. geo_activity_playground/webui/templates/summary/index.html.j2 +91 -2
  22. {geo_activity_playground-0.40.1.dist-info → geo_activity_playground-0.41.0.dist-info}/METADATA +1 -1
  23. {geo_activity_playground-0.40.1.dist-info → geo_activity_playground-0.41.0.dist-info}/RECORD +27 -22
  24. geo_activity_playground/webui/blueprints/eddington_blueprint.py +0 -194
  25. /geo_activity_playground/webui/templates/eddington/{index.html.j2 → distance.html.j2} +0 -0
  26. {geo_activity_playground-0.40.1.dist-info → geo_activity_playground-0.41.0.dist-info}/LICENSE +0 -0
  27. {geo_activity_playground-0.40.1.dist-info → geo_activity_playground-0.41.0.dist-info}/WHEEL +0 -0
  28. {geo_activity_playground-0.40.1.dist-info → geo_activity_playground-0.41.0.dist-info}/entry_points.txt +0 -0
@@ -1,194 +0,0 @@
1
- import datetime
2
-
3
- import altair as alt
4
- import numpy as np
5
- import pandas as pd
6
- from flask import Blueprint
7
- from flask import render_template
8
- from flask import request
9
-
10
- from ...core.activities import ActivityRepository
11
- from ...core.meta_search import apply_search_query
12
- from ..search_util import search_query_from_form
13
- from ..search_util import SearchQueryHistory
14
-
15
-
16
- def register_eddington_blueprint(
17
- repository: ActivityRepository, search_query_history: SearchQueryHistory
18
- ) -> Blueprint:
19
- blueprint = Blueprint("eddington", __name__, template_folder="templates")
20
-
21
- @blueprint.route("/")
22
- def index():
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
- )
30
-
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"])
45
- )
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),
68
- )
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
- (
94
- (
95
- alt.Chart(
96
- eddington_df,
97
- height=500,
98
- width=800,
99
- title=f"Eddington Number {en}",
100
- )
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
- ],
118
- )
119
- )
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
- )
125
- )
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())
179
- )
180
- eddington_number_history["eddington_number"].append(len(top_days))
181
- history = pd.DataFrame(eddington_number_history)
182
-
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
- alt.Tooltip("date", title="Date"),
191
- alt.Tooltip("eddington_number", title="Eddington number"),
192
- ],
193
- )
194
- ).to_json(format="vega")