geo-activity-playground 0.40.0__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.
- geo_activity_playground/alembic/versions/38882503dc7c_add_tags_to_activities.py +70 -0
- geo_activity_playground/alembic/versions/script.py.mako +0 -6
- geo_activity_playground/core/activities.py +17 -30
- geo_activity_playground/core/datamodel.py +83 -2
- geo_activity_playground/core/test_datamodel.py +14 -1
- geo_activity_playground/importers/strava_checkout.py +2 -5
- geo_activity_playground/webui/app.py +6 -2
- geo_activity_playground/webui/blueprints/activity_blueprint.py +20 -3
- geo_activity_playground/webui/blueprints/bubble_chart_blueprint.py +50 -25
- geo_activity_playground/webui/blueprints/calendar_blueprint.py +12 -4
- geo_activity_playground/webui/blueprints/eddington_blueprints.py +253 -0
- geo_activity_playground/webui/blueprints/entry_views.py +30 -15
- geo_activity_playground/webui/blueprints/explorer_blueprint.py +83 -9
- geo_activity_playground/webui/blueprints/summary_blueprint.py +102 -42
- geo_activity_playground/webui/columns.py +37 -0
- geo_activity_playground/webui/templates/activity/show.html.j2 +15 -4
- geo_activity_playground/webui/templates/bubble_chart/index.html.j2 +24 -8
- geo_activity_playground/webui/templates/eddington/elevation_gain.html.j2 +150 -0
- geo_activity_playground/webui/templates/elevation_eddington/index.html.j2 +150 -0
- geo_activity_playground/webui/templates/explorer/server-side.html.j2 +72 -0
- geo_activity_playground/webui/templates/home.html.j2 +14 -5
- geo_activity_playground/webui/templates/page.html.j2 +10 -1
- geo_activity_playground/webui/templates/summary/index.html.j2 +91 -2
- {geo_activity_playground-0.40.0.dist-info → geo_activity_playground-0.41.0.dist-info}/METADATA +1 -1
- {geo_activity_playground-0.40.0.dist-info → geo_activity_playground-0.41.0.dist-info}/RECORD +29 -24
- geo_activity_playground/webui/blueprints/eddington_blueprint.py +0 -194
- /geo_activity_playground/webui/templates/eddington/{index.html.j2 → distance.html.j2} +0 -0
- {geo_activity_playground-0.40.0.dist-info → geo_activity_playground-0.41.0.dist-info}/LICENSE +0 -0
- {geo_activity_playground-0.40.0.dist-info → geo_activity_playground-0.41.0.dist-info}/WHEEL +0 -0
- {geo_activity_playground-0.40.0.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")
|
File without changes
|
{geo_activity_playground-0.40.0.dist-info → geo_activity_playground-0.41.0.dist-info}/LICENSE
RENAMED
File without changes
|
File without changes
|
File without changes
|