geo-activity-playground 0.31.0__py3-none-any.whl → 0.32.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 +1 -0
- geo_activity_playground/core/heatmap.py +63 -0
- geo_activity_playground/importers/directory.py +6 -2
- geo_activity_playground/webui/activity/controller.py +47 -31
- geo_activity_playground/webui/summary/controller.py +1 -1
- geo_activity_playground/webui/upload/controller.py +1 -2
- {geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/METADATA +1 -1
- {geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/RECORD +11 -11
- {geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/LICENSE +0 -0
- {geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/WHEEL +0 -0
- {geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/entry_points.txt +0 -0
@@ -29,6 +29,7 @@ class Config:
|
|
29
29
|
)
|
30
30
|
heart_rate_resting: int = 0
|
31
31
|
heart_rate_maximum: Optional[int] = None
|
32
|
+
ignore_suffixes: list[str] = dataclasses.field(default_factory=list)
|
32
33
|
kind_renames: dict[str, str] = dataclasses.field(default_factory=dict)
|
33
34
|
kinds_without_achievements: list[str] = dataclasses.field(default_factory=list)
|
34
35
|
metadata_extraction_regexes: list[str] = dataclasses.field(default_factory=list)
|
@@ -142,6 +142,69 @@ def build_map_from_tiles(tile_bounds: TileBounds) -> np.ndarray:
|
|
142
142
|
return background
|
143
143
|
|
144
144
|
|
145
|
+
def build_map_from_tiles_around_center(
|
146
|
+
center: tuple[float, float],
|
147
|
+
zoom: int,
|
148
|
+
target: tuple[int, int],
|
149
|
+
inner_target: tuple[int, int],
|
150
|
+
) -> np.ndarray:
|
151
|
+
background = np.zeros((target[1], target[0], 3))
|
152
|
+
|
153
|
+
# We will work with the center point and have it in terms of tiles `t` and also in terms of pixels `p`. At the start we know that the tile center must be in the middle of the image.
|
154
|
+
t = np.array(center)
|
155
|
+
p = np.array([inner_target[0] / 2, inner_target[1] / 2])
|
156
|
+
|
157
|
+
# Shift both such that they are in the top-left corner of an even tile.
|
158
|
+
t_offset = np.array([center[0] % 1, center[1] % 1])
|
159
|
+
t -= t_offset
|
160
|
+
p -= t_offset * OSM_TILE_SIZE
|
161
|
+
|
162
|
+
# Shift until we have left the image.
|
163
|
+
shift = np.ceil(p / OSM_TILE_SIZE)
|
164
|
+
p -= shift * OSM_TILE_SIZE
|
165
|
+
t -= shift
|
166
|
+
|
167
|
+
num_tiles = np.ceil(np.array(target) / OSM_TILE_SIZE) + 1
|
168
|
+
|
169
|
+
for x in range(int(t[0]), int(t[0] + num_tiles[0])):
|
170
|
+
for y in range(int(t[1]), int(t[1]) + int(num_tiles[1])):
|
171
|
+
source_x_min = 0
|
172
|
+
source_y_min = 0
|
173
|
+
source_x_max = source_x_min + OSM_TILE_SIZE
|
174
|
+
source_y_max = source_y_min + OSM_TILE_SIZE
|
175
|
+
|
176
|
+
target_x_min = (x - int(t[0])) * OSM_TILE_SIZE + int(p[0])
|
177
|
+
target_y_min = (y - int(t[1])) * OSM_TILE_SIZE + int(p[1])
|
178
|
+
target_x_max = target_x_min + OSM_TILE_SIZE
|
179
|
+
target_y_max = target_y_min + OSM_TILE_SIZE
|
180
|
+
|
181
|
+
if target_x_min < 0:
|
182
|
+
source_x_min -= target_x_min
|
183
|
+
target_x_min = 0
|
184
|
+
if target_y_min < 0:
|
185
|
+
source_y_min -= target_y_min
|
186
|
+
target_y_min = 0
|
187
|
+
if target_x_max > target[0]:
|
188
|
+
a = target_x_max - target[0]
|
189
|
+
target_x_max -= a
|
190
|
+
source_x_max -= a
|
191
|
+
if target_y_max > target[1]:
|
192
|
+
a = target_y_max - target[1]
|
193
|
+
target_y_max -= a
|
194
|
+
source_y_max -= a
|
195
|
+
|
196
|
+
if source_x_max < 0 or source_y_max < 0:
|
197
|
+
continue
|
198
|
+
|
199
|
+
tile = np.array(get_tile(zoom, x, y)) / 255
|
200
|
+
|
201
|
+
background[target_y_min:target_y_max, target_x_min:target_x_max] = tile[
|
202
|
+
source_y_min:source_y_max, source_x_min:source_x_max, :3
|
203
|
+
]
|
204
|
+
|
205
|
+
return background
|
206
|
+
|
207
|
+
|
145
208
|
def convert_to_grayscale(image: np.ndarray) -> np.ndarray:
|
146
209
|
image = np.sum(image * [0.2126, 0.7152, 0.0722], axis=2)
|
147
210
|
image = np.dstack((image, image, image))
|
@@ -10,6 +10,7 @@ from typing import Optional
|
|
10
10
|
from tqdm import tqdm
|
11
11
|
|
12
12
|
from geo_activity_playground.core.activities import ActivityMeta
|
13
|
+
from geo_activity_playground.core.config import Config
|
13
14
|
from geo_activity_playground.core.paths import activity_extracted_dir
|
14
15
|
from geo_activity_playground.core.paths import activity_extracted_meta_dir
|
15
16
|
from geo_activity_playground.core.paths import activity_extracted_time_series_dir
|
@@ -24,13 +25,16 @@ ACTIVITY_DIR = pathlib.Path("Activities")
|
|
24
25
|
|
25
26
|
|
26
27
|
def import_from_directory(
|
27
|
-
metadata_extraction_regexes: list[str], num_processes: Optional[int]
|
28
|
+
metadata_extraction_regexes: list[str], num_processes: Optional[int], config: Config
|
28
29
|
) -> None:
|
29
30
|
|
30
31
|
activity_paths = [
|
31
32
|
path
|
32
33
|
for path in ACTIVITY_DIR.rglob("*.*")
|
33
|
-
if path.is_file()
|
34
|
+
if path.is_file()
|
35
|
+
and path.suffixes
|
36
|
+
and not path.stem.startswith(".")
|
37
|
+
and not path.suffix in config.ignore_suffixes
|
34
38
|
]
|
35
39
|
work_tracker = WorkTracker(activity_extracted_dir() / "work-tracker-extract.pickle")
|
36
40
|
new_activity_paths = work_tracker.filter(activity_paths)
|
@@ -23,9 +23,11 @@ from geo_activity_playground.core.config import Config
|
|
23
23
|
from geo_activity_playground.core.heart_rate import HeartRateZoneComputer
|
24
24
|
from geo_activity_playground.core.heatmap import add_margin_to_geo_bounds
|
25
25
|
from geo_activity_playground.core.heatmap import build_map_from_tiles
|
26
|
+
from geo_activity_playground.core.heatmap import build_map_from_tiles_around_center
|
26
27
|
from geo_activity_playground.core.heatmap import GeoBounds
|
27
28
|
from geo_activity_playground.core.heatmap import get_bounds
|
28
29
|
from geo_activity_playground.core.heatmap import get_sensible_zoom_level
|
30
|
+
from geo_activity_playground.core.heatmap import OSM_MAX_ZOOM
|
29
31
|
from geo_activity_playground.core.heatmap import OSM_TILE_SIZE
|
30
32
|
from geo_activity_playground.core.heatmap import PixelBounds
|
31
33
|
from geo_activity_playground.core.heatmap import TileBounds
|
@@ -459,42 +461,55 @@ def make_sharepic(
|
|
459
461
|
time_series: pd.DataFrame,
|
460
462
|
sharepic_suppressed_fields: list[str],
|
461
463
|
) -> bytes:
|
462
|
-
|
464
|
+
tile_x = time_series["x"]
|
465
|
+
tile_y = time_series["y"]
|
466
|
+
tile_width = tile_x.max() - tile_x.min()
|
467
|
+
tile_height = tile_y.max() - tile_y.min()
|
468
|
+
|
469
|
+
target_width = 600
|
470
|
+
target_height = 600
|
471
|
+
footer_height = 100
|
472
|
+
target_map_height = target_height - footer_height
|
473
|
+
|
474
|
+
zoom = int(
|
475
|
+
min(
|
476
|
+
np.log2(target_width / tile_width / OSM_TILE_SIZE),
|
477
|
+
np.log2(target_map_height / tile_height / OSM_TILE_SIZE),
|
478
|
+
OSM_MAX_ZOOM,
|
479
|
+
)
|
480
|
+
)
|
463
481
|
|
464
|
-
|
465
|
-
|
466
|
-
tile_bounds = get_sensible_zoom_level(geo_bounds, (1500, 1500))
|
467
|
-
tile_bounds = make_tile_bounds_square(tile_bounds)
|
468
|
-
background = build_map_from_tiles(tile_bounds)
|
469
|
-
# background = convert_to_grayscale(background)
|
482
|
+
tile_xz = tile_x * 2**zoom
|
483
|
+
tile_yz = tile_y * 2**zoom
|
470
484
|
|
471
|
-
|
472
|
-
|
485
|
+
tile_xz_center = (
|
486
|
+
(tile_xz.max() + tile_xz.min()) / 2,
|
487
|
+
(tile_yz.max() + tile_yz.min()) / 2,
|
488
|
+
)
|
473
489
|
|
474
|
-
background =
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
490
|
+
background = build_map_from_tiles_around_center(
|
491
|
+
tile_xz_center,
|
492
|
+
zoom,
|
493
|
+
(target_width, target_height),
|
494
|
+
(target_width, target_map_height),
|
495
|
+
)
|
479
496
|
|
480
497
|
img = Image.fromarray((background * 255).astype("uint8"), "RGB")
|
481
498
|
draw = ImageDraw.Draw(img, mode="RGBA")
|
482
499
|
|
483
500
|
for _, group in time_series.groupby("segment_id"):
|
484
|
-
xs, ys = compute_tile_float(
|
485
|
-
group["latitude"], group["longitude"], tile_bounds.zoom
|
486
|
-
)
|
487
501
|
yx = list(
|
488
|
-
(
|
489
|
-
|
490
|
-
|
502
|
+
zip(
|
503
|
+
(tile_xz - tile_xz_center[0]) * OSM_TILE_SIZE + target_width / 2,
|
504
|
+
(tile_yz - tile_xz_center[1]) * OSM_TILE_SIZE + target_map_height / 2,
|
491
505
|
)
|
492
|
-
for x, y in zip(xs, ys)
|
493
506
|
)
|
494
507
|
|
495
508
|
draw.line(yx, fill="red", width=4)
|
496
509
|
|
497
|
-
draw.rectangle(
|
510
|
+
draw.rectangle(
|
511
|
+
[0, img.height - footer_height, img.width, img.height], fill=(0, 0, 0, 180)
|
512
|
+
)
|
498
513
|
|
499
514
|
facts = {
|
500
515
|
"kind": f"{activity['kind']}",
|
@@ -515,19 +530,20 @@ def make_sharepic(
|
|
515
530
|
if not key in sharepic_suppressed_fields
|
516
531
|
}
|
517
532
|
|
518
|
-
draw.text(
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
533
|
+
draw.text(
|
534
|
+
(35, img.height - footer_height + 10),
|
535
|
+
" ".join(facts.values()),
|
536
|
+
font_size=20,
|
537
|
+
)
|
523
538
|
|
524
|
-
|
525
|
-
|
526
|
-
|
539
|
+
draw.text(
|
540
|
+
(img.width - 250, img.height - 20),
|
541
|
+
"Map: © Open Street Map Contributors",
|
542
|
+
font_size=14,
|
543
|
+
)
|
527
544
|
|
528
545
|
f = io.BytesIO()
|
529
546
|
img.save(f, format="png")
|
530
|
-
# pl.imsave(f, background, format="png")
|
531
547
|
return bytes(f.getbuffer())
|
532
548
|
|
533
549
|
|
@@ -21,7 +21,7 @@ class SummaryController:
|
|
21
21
|
def render(self) -> dict:
|
22
22
|
kind_scale = make_kind_scale(self._repository.meta, self._config)
|
23
23
|
df = embellished_activities(self._repository.meta)
|
24
|
-
df = df.loc[df["consider_for_achievements"]]
|
24
|
+
# df = df.loc[df["consider_for_achievements"]]
|
25
25
|
|
26
26
|
year_kind_total = (
|
27
27
|
df[["year", "kind", "distance_km", "hours"]]
|
@@ -102,8 +102,7 @@ def scan_for_activities(
|
|
102
102
|
) -> None:
|
103
103
|
if pathlib.Path("Activities").exists():
|
104
104
|
import_from_directory(
|
105
|
-
config.metadata_extraction_regexes,
|
106
|
-
config.num_processes,
|
105
|
+
config.metadata_extraction_regexes, config.num_processes, config
|
107
106
|
)
|
108
107
|
if pathlib.Path("Strava Export").exists():
|
109
108
|
import_from_strava_checkout()
|
{geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/RECORD
RENAMED
@@ -2,11 +2,11 @@ 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=soxMtdijnkZ1bYZU0q6wuM8NPNFoUpLwYp3IvBOaKJY,6927
|
5
|
-
geo_activity_playground/core/config.py,sha256=
|
5
|
+
geo_activity_playground/core/config.py,sha256=T6u8Ha2yUTmSA-TcI0_yg_vNIh-JdAyKt7vs-cfQmuE,4817
|
6
6
|
geo_activity_playground/core/coordinates.py,sha256=tDfr9mlXhK6E_MMIJ0vYWVCoH0Lq8uyuaqUgaa8i0jg,966
|
7
7
|
geo_activity_playground/core/enrichment.py,sha256=fUmk6avy_rqePlHmJQFTQhAxjgIRaxxmq18N2OSXBBg,7771
|
8
8
|
geo_activity_playground/core/heart_rate.py,sha256=IwMt58TpjOYqpAxtsj07zP2ttpN_J3GZeiv-qGhYyJc,1598
|
9
|
-
geo_activity_playground/core/heatmap.py,sha256=
|
9
|
+
geo_activity_playground/core/heatmap.py,sha256=KqqXo9ayppwXU3VEkhqtcyC-EPkRUVZ-J0EK6FhR50M,6474
|
10
10
|
geo_activity_playground/core/paths.py,sha256=RBeUi38riP_msTGPy1TsPRNiblzE-lFivaJSLULE8b0,2503
|
11
11
|
geo_activity_playground/core/privacy_zones.py,sha256=4TumHsVUN1uW6RG3ArqTXDykPVipF98DCxVBe7YNdO8,512
|
12
12
|
geo_activity_playground/core/similarity.py,sha256=Jo8jRViuORCxdIGvyaflgsQhwu9S_jn10a450FRL18A,3159
|
@@ -22,7 +22,7 @@ geo_activity_playground/explorer/video.py,sha256=ROAmV9shfJyqTgnXVD41KFORiwnRgVp
|
|
22
22
|
geo_activity_playground/importers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
23
23
|
geo_activity_playground/importers/activity_parsers.py,sha256=XNQs0ziqAcVqIoiLAX5Ndmhb6v__29XdjUPvNvc7oBI,11082
|
24
24
|
geo_activity_playground/importers/csv_parser.py,sha256=O1pP5GLhWhnWcy2Lsrr9g17Zspuibpt-GtZ3ZS5eZF4,2143
|
25
|
-
geo_activity_playground/importers/directory.py,sha256=
|
25
|
+
geo_activity_playground/importers/directory.py,sha256=CA-vFOMm8G4MSM_Q09OwQKduCApL2PWaxLTVxgw_xpw,5908
|
26
26
|
geo_activity_playground/importers/strava_api.py,sha256=cJCZsLemhOlxTtZh0z_npidgae9SD5HyEUry2uvem_A,7775
|
27
27
|
geo_activity_playground/importers/strava_checkout.py,sha256=N-uGTkhBJMC7cPYjRRXHOSLwpK3wc6aaSrY2RQfSitA,9419
|
28
28
|
geo_activity_playground/importers/test_csv_parser.py,sha256=LXqva7GuSAfXYE2zZQrg-69lCtfy5MxLSq6BRwL_VyI,1191
|
@@ -31,7 +31,7 @@ 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=Ub2mC9S9TII7CJaaWahnbNtT76uOGKNDWE0-j2C56CA,3893
|
34
|
-
geo_activity_playground/webui/activity/controller.py,sha256=
|
34
|
+
geo_activity_playground/webui/activity/controller.py,sha256=zOPoj4N-B-x1O_qp5ZUvlT5gmDjpIGuqKqnv4f1-B54,19570
|
35
35
|
geo_activity_playground/webui/activity/templates/activity/day.html.j2,sha256=o18e-TMtgCrY7iroInVhRA267l-o6uGNlstIwsvFnww,2735
|
36
36
|
geo_activity_playground/webui/activity/templates/activity/edit.html.j2,sha256=ckcTTxcQOhmvvAGNTEOtWCUG4LhvO4HfQImlIa5qKs8,1530
|
37
37
|
geo_activity_playground/webui/activity/templates/activity/lines.html.j2,sha256=5gB1aDjRgi_RventenRfC10_FtMT4ch_VuWvA9AMlBY,1121
|
@@ -100,7 +100,7 @@ geo_activity_playground/webui/static/web-app-manifest-192x192.png,sha256=eEImN6i
|
|
100
100
|
geo_activity_playground/webui/static/web-app-manifest-512x512.png,sha256=vU9oQ4HnQerFDZVzcAT9twj4_Doc6_9v9wVvoRI-f_E,48318
|
101
101
|
geo_activity_playground/webui/summary/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
102
102
|
geo_activity_playground/webui/summary/blueprint.py,sha256=tfA2aPF19yKwkQOb5lPQBySoQYYhTn49Iuh0SYvsGP8,593
|
103
|
-
geo_activity_playground/webui/summary/controller.py,sha256=
|
103
|
+
geo_activity_playground/webui/summary/controller.py,sha256=UU6ClARzdvUQnIaSyuG3mbNxtuCjYCUM22P1aRFwOuQ,9445
|
104
104
|
geo_activity_playground/webui/summary/templates/summary/index.html.j2,sha256=S_kpXPldrxIAEBdlG0YlXlvMHI4dQc4QZtejhHM4_N8,4472
|
105
105
|
geo_activity_playground/webui/templates/home.html.j2,sha256=EvEgvr_JeppGqLEJzcDc0kL-8e4OUV8aleWTP5eDeh8,2173
|
106
106
|
geo_activity_playground/webui/templates/page.html.j2,sha256=znTbtD2NALrhmUN_Q-F1ElGlKtecoUv8vOCcUtojrdI,11134
|
@@ -109,11 +109,11 @@ geo_activity_playground/webui/tile/blueprint.py,sha256=cK0o2Z3BrLycgF9zw0F8s9qF-
|
|
109
109
|
geo_activity_playground/webui/tile/controller.py,sha256=PISh4vKs27b-LxFfTARtr5RAwHFresA1Kw1MDcERSRU,1221
|
110
110
|
geo_activity_playground/webui/upload/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
111
111
|
geo_activity_playground/webui/upload/blueprint.py,sha256=xX9scEmleN_dL03jfhWRh5yI1WsFyhxUFiS_Ul2HWy4,1428
|
112
|
-
geo_activity_playground/webui/upload/controller.py,sha256=
|
112
|
+
geo_activity_playground/webui/upload/controller.py,sha256=EvoUnmKBo3QS2TLak7-yVZ16sEDyEB6Nf2MN_scHuhQ,4080
|
113
113
|
geo_activity_playground/webui/upload/templates/upload/index.html.j2,sha256=I1Ix8tDS3YBdi-HdaNfjkzYXVVCjfUTe5PFTnap1ydc,775
|
114
114
|
geo_activity_playground/webui/upload/templates/upload/reload.html.j2,sha256=YZWX5eDeNyqKJdQAywDBcU8DZBm22rRBbZqFjrFrCvQ,556
|
115
|
-
geo_activity_playground-0.
|
116
|
-
geo_activity_playground-0.
|
117
|
-
geo_activity_playground-0.
|
118
|
-
geo_activity_playground-0.
|
119
|
-
geo_activity_playground-0.
|
115
|
+
geo_activity_playground-0.32.0.dist-info/LICENSE,sha256=4RpAwKO8bPkfXH2lnpeUW0eLkNWglyG4lbrLDU_MOwY,1070
|
116
|
+
geo_activity_playground-0.32.0.dist-info/METADATA,sha256=02jGl-aJPw8GRimnYlMTNECzPhE0ei6fpiidYbK7UDM,1612
|
117
|
+
geo_activity_playground-0.32.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
118
|
+
geo_activity_playground-0.32.0.dist-info/entry_points.txt,sha256=pbNlLI6IIZIp7nPYCfAtiSiz2oxJSCl7DODD6SPkLKk,81
|
119
|
+
geo_activity_playground-0.32.0.dist-info/RECORD,,
|
{geo_activity_playground-0.31.0.dist-info → geo_activity_playground-0.32.0.dist-info}/LICENSE
RENAMED
File without changes
|
File without changes
|
File without changes
|