huff 1.1.2__py3-none-any.whl → 1.3.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.
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.1.2
8
- # Last update: 2025-05-03 13:30
7
+ # Version: 1.3.0
8
+ # Last update: 2025-05-22 05:44
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
+ ]