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/osm.py ADDED
@@ -0,0 +1,250 @@
1
+ #-----------------------------------------------------------------------
2
+ # Name: osm (huff package)
3
+ # Purpose: Helper functions for OpenStreetMap API
4
+ # Author: Thomas Wieland
5
+ # ORCID: 0000-0001-5168-9846
6
+ # mail: geowieland@googlemail.com
7
+ # Version: 1.3.1
8
+ # Last update: 2025-05-28 18:01
9
+ # Copyright (c) 2025 Thomas Wieland
10
+ #-----------------------------------------------------------------------
11
+
12
+
13
+ import pandas as pd
14
+ import geopandas as gpd
15
+ import math
16
+ import requests
17
+ import tempfile
18
+ import time
19
+ import os
20
+ from PIL import Image
21
+ import matplotlib.pyplot as plt
22
+ import contextily as cx
23
+ from shapely.geometry import box
24
+
25
+
26
+ class Client:
27
+
28
+ def __init__(
29
+ self,
30
+ server = "http://a.tile.openstreetmap.org/",
31
+ headers = {
32
+ 'User-Agent': 'huff.osm/1.0.0 (your_name@your_email_provider.com)'
33
+ }
34
+ ):
35
+
36
+ self.server = server
37
+ self.headers = headers
38
+
39
+ def download_tile(
40
+ self,
41
+ zoom,
42
+ x,
43
+ y,
44
+ timeout = 10
45
+ ):
46
+
47
+ osm_url = self.server + f"{zoom}/{x}/{y}.png"
48
+
49
+ response = requests.get(
50
+ osm_url,
51
+ headers = self.headers,
52
+ timeout = timeout
53
+ )
54
+
55
+ if response.status_code == 200:
56
+
57
+ with tempfile.NamedTemporaryFile(delete=False, suffix='.png') as tmp_file:
58
+ tmp_file.write(response.content)
59
+ tmp_file_path = tmp_file.name
60
+ return Image.open(tmp_file_path)
61
+
62
+ else:
63
+
64
+ print(f"Error while accessing OSM server. Status code: {response.status_code} - {response.reason}")
65
+
66
+ return None
67
+
68
+
69
+ def get_basemap(
70
+ sw_lat,
71
+ sw_lon,
72
+ ne_lat,
73
+ ne_lon,
74
+ zoom = 15
75
+ ):
76
+
77
+ def lat_lon_to_tile(
78
+ lat,
79
+ lon,
80
+ zoom
81
+ ):
82
+
83
+ n = 2 ** zoom
84
+ x = int(n * ((lon + 180) / 360))
85
+ y = int(n * (1 - (math.log(math.tan(math.radians(lat)) + 1 / math.cos(math.radians(lat))) / math.pi)) / 2)
86
+ return x, y
87
+
88
+ def stitch_tiles(
89
+ zoom,
90
+ sw_lat,
91
+ sw_lon,
92
+ ne_lat,
93
+ ne_lon,
94
+ delay = 0.1
95
+ ):
96
+
97
+ osm_client = Client(
98
+ server = "http://a.tile.openstreetmap.org/"
99
+ )
100
+
101
+ sw_x_tile, sw_y_tile = lat_lon_to_tile(sw_lat, sw_lon, zoom)
102
+ ne_x_tile, ne_y_tile = lat_lon_to_tile(ne_lat, ne_lon, zoom)
103
+
104
+ tile_size = 256
105
+ width = (ne_x_tile - sw_x_tile + 1) * tile_size
106
+ height = (sw_y_tile - ne_y_tile + 1) * tile_size
107
+
108
+ stitched_image = Image.new('RGB', (width, height))
109
+
110
+ for x in range(sw_x_tile, ne_x_tile + 1):
111
+ for y in range(ne_y_tile, sw_y_tile + 1):
112
+ tile = osm_client.download_tile(
113
+ zoom = zoom,
114
+ x = x,
115
+ y = y
116
+ )
117
+ if tile:
118
+
119
+ stitched_image.paste(tile, ((x - sw_x_tile) * tile_size, (sw_y_tile - y) * tile_size))
120
+ else:
121
+ print(f"Error while retrieving tile {x}, {y}.")
122
+
123
+ time.sleep(delay)
124
+
125
+ return stitched_image
126
+
127
+ stitched_image = stitch_tiles(zoom, sw_lat, sw_lon, ne_lat, ne_lon)
128
+
129
+ if stitched_image:
130
+
131
+ stitched_image_path = "osm_map.png"
132
+ stitched_image.save(stitched_image_path)
133
+
134
+ else:
135
+ print("Error while building stitched images")
136
+
137
+
138
+ def map_with_basemap(
139
+ layers: list,
140
+ osm_basemap: bool = True,
141
+ zoom: int = 15,
142
+ styles: dict = {},
143
+ save_output: bool = True,
144
+ output_filepath: str = "osm_map_with_basemap.png",
145
+ output_dpi = 300
146
+ ):
147
+
148
+ if not layers:
149
+ raise ValueError("List layers is empty")
150
+
151
+ combined = gpd.GeoDataFrame(
152
+ pd.concat(
153
+ layers,
154
+ ignore_index = True
155
+ ),
156
+ crs = layers[0].crs
157
+ )
158
+
159
+ combined_wgs84 = combined.to_crs(epsg=4326)
160
+ bounds = combined_wgs84.total_bounds
161
+
162
+ sw_lon, sw_lat, ne_lon, ne_lat = bounds[0]*0.9999, bounds[1]*0.9999, bounds[2]*1.0001, bounds[3]*1.0001
163
+
164
+ if osm_basemap:
165
+
166
+ get_basemap(sw_lat, sw_lon, ne_lat, ne_lon, zoom=zoom)
167
+
168
+ fig, ax = plt.subplots(figsize=(10, 10))
169
+
170
+ if osm_basemap:
171
+
172
+ img = Image.open("osm_map.png")
173
+ extent_img = [sw_lon, ne_lon, sw_lat, ne_lat]
174
+ ax.imshow(img, extent=extent_img, origin="upper")
175
+
176
+ i = 0
177
+ for layer in layers:
178
+
179
+ layer_3857 = layer.to_crs(epsg=3857)
180
+
181
+ if styles != {}:
182
+
183
+ layer_style = styles[i]
184
+ layer_color = layer_style["color"]
185
+ layer_alpha = layer_style["alpha"]
186
+
187
+ if isinstance(layer_color, str):
188
+
189
+ layer_3857.plot(
190
+ ax=ax,
191
+ color=layer_color,
192
+ alpha=layer_alpha
193
+ )
194
+
195
+ elif isinstance(layer_color, dict):
196
+
197
+ color_key = list(layer_color.keys())[0]
198
+ color_mapping = layer_color[color_key]
199
+
200
+ if color_key not in layer_3857.columns:
201
+ raise KeyError ("Column", color_key, "not in layer.")
202
+
203
+ for value, color in color_mapping.items():
204
+
205
+ subset = layer_3857[layer_3857[color_key].astype(str) == str(value)]
206
+
207
+ if not subset.empty:
208
+ subset.plot(
209
+ ax=ax,
210
+ color=color,
211
+ alpha=layer_alpha
212
+ )
213
+
214
+ else:
215
+
216
+ layer_3857.plot(
217
+ ax=ax,
218
+ alpha=0.6
219
+ )
220
+
221
+ i = i+1
222
+
223
+ bbox = box(sw_lon, sw_lat, ne_lon, ne_lat)
224
+ extent_geom = gpd.GeoSeries([bbox], crs=4326).to_crs(epsg=3857).total_bounds
225
+
226
+ ax.set_xlim(extent_geom[0], extent_geom[2])
227
+ ax.set_ylim(extent_geom[1], extent_geom[3])
228
+
229
+ if osm_basemap:
230
+ cx.add_basemap(
231
+ ax,
232
+ source=cx.providers.OpenStreetMap.Mapnik,
233
+ zoom=zoom
234
+ )
235
+
236
+ plt.axis('off')
237
+ plt.show()
238
+
239
+ if save_output:
240
+
241
+ plt.savefig(
242
+ output_filepath,
243
+ dpi = output_dpi,
244
+ bbox_inches="tight"
245
+ )
246
+
247
+ plt.close()
248
+
249
+ if os.path.exists("osm_map.png"):
250
+ os.remove("osm_map.png")
@@ -1,43 +1,43 @@
1
- <!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
2
- <qgis version="3.28.3-Firenze">
3
- <identifier></identifier>
4
- <parentidentifier></parentidentifier>
5
- <language></language>
6
- <type>dataset</type>
7
- <title></title>
8
- <abstract></abstract>
9
- <contact>
10
- <name></name>
11
- <organization></organization>
12
- <position></position>
13
- <voice></voice>
14
- <fax></fax>
15
- <email></email>
16
- <role></role>
17
- </contact>
18
- <links/>
19
- <fees></fees>
20
- <encoding></encoding>
21
- <crs>
22
- <spatialrefsys nativeFormat="Wkt">
23
- <wkt>PROJCRS["DHDN / 3-degree Gauss-Kruger zone 3",BASEGEOGCRS["DHDN",DATUM["Deutsches Hauptdreiecksnetz",ELLIPSOID["Bessel 1841",6377397.155,299.1528128,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4314]],CONVERSION["3-degree Gauss-Kruger zone 3",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",9,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",1,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",3500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["northing (X)",north,ORDER[1],LENGTHUNIT["metre",1]],AXIS["easting (Y)",east,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping."],AREA["Germany - former West Germany onshore between 7�30'E and 10�30'E - states of Baden-Wurtemberg, Bayern, Bremen, Hamberg, Hessen, Niedersachsen, Nordrhein-Westfalen, Rhineland-Pfalz, Schleswig-Holstein."],BBOX[47.27,7.5,55.09,10.51]],ID["EPSG",31467]]</wkt>
24
- <proj4>+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7 +units=m +no_defs</proj4>
25
- <srsid>2647</srsid>
26
- <srid>31467</srid>
27
- <authid>EPSG:31467</authid>
28
- <description>DHDN / 3-degree Gauss-Kruger zone 3</description>
29
- <projectionacronym>tmerc</projectionacronym>
30
- <ellipsoidacronym>EPSG:7004</ellipsoidacronym>
31
- <geographicflag>false</geographicflag>
32
- </spatialrefsys>
33
- </crs>
34
- <extent>
35
- <spatial maxy="0" dimensions="2" maxx="0" maxz="0" crs="EPSG:31467" miny="0" minz="0" minx="0"/>
36
- <temporal>
37
- <period>
38
- <start></start>
39
- <end></end>
40
- </period>
41
- </temporal>
42
- </extent>
43
- </qgis>
1
+ <!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
2
+ <qgis version="3.28.3-Firenze">
3
+ <identifier></identifier>
4
+ <parentidentifier></parentidentifier>
5
+ <language></language>
6
+ <type>dataset</type>
7
+ <title></title>
8
+ <abstract></abstract>
9
+ <contact>
10
+ <name></name>
11
+ <organization></organization>
12
+ <position></position>
13
+ <voice></voice>
14
+ <fax></fax>
15
+ <email></email>
16
+ <role></role>
17
+ </contact>
18
+ <links/>
19
+ <fees></fees>
20
+ <encoding></encoding>
21
+ <crs>
22
+ <spatialrefsys nativeFormat="Wkt">
23
+ <wkt>PROJCRS["DHDN / 3-degree Gauss-Kruger zone 3",BASEGEOGCRS["DHDN",DATUM["Deutsches Hauptdreiecksnetz",ELLIPSOID["Bessel 1841",6377397.155,299.1528128,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4314]],CONVERSION["3-degree Gauss-Kruger zone 3",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",9,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",1,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",3500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["northing (X)",north,ORDER[1],LENGTHUNIT["metre",1]],AXIS["easting (Y)",east,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping."],AREA["Germany - former West Germany onshore between 7�30'E and 10�30'E - states of Baden-Wurtemberg, Bayern, Bremen, Hamberg, Hessen, Niedersachsen, Nordrhein-Westfalen, Rhineland-Pfalz, Schleswig-Holstein."],BBOX[47.27,7.5,55.09,10.51]],ID["EPSG",31467]]</wkt>
24
+ <proj4>+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7 +units=m +no_defs</proj4>
25
+ <srsid>2647</srsid>
26
+ <srid>31467</srid>
27
+ <authid>EPSG:31467</authid>
28
+ <description>DHDN / 3-degree Gauss-Kruger zone 3</description>
29
+ <projectionacronym>tmerc</projectionacronym>
30
+ <ellipsoidacronym>EPSG:7004</ellipsoidacronym>
31
+ <geographicflag>false</geographicflag>
32
+ </spatialrefsys>
33
+ </crs>
34
+ <extent>
35
+ <spatial maxy="0" dimensions="2" maxx="0" maxz="0" crs="EPSG:31467" miny="0" minz="0" minx="0"/>
36
+ <temporal>
37
+ <period>
38
+ <start></start>
39
+ <end></end>
40
+ </period>
41
+ </temporal>
42
+ </extent>
43
+ </qgis>
@@ -1,43 +1,43 @@
1
- <!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
2
- <qgis version="3.28.3-Firenze">
3
- <identifier></identifier>
4
- <parentidentifier></parentidentifier>
5
- <language></language>
6
- <type>dataset</type>
7
- <title></title>
8
- <abstract></abstract>
9
- <contact>
10
- <name></name>
11
- <organization></organization>
12
- <position></position>
13
- <voice></voice>
14
- <fax></fax>
15
- <email></email>
16
- <role></role>
17
- </contact>
18
- <links/>
19
- <fees></fees>
20
- <encoding></encoding>
21
- <crs>
22
- <spatialrefsys nativeFormat="Wkt">
23
- <wkt>PROJCRS["DHDN / 3-degree Gauss-Kruger zone 3",BASEGEOGCRS["DHDN",DATUM["Deutsches Hauptdreiecksnetz",ELLIPSOID["Bessel 1841",6377397.155,299.1528128,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4314]],CONVERSION["3-degree Gauss-Kruger zone 3",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",9,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",1,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",3500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["northing (X)",north,ORDER[1],LENGTHUNIT["metre",1]],AXIS["easting (Y)",east,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping."],AREA["Germany - former West Germany onshore between 7�30'E and 10�30'E - states of Baden-Wurtemberg, Bayern, Bremen, Hamberg, Hessen, Niedersachsen, Nordrhein-Westfalen, Rhineland-Pfalz, Schleswig-Holstein."],BBOX[47.27,7.5,55.09,10.51]],ID["EPSG",31467]]</wkt>
24
- <proj4>+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7 +units=m +no_defs</proj4>
25
- <srsid>2647</srsid>
26
- <srid>31467</srid>
27
- <authid>EPSG:31467</authid>
28
- <description>DHDN / 3-degree Gauss-Kruger zone 3</description>
29
- <projectionacronym>tmerc</projectionacronym>
30
- <ellipsoidacronym>EPSG:7004</ellipsoidacronym>
31
- <geographicflag>false</geographicflag>
32
- </spatialrefsys>
33
- </crs>
34
- <extent>
35
- <spatial maxy="0" dimensions="2" maxx="0" maxz="0" crs="EPSG:31467" miny="0" minz="0" minx="0"/>
36
- <temporal>
37
- <period>
38
- <start></start>
39
- <end></end>
40
- </period>
41
- </temporal>
42
- </extent>
43
- </qgis>
1
+ <!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>
2
+ <qgis version="3.28.3-Firenze">
3
+ <identifier></identifier>
4
+ <parentidentifier></parentidentifier>
5
+ <language></language>
6
+ <type>dataset</type>
7
+ <title></title>
8
+ <abstract></abstract>
9
+ <contact>
10
+ <name></name>
11
+ <organization></organization>
12
+ <position></position>
13
+ <voice></voice>
14
+ <fax></fax>
15
+ <email></email>
16
+ <role></role>
17
+ </contact>
18
+ <links/>
19
+ <fees></fees>
20
+ <encoding></encoding>
21
+ <crs>
22
+ <spatialrefsys nativeFormat="Wkt">
23
+ <wkt>PROJCRS["DHDN / 3-degree Gauss-Kruger zone 3",BASEGEOGCRS["DHDN",DATUM["Deutsches Hauptdreiecksnetz",ELLIPSOID["Bessel 1841",6377397.155,299.1528128,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],ID["EPSG",4314]],CONVERSION["3-degree Gauss-Kruger zone 3",METHOD["Transverse Mercator",ID["EPSG",9807]],PARAMETER["Latitude of natural origin",0,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8801]],PARAMETER["Longitude of natural origin",9,ANGLEUNIT["degree",0.0174532925199433],ID["EPSG",8802]],PARAMETER["Scale factor at natural origin",1,SCALEUNIT["unity",1],ID["EPSG",8805]],PARAMETER["False easting",3500000,LENGTHUNIT["metre",1],ID["EPSG",8806]],PARAMETER["False northing",0,LENGTHUNIT["metre",1],ID["EPSG",8807]]],CS[Cartesian,2],AXIS["northing (X)",north,ORDER[1],LENGTHUNIT["metre",1]],AXIS["easting (Y)",east,ORDER[2],LENGTHUNIT["metre",1]],USAGE[SCOPE["Cadastre, engineering survey, topographic mapping."],AREA["Germany - former West Germany onshore between 7�30'E and 10�30'E - states of Baden-Wurtemberg, Bayern, Bremen, Hamberg, Hessen, Niedersachsen, Nordrhein-Westfalen, Rhineland-Pfalz, Schleswig-Holstein."],BBOX[47.27,7.5,55.09,10.51]],ID["EPSG",31467]]</wkt>
24
+ <proj4>+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7 +units=m +no_defs</proj4>
25
+ <srsid>2647</srsid>
26
+ <srid>31467</srid>
27
+ <authid>EPSG:31467</authid>
28
+ <description>DHDN / 3-degree Gauss-Kruger zone 3</description>
29
+ <projectionacronym>tmerc</projectionacronym>
30
+ <ellipsoidacronym>EPSG:7004</ellipsoidacronym>
31
+ <geographicflag>false</geographicflag>
32
+ </spatialrefsys>
33
+ </crs>
34
+ <extent>
35
+ <spatial maxy="0" dimensions="2" maxx="0" maxz="0" crs="EPSG:31467" miny="0" minz="0" minx="0"/>
36
+ <temporal>
37
+ <period>
38
+ <start></start>
39
+ <end></end>
40
+ </period>
41
+ </temporal>
42
+ </extent>
43
+ </qgis>
huff/tests/tests_huff.py CHANGED
@@ -4,13 +4,16 @@
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 13:10
9
9
  # Copyright (c) 2025 Thomas Wieland
10
10
  #-----------------------------------------------------------------------
11
11
 
12
12
 
13
13
  from huff.models import create_interaction_matrix, get_isochrones, load_geodata, load_interaction_matrix
14
+ from huff.osm import map_with_basemap
15
+ from huff.gistools import buffers, point_spatial_join
16
+
14
17
 
15
18
  # Customer origins (statistical districts):
16
19
 
@@ -21,6 +24,14 @@ Haslach = load_geodata(
21
24
  )
22
25
  # Loading customer origins (shapefile)
23
26
 
27
+ Haslach_buf = Haslach.buffers(
28
+ segments_distance=[500,1000,1500],
29
+ save_output=True,
30
+ output_filepath="Haslach_buf.shp",
31
+ output_crs="EPSG:31467"
32
+ )
33
+ # Buffers for customer origins
34
+
24
35
  Haslach.summary()
25
36
  # Summary of customer origins
26
37
 
@@ -56,22 +67,24 @@ Haslach_supermarkets.define_attraction_weighting(
56
67
  )
57
68
  # Define attraction weighting (gamma)
58
69
 
59
- # Haslach_supermarkets.isochrones(
60
- # segments_minutes=[5, 10, 15],
61
- # profile = "driving-car",
62
- # save_output=True,
63
- # ors_auth="5b3ce3597851110001cf62480a15aafdb5a64f4d91805929f8af6abd",
64
- # output_filepath="Haslach_supermarkets_iso.shp"
65
- # )
66
- # # Obtaining isochrones for driving by car (5, 10 and 15 minutes)
70
+ Haslach_supermarkets.isochrones(
71
+ segments_minutes=[3, 6, 9, 12, 15],
72
+ profile = "foot-walking",
73
+ save_output=True,
74
+ ors_auth="5b3ce3597851110001cf62480a15aafdb5a64f4d91805929f8af6abd",
75
+ output_filepath="Haslach_supermarkets_iso.shp",
76
+ output_crs="EPSG:31467"
77
+ )
78
+ # Obtaining isochrones for walking (5 and 10 minutes)
79
+ # ORS API documentation: https://openrouteservice.org/dev/#/api-docs/v2/
67
80
 
68
- # Haslach_supermarkets.summary()
69
- # # Summary of updated customer origins
81
+ Haslach_supermarkets.summary()
82
+ # Summary of updated customer origins
70
83
 
71
- # Haslach_supermarkets_isochrones = Haslach_supermarkets.get_isochrones_gdf()
72
- # # Extracting isochrones
84
+ Haslach_supermarkets_isochrones = Haslach_supermarkets.get_isochrones_gdf()
85
+ # Extracting isochrones
73
86
 
74
- # print(Haslach_supermarkets_isochrones)
87
+ print(Haslach_supermarkets_isochrones)
75
88
 
76
89
 
77
90
  # Using customer origins and supply locations for building interaction matrix:
@@ -83,10 +96,11 @@ haslach_interactionmatrix = create_interaction_matrix(
83
96
  # Creating interaction matrix
84
97
 
85
98
  interaction_matrix = haslach_interactionmatrix.transport_costs(
86
- #ors_auth="5b3ce3597851110001cf62480a15aafdb5a64f4d91805929f8af6abd"
87
- network=False
99
+ ors_auth="5b3ce3597851110001cf62480a15aafdb5a64f4d91805929f8af6abd"
100
+ #network=False
88
101
  )
89
102
  # Obtaining transport costs (default: driving-car)
103
+ # ORS API documentation: https://openrouteservice.org/dev/#/api-docs/v2/
90
104
 
91
105
  interaction_matrix = interaction_matrix.flows()
92
106
  # Calculating spatial flows
@@ -120,6 +134,7 @@ mci_fit.get_market_areas_df()
120
134
 
121
135
 
122
136
  # Loading own interaction matrix:
137
+ # Data source: Wieland 2015 (https://nbn-resolving.org/urn:nbn:de:bvb:20-opus-180753)
123
138
 
124
139
  Wieland2015_interaction_matrix = load_interaction_matrix(
125
140
  data="data/Wieland2015.xlsx",
@@ -134,7 +149,6 @@ Wieland2015_interaction_matrix = load_interaction_matrix(
134
149
  probabilities_col="MA",
135
150
  data_type="xlsx"
136
151
  )
137
- # Data source: Wieland 2015 (https://nbn-resolving.org/urn:nbn:de:bvb:20-opus-180753)
138
152
 
139
153
  Wieland2015_interaction_matrix.summary()
140
154
  # Summary of interaction matrix
@@ -150,4 +164,97 @@ Wieland2015_fit = Wieland2015_interaction_matrix.mci_fit(
150
164
  # Fitting MCI model with four independent variables
151
165
 
152
166
  Wieland2015_fit.summary()
153
- # MCI model summary
167
+ # MCI model summary
168
+
169
+
170
+ # Buffer analysis:
171
+
172
+ Haslach_supermarkets_gdf = Haslach_supermarkets.get_geodata_gpd_original()
173
+ Haslach_buffers = Haslach_buf.get_buffers_gdf()
174
+ # Extracting points and buffer polygons
175
+
176
+ Haslach_districts_buf = point_spatial_join(
177
+ polygon_gdf = Haslach_buffers,
178
+ point_gdf = Haslach_supermarkets_gdf,
179
+ polygon_ref_cols = ["BEZEICHN", "segment"],
180
+ point_stat_col = "VKF_qm"
181
+ )
182
+ # Spatial join with buffers and points
183
+ # Statistics for supermarket selling space by buffers of statistical districts
184
+ # (How much selling space in 500, 1000, and 1500 metres?)
185
+
186
+ Haslach_districts_buf[0].to_file("Haslach_districts_buf.shp")
187
+ # Save joined points as shapefile
188
+
189
+ print(Haslach_districts_buf[1])
190
+ # Showing df with overlay statistics
191
+
192
+
193
+ # Isochrones analysis:
194
+
195
+ Haslach_districts = Haslach.get_geodata_gpd_original()
196
+
197
+ Haslach_supermarkets_iso = point_spatial_join(
198
+ polygon_gdf = Haslach_supermarkets_isochrones,
199
+ point_gdf = Haslach_districts,
200
+ polygon_ref_cols = ["LFDNR", "segment"],
201
+ point_stat_col = "pop"
202
+ )
203
+ # Spatial join with isochrones and points
204
+ # Statistics for population by isochrones of supermarkets
205
+ # (How much population in 5, 10, and 15 minutes?)
206
+
207
+ Haslach_supermarkets_iso[0].to_file("Haslach_supermarkets_iso.shp")
208
+ # Save joined points as shapefile
209
+
210
+ print(Haslach_supermarkets_iso[1])
211
+ # Showing df with overlay statistics
212
+
213
+
214
+ # Creating map:
215
+
216
+ Haslach_gdf = Haslach.get_geodata_gpd_original()
217
+ Haslach_supermarkets_gdf = Haslach_supermarkets.get_geodata_gpd_original()
218
+ Haslach_supermarkets_gdf_iso = Haslach_supermarkets.get_isochrones_gdf()
219
+ # Extracttion geopandas.GeoDataFrames
220
+
221
+ map_with_basemap(
222
+ layers = [
223
+ Haslach_supermarkets_gdf_iso,
224
+ Haslach_gdf,
225
+ Haslach_supermarkets_gdf
226
+ ],
227
+ styles={
228
+ 0: {
229
+ "color": {
230
+ "segment_minutes": {
231
+ "3": "green",
232
+ "6": "yellow",
233
+ "9": "orange",
234
+ "12": "red",
235
+ "13": "darkred"
236
+ }
237
+ },
238
+ "alpha": 0.3
239
+ },
240
+ 1: {
241
+ "color": "green",
242
+ "alpha": 1
243
+ },
244
+ 2: {
245
+ "color": {
246
+ "Name": {
247
+ "Aldi S├╝d": "blue",
248
+ "Edeka": "yellow",
249
+ "Lidl": "red",
250
+ "Netto": "orange",
251
+ "Real": "black",
252
+ "Treff 3000": "fuchsia"
253
+ }
254
+ },
255
+ "alpha": 1
256
+ }
257
+ },
258
+ output_filepath = "Haslach_map.png"
259
+ )
260
+ # Map with three layers and OSM basemap