riverjoin 0.1.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.
@@ -0,0 +1,47 @@
1
+ Metadata-Version: 2.4
2
+ Name: riverjoin
3
+ Version: 0.1.0
4
+ Summary: This is a river join implementation in Python.
5
+ Author-email: Supath Dhital <sdhital@crimson.ua.edu>, Yixian Chen <ychen223@ua.edu>
6
+ Project-URL: Homepage, https://github.com/sdmlua/riverjoin_py
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ Requires-Dist: geopandas
10
+ Requires-Dist: pathlib
11
+ Requires-Dist: fiona
12
+ Requires-Dist: folium
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest; extra == "dev"
15
+ Requires-Dist: black; extra == "dev"
16
+
17
+ # Framework for Spatially Joining two Hydrofabric Flowlines
18
+ <hr style="border: 1px solid black; margin: 0;">
19
+
20
+ ## Update the code
21
+ ```bash
22
+ git clone https://github.com/sdmlua/riverjoin_py
23
+ cd riverjoin_py
24
+ ```
25
+
26
+ Use the ```uv``` to work and update the code,
27
+ ```bash
28
+ pip install uv
29
+
30
+ #Create a virtual env and start collabortaing the code
31
+ uv venv
32
+
33
+ #activate the virtual environment
34
+ source .venv/bin/activate
35
+
36
+ #Install all the dependencies and all development packages into it
37
+ uv pip install e .
38
+ uv pip install -e ".[dev]"
39
+
40
+ #Then add/edit modules under the src/ and run the code through the tests
41
+ #For instance
42
+ pytest tests/spatial_join.py
43
+ ```
44
+ Once all changes are made, update the code style with ```black``` code formatter.
45
+ ```bash
46
+ black .
47
+ ```
@@ -0,0 +1,31 @@
1
+ # Framework for Spatially Joining two Hydrofabric Flowlines
2
+ <hr style="border: 1px solid black; margin: 0;">
3
+
4
+ ## Update the code
5
+ ```bash
6
+ git clone https://github.com/sdmlua/riverjoin_py
7
+ cd riverjoin_py
8
+ ```
9
+
10
+ Use the ```uv``` to work and update the code,
11
+ ```bash
12
+ pip install uv
13
+
14
+ #Create a virtual env and start collabortaing the code
15
+ uv venv
16
+
17
+ #activate the virtual environment
18
+ source .venv/bin/activate
19
+
20
+ #Install all the dependencies and all development packages into it
21
+ uv pip install e .
22
+ uv pip install -e ".[dev]"
23
+
24
+ #Then add/edit modules under the src/ and run the code through the tests
25
+ #For instance
26
+ pytest tests/spatial_join.py
27
+ ```
28
+ Once all changes are made, update the code style with ```black``` code formatter.
29
+ ```bash
30
+ black .
31
+ ```
@@ -0,0 +1,32 @@
1
+ [project]
2
+ name = "riverjoin"
3
+ version = "0.1.0"
4
+ description = "This is a river join implementation in Python."
5
+ authors = [
6
+ { name = "Supath Dhital", email = "sdhital@crimson.ua.edu" },
7
+ { name = "Yixian Chen", email = "ychen223@ua.edu" }
8
+ ]
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "geopandas",
13
+ "pathlib",
14
+ "fiona",
15
+ "folium",
16
+ ]
17
+
18
+ [project.urls]
19
+ Homepage = "https://github.com/sdmlua/riverjoin_py"
20
+
21
+ [tool.setuptools]
22
+ package-dir = {"" = "src"}
23
+
24
+ [build-system]
25
+ requires = ["setuptools>=61.0"]
26
+ build-backend = "setuptools.build_meta"
27
+
28
+ [project.optional-dependencies]
29
+ dev = [
30
+ "pytest",
31
+ "black"
32
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,55 @@
1
+ import warnings
2
+
3
+ warnings.simplefilter("ignore")
4
+
5
+ from riverjoin.modules.project_initialization import setup_project
6
+ from riverjoin.modules.setup_hydrofabric import clip_flowlines
7
+
8
+ from riverjoin.modules.project_initialization import setup_project
9
+ from riverjoin.modules.setup_hydrofabric import clip_flowlines
10
+ from riverjoin.modules.flowlines_buffer import StreamNetworkExtractor
11
+ from riverjoin.modules.traced_downstream import traced_downstream
12
+ from riverjoin.modules.situation_checker import check_situation
13
+ from riverjoin.modules.perpendicularlines import (
14
+ create_nodes,
15
+ generate_perpendicular_lines,
16
+ PerpendicularCleaner,
17
+ SpatialJoinWithPerpendicularlines,
18
+ merge_and_drop_duplicates,
19
+ ReconstructDisconnectedSegments,
20
+ )
21
+ from riverjoin.modules.interactive_map import VizualizeOutputInteractively
22
+ from riverjoin.modules.compare_linelength import compare_linelength
23
+ from riverjoin.modules.attribute_transfer import (
24
+ NodeExtractor,
25
+ JoinNearestFlowLineAttributes,
26
+ AggregateJoinedFlowlines,
27
+ )
28
+
29
+
30
+ # utilities
31
+ from riverjoin.utilis import FlowlineFieldViewer
32
+
33
+ # Combined seamless workflow
34
+ from riverjoin.combined_workflow import run_riverjoin
35
+
36
+ __all__ = [
37
+ "setup_project",
38
+ "clip_flowlines",
39
+ "StreamNetworkExtractor",
40
+ "traced_downstream",
41
+ "check_situation",
42
+ "create_nodes",
43
+ "generate_perpendicular_lines",
44
+ "PerpendicularCleaner",
45
+ "SpatialJoinWithPerpendicularlines",
46
+ "merge_and_drop_duplicates",
47
+ "ReconstructDisconnectedSegments",
48
+ "VizualizeOutputInteractively",
49
+ "compare_linelength",
50
+ "NodeExtractor",
51
+ "JoinNearestFlowLineAttributes",
52
+ "AggregateJoinedFlowlines",
53
+ "FlowlineFieldViewer",
54
+ "run_riverjoin",
55
+ ]
@@ -0,0 +1,218 @@
1
+ """
2
+ This code is the compiled workflow where all the steps are combined into a single script for easier execution.
3
+
4
+ Author: Supath Dhital, Yixian Chen
5
+ Date: Nov 13, 2025
6
+ """
7
+
8
+ import os
9
+ from pathlib import Path
10
+ from typing import Optional, Union, List
11
+
12
+ from riverjoin.modules.project_initialization import setup_project
13
+
14
+ from riverjoin.modules.setup_hydrofabric import clip_flowlines
15
+ from riverjoin.modules.flowlines_buffer import StreamNetworkExtractor
16
+ from riverjoin.modules.traced_downstream import traced_downstream
17
+ from riverjoin.modules.situation_checker import check_situation
18
+ from riverjoin.modules.perpendicularlines import (
19
+ create_nodes,
20
+ generate_perpendicular_lines,
21
+ PerpendicularCleaner,
22
+ SpatialJoinWithPerpendicularlines,
23
+ merge_and_drop_duplicates,
24
+ ReconstructDisconnectedSegments,
25
+ )
26
+ from riverjoin.modules.compare_linelength import compare_linelength
27
+
28
+ from riverjoin.modules.attribute_transfer import (
29
+ NodeExtractor,
30
+ JoinNearestFlowLineAttributes,
31
+ AggregateJoinedFlowlines,
32
+ )
33
+
34
+
35
+ # Combined workflow
36
+ class run_riverjoin:
37
+ """
38
+ First it initializes the project structure using setup_project class.
39
+ then Setup the hydrofabric--> which includes clipping the flowlines based on user defined boundary or bbox
40
+ the extract the flowlines with multiple steps including buffer intersection, tracing downstream disconnected segments,
41
+ situation check, creating perpendicular nodes, generating perpendicular lines, cleaning the perpendicular lines,
42
+ spatial join with perpendicular lines, merging and dropping duplicates, reconstructing disconnected segments if any.
43
+ finally visualizing the output interactively.
44
+
45
+ And, Finally attribute will be transferred from one network to another.
46
+ """
47
+
48
+ def __init__(
49
+ self,
50
+ join_fl: str,
51
+ target_fl: str,
52
+ unique_id: str,
53
+ unique_id_nextDown: str,
54
+ target_reach_unique_id_field: str,
55
+ join_fl_layer: Optional[str] = None,
56
+ target_fl_layer: Optional[str] = None,
57
+ boundary: Optional[str] = None,
58
+ boundary_layer: Optional[str] = None,
59
+ output_clip_layer: Optional[str] = None,
60
+ identifier: Optional[str] = None,
61
+ node_output_layer: Optional[str] = None,
62
+ strm_order_field: Optional[str] = None,
63
+ filter_eqn: Optional[Union[str, List[str]]] = None,
64
+ node_number: Optional[int] = None,
65
+ node_spacing: Optional[float] = None,
66
+ transfer_attributes: bool = True,
67
+ buffer_distance: int = 100,
68
+ spacing_join_fl: float = 500,
69
+ perp_line_length: float = 600,
70
+ min_join_count: int = 5,
71
+ min_strm_order: int = 2,
72
+ ):
73
+ self.join_fl = join_fl
74
+ self.target_fl = target_fl
75
+ self.join_fl_layer = join_fl_layer
76
+ self.target_fl_layer = target_fl_layer
77
+ self.boundary = boundary
78
+ self.boundary_layer = boundary_layer
79
+ self.output_clip_layer = output_clip_layer
80
+ self.unique_id = unique_id
81
+ self.unique_id_nextDown = unique_id_nextDown
82
+ self.target_reach_unique_id_field = target_reach_unique_id_field
83
+ self.buffer_distance = buffer_distance
84
+ self.spacing = spacing_join_fl
85
+ self.node_spacing = node_spacing
86
+ self.node_number = node_number
87
+ self.perp_line_length = perp_line_length
88
+ self.identifier = identifier
89
+ self.node_output_layer = node_output_layer
90
+ self.min_join_count = min_join_count
91
+ self.min_strm_order = min_strm_order
92
+ self.strm_order_field = strm_order_field
93
+ self.filter_eqn = filter_eqn
94
+ self.transfer_attributes = transfer_attributes
95
+
96
+ # Initialize project structure
97
+ self.project_paths = setup_project()
98
+ self.output_fl = self.project_paths.output_reach_gpkg
99
+ self.extracted_fl = self.project_paths.output_final_reach_gpkg
100
+
101
+ # Clip flowlines
102
+ clip_flowlines(
103
+ join_fl=self.join_fl,
104
+ target_fl=self.target_fl,
105
+ join_fl_layer=self.join_fl_layer,
106
+ target_fl_layer=self.target_fl_layer,
107
+ boundary=self.boundary,
108
+ boundary_layer=self.boundary_layer,
109
+ output_clip_layer=self.output_clip_layer,
110
+ )
111
+
112
+ # Buffer intersection
113
+ StreamNetworkExtractor(
114
+ join_fl=self.join_fl,
115
+ unique_id=self.unique_id,
116
+ buffer_distance=self.buffer_distance,
117
+ join_fl_layer=self.join_fl_layer,
118
+ output_clip_layer=self.output_clip_layer,
119
+ identifier=self.identifier,
120
+ )
121
+
122
+ # Check the situation of the extraction--> maybe need to terminate the process here if no or all flowlines got extracted!!
123
+ cs = check_situation(
124
+ identifier=self.identifier,
125
+ )
126
+
127
+ # Run the next steps or terminate based on situation
128
+ if cs.situation == "extract_upstream_others":
129
+ # tracing the downstream segments
130
+ traced_downstream(
131
+ unique_id=self.unique_id,
132
+ unique_id_nextDown=self.unique_id_nextDown,
133
+ join_fl=self.join_fl,
134
+ join_fl_layer=self.join_fl_layer,
135
+ identifier=self.identifier,
136
+ )
137
+
138
+ # create nodes for perpendicular lines for further extraction
139
+ create_nodes(
140
+ target_reach_unique_id_field=self.target_reach_unique_id_field,
141
+ output_clip_layer=self.output_clip_layer,
142
+ identifier=self.identifier,
143
+ spacing=self.spacing,
144
+ )
145
+
146
+ # Generate perpendicular lines along the created nodes
147
+ generate_perpendicular_lines(
148
+ spacing=self.spacing,
149
+ perp_line_length=self.perp_line_length,
150
+ identifier=self.identifier,
151
+ node_output_layer=self.node_output_layer,
152
+ )
153
+
154
+ # Perpendicular lines cleaning
155
+ PerpendicularCleaner(
156
+ spacing=self.spacing,
157
+ perp_line_length=self.perp_line_length,
158
+ identifier=self.identifier,
159
+ )
160
+
161
+ # Spatial join with perpendicular lines
162
+ SpatialJoinWithPerpendicularlines(
163
+ join_fl=self.join_fl,
164
+ unique_id=self.unique_id,
165
+ min_join_count=self.min_join_count,
166
+ min_strm_order=self.min_strm_order,
167
+ join_fl_layer=self.join_fl_layer,
168
+ strm_order_field=self.strm_order_field,
169
+ identifier=self.identifier,
170
+ filter_eqn=self.filter_eqn,
171
+ )
172
+
173
+ # Merging and dropping duplicates
174
+ merge_and_drop_duplicates(
175
+ join_fl=self.join_fl,
176
+ join_fl_layer=self.join_fl_layer,
177
+ identifier=self.identifier,
178
+ )
179
+
180
+ # Reconstructing disconnected segments if any
181
+ ReconstructDisconnectedSegments(
182
+ unique_id=self.unique_id,
183
+ unique_id_nextDown=self.unique_id_nextDown,
184
+ join_fl=self.join_fl,
185
+ join_fl_layer=self.join_fl_layer,
186
+ identifier=self.identifier,
187
+ )
188
+
189
+ # Compare the basic statistics of line length between the extracted and target flowlines
190
+ compare_linelength(
191
+ identifier=self.identifier,
192
+ output_fl=self.output_fl,
193
+ extracted_fl=self.extracted_fl,
194
+ output_layer=self.output_clip_layer,
195
+ )
196
+
197
+ # Transfer the attribute from one network to another
198
+ if self.transfer_attributes:
199
+ NodeExtractor(
200
+ target_network_unique_id_field=self.unique_id,
201
+ identifier=self.identifier,
202
+ spacing=self.node_spacing,
203
+ node_number=self.node_number,
204
+ )
205
+
206
+ JoinNearestFlowLineAttributes(
207
+ target_network_unique_id_field=self.unique_id,
208
+ identifier=self.identifier,
209
+ )
210
+
211
+ AggregateJoinedFlowlines(
212
+ target_network_unique_id_field=self.unique_id,
213
+ join_network_unique_id_field=self.target_reach_unique_id_field,
214
+ identifier=self.identifier,
215
+ )
216
+ else:
217
+ id_msg = f" for {self.identifier}" if self.identifier is not None else ""
218
+ print(f"Terminating further processing as '{cs.situation}'{id_msg}.")
@@ -0,0 +1,47 @@
1
+ from riverjoin.modules.project_initialization import setup_project
2
+ from riverjoin.modules.setup_hydrofabric import clip_flowlines
3
+
4
+ from riverjoin.modules.project_initialization import setup_project
5
+ from riverjoin.modules.setup_hydrofabric import clip_flowlines
6
+ from riverjoin.modules.flowlines_buffer import StreamNetworkExtractor
7
+ from riverjoin.modules.traced_downstream import traced_downstream
8
+ from riverjoin.modules.situation_checker import check_situation
9
+ from riverjoin.modules.perpendicularlines import (
10
+ create_nodes,
11
+ generate_perpendicular_lines,
12
+ PerpendicularCleaner,
13
+ SpatialJoinWithPerpendicularlines,
14
+ merge_and_drop_duplicates,
15
+ ReconstructDisconnectedSegments,
16
+ )
17
+ from riverjoin.modules.interactive_map import VizualizeOutputInteractively
18
+ from riverjoin.modules.compare_linelength import compare_linelength
19
+ from riverjoin.modules.attribute_transfer import (
20
+ NodeExtractor,
21
+ JoinNearestFlowLineAttributes,
22
+ AggregateJoinedFlowlines,
23
+ )
24
+
25
+
26
+ # utilities
27
+ from riverjoin.utilis import FlowlineFieldViewer
28
+
29
+ __all__ = [
30
+ "setup_project",
31
+ "clip_flowlines",
32
+ "StreamNetworkExtractor",
33
+ "traced_downstream",
34
+ "check_situation",
35
+ "create_nodes",
36
+ "generate_perpendicular_lines",
37
+ "PerpendicularCleaner",
38
+ "SpatialJoinWithPerpendicularlines",
39
+ "merge_and_drop_duplicates",
40
+ "ReconstructDisconnectedSegments",
41
+ "VizualizeOutputInteractively",
42
+ "compare_linelength",
43
+ "NodeExtractor",
44
+ "JoinNearestFlowLineAttributes",
45
+ "AggregateJoinedFlowlines",
46
+ "FlowlineFieldViewer",
47
+ ]