ObjectNat 0.1.4__tar.gz → 0.2.0__tar.gz

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.

Potentially problematic release.


This version of ObjectNat might be problematic. Click here for more details.

Files changed (26) hide show
  1. {objectnat-0.1.4 → objectnat-0.2.0}/PKG-INFO +29 -20
  2. {objectnat-0.1.4 → objectnat-0.2.0}/README.md +24 -15
  3. {objectnat-0.1.4 → objectnat-0.2.0}/pyproject.toml +16 -9
  4. objectnat-0.2.0/src/objectnat/__init__.py +13 -0
  5. objectnat-0.1.4/src/objectnat/__init__.py → objectnat-0.2.0/src/objectnat/_api.py +4 -7
  6. objectnat-0.2.0/src/objectnat/_config.py +67 -0
  7. objectnat-0.2.0/src/objectnat/_version.py +1 -0
  8. {objectnat-0.1.4 → objectnat-0.2.0}/src/objectnat/methods/balanced_buildings.py +4 -1
  9. {objectnat-0.1.4 → objectnat-0.2.0}/src/objectnat/methods/cluster_points_in_polygons.py +4 -1
  10. {objectnat-0.1.4 → objectnat-0.2.0}/src/objectnat/methods/coverage_zones.py +6 -21
  11. objectnat-0.2.0/src/objectnat/methods/isochrones.py +140 -0
  12. objectnat-0.2.0/src/objectnat/methods/living_buildings_osm.py +172 -0
  13. objectnat-0.2.0/src/objectnat/methods/provision/__init__.py +0 -0
  14. objectnat-0.2.0/src/objectnat/methods/provision/city_provision.py +291 -0
  15. objectnat-0.2.0/src/objectnat/methods/provision/provision.py +90 -0
  16. objectnat-0.2.0/src/objectnat/methods/provision/provision_exceptions.py +59 -0
  17. {objectnat-0.1.4 → objectnat-0.2.0}/src/objectnat/methods/visibility_analysis.py +4 -1
  18. objectnat-0.2.0/src/objectnat/utils/__init__.py +1 -0
  19. objectnat-0.2.0/src/objectnat/utils/utils.py +19 -0
  20. objectnat-0.1.4/src/objectnat/methods/adjacency_matrix.py +0 -39
  21. objectnat-0.1.4/src/objectnat/methods/demands.py +0 -43
  22. objectnat-0.1.4/src/objectnat/methods/isochrones.py +0 -66
  23. objectnat-0.1.4/src/objectnat/methods/osm_graph.py +0 -23
  24. objectnat-0.1.4/src/objectnat/methods/provision.py +0 -135
  25. {objectnat-0.1.4 → objectnat-0.2.0}/LICENSE.txt +0 -0
  26. {objectnat-0.1.4 → objectnat-0.2.0}/src/objectnat/methods/__init__.py +0 -0
@@ -1,18 +1,18 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ObjectNat
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: ObjectNat is an open-source library created for geospatial analysis created by IDU team
5
5
  License: BSD-3-Clause
6
- Author: Danila
6
+ Author: DDonnyy
7
7
  Author-email: 63115678+DDonnyy@users.noreply.github.com
8
- Requires-Python: >=3.10,<4.0
8
+ Requires-Python: >=3.10,<3.13
9
9
  Classifier: License :: OSI Approved :: BSD License
10
10
  Classifier: Programming Language :: Python :: 3
11
11
  Classifier: Programming Language :: Python :: 3.10
12
12
  Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
- Requires-Dist: dongraphio (>=0.3.13,<0.4.0)
15
14
  Requires-Dist: geopandas (>=0.14.3,<0.15.0)
15
+ Requires-Dist: iduedu (>=0.1.3,<0.2.0)
16
16
  Requires-Dist: joblib (>=1.4.2,<2.0.0)
17
17
  Requires-Dist: networkit (>=11.0,<12.0)
18
18
  Requires-Dist: networkx (>=3.2.1,<4.0.0)
@@ -20,7 +20,7 @@ Requires-Dist: numpy (>=1.23.5,<2.0.0)
20
20
  Requires-Dist: pandarallel (>=1.6.5,<2.0.0)
21
21
  Requires-Dist: pandas (>=2.2.0,<3.0.0)
22
22
  Requires-Dist: population-restorator (>=0.2.3,<0.3.0)
23
- Requires-Dist: provisio (>=0.1.7,<0.2.0)
23
+ Requires-Dist: pulp (>=2.8.0,<3.0.0)
24
24
  Requires-Dist: scikit-learn (>=1.4.0,<2.0.0)
25
25
  Requires-Dist: tqdm (>=4.66.2,<5.0.0)
26
26
  Description-Content-Type: text/markdown
@@ -28,58 +28,58 @@ Description-Content-Type: text/markdown
28
28
  # ObjectNat - Meta Library
29
29
 
30
30
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
31
+ [![PyPI version](https://img.shields.io/pypi/v/objectnat.svg)](https://pypi.org/project/objectnat/)
31
32
 
32
33
  <p align="center">
33
- <img src="https://i.ibb.co/FWtHNQv/logo.png" alt="logo" width="400">
34
+ <img src="https://github.com/user-attachments/assets/d3878cce-8eba-4f96-8458-9a798d436120" alt="logo" width="400">
34
35
  </p>
35
36
 
36
37
  #### **ObjectNat** is an open-source library created for geospatial analysis created by **IDU team**
37
38
 
38
39
  ## ObjectNat Components
39
40
 
40
- - [dongraphio](https://github.com/DDonnyy/dongraphio) : `dongraphio` provides graph functions
41
- - [provisio](https://github.com/DDonnyy/provisio) : `provisio` provides main provisio fuctions
41
+ - [IduEdu](https://github.com/DDonnyy/IduEdu) : `IduEdu` provides graph functions
42
42
  - [population-restorator](https://github.com/kanootoko/population-restorator) : `restorator` provides city resettlement
43
43
 
44
44
  ## Features and how to use
45
45
 
46
- 1. **[City graph from OSM](./examples/graph_generator.ipynb)** - Function to assemble a road, pedestrian, and public
47
- transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
46
+ 1. **[City graph from OSM (IduEdu)](https://github.com/DDonnyy/IduEdu/blob/main/examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian,
47
+ and public transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
48
48
 
49
- <img src="https://i.ibb.co/VpsPgL1/Graph-generator-v1.webp" alt="Graph-generator-v1" height="250">
49
+ <img src="https://github.com/user-attachments/assets/8dc98da9-8462-415e-8cc8-bdfca788e206" alt="IntermodalGraph" height="250">
50
50
 
51
51
  2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided
52
52
  graph and edge weight type (time or distance). The intermodal graph can be obtained using the previous example.
53
+
53
54
  3. **[Isochrones,transport accessibility](./examples/isochrone_generator.ipynb)** - Function for generating isochrones to
54
55
  analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
55
56
  pedestrian, automobile, or public transport graphs, or a combination thereof.
56
57
 
57
- <img src="https://i.ibb.co/QM0tmZ2/isochrones-from-2-points.webp" alt="isochrones-from-2-points" height="250">
58
+ <img src="https://github.com/user-attachments/assets/37f308a5-db56-497d-b080-4edef3584fe5" alt="isochrones" height="250">
58
59
 
59
60
  4. **[Population restoration](./examples/restore_population.ipynb)** - Function for resettling population into the provided
60
61
  layer of residential buildings. This function distributes people among dwellings based on the total city population
61
62
  and the living area of each house.
62
63
  5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential
63
- buildings and population with services. In case of missing data, this function utilizes previously described
64
- functionality to retrieve the necessary information.
64
+ buildings and population with services.
65
+
66
+ <img src="https://github.com/user-attachments/assets/5f2b3c55-9a02-4d70-80f4-503b77023eda" alt="ProvisionSchools" height="250">
65
67
 
66
- <img src="https://i.ibb.co/CW7Xj5F/Burger-Provision5min.webp" alt="Burger-Provision5min" height="250">
67
-
68
68
  6. **[Visibility analysis](./examples/visibility_analysis.ipynb)** - Function to get a quick estimate of visibility from a
69
69
  given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a
70
70
  large
71
71
  urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
72
72
  results. Points can be generated using a road graph and random point distribution along edges.
73
73
 
74
- <img src="https://i.ibb.co/LxcGTfN/visibility-from-point.webp" alt="visibility-from-point" height="250">
75
-
76
- <img src="https://i.ibb.co/zNRzXc5/visibility-catchment-area.webp" alt="visibility-catchment-area" height="250">
74
+ <img src="https://github.com/user-attachments/assets/2927ac86-01e8-4b0e-9ea8-72ad81c13cf5" alt="visibility-from-point" height="250">
77
75
 
76
+ <img src="https://github.com/user-attachments/assets/b5b0d4b3-a02f-4ade-8772-475703cd6435" alt="visibility-catchment-area" height="250">
77
+
78
78
  7. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
79
79
  points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
80
80
  between types of services within the clusters.
81
81
 
82
- <img src="https://i.ibb.co/fF3c4YC/service-clusterization.webp" alt="service-clusterization" height="250">
82
+ <img src="https://github.com/user-attachments/assets/2a9ad722-87d2-4954-9612-5ac3765aa824" alt="service-clusterization" height="250">
83
83
 
84
84
  ## Installation
85
85
 
@@ -88,7 +88,16 @@ Description-Content-Type: text/markdown
88
88
  ```
89
89
  pip install ObjectNat
90
90
  ```
91
+ ### Configuration changes
92
+
93
+ ```python
94
+ from objectnat import config
91
95
 
96
+ config.set_timeout(10) # Timeout for overpass queries
97
+ config.change_logger_lvl('INFO') # To mute all debug msgs
98
+ config.set_enable_tqdm(False) # To mute all tqdm's progress bars
99
+ config.set_overpass_url('http://your.overpass-api.de/interpreter/URL')
100
+ ```
92
101
  ## Contacts
93
102
 
94
103
  - [NCCR](https://actcognitive.org/) - National
@@ -1,58 +1,58 @@
1
1
  # ObjectNat - Meta Library
2
2
 
3
3
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
4
+ [![PyPI version](https://img.shields.io/pypi/v/objectnat.svg)](https://pypi.org/project/objectnat/)
4
5
 
5
6
  <p align="center">
6
- <img src="https://i.ibb.co/FWtHNQv/logo.png" alt="logo" width="400">
7
+ <img src="https://github.com/user-attachments/assets/d3878cce-8eba-4f96-8458-9a798d436120" alt="logo" width="400">
7
8
  </p>
8
9
 
9
10
  #### **ObjectNat** is an open-source library created for geospatial analysis created by **IDU team**
10
11
 
11
12
  ## ObjectNat Components
12
13
 
13
- - [dongraphio](https://github.com/DDonnyy/dongraphio) : `dongraphio` provides graph functions
14
- - [provisio](https://github.com/DDonnyy/provisio) : `provisio` provides main provisio fuctions
14
+ - [IduEdu](https://github.com/DDonnyy/IduEdu) : `IduEdu` provides graph functions
15
15
  - [population-restorator](https://github.com/kanootoko/population-restorator) : `restorator` provides city resettlement
16
16
 
17
17
  ## Features and how to use
18
18
 
19
- 1. **[City graph from OSM](./examples/graph_generator.ipynb)** - Function to assemble a road, pedestrian, and public
20
- transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
19
+ 1. **[City graph from OSM (IduEdu)](https://github.com/DDonnyy/IduEdu/blob/main/examples/get_any_graph.ipynb)** - Functions to assemble a road, pedestrian,
20
+ and public transport graph from OpenStreetMap (OSM) and creating Intermodal graph.
21
21
 
22
- <img src="https://i.ibb.co/VpsPgL1/Graph-generator-v1.webp" alt="Graph-generator-v1" height="250">
22
+ <img src="https://github.com/user-attachments/assets/8dc98da9-8462-415e-8cc8-bdfca788e206" alt="IntermodalGraph" height="250">
23
23
 
24
24
  2. **[Adjacency matrix](./examples/calculate_adjacency_matrix.ipynb)** - Calculate adjacency matrix based on the provided
25
25
  graph and edge weight type (time or distance). The intermodal graph can be obtained using the previous example.
26
+
26
27
  3. **[Isochrones,transport accessibility](./examples/isochrone_generator.ipynb)** - Function for generating isochrones to
27
28
  analyze transportation accessibility from specified starting coordinates. Isochrones can be constructed based on
28
29
  pedestrian, automobile, or public transport graphs, or a combination thereof.
29
30
 
30
- <img src="https://i.ibb.co/QM0tmZ2/isochrones-from-2-points.webp" alt="isochrones-from-2-points" height="250">
31
+ <img src="https://github.com/user-attachments/assets/37f308a5-db56-497d-b080-4edef3584fe5" alt="isochrones" height="250">
31
32
 
32
33
  4. **[Population restoration](./examples/restore_population.ipynb)** - Function for resettling population into the provided
33
34
  layer of residential buildings. This function distributes people among dwellings based on the total city population
34
35
  and the living area of each house.
35
36
  5. **[Service provision](./examples/calculate_provision.ipynb)** - Function for calculating the provision of residential
36
- buildings and population with services. In case of missing data, this function utilizes previously described
37
- functionality to retrieve the necessary information.
37
+ buildings and population with services.
38
+
39
+ <img src="https://github.com/user-attachments/assets/5f2b3c55-9a02-4d70-80f4-503b77023eda" alt="ProvisionSchools" height="250">
38
40
 
39
- <img src="https://i.ibb.co/CW7Xj5F/Burger-Provision5min.webp" alt="Burger-Provision5min" height="250">
40
-
41
41
  6. **[Visibility analysis](./examples/visibility_analysis.ipynb)** - Function to get a quick estimate of visibility from a
42
42
  given point(s) to buildings within a given distance. Also, there is a visibility catchment area calculator for a
43
43
  large
44
44
  urban area. This function is designed to work with at least 1000 points spaced 10-20 meters apart for optimal
45
45
  results. Points can be generated using a road graph and random point distribution along edges.
46
46
 
47
- <img src="https://i.ibb.co/LxcGTfN/visibility-from-point.webp" alt="visibility-from-point" height="250">
48
-
49
- <img src="https://i.ibb.co/zNRzXc5/visibility-catchment-area.webp" alt="visibility-catchment-area" height="250">
47
+ <img src="https://github.com/user-attachments/assets/2927ac86-01e8-4b0e-9ea8-72ad81c13cf5" alt="visibility-from-point" height="250">
50
48
 
49
+ <img src="https://github.com/user-attachments/assets/b5b0d4b3-a02f-4ade-8772-475703cd6435" alt="visibility-catchment-area" height="250">
50
+
51
51
  7. **[Point clusterization](./examples/point_clusterization.ipynb)** - Function to generate cluster polygons for given
52
52
  points based on a specified minimum distance and minimum points per cluster. Optionally, calculate the relative ratio
53
53
  between types of services within the clusters.
54
54
 
55
- <img src="https://i.ibb.co/fF3c4YC/service-clusterization.webp" alt="service-clusterization" height="250">
55
+ <img src="https://github.com/user-attachments/assets/2a9ad722-87d2-4954-9612-5ac3765aa824" alt="service-clusterization" height="250">
56
56
 
57
57
  ## Installation
58
58
 
@@ -61,7 +61,16 @@
61
61
  ```
62
62
  pip install ObjectNat
63
63
  ```
64
+ ### Configuration changes
65
+
66
+ ```python
67
+ from objectnat import config
64
68
 
69
+ config.set_timeout(10) # Timeout for overpass queries
70
+ config.change_logger_lvl('INFO') # To mute all debug msgs
71
+ config.set_enable_tqdm(False) # To mute all tqdm's progress bars
72
+ config.set_overpass_url('http://your.overpass-api.de/interpreter/URL')
73
+ ```
65
74
  ## Contacts
66
75
 
67
76
  - [NCCR](https://actcognitive.org/) - National
@@ -1,28 +1,29 @@
1
1
  [tool.poetry]
2
2
  name = "ObjectNat"
3
- version = "0.1.4"
3
+ version = "0.2.0"
4
4
  description = "ObjectNat is an open-source library created for geospatial analysis created by IDU team"
5
5
  license = "BSD-3-Clause"
6
- authors = ["Danila <63115678+DDonnyy@users.noreply.github.com>"]
6
+ authors = ["DDonnyy <63115678+DDonnyy@users.noreply.github.com>"]
7
7
  readme = "README.md"
8
8
 
9
9
  packages = [{ include = "objectnat", from = "src" }]
10
10
 
11
11
  [tool.poetry.dependencies]
12
- python = "^3.10"
13
- geopandas = "^0.14.3"
14
- tqdm = "^4.66.2"
15
- networkit = "^11.0"
12
+ python = ">=3.10,<3.13"
16
13
  numpy = "^1.23.5"
17
14
  pandas = "^2.2.0"
15
+ geopandas = "^0.14.3"
16
+ tqdm = "^4.66.2"
17
+ pandarallel = "^1.6.5"
18
18
  networkx = "^3.2.1"
19
+ networkit = "^11.0"
20
+ pulp = "^2.8.0"
19
21
  population-restorator = "^0.2.3"
20
- dongraphio = "^0.3.13"
21
- provisio = "^0.1.7"
22
+ iduedu = "^0.1.3"
22
23
  joblib = "^1.4.2"
23
- pandarallel = "^1.6.5"
24
24
  scikit-learn = "^1.4.0"
25
25
 
26
+
26
27
  [tool.poetry.group.dev.dependencies]
27
28
  black = "^24.2.0"
28
29
  pylint = "^3.0.3"
@@ -46,6 +47,11 @@ disable = [
46
47
  "duplicate-code",
47
48
  "missing-module-docstring",
48
49
  "missing-function-docstring",
50
+ "too-many-locals",
51
+ "too-many-branches",
52
+ "too-many-statements",
53
+ "too-many-arguments",
54
+ "cyclic-import"
49
55
  ]
50
56
  good-names = [
51
57
 
@@ -59,3 +65,4 @@ use_parentheses = true
59
65
  ensure_newline_before_comments = true
60
66
  line_length = 120
61
67
  split_on_trailing_comma = true
68
+ skip = ["__init__.py"]
@@ -0,0 +1,13 @@
1
+ """
2
+ ObjectNat
3
+ ========
4
+
5
+
6
+ ObjectNat is an open-source library created for geospatial analysis created by IDU team.
7
+
8
+ Homepage https://github.com/DDonnyy/ObjectNat.
9
+ """
10
+
11
+ from ._config import config
12
+ from ._api import *
13
+ from ._version import VERSION as __version__
@@ -1,15 +1,12 @@
1
- __version__ = "0.1.4"
1
+ # pylint: disable=unused-import,wildcard-import,unused-wildcard-import
2
+ from iduedu import *
2
3
 
3
- from dongraphio.enums import GraphType
4
-
5
- from .methods.adjacency_matrix import get_adjacency_matrix
6
4
  from .methods.balanced_buildings import get_balanced_buildings
7
5
  from .methods.cluster_points_in_polygons import get_clusters_polygon
8
6
  from .methods.coverage_zones import get_isochrone_zone_coverage, get_radius_zone_coverage
9
- from .methods.demands import get_demands
10
7
  from .methods.isochrones import get_accessibility_isochrones
11
- from .methods.osm_graph import get_intermodal_graph_from_osm
12
- from .methods.provision import NoOsmIdException, NoWeightAdjacencyException, get_provision
8
+ from .methods.living_buildings_osm import download_buildings
9
+ from .methods.provision.provision import clip_provision, get_service_provision, recalculate_links
13
10
  from .methods.visibility_analysis import (
14
11
  calculate_visibility_catchment_area,
15
12
  get_visibilities_from_points,
@@ -0,0 +1,67 @@
1
+ import sys
2
+ from typing import Literal
3
+
4
+ from iduedu import config as iduedu_config
5
+ from loguru import logger
6
+
7
+
8
+ class Config:
9
+ """
10
+ A configuration class to manage global settings for the application, such as Overpass API URL,
11
+ timeouts, and logging options.
12
+
13
+ Attributes
14
+ ----------
15
+ overpass_url : str
16
+ URL for accessing the Overpass API. Defaults to "http://lz4.overpass-api.de/api/interpreter".
17
+ timeout : int or None
18
+ Timeout in seconds for API requests. If None, no timeout is applied.
19
+ enable_tqdm_bar : bool
20
+ Enables or disables progress bars (via tqdm). Defaults to True.
21
+ logger : Logger
22
+ Logging instance to handle application logging.
23
+
24
+ Methods
25
+ -------
26
+ change_logger_lvl(lvl: Literal["TRACE", "DEBUG", "INFO", "WARN", "ERROR"])
27
+ Changes the logging level to the specified value.
28
+ set_overpass_url(url: str)
29
+ Sets a new Overpass API URL.
30
+ set_timeout(timeout: int)
31
+ Sets the timeout for API requests.
32
+ set_enable_tqdm(enable: bool)
33
+ Enables or disables progress bars in the application.
34
+ """
35
+
36
+ def __init__(
37
+ self,
38
+ overpass_url="http://lz4.overpass-api.de/api/interpreter",
39
+ timeout=None,
40
+ enable_tqdm_bar=True,
41
+ ):
42
+ self.overpass_url = overpass_url
43
+ self.timeout = timeout
44
+ self.enable_tqdm_bar = enable_tqdm_bar
45
+ self.logger = logger
46
+ self.iduedu_config = iduedu_config
47
+
48
+ def change_logger_lvl(self, lvl: Literal["TRACE", "DEBUG", "INFO", "WARN", "ERROR"]):
49
+ self.logger.remove()
50
+ self.logger.add(sys.stderr, level=lvl)
51
+ self.iduedu_config.change_logger_lvl(lvl)
52
+
53
+ def set_overpass_url(self, url: str):
54
+ self.overpass_url = url
55
+ self.iduedu_config.set_overpass_url(url)
56
+
57
+ def set_timeout(self, timeout: int):
58
+ self.timeout = timeout
59
+ self.iduedu_config.set_timeout(timeout)
60
+
61
+ def set_enable_tqdm(self, enable: bool):
62
+ self.enable_tqdm_bar = enable
63
+ self.iduedu_config.set_enable_tqdm(enable)
64
+
65
+
66
+ config = Config()
67
+ config.change_logger_lvl("INFO")
@@ -0,0 +1 @@
1
+ VERSION = "0.2.0"
@@ -1,7 +1,10 @@
1
1
  import geopandas as gpd
2
2
  import population_restorator.balancer.houses as b_build
3
3
  import population_restorator.balancer.territories as b_terr
4
- from loguru import logger
4
+
5
+ from objectnat import config
6
+
7
+ logger = config.logger
5
8
 
6
9
 
7
10
  def get_balanced_buildings(
@@ -2,9 +2,12 @@ from typing import Literal
2
2
 
3
3
  import geopandas as gpd
4
4
  import pandas as pd
5
- from loguru import logger
6
5
  from sklearn.cluster import DBSCAN, HDBSCAN
7
6
 
7
+ from objectnat import config
8
+
9
+ logger = config.logger
10
+
8
11
 
9
12
  def _get_cluster(services_select, min_dist, min_point, method):
10
13
  services_coords = pd.DataFrame(
@@ -2,8 +2,6 @@ from typing import Literal
2
2
 
3
3
  import geopandas as gpd
4
4
  import networkx as nx
5
- import pandas as pd
6
- from dongraphio import GraphType
7
5
 
8
6
  from .isochrones import get_accessibility_isochrones
9
7
 
@@ -48,7 +46,6 @@ def get_isochrone_zone_coverage(
48
46
  weight_type: Literal["time_min", "length_meter"],
49
47
  weight_value: int,
50
48
  city_graph: nx.Graph,
51
- graph_type: list[GraphType],
52
49
  ) -> tuple[gpd.GeoDataFrame, gpd.GeoDataFrame | None, gpd.GeoDataFrame | None]:
53
50
  """
54
51
  Create isochrones for each service location based on travel time/distance.
@@ -56,15 +53,13 @@ def get_isochrone_zone_coverage(
56
53
  Parameters
57
54
  ----------
58
55
  services : gpd.GeoDataFrame
59
- GeoDataFrame containing the service locations.
56
+ Layer containing the service locations.
60
57
  weight_type : str
61
58
  Type of weight used for calculating isochrones, either "time_min" or "length_meter".
62
59
  weight_value : int
63
60
  The value of the weight, representing time in minutes or distance in meters.
64
61
  city_graph : nx.Graph
65
62
  The graph representing the city's transportation network.
66
- graph_type : list[GraphType]
67
- List of graph types to be used for isochrone calculations.
68
63
 
69
64
  Returns
70
65
  -------
@@ -76,10 +71,10 @@ def get_isochrone_zone_coverage(
76
71
  >>> import networkx as nx
77
72
  >>> import geopandas as gpd
78
73
  >>> from shapely.geometry import Point
79
- >>> from dongraphio import GraphType
74
+ >>> from iduedu import get_intermodal_graph
80
75
 
81
- >>> # Create a sample city graph or download it from osm with get_intermodal_graph_from_osm()
82
- >>> city_graph = nx.MultiDiGraph()
76
+ >>> # Create a sample city graph with get_intermodal_graph()
77
+ >>> graph = get_intermodal_graph(polygon=my_territory_polygon)
83
78
 
84
79
  >>> # Create a sample GeoDataFrame for services
85
80
  >>> services = gpd.read_file('services.geojson')
@@ -87,19 +82,9 @@ def get_isochrone_zone_coverage(
87
82
  >>> # Define parameters
88
83
  >>> weight_type = "time_min"
89
84
  >>> weight_value = 10
90
- >>> graph_type = [GraphType.PUBLIC_TRANSPORT, GraphType.WALK]
91
85
 
92
86
  >>> # Get isochrone zone coverage
93
- >>> isochrone_zones = get_isochrone_zone_coverage(services, weight_type, weight_value, city_graph, graph_type)
94
- >>> isochrone_zones[0] # represent isochrones geodataframe
87
+ >>> isochrones, pt_stops, pt_routes = get_isochrone_zone_coverage(services, weight_type, weight_value, city_graph)
95
88
  """
96
- assert services.crs == city_graph.graph["crs"], "CRS not match"
97
- points = services.geometry.representative_point()
98
- iso, routes, stops = get_accessibility_isochrones(
99
- points, graph_type, weight_value, weight_type, city_graph, points.crs.to_epsg()
100
- )
101
- services_ = services.copy()
102
- iso = gpd.GeoDataFrame(
103
- pd.concat([iso.drop(columns=["point", "point_number"]), services_.drop(columns=["geometry"])], axis=1)
104
- )
89
+ iso, routes, stops = get_accessibility_isochrones(services, weight_value, weight_type, city_graph)
105
90
  return iso, routes, stops
@@ -0,0 +1,140 @@
1
+ from typing import Literal
2
+
3
+ import geopandas as gpd
4
+ import networkx as nx
5
+ import numpy as np
6
+ import pandas as pd
7
+ from osmnx import graph_to_gdfs
8
+ from pyproj import CRS
9
+ from scipy.spatial import KDTree
10
+ from shapely import Point
11
+ from shapely.ops import unary_union
12
+
13
+ from objectnat import config
14
+
15
+ logger = config.logger
16
+
17
+
18
+ def get_accessibility_isochrones(
19
+ points: gpd.GeoDataFrame,
20
+ weight_value: float,
21
+ weight_type: Literal["time_min", "length_meter"],
22
+ graph_nx: nx.Graph,
23
+ ) -> tuple[gpd.GeoDataFrame, gpd.GeoDataFrame | None, gpd.GeoDataFrame | None]:
24
+ """
25
+ Calculate accessibility isochrones from a gpd.GeoDataFrame based on the provided city graph.
26
+
27
+ Isochrones represent areas that can be reached from a given point within a specific time or distance,
28
+ using a graph that contains road and transport network data.
29
+
30
+ Parameters
31
+ ----------
32
+ points : gpd.GeoDataFrame
33
+ A GeoDataFrame containing the geometry from which accessibility isochrones should be calculated.
34
+ The CRS of this GeoDataFrame must match the CRS of the provided graph.
35
+ weight_value : float
36
+ The maximum distance or time threshold for calculating isochrones.
37
+ weight_type : Literal["time_min", "length_meter"]
38
+ The type of weight to use for distance calculations. Either time in minutes ("time_min") or distance
39
+ in meters ("length_meter").
40
+ graph_nx : nx.Graph
41
+ A NetworkX graph representing the city network.
42
+ The graph must contain the appropriate CRS and, for time-based isochrones, a speed attribute.
43
+
44
+ Returns
45
+ -------
46
+ tuple[gpd.GeoDataFrame, gpd.GeoDataFrame | None, gpd.GeoDataFrame | None]
47
+ A tuple containing:
48
+ - isochrones : GeoDataFrame with the calculated isochrone geometries.
49
+ - public transport stops (if applicable) : GeoDataFrame with public transport stops within the isochrone, or None if not applicable.
50
+ - public transport routes (if applicable) : GeoDataFrame with public transport routes within the isochrone, or None if not applicable.
51
+
52
+ Examples
53
+ --------
54
+ >>> from iduedu import get_intermodal_graph
55
+ >>> graph = get_intermodal_graph(polygon=my_territory_polygon)
56
+ >>> points = gpd.GeoDataFrame(geometry=[Point(30.33, 59.95)], crs=4326).to_crs(graph.graph['crs'])
57
+ >>> isochrones, pt_stops, pt_routes = get_accessibility_isochrones(points, weight_value=15, weight_type="time_min", graph_nx=my_graph)
58
+
59
+ """
60
+
61
+ assert points.crs == CRS.from_epsg(
62
+ graph_nx.graph["crs"]
63
+ ), f'CRS mismatch , points.crs = {points.crs.to_epsg()}, graph["crs"] = {graph_nx.graph["crs"]}'
64
+
65
+ nodes_with_data = list(graph_nx.nodes(data=True))
66
+ logger.info("Calculating isochrones distances...")
67
+ coordinates = np.array([(data["x"], data["y"]) for node, data in nodes_with_data])
68
+ tree = KDTree(coordinates)
69
+
70
+ target_coord = [(p.x, p.y) for p in points.representative_point()]
71
+ distances, indices = tree.query(target_coord)
72
+
73
+ nearest_nodes = [nodes_with_data[idx][0] for idx in indices]
74
+ del nodes_with_data
75
+ dist_nearest = pd.DataFrame(data=distances, index=nearest_nodes, columns=["dist"])
76
+ speed = 0
77
+ if graph_nx.graph["type"] in ["walk", "intermodal"] and weight_type == "time_min":
78
+ try:
79
+ speed = graph_nx.graph["walk_speed"]
80
+ except KeyError:
81
+ logger.warning("There is no walk_speed in graph, set to the default speed - 83.33 m/min")
82
+ speed = 83.33
83
+ dist_nearest = dist_nearest / speed
84
+ elif weight_type == "time_min":
85
+ speed = 20 * 1000 / 60
86
+ dist_nearest = dist_nearest / speed
87
+
88
+ if (dist_nearest > weight_value).all().all():
89
+ raise RuntimeError(
90
+ "The point(s) lie further from the graph than weight_value, it's impossible to "
91
+ "construct isochrones. Check the coordinates of the point(s)/their projection"
92
+ )
93
+
94
+ data = []
95
+ for source in nearest_nodes:
96
+ dist, path = nx.single_source_dijkstra(graph_nx, source, weight=weight_type, cutoff=weight_value)
97
+ for target_node, way in path.items():
98
+ source = way[0]
99
+ distance = dist.get(target_node, np.nan)
100
+ data.append((source, target_node, distance))
101
+ del dist
102
+ dist_matrix = pd.DataFrame(data, columns=["source", "destination", "distance"])
103
+ del data
104
+ dist_matrix = dist_matrix.pivot_table(index="source", columns="destination", values="distance", sort=False)
105
+
106
+ dist_matrix = dist_matrix.add(dist_nearest.dist, axis=0)
107
+ dist_matrix = dist_matrix.mask(dist_matrix >= weight_value, np.nan)
108
+ dist_matrix.dropna(how="all", inplace=True)
109
+
110
+ results = []
111
+ logger.info("Building isochrones geometry...")
112
+ for _, row in dist_matrix.iterrows():
113
+ geometry = []
114
+ for node_to, value in row.items():
115
+ if not pd.isna(value):
116
+ node = graph_nx.nodes[node_to]
117
+ point = Point(node["x"], node["y"])
118
+ geometry.append(
119
+ point.buffer(round((weight_value - value) * speed * 0.8, 2))
120
+ if weight_type == "time_min"
121
+ else point.buffer(round((weight_value - value) * 0.8, 2))
122
+ )
123
+ geometry = unary_union(geometry)
124
+ results.append(geometry)
125
+
126
+ isochrones = gpd.GeoDataFrame(data=points, geometry=results, crs=graph_nx.graph["crs"])
127
+ isochrones["weight_type"] = weight_type
128
+ isochrones["weight_value"] = weight_value
129
+
130
+ isochrones_subgraph = graph_nx.subgraph(dist_matrix.columns)
131
+ nodes = pd.DataFrame.from_dict(dict(isochrones_subgraph.nodes(data=True)), orient="index")
132
+ if "desc" in nodes.columns and "stop" in nodes["desc"].unique():
133
+ pt_nodes = nodes[nodes["desc"] == "stop"]
134
+ nodes, edges = graph_to_gdfs(isochrones_subgraph.subgraph(pt_nodes.index))
135
+ nodes.reset_index(drop=True, inplace=True)
136
+ nodes = nodes[["desc", "route", "geometry"]]
137
+ edges.reset_index(drop=True, inplace=True)
138
+ edges = edges[["type", "route", "geometry"]]
139
+ return isochrones, nodes, edges
140
+ return isochrones, None, None