Skip to content

Commit 653e1e0

Browse files
committed
Add type annotations across modules for enhanced clarity and checking
Introduced type hints for functions in core modules (`filters.py`, `process.py`, `handlers.py`, etc.) to improve code clarity and enable static type checking. Adjusted related docstrings and examples to align with the updates. Updated `mkdocs.yml` to include Code of Conduct in documentation.
1 parent 5bd23e0 commit 653e1e0

9 files changed

Lines changed: 38 additions & 29 deletions

File tree

docs/examples.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/usage/getting-started-import-and-preprocess.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import pyforestscan
88

99
Then, you can use it to load point cloud data and extract forest structure metrics.
1010

11-
The following sections will provide an overview of usage of the major functions of pyforestscan. For a complete reference of all functions in pyforestscan, please check the [API documentation](api.md). For comprehensive examples of these functions, please see the [example jupyter notebooks](examples).
11+
The following sections will provide an overview of usage of the major functions of pyforestscan. For a complete reference of all functions in pyforestscan, please check the [API documentation](/api/calculate/). For comprehensive examples of these functions, please see the [example jupyter notebooks](/examples/getting-started-importing-preprocessing-dtm-chm/).
1212

1313
## Importing Point Cloud Data
1414

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ nav:
4747
- usage/forest-structure/fhd.md
4848
- Benchmarks: benchmarks.md
4949
- Contributing: contributing.md
50+
- Code of Conduct: code_of_conduct.md
5051
- Changelog: https://github.com/iosefa/PyForestScan/releases
5152
- Report Issues: https://github.com/iosefa/PyForestScan/issues
5253
- Examples:

pyforestscan/calculate.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import numpy as np
2+
23
from scipy.interpolate import griddata
34
from scipy.stats import entropy
45
from scipy import ndimage
6+
from typing import List, Tuple
57

68

7-
def generate_dtm(ground_points, resolution=2.0):
9+
def generate_dtm(ground_points, resolution=2.0) -> Tuple[np.ndarray, List]:
810
"""
911
Generates a Digital Terrain Model (DTM) raster from classified ground points.
1012
@@ -50,7 +52,7 @@ def generate_dtm(ground_points, resolution=2.0):
5052
return dtm, extent
5153

5254

53-
def assign_voxels(arr, voxel_resolution):
55+
def assign_voxels(arr, voxel_resolution) -> Tuple[np.ndarray, List]:
5456
"""
5557
Assigns voxel grids to spatial data points based on the specified resolutions.
5658
@@ -59,7 +61,7 @@ def assign_voxels(arr, voxel_resolution):
5961
voxel_resolution (tuple of floats): The resolution for x, y, and z dimensions of the voxel grid.
6062
6163
Returns:
62-
tuple of (numpy.ndarray, list): A tuple containing the histogram of the voxel grid (with corrected orientation) and the extent of the point cloud.
64+
tuple of (numpy.ndarray, List): A tuple containing the histogram of the voxel grid (with corrected orientation) and the extent of the point cloud.
6365
"""
6466
dx, dy, dz = voxel_resolution
6567

@@ -86,7 +88,7 @@ def calculate_pad(voxel_returns,
8688
voxel_height=1.0,
8789
beer_lambert_constant=1.0,
8890
drop_ground=True
89-
):
91+
) -> np.ndarray:
9092
"""
9193
Calculate the Plant Area Density (PAD) using the Beer-Lambert Law.
9294
@@ -136,7 +138,7 @@ def calculate_pad(voxel_returns,
136138
def calculate_pai(pad,
137139
voxel_height,
138140
min_height=1.0,
139-
max_height=None):
141+
max_height=None) -> np.ndarray:
140142
"""
141143
Calculate Plant Area Index (PAI) from Plant Area Density (PAD) data by summing PAD values along the height (Z) axis.
142144
@@ -166,7 +168,7 @@ def calculate_pai(pad,
166168
return pai
167169

168170

169-
def calculate_fhd(voxel_returns):
171+
def calculate_fhd(voxel_returns) -> np.ndarray:
170172
"""
171173
Calculate the Foliage Height Diversity (FHD) for a given set of voxel returns.
172174
@@ -197,7 +199,7 @@ def calculate_fhd(voxel_returns):
197199

198200

199201
def calculate_chm(arr, voxel_resolution, interpolation="linear",
200-
interp_valid_region=False, interp_clean_edges=False):
202+
interp_valid_region=False, interp_clean_edges=False) -> Tuple[np.ndarray, List]:
201203
"""
202204
Calculate the Canopy Height Model (CHM) for a given voxel grid.
203205

pyforestscan/filters.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
from typing import List
2+
13
from pyforestscan.handlers import _build_pdal_pipeline
24
from pyforestscan.pipeline import _filter_hag, _filter_ground, _filter_statistical_outlier, _filter_smrf, \
35
_filter_radius, _select_ground
46

57

6-
def filter_hag(arrays, lower_limit=0, upper_limit=None):
8+
def filter_hag(arrays, lower_limit=0, upper_limit=None) -> List:
79
"""
810
Apply a Height Above Ground (HAG) filter to a list of point cloud arrays.
911
@@ -27,7 +29,7 @@ def filter_hag(arrays, lower_limit=0, upper_limit=None):
2729
return pipeline.arrays
2830

2931

30-
def filter_ground(arrays):
32+
def filter_ground(arrays) -> List:
3133
"""
3234
Remove ground points (classification 2) from a list of point cloud arrays.
3335
@@ -41,7 +43,7 @@ def filter_ground(arrays):
4143
return pipeline.arrays
4244

4345

44-
def filter_select_ground(arrays):
46+
def filter_select_ground(arrays) -> List:
4547
"""
4648
Select only ground points (classification 2) from a list of point cloud arrays.
4749
@@ -55,7 +57,7 @@ def filter_select_ground(arrays):
5557
return pipeline.arrays
5658

5759

58-
def remove_outliers_and_clean(arrays, mean_k=8, multiplier=3.0, remove=False):
60+
def remove_outliers_and_clean(arrays, mean_k=8, multiplier=3.0, remove=False) -> List:
5961
"""
6062
Processes input arrays by removing statistical outliers and optionally cleans
6163
the data, filtering out specific classifications.
@@ -115,7 +117,7 @@ def classify_ground_points(
115117
slope=0.15,
116118
threshold=0.5,
117119
window=18.0
118-
):
120+
) -> List:
119121
"""
120122
Apply the SMRF (Simple Morphological Filter) to classify ground points in the point cloud arrays.
121123
@@ -166,7 +168,7 @@ def classify_ground_points(
166168
return processed_arrays
167169

168170

169-
def downsample_poisson(arrays, thin_radius):
171+
def downsample_poisson(arrays, thin_radius) -> List:
170172
"""
171173
Downsample point cloud arrays using Poisson (radius-based) thinning.
172174

pyforestscan/handlers.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
23
import geopandas as gpd
34
import json
45
import pdal
@@ -8,6 +9,7 @@
89
from pyproj import CRS
910
from rasterio.transform import from_bounds
1011
from shapely.geometry import MultiPolygon
12+
from typing import List, Tuple
1113
from urllib.parse import urlparse
1214

1315
from pyforestscan.pipeline import _crop_polygon, _filter_radius, _hag_delaunay, _hag_raster
@@ -22,7 +24,7 @@ def _is_url(input_str):
2224
return False
2325

2426

25-
def simplify_crs(crs_list):
27+
def simplify_crs(crs_list) -> List:
2628
"""
2729
Convert a list of coordinate reference system (CRS) representations to their corresponding EPSG codes.
2830
@@ -48,7 +50,7 @@ def simplify_crs(crs_list):
4850
return epsg_codes
4951

5052

51-
def load_polygon_from_file(vector_file_path, index=0):
53+
def load_polygon_from_file(vector_file_path, index=0) -> Tuple[str, str]:
5254
"""
5355
Load a polygon geometry and its CRS from a given vector file.
5456
@@ -79,7 +81,7 @@ def load_polygon_from_file(vector_file_path, index=0):
7981
return polygon.wkt, gdf.crs.to_string()
8082

8183

82-
def get_raster_epsg(dtm_path):
84+
def get_raster_epsg(dtm_path) -> str:
8385
"""
8486
Retrieve the EPSG code from a raster file.
8587
@@ -164,7 +166,7 @@ def _build_pdal_pipeline(arrays, pipeline_stages):
164166
return pipeline
165167

166168

167-
def validate_crs(crs_list):
169+
def validate_crs(crs_list) -> bool:
168170
"""
169171
Validate that all CRS (Coordinate Reference System) representations in the list are identical.
170172
@@ -183,7 +185,9 @@ def validate_crs(crs_list):
183185
return True
184186

185187

186-
def read_lidar(input_file, srs, bounds=None, thin_radius=None, hag=False, hag_dtm=False, dtm=None, crop_poly=False, poly=None):
188+
def read_lidar(input_file, srs, bounds=None, thin_radius=None,
189+
hag=False, hag_dtm=False, dtm=None, crop_poly=False,
190+
poly=None) -> np.ndarray or None:
187191
"""
188192
Read and process a LiDAR point cloud file using PDAL with various options.
189193
@@ -285,7 +289,7 @@ def read_lidar(input_file, srs, bounds=None, thin_radius=None, hag=False, hag_dt
285289
return point_cloud if point_cloud else None
286290

287291

288-
def write_las(arrays, output_file, srs=None, compress=True):
292+
def write_las(arrays, output_file, srs=None, compress=True) -> None:
289293
"""
290294
Write point cloud data to a LAS or LAZ file.
291295
@@ -342,7 +346,7 @@ def write_las(arrays, output_file, srs=None, compress=True):
342346
pipeline.execute()
343347

344348

345-
def create_geotiff(layer, output_file, crs, spatial_extent, nodata=-9999):
349+
def create_geotiff(layer, output_file, crs, spatial_extent, nodata=-9999) -> None:
346350
"""
347351
Create a GeoTIFF file from the given data layer.
348352

pyforestscan/process.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def _crop_dtm(dtm_path, tile_min_x, tile_min_y, tile_max_x, tile_max_y):
5050

5151
def process_with_tiles(ept_file, tile_size, output_path, metric, voxel_size,
5252
voxel_height=1, buffer_size=0.1, srs=None, hag=False,
53-
hag_dtm=False, dtm=None, bounds=None, interpolation=None, remove_outliers=False):
53+
hag_dtm=False, dtm=None, bounds=None, interpolation=None, remove_outliers=False) -> None:
5454
"""
5555
Process a large EPT point cloud by tiling, compute CHM or other metrics for each tile,
5656
and write the results to the specified output directory.

pyforestscan/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def _read_ept_json(ept_source):
2121
return ept_json
2222

2323

24-
def get_srs_from_ept(ept_file):
24+
def get_srs_from_ept(ept_file) -> str or None:
2525
"""
2626
Extract the Spatial Reference System (SRS) from an EPT (Entwine Point Tile) file.
2727
@@ -46,7 +46,7 @@ def get_srs_from_ept(ept_file):
4646
return None
4747

4848

49-
def get_bounds_from_ept(ept_file):
49+
def get_bounds_from_ept(ept_file) -> tuple[float, float, float, float, float, float]:
5050
"""
5151
Extract the spatial bounds of a point cloud from an EPT (Entwine Point Tile) file using PDAL.
5252
@@ -75,7 +75,7 @@ def tile_las_in_memory(
7575
overlap,
7676
output_dir,
7777
srs=None
78-
):
78+
) -> None:
7979
"""
8080
Read an entire LAS/LAZ/COPC file into memory and subdivide it into tiles
8181
with a specified overlap on the right and bottom edges. Writes each tile as a new LAS file.

pyforestscan/visualize.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def plot_2d(points, x_dim='X',
99
fig_size=None, fig_title=None,
1010
slice_dim=None, slice_val=0.0,
1111
slice_tolerance=5, save_fname=None
12-
):
12+
) -> None:
1313
"""
1414
Plot a 2D scatter plot of point cloud data with customizable axes, coloring, slicing, and figure settings.
1515
@@ -84,7 +84,7 @@ def plot_2d(points, x_dim='X',
8484

8585

8686
def plot_metric(title, metric, extent, metric_name=None, cmap='viridis', fig_size=None,
87-
save_fname=None):
87+
save_fname=None) -> None:
8888
"""
8989
Plot a 2D metric array as an image with geospatial extent, colorbar, and customizable settings.
9090
@@ -126,7 +126,8 @@ def plot_metric(title, metric, extent, metric_name=None, cmap='viridis', fig_siz
126126

127127

128128
def plot_pad(pad, slice_index=None, axis='x', cmap='viridis',
129-
hag_values=None, horizontal_values=None, title=None, save_fname=None):
129+
hag_values=None, horizontal_values=None, title=None,
130+
save_fname=None) -> None:
130131
"""
131132
Visualize 3D Plant Area Density (PAD) data as a 2D image, using projection or slicing.
132133

0 commit comments

Comments
 (0)