huff 1.2.0__py3-none-any.whl → 1.3.1__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 CHANGED
@@ -4,13 +4,15 @@
4
4
  # Author: Thomas Wieland
5
5
  # ORCID: 0000-0001-5168-9846
6
6
  # mail: geowieland@googlemail.com
7
- # Version: 1.2.0
8
- # Last update: 2025-05-14 18:28
7
+ # Version: 1.3.1
8
+ # Last update: 2025-05-28 18:01
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
12
12
 
13
13
  import geopandas as gp
14
+ import pandas as pd
15
+ from pandas.api.types import is_numeric_dtype
14
16
  from math import pi, sin, cos, acos
15
17
 
16
18
 
@@ -60,6 +62,65 @@ def distance_matrix(
60
62
  return matrix
61
63
 
62
64
 
65
+ def buffers(
66
+ point_gdf: gp.GeoDataFrame,
67
+ unique_id_col: str,
68
+ distances: list,
69
+ donut: bool = True,
70
+ save_output: bool = True,
71
+ output_filepath: str = "buffers.shp",
72
+ output_crs: str = "EPSG:4326"
73
+ ):
74
+
75
+ all_buffers_gdf = gp.GeoDataFrame(columns=[unique_id_col, "segment", "geometry"])
76
+
77
+ for idx, row in point_gdf.iterrows():
78
+
79
+ point_buffers = []
80
+
81
+ for distance in distances:
82
+
83
+ point = row["geometry"]
84
+ point_buffer = point.buffer(distance)
85
+
86
+ point_buffer_gdf = gp.GeoDataFrame(
87
+ {
88
+ unique_id_col: row[unique_id_col],
89
+ "geometry": [point_buffer],
90
+ "segment": [distance]
91
+ },
92
+ crs=point_gdf.crs
93
+ )
94
+
95
+ point_buffers.append(point_buffer_gdf)
96
+
97
+ point_buffers_gdf = pd.concat(
98
+ point_buffers,
99
+ ignore_index = True
100
+ )
101
+
102
+ if donut:
103
+ point_buffers_gdf = overlay_difference(
104
+ polygon_gdf = point_buffers_gdf,
105
+ sort_col = "segment"
106
+ )
107
+
108
+ all_buffers_gdf = pd.concat(
109
+ [
110
+ all_buffers_gdf,
111
+ point_buffers_gdf
112
+ ],
113
+ ignore_index = True)
114
+
115
+ all_buffers_gdf = all_buffers_gdf.to_crs(output_crs)
116
+
117
+ if save_output:
118
+ all_buffers_gdf.to_file(output_filepath)
119
+ print ("Saved as", output_filepath)
120
+
121
+ return all_buffers_gdf
122
+
123
+
63
124
  def overlay_difference(
64
125
  polygon_gdf: gp.GeoDataFrame,
65
126
  sort_col: str = None,
@@ -74,6 +135,7 @@ def overlay_difference(
74
135
  new_data = []
75
136
 
76
137
  for i in range(len(polygon_gdf) - 1, 0, -1):
138
+
77
139
  current_polygon = polygon_gdf.iloc[i].geometry
78
140
  previous_polygon = polygon_gdf.iloc[i - 1].geometry
79
141
  difference_polygon = current_polygon.difference(previous_polygon)
@@ -85,7 +147,9 @@ def overlay_difference(
85
147
  new_data.append(polygon_gdf.iloc[i].drop("geometry"))
86
148
 
87
149
  inner_most_polygon = polygon_gdf.iloc[0].geometry
150
+
88
151
  if inner_most_polygon.is_valid:
152
+
89
153
  new_geometries.append(inner_most_polygon)
90
154
  new_data.append(polygon_gdf.iloc[0].drop("geometry"))
91
155
 
@@ -93,4 +157,60 @@ def overlay_difference(
93
157
  new_data, geometry=new_geometries, crs=polygon_gdf.crs
94
158
  )
95
159
 
96
- return polygon_gdf_difference
160
+ return polygon_gdf_difference
161
+
162
+
163
+ def point_spatial_join(
164
+ polygon_gdf: gp.GeoDataFrame,
165
+ point_gdf: gp.GeoDataFrame,
166
+ join_type: str = "inner",
167
+ polygon_ref_cols: list = [],
168
+ point_stat_col: str = None
169
+ ):
170
+
171
+ if polygon_gdf.crs != point_gdf.crs:
172
+ raise ValueError (f"Coordinate reference systems of polygon and point data do not match. Polygons: {str(polygon_gdf.crs)}, points: {str(point_gdf.crs)}")
173
+
174
+ if polygon_ref_cols != []:
175
+ for polygon_ref_col in polygon_ref_cols:
176
+ if polygon_ref_col not in polygon_gdf.columns:
177
+ raise KeyError (f"Column {polygon_ref_col} not in polygon data")
178
+
179
+ if point_stat_col is not None:
180
+ if point_stat_col not in point_gdf.columns:
181
+ raise KeyError (f"Column {point_stat_col} not in point data")
182
+ if not is_numeric_dtype(point_gdf[point_stat_col]):
183
+ raise TypeError (f"Column {point_stat_col} is not numeric")
184
+
185
+ shp_points_gdf_join = point_gdf.sjoin(
186
+ polygon_gdf,
187
+ how=join_type
188
+ )
189
+
190
+ spatial_join_stat = None
191
+
192
+ if polygon_ref_cols != [] and point_stat_col is not None:
193
+ shp_points_gdf_join_count = shp_points_gdf_join.groupby(polygon_ref_cols)[point_stat_col].count()
194
+ shp_points_gdf_join_sum = shp_points_gdf_join.groupby(polygon_ref_cols)[point_stat_col].sum()
195
+ shp_points_gdf_join_min = shp_points_gdf_join.groupby(polygon_ref_cols)[point_stat_col].min()
196
+ shp_points_gdf_join_max = shp_points_gdf_join.groupby(polygon_ref_cols)[point_stat_col].max()
197
+ shp_points_gdf_join_mean = shp_points_gdf_join.groupby(polygon_ref_cols)[point_stat_col].mean()
198
+
199
+ shp_points_gdf_join_count = shp_points_gdf_join_count.rename("count").to_frame()
200
+ shp_points_gdf_join_sum = shp_points_gdf_join_sum.rename("sum").to_frame()
201
+ shp_points_gdf_join_min = shp_points_gdf_join_min.rename("min").to_frame()
202
+ shp_points_gdf_join_max = shp_points_gdf_join_max.rename("max").to_frame()
203
+ shp_points_gdf_join_mean = shp_points_gdf_join_mean.rename("mean").to_frame()
204
+ spatial_join_stat = shp_points_gdf_join_count.join(
205
+ [
206
+ shp_points_gdf_join_sum,
207
+ shp_points_gdf_join_min,
208
+ shp_points_gdf_join_max,
209
+ shp_points_gdf_join_mean
210
+ ]
211
+ )
212
+
213
+ return [
214
+ shp_points_gdf_join,
215
+ spatial_join_stat
216
+ ]
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.2.0
8
- # Last update: 2025-05-14 18:33
7
+ # Version: 1.3.1
8
+ # Last update: 2025-05-28 18:01
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
@@ -18,7 +18,7 @@ from statsmodels.formula.api import ols
18
18
  from shapely.geometry import Point
19
19
  from shapely import wkt
20
20
  from huff.ors import Client, TimeDistanceMatrix, Isochrone
21
- from huff.gistools import overlay_difference, distance_matrix
21
+ from huff.gistools import overlay_difference, distance_matrix, buffers
22
22
 
23
23
 
24
24
  class CustomerOrigins:
@@ -28,13 +28,15 @@ class CustomerOrigins:
28
28
  geodata_gpd,
29
29
  geodata_gpd_original,
30
30
  metadata,
31
- isochrones_gdf
31
+ isochrones_gdf,
32
+ buffers_gdf
32
33
  ):
33
34
 
34
35
  self.geodata_gpd = geodata_gpd
35
36
  self.geodata_gpd_original = geodata_gpd_original
36
37
  self.metadata = metadata
37
38
  self.isochrones_gdf = isochrones_gdf
39
+ self.buffers_gdf = buffers_gdf
38
40
 
39
41
  def get_geodata_gpd(self):
40
42
 
@@ -48,10 +50,14 @@ class CustomerOrigins:
48
50
 
49
51
  return self.metadata
50
52
 
51
- def get_isochrones(self):
53
+ def get_isochrones_gdf(self):
52
54
 
53
55
  return self.isochrones_gdf
54
56
 
57
+ def get_buffers_gdf(self):
58
+
59
+ return self.buffers_gdf
60
+
55
61
  def summary(self):
56
62
 
57
63
  metadata = self.metadata
@@ -77,6 +83,11 @@ class CustomerOrigins:
77
83
  else:
78
84
  print("Including isochrones YES")
79
85
 
86
+ if self.buffers_gdf is None:
87
+ print("Including buffers NO")
88
+ else:
89
+ print("Including buffers YES")
90
+
80
91
  return metadata
81
92
 
82
93
  def define_marketsize(
@@ -151,6 +162,32 @@ class CustomerOrigins:
151
162
 
152
163
  return self
153
164
 
165
+ def buffers(
166
+ self,
167
+ segments_distance: list = [500, 1000],
168
+ donut: bool = True,
169
+ save_output: bool = True,
170
+ output_filepath: str = "customer_origins_buffers.shp",
171
+ output_crs: str = "EPSG:4326"
172
+ ):
173
+
174
+ geodata_gpd_original = self.get_geodata_gpd_original()
175
+ metadata = self.metadata
176
+
177
+ buffers_gdf = buffers(
178
+ point_gdf = geodata_gpd_original,
179
+ unique_id_col = metadata["unique_id"],
180
+ distances = segments_distance,
181
+ donut = donut,
182
+ save_output = save_output,
183
+ output_filepath = output_filepath,
184
+ output_crs = output_crs
185
+ )
186
+
187
+ self.buffers_gdf = buffers_gdf
188
+
189
+ return self
190
+
154
191
 
155
192
  class SupplyLocations:
156
193
 
@@ -159,13 +196,15 @@ class SupplyLocations:
159
196
  geodata_gpd,
160
197
  geodata_gpd_original,
161
198
  metadata,
162
- isochrones_gdf
199
+ isochrones_gdf,
200
+ buffers_gdf
163
201
  ):
164
202
 
165
203
  self.geodata_gpd = geodata_gpd
166
204
  self.geodata_gpd_original = geodata_gpd_original
167
205
  self.metadata = metadata
168
206
  self.isochrones_gdf = isochrones_gdf
207
+ self.buffers_gdf = buffers_gdf
169
208
 
170
209
  def get_geodata_gpd(self):
171
210
 
@@ -182,6 +221,10 @@ class SupplyLocations:
182
221
  def get_isochrones_gdf(self):
183
222
 
184
223
  return self.isochrones_gdf
224
+
225
+ def get_buffers_gdf(self):
226
+
227
+ return self.buffers_gdf
185
228
 
186
229
  def summary(self):
187
230
 
@@ -346,6 +389,32 @@ class SupplyLocations:
346
389
 
347
390
  return self
348
391
 
392
+ def buffers(
393
+ self,
394
+ segments_distance: list = [500, 1000],
395
+ donut: bool = True,
396
+ save_output: bool = True,
397
+ output_filepath: str = "supply_locations_buffers.shp",
398
+ output_crs: str = "EPSG:4326"
399
+ ):
400
+
401
+ geodata_gpd_original = self.get_geodata_gpd_original()
402
+ metadata = self.metadata
403
+
404
+ buffers_gdf = buffers(
405
+ point_gdf = geodata_gpd_original,
406
+ unique_id_col = metadata["unique_id"],
407
+ distances = segments_distance,
408
+ donut = donut,
409
+ save_output = save_output,
410
+ output_filepath = output_filepath,
411
+ output_crs = output_crs
412
+ )
413
+
414
+ self.buffers_gdf = buffers_gdf
415
+
416
+ return self
417
+
349
418
 
350
419
  class InteractionMatrix:
351
420
 
@@ -459,14 +528,10 @@ class InteractionMatrix:
459
528
  range_type = transport_costs_matrix_config["range_type"]
460
529
 
461
530
  transport_costs_matrix["source"] = transport_costs_matrix["source"].astype(int)
462
- transport_costs_matrix["source"] = transport_costs_matrix["source"].map(
463
- dict(enumerate(customer_origins_ids))
464
- )
531
+ transport_costs_matrix["source"] = transport_costs_matrix["source"].map(dict(enumerate(customer_origins_ids)))
465
532
 
466
533
  transport_costs_matrix["destination"] = transport_costs_matrix["destination"].astype(int)
467
- transport_costs_matrix["destination"] = transport_costs_matrix["destination"].map(
468
- dict(enumerate(supply_locations_ids))
469
- )
534
+ transport_costs_matrix["destination"] = transport_costs_matrix["destination"].map(dict(enumerate(supply_locations_ids)))
470
535
 
471
536
  transport_costs_matrix["source_destination"] = transport_costs_matrix["source"].astype(str)+"_"+transport_costs_matrix["destination"].astype(str)
472
537
  transport_costs_matrix = transport_costs_matrix[["source_destination", range_type]]
@@ -952,8 +1017,7 @@ class MCIModel:
952
1017
  transformation = "LCT"
953
1018
  ):
954
1019
 
955
- interaction_matrix = self.interaction_matrix
956
-
1020
+ interaction_matrix = self.interaction_matrix
957
1021
  interaction_matrix_df = interaction_matrix.get_interaction_matrix_df()
958
1022
 
959
1023
  if interaction_matrix_df["t_ij"].isna().all():
@@ -966,7 +1030,8 @@ class MCIModel:
966
1030
  cols = ["A_j", "t_ij"]
967
1031
  )
968
1032
 
969
- customer_origins_metadata = interaction_matrix.get_customer_origins().get_metadata()
1033
+ customer_origins = interaction_matrix.get_customer_origins()
1034
+ customer_origins_metadata = customer_origins.get_metadata()
970
1035
 
971
1036
  t_ij_weighting = customer_origins_metadata["weighting"][0]["param"]
972
1037
 
@@ -975,7 +1040,8 @@ class MCIModel:
975
1040
  else:
976
1041
  mci_formula = f"t_ij**{t_ij_weighting}"
977
1042
 
978
- supply_locations_metadata = interaction_matrix.get_supply_locations().get_metadata()
1043
+ supply_locations = interaction_matrix.get_supply_locations()
1044
+ supply_locations_metadata = supply_locations.get_metadata()
979
1045
  attraction_col = supply_locations_metadata["attraction_col"]
980
1046
  attraction_weighting = supply_locations_metadata["weighting"]
981
1047
 
@@ -991,17 +1057,27 @@ class MCIModel:
991
1057
  if transformation == "ILCT":
992
1058
  interaction_matrix_df["U_ij"] = np.exp(interaction_matrix_df["U_ij"])
993
1059
 
994
- self.interaction_matrix = interaction_matrix_df
1060
+ interaction_matrix = InteractionMatrix(
1061
+ interaction_matrix_df,
1062
+ customer_origins,
1063
+ supply_locations
1064
+ )
1065
+ self.interaction_matrix = interaction_matrix
995
1066
 
996
1067
  return self
997
1068
 
998
- def probabilities (self):
1069
+ def probabilities (
1070
+ self,
1071
+ transformation = "LCT"
1072
+ ):
999
1073
 
1000
- interaction_matrix_df = self.interaction_matrix_df
1074
+ interaction_matrix = self.interaction_matrix
1075
+ interaction_matrix_df = interaction_matrix.get_interaction_matrix_df()
1001
1076
 
1002
1077
  if interaction_matrix_df["U_ij"].isna().all():
1003
- self.utility()
1004
- interaction_matrix_df = self.interaction_matrix_df
1078
+ self.utility(transformation = transformation)
1079
+ interaction_matrix = self.interaction_matrix
1080
+ interaction_matrix_df = interaction_matrix.get_interaction_matrix_df()
1005
1081
 
1006
1082
  utility_i = pd.DataFrame(interaction_matrix_df.groupby("i")["U_ij"].sum())
1007
1083
  utility_i = utility_i.rename(columns = {"U_ij": "U_i"})
@@ -1017,14 +1093,22 @@ class MCIModel:
1017
1093
 
1018
1094
  interaction_matrix_df = interaction_matrix_df.drop(columns=["U_i"])
1019
1095
 
1020
- self.interaction_matrix_df = interaction_matrix_df
1096
+ interaction_matrix.interaction_matrix_df = interaction_matrix_df
1097
+ self.interaction_matrix = interaction_matrix
1021
1098
 
1022
1099
  return self
1023
1100
 
1024
- def flows (self):
1101
+ def flows (
1102
+ self,
1103
+ transformation = "LCT"
1104
+ ):
1025
1105
 
1026
- interaction_matrix_df = self.interaction_matrix_df
1106
+ interaction_matrix = self.interaction_matrix
1107
+ interaction_matrix_df = interaction_matrix.get_interaction_matrix_df()
1027
1108
 
1109
+ if "C_i" not in interaction_matrix_df.columns:
1110
+ raise ValueError ("No market size column defined in interaction matrix.")
1111
+
1028
1112
  if interaction_matrix_df["C_i"].isna().all():
1029
1113
  raise ValueError ("Market size column in customer origins not defined. Use CustomerOrigins.define_marketsize()")
1030
1114
 
@@ -1034,8 +1118,9 @@ class MCIModel:
1034
1118
  )
1035
1119
 
1036
1120
  if interaction_matrix_df["p_ij"].isna().all():
1037
- self.probabilities()
1038
- interaction_matrix_df = self.interaction_matrix_df
1121
+ self.probabilities(transformation=transformation)
1122
+ interaction_matrix = self.interaction_matrix
1123
+ interaction_matrix_df = interaction_matrix.get_interaction_matrix_df()
1039
1124
 
1040
1125
  interaction_matrix_df["E_ij"] = interaction_matrix_df["p_ij"] * interaction_matrix_df["C_i"]
1041
1126
 
@@ -1080,16 +1165,20 @@ def load_geodata (
1080
1165
  ):
1081
1166
 
1082
1167
  if location_type is None or (location_type != "origins" and location_type != "destinations"):
1083
- raise ValueError ("location_type must be either 'origins' or 'destinations'")
1168
+ raise ValueError ("Argument location_type must be either 'origins' or 'destinations'")
1084
1169
 
1085
1170
  if isinstance(data, gp.GeoDataFrame):
1086
1171
  geodata_gpd_original = data
1172
+ if not all(geodata_gpd_original.geometry.geom_type == "Point"):
1173
+ raise ValueError ("Input geopandas.GeoDataFrame must be of type 'Point'")
1087
1174
  crs_input = geodata_gpd_original.crs
1088
1175
  elif isinstance(data, pd.DataFrame):
1089
1176
  geodata_tab = data
1090
1177
  elif isinstance(data, str):
1091
1178
  if data_type == "shp":
1092
1179
  geodata_gpd_original = gp.read_file(data)
1180
+ if not all(geodata_gpd_original.geometry.geom_type == "Point"):
1181
+ raise ValueError ("Input shapefile must be of type 'Point'")
1093
1182
  crs_input = geodata_gpd_original.crs
1094
1183
  elif data_type == "csv" or data_type == "xlsx":
1095
1184
  if x_col is None:
@@ -1111,6 +1200,12 @@ def load_geodata (
1111
1200
  raise TypeError("data must be pandas.DataFrame, geopandas.GeoDataFrame or file (.csv, .xlsx, .shp)")
1112
1201
 
1113
1202
  if data_type == "csv" or data_type == "xlsx" or (isinstance(data, pd.DataFrame) and not isinstance(data, gp.GeoDataFrame)):
1203
+
1204
+ check_vars(
1205
+ df = geodata_tab,
1206
+ cols = [x_col, y_col]
1207
+ )
1208
+
1114
1209
  geodata_gpd_original = gp.GeoDataFrame(
1115
1210
  geodata_tab,
1116
1211
  geometry = gp.points_from_xy(
@@ -1146,6 +1241,7 @@ def load_geodata (
1146
1241
  geodata_gpd,
1147
1242
  geodata_gpd_original,
1148
1243
  metadata,
1244
+ None,
1149
1245
  None
1150
1246
  )
1151
1247
  elif location_type == "destinations":
@@ -1153,6 +1249,7 @@ def load_geodata (
1153
1249
  geodata_gpd,
1154
1250
  geodata_gpd_original,
1155
1251
  metadata,
1252
+ None,
1156
1253
  None
1157
1254
  )
1158
1255
 
@@ -1349,7 +1446,8 @@ def load_interaction_matrix(
1349
1446
  geodata_gpd = customer_origins_geodata_gpd,
1350
1447
  geodata_gpd_original = customer_origins_geodata_original_tab,
1351
1448
  metadata = customer_origins_metadata,
1352
- isochrones_gdf = None
1449
+ isochrones_gdf = None,
1450
+ buffers_gdf = None
1353
1451
  )
1354
1452
 
1355
1453
  if supply_locations_coords_col is not None:
@@ -1415,7 +1513,8 @@ def load_interaction_matrix(
1415
1513
  geodata_gpd = supply_locations_geodata_gpd,
1416
1514
  geodata_gpd_original = supply_locations_geodata_original_tab,
1417
1515
  metadata = supply_locations_metadata,
1418
- isochrones_gdf = None
1516
+ isochrones_gdf = None,
1517
+ buffers_gdf = None
1419
1518
  )
1420
1519
 
1421
1520
  interaction_matrix_df = interaction_matrix_df.rename(
@@ -1494,7 +1593,7 @@ def get_isochrones(
1494
1593
  profile: str = "driving-car",
1495
1594
  donut: bool = True,
1496
1595
  ors_server: str = "https://api.openrouteservice.org/v2/",
1497
- ors_auth: str = None,
1596
+ ors_auth: str = None,
1498
1597
  timeout = 10,
1499
1598
  delay = 1,
1500
1599
  save_output: bool = True,
@@ -1544,6 +1643,8 @@ def get_isochrones(
1544
1643
  time.sleep(delay)
1545
1644
 
1546
1645
  isochrone_gdf[unique_id_col] = unique_id_values[i]
1646
+
1647
+ isochrone_gdf["segment_minutes"] = isochrone_gdf["segment"]/60
1547
1648
 
1548
1649
  isochrones_gdf = pd.concat(
1549
1650
  [
@@ -1555,6 +1656,9 @@ def get_isochrones(
1555
1656
 
1556
1657
  i = i+1
1557
1658
 
1659
+ isochrones_gdf["segment"] = isochrones_gdf["segment"].astype(int)
1660
+ isochrones_gdf["segment_minutes"] = isochrones_gdf["segment_minutes"].astype(int)
1661
+
1558
1662
  isochrones_gdf.set_crs(
1559
1663
  output_crs,
1560
1664
  allow_override=True,
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.2.0
8
- # Last update: 2025-05-14 18:28
7
+ # Version: 1.3.1
8
+ # Last update: 2025-05-28 18:01
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
@@ -119,7 +119,6 @@ class Client:
119
119
  def isochrone(
120
120
  self,
121
121
  locations: list,
122
- id: list = [],
123
122
  segments: list = [900, 600, 300],
124
123
  range_type: str = "time",
125
124
  intersections: str = "true",
@@ -130,6 +129,12 @@ class Client:
130
129
  output_crs: str = "EPSG:4326"
131
130
  ):
132
131
 
132
+ if len(segments) > 10:
133
+ raise ValueError ("ORS client does not allow >10 intervals in an Isochrones query. See https://openrouteservice.org/restrictions/.")
134
+
135
+ if len(locations) > 5:
136
+ raise ValueError ("ORS client does not allow >5 locations in an Isochrones query. See https://openrouteservice.org/restrictions/.")
137
+
133
138
  ors_url = self.server + "isochrones/" + profile
134
139
  auth = self.auth
135
140
 
@@ -162,9 +167,9 @@ class Client:
162
167
  timeout=timeout
163
168
  )
164
169
 
165
- except:
170
+ except Exception as e:
166
171
 
167
- print ("Unknown error while accessing ORS server")
172
+ print ("Error while accessing ORS server: ", str(e))
168
173
 
169
174
  status_code = 99999
170
175
  isochrones_gdf = None
@@ -200,7 +205,7 @@ class Client:
200
205
 
201
206
  isochrones_gdf["segment"] = 0
202
207
  isochrones_gdf_properties_dict = dict(isochrones_gdf["properties"])
203
-
208
+
204
209
  for i in range(len(isochrones_gdf_properties_dict)):
205
210
  isochrones_gdf.iloc[i,3] = isochrones_gdf_properties_dict[i]["value"]
206
211
 
@@ -212,9 +217,9 @@ class Client:
212
217
  print ("Saved as", output_filepath)
213
218
 
214
219
  else:
215
-
216
- print ("Error while accessing ORS server. Status Code: " + str(status_code))
217
-
220
+
221
+ print(f"Error while accessing ORS server. Status code: {status_code} - {response.reason}")
222
+
218
223
  isochrones_gdf = None
219
224
  metadata = None
220
225
 
@@ -233,14 +238,14 @@ class Client:
233
238
  sources: list = [],
234
239
  destinations: list = [],
235
240
  id: str = None,
236
- range_type = "time",
237
- profile = "driving-car",
241
+ range_type: str = "time",
242
+ profile: str = "driving-car",
238
243
  metrics: list = [],
239
244
  resolve_locations: bool = False,
240
245
  units: str = "mi",
241
- timeout = 10,
242
- save_output = False,
243
- output_filepath = "matrix.csv",
246
+ timeout: int = 10,
247
+ save_output: bool = False,
248
+ output_filepath: str = "matrix.csv",
244
249
  csv_sep = ";",
245
250
  csv_decimal = ",",
246
251
  csv_encoding = None
@@ -285,9 +290,9 @@ class Client:
285
290
  timeout=timeout
286
291
  )
287
292
 
288
- except:
289
-
290
- print ("Unknown error while accessing ORS server")
293
+ except Exception as e:
294
+
295
+ print ("Error while accessing ORS server: ", str(e))
291
296
 
292
297
  status_code = 99999
293
298
  matrix_df = None
@@ -368,7 +373,7 @@ class Client:
368
373
 
369
374
  else:
370
375
 
371
- print ("Error in accessing ORS server. Status Code: " + str(status_code))
376
+ print(f"Error while accessing ORS server. Status code: {status_code} - {response.reason}")
372
377
 
373
378
  matrix_df = None
374
379
  metadata = None