huff 1.1.1__py3-none-any.whl → 1.1.2__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.
- huff/gistools.py +50 -3
- huff/models.py +69 -46
- huff/ors.py +2 -2
- huff/tests/tests_huff.py +2 -2
- {huff-1.1.1.dist-info → huff-1.1.2.dist-info}/METADATA +2 -1
- {huff-1.1.1.dist-info → huff-1.1.2.dist-info}/RECORD +8 -8
- {huff-1.1.1.dist-info → huff-1.1.2.dist-info}/WHEEL +0 -0
- {huff-1.1.1.dist-info → huff-1.1.2.dist-info}/top_level.txt +0 -0
huff/gistools.py
CHANGED
@@ -4,13 +4,60 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.1.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.1.2
|
8
|
+
# Last update: 2025-05-03 13:30
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
12
12
|
|
13
|
-
import geopandas as gp
|
13
|
+
import geopandas as gp
|
14
|
+
from math import pi, sin, cos, acos
|
15
|
+
|
16
|
+
|
17
|
+
def distance_matrix(
|
18
|
+
sources: list,
|
19
|
+
destinations: list,
|
20
|
+
unit: str = "m",
|
21
|
+
):
|
22
|
+
|
23
|
+
def euclidean_distance (
|
24
|
+
source: list,
|
25
|
+
destination: list,
|
26
|
+
unit: str = "m"
|
27
|
+
):
|
28
|
+
|
29
|
+
lon1 = source[0]
|
30
|
+
lat1 = source[1]
|
31
|
+
lon2 = destination[0]
|
32
|
+
lat2 = destination[1]
|
33
|
+
|
34
|
+
lat1_r = lat1*pi/180
|
35
|
+
lon1_r = lon1*pi/180
|
36
|
+
lat2_r = lat2*pi/180
|
37
|
+
lon2_r = lon2*pi/180
|
38
|
+
|
39
|
+
distance = 6378 * (acos(sin(lat1_r) * sin(lat2_r) + cos(lat1_r) * cos(lat2_r) * cos(lon2_r - lon1_r)))
|
40
|
+
if unit == "m":
|
41
|
+
distance = distance*1000
|
42
|
+
if unit == "mile":
|
43
|
+
distance = distance/1.60934
|
44
|
+
|
45
|
+
return distance
|
46
|
+
|
47
|
+
matrix = []
|
48
|
+
|
49
|
+
for source in sources:
|
50
|
+
row = []
|
51
|
+
for destination in destinations:
|
52
|
+
dist = euclidean_distance(
|
53
|
+
source,
|
54
|
+
destination,
|
55
|
+
unit
|
56
|
+
)
|
57
|
+
row.append(dist)
|
58
|
+
matrix.append(row)
|
59
|
+
|
60
|
+
return matrix
|
14
61
|
|
15
62
|
|
16
63
|
def overlay_difference(
|
huff/models.py
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.1.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.1.2
|
8
|
+
# Last update: 2025-05-03 13:29
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
@@ -15,7 +15,7 @@ import geopandas as gp
|
|
15
15
|
import numpy as np
|
16
16
|
import time
|
17
17
|
from huff.ors import Client, TimeDistanceMatrix, Isochrone
|
18
|
-
from huff.gistools import overlay_difference
|
18
|
+
from huff.gistools import overlay_difference, distance_matrix
|
19
19
|
|
20
20
|
|
21
21
|
class CustomerOrigins:
|
@@ -373,13 +373,19 @@ class InteractionMatrix:
|
|
373
373
|
|
374
374
|
def transport_costs(
|
375
375
|
self,
|
376
|
+
network: bool = True,
|
376
377
|
range_type: str = "time",
|
377
378
|
time_unit: str = "minutes",
|
379
|
+
distance_unit: str = "kilometers",
|
378
380
|
ors_server: str = "https://api.openrouteservice.org/v2/",
|
379
381
|
ors_auth: str = None,
|
380
382
|
save_output: bool = False,
|
381
383
|
output_filepath: str = "transport_costs_matrix.csv"
|
382
384
|
):
|
385
|
+
|
386
|
+
if not network and range_type == "time":
|
387
|
+
print ("Calculating euclidean distances (network = False). Setting range_type = 'distance'")
|
388
|
+
range_type = "distance"
|
383
389
|
|
384
390
|
interaction_matrix_df = self.get_interaction_matrix_df()
|
385
391
|
|
@@ -401,53 +407,70 @@ class InteractionMatrix:
|
|
401
407
|
|
402
408
|
customer_origins_index = list(range(len(customer_origins_coords)))
|
403
409
|
locations_coords_index = list(range(len(customer_origins_index), len(locations_coords)))
|
404
|
-
|
405
|
-
ors_client = Client(
|
406
|
-
server = ors_server,
|
407
|
-
auth = ors_auth
|
408
|
-
)
|
409
|
-
time_distance_matrix = ors_client.matrix(
|
410
|
-
locations = locations_coords,
|
411
|
-
save_output = save_output,
|
412
|
-
output_filepath = output_filepath,
|
413
|
-
sources = customer_origins_index,
|
414
|
-
destinations = locations_coords_index,
|
415
|
-
range_type = range_type
|
416
|
-
)
|
417
|
-
|
418
|
-
if time_distance_matrix.get_metadata() is None:
|
419
|
-
raise ValueError ("No transport costs matrix was built.")
|
420
410
|
|
421
|
-
|
422
|
-
transport_costs_matrix_config = time_distance_matrix.get_config()
|
423
|
-
range_type = transport_costs_matrix_config["range_type"]
|
411
|
+
if network:
|
424
412
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
413
|
+
ors_client = Client(
|
414
|
+
server = ors_server,
|
415
|
+
auth = ors_auth
|
416
|
+
)
|
417
|
+
time_distance_matrix = ors_client.matrix(
|
418
|
+
locations = locations_coords,
|
419
|
+
save_output = save_output,
|
420
|
+
output_filepath = output_filepath,
|
421
|
+
sources = customer_origins_index,
|
422
|
+
destinations = locations_coords_index,
|
423
|
+
range_type = range_type
|
424
|
+
)
|
425
|
+
|
426
|
+
if time_distance_matrix.get_metadata() is None:
|
427
|
+
raise ValueError ("No transport costs matrix was built.")
|
437
428
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
)
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
429
|
+
transport_costs_matrix = time_distance_matrix.get_matrix()
|
430
|
+
transport_costs_matrix_config = time_distance_matrix.get_config()
|
431
|
+
range_type = transport_costs_matrix_config["range_type"]
|
432
|
+
|
433
|
+
transport_costs_matrix["source"] = transport_costs_matrix["source"].astype(int)
|
434
|
+
transport_costs_matrix["source"] = transport_costs_matrix["source"].map(
|
435
|
+
dict(enumerate(customer_origins_ids))
|
436
|
+
)
|
437
|
+
|
438
|
+
transport_costs_matrix["destination"] = transport_costs_matrix["destination"].astype(int)
|
439
|
+
transport_costs_matrix["destination"] = transport_costs_matrix["destination"].map(
|
440
|
+
dict(enumerate(supply_locations_ids))
|
441
|
+
)
|
442
|
+
|
443
|
+
transport_costs_matrix["source_destination"] = transport_costs_matrix["source"].astype(str)+"_"+transport_costs_matrix["destination"].astype(str)
|
444
|
+
transport_costs_matrix = transport_costs_matrix[["source_destination", range_type]]
|
445
|
+
|
446
|
+
interaction_matrix_df = interaction_matrix_df.merge(
|
447
|
+
transport_costs_matrix,
|
448
|
+
left_on="ij",
|
449
|
+
right_on="source_destination"
|
450
|
+
)
|
451
|
+
|
452
|
+
interaction_matrix_df["t_ij"] = interaction_matrix_df[range_type]
|
453
|
+
if time_unit == "minutes":
|
454
|
+
interaction_matrix_df["t_ij"] = interaction_matrix_df["t_ij"]/60
|
455
|
+
if time_unit == "hours":
|
456
|
+
interaction_matrix_df["t_ij"] = interaction_matrix_df["t_ij"]/60/60
|
457
|
+
|
458
|
+
interaction_matrix_df = interaction_matrix_df.drop(columns=["source_destination", range_type])
|
459
|
+
|
460
|
+
else:
|
461
|
+
|
462
|
+
distance_matrix_result = distance_matrix(
|
463
|
+
sources = customer_origins_coords,
|
464
|
+
destinations = supply_locations_coords,
|
465
|
+
unit = "m"
|
466
|
+
)
|
467
|
+
|
468
|
+
distance_matrix_result_flat = [distance for sublist in distance_matrix_result for distance in sublist]
|
469
|
+
|
470
|
+
interaction_matrix_df["t_ij"] = distance_matrix_result_flat
|
449
471
|
|
450
|
-
|
472
|
+
if distance_unit == "kilometers":
|
473
|
+
interaction_matrix_df["t_ij"] = interaction_matrix_df["t_ij"]/1000
|
451
474
|
|
452
475
|
self.interaction_matrix_df = interaction_matrix_df
|
453
476
|
|
huff/ors.py
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.1.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.1.2
|
8
|
+
# Last update: 2025-05-03 13:33
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
huff/tests/tests_huff.py
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# Author: Thomas Wieland
|
5
5
|
# ORCID: 0000-0001-5168-9846
|
6
6
|
# mail: geowieland@googlemail.com
|
7
|
-
# Version: 1.1.
|
8
|
-
# Last update: 2025-
|
7
|
+
# Version: 1.1.2
|
8
|
+
# Last update: 2025-05-03 13:32
|
9
9
|
# Copyright (c) 2025 Thomas Wieland
|
10
10
|
#-----------------------------------------------------------------------
|
11
11
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: huff
|
3
|
-
Version: 1.1.
|
3
|
+
Version: 1.1.2
|
4
4
|
Summary: huff: Huff Model Market Area Analysis
|
5
5
|
Author: Thomas Wieland
|
6
6
|
Author-email: geowieland@googlemail.com
|
@@ -32,6 +32,7 @@ See the /tests directory for usage examples of most of the included functions.
|
|
32
32
|
|
33
33
|
Attribution of OpenRouteService:
|
34
34
|
© openrouteservice.org by HeiGIT | Map data © OpenStreetMap contributors
|
35
|
+
|
35
36
|
Visit https://openrouteservice.org/
|
36
37
|
|
37
38
|
## Literature
|
@@ -1,9 +1,9 @@
|
|
1
1
|
huff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
2
|
-
huff/gistools.py,sha256=
|
3
|
-
huff/models.py,sha256=
|
4
|
-
huff/ors.py,sha256=
|
2
|
+
huff/gistools.py,sha256=vuEpNC-IEIrNtzptdjzyvOP05qFbJYfeHpPZfo_OMvs,2721
|
3
|
+
huff/models.py,sha256=yKty9d8nG05HSjNIAPiGNaDeEHLGySZhpNZJHnmPYdU,31300
|
4
|
+
huff/ors.py,sha256=dkuVj14Jr69D2xp8NSi2QDkXNNLrudUs9f-i_UtKOdQ,11467
|
5
5
|
huff/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
huff/tests/tests_huff.py,sha256=
|
6
|
+
huff/tests/tests_huff.py,sha256=4AbQcD46iG7IsFioigVwRwOyeHMniYELIspMh-rCEHk,2515
|
7
7
|
huff/tests/data/Haslach.cpg,sha256=OtMDH1UDpEBK-CUmLugjLMBNTqZoPULF3QovKiesmCQ,5
|
8
8
|
huff/tests/data/Haslach.dbf,sha256=GVPIt05OzDO7UrRDcsMhiYWvyXAPg6Z-qkiysFzj-fc,506
|
9
9
|
huff/tests/data/Haslach.prj,sha256=2Jy1Vlzh7UxQ1MXpZ9UYLs2SxfrObj2xkEkZyLqmGTY,437
|
@@ -16,7 +16,7 @@ huff/tests/data/Haslach_supermarkets.prj,sha256=2Jy1Vlzh7UxQ1MXpZ9UYLs2SxfrObj2x
|
|
16
16
|
huff/tests/data/Haslach_supermarkets.qmd,sha256=j9i4_Pz7ZMSG2UDSb3nuhJpw0KWXIRhiiDymqJP6_Fo,2479
|
17
17
|
huff/tests/data/Haslach_supermarkets.shp,sha256=X7QbQ0BTMag_B-bDRbpr-go2BQIXo3Y8zMAKpYZmlps,324
|
18
18
|
huff/tests/data/Haslach_supermarkets.shx,sha256=j23QHX-SmdAeN04rw0x8nUOran-OCg_T6r_LvzzEPWs,164
|
19
|
-
huff-1.1.
|
20
|
-
huff-1.1.
|
21
|
-
huff-1.1.
|
22
|
-
huff-1.1.
|
19
|
+
huff-1.1.2.dist-info/METADATA,sha256=xTrAKBys0WpSPbu7ojxZ-gSTs5l3zQ0uKlnmiK3gvfA,2541
|
20
|
+
huff-1.1.2.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
21
|
+
huff-1.1.2.dist-info/top_level.txt,sha256=nlzX-PxZNFmIxANIJMySuIFPihd6qOBkRlhIC28NEsQ,5
|
22
|
+
huff-1.1.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|