Skip to content

Commit f645b46

Browse files
author
BriannaLind
committed
ran black
1 parent 5e6aa0c commit f645b46

File tree

9 files changed

+114
-79
lines changed

9 files changed

+114
-79
lines changed

src/planet_overlap/analysis.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,20 @@ def filter_quality(
3030

3131

3232
def compute_central_coordinates(
33-
geometries: List[Dict[str, Any]]
33+
geometries: List[Dict[str, Any]],
3434
) -> Tuple[np.ndarray, np.ndarray]:
3535
"""Compute central latitude and longitude for each polygon."""
3636
central_lon = np.array(
37-
[np.mean([pt[0] for pt in geom["coordinates"][0]]) for geom in geometries]
37+
[
38+
np.mean([pt[0] for pt in geom["coordinates"][0]])
39+
for geom in geometries
40+
]
3841
)
3942
central_lat = np.array(
40-
[np.mean([pt[1] for pt in geom["coordinates"][0]]) for geom in geometries]
43+
[
44+
np.mean([pt[1] for pt in geom["coordinates"][0]])
45+
for geom in geometries
46+
]
4147
)
4248
return central_lon, central_lat
4349

@@ -81,9 +87,9 @@ def calculate_intersections(
8187
area_threshold: float = 25.0,
8288
) -> Tuple[np.ndarray, np.ndarray]:
8389
(
84-
" Compute pairwise intersected areas and sun angle differences between polygons."
85-
"Only compares polygons from the same instrument and different satellites."
86-
)
90+
" Compute pairwise intersected areas and sun angle differences between polygons."
91+
"Only compares polygons from the same instrument and different satellites."
92+
)
8793
n = len(polygons)
8894
area_2d = np.zeros((n, n), dtype=np.float32)
8995
sun_diff_2d = np.zeros((n, n), dtype=np.float32)
@@ -117,9 +123,7 @@ def process_tiles(
117123
min_view_angle: float = 3,
118124
min_sun_angle: float = 0,
119125
) -> gpd.GeoDataFrame:
120-
(
121-
" Process multiple tiles/datasets and return a unified GeoDataFrame."
122-
)
126+
(" Process multiple tiles/datasets and return a unified GeoDataFrame.")
123127
merged_properties = []
124128
merged_geometries = []
125129
merged_ids = []
@@ -160,7 +164,9 @@ def process_tiles(
160164
"central_lon": central_lon,
161165
"central_lat": central_lat,
162166
"local_times": local_times,
163-
"max_sun_diff": [sun_diff_2d[i, :].max() for i in range(len(polygons))],
167+
"max_sun_diff": [
168+
sun_diff_2d[i, :].max() for i in range(len(polygons))
169+
],
164170
}
165171
)
166172
gdf.set_index("id", inplace=True)

src/planet_overlap/client.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,35 @@ def prepare_filters(
2020
geojson_paths: List[str], date_ranges: List[Tuple[str, str]]
2121
) -> dict:
2222
(
23-
" Build filters for multiple AOIs and date ranges. Args: geojson_paths: List of"
24-
"file paths to AOI geojsons. date_ranges: List of (start_date, end_date) tuples."
25-
"Returns: Dictionary containing combined filters."
26-
)
23+
" Build filters for multiple AOIs and date ranges. Args: geojson_paths: List of"
24+
"file paths to AOI geojsons. date_ranges: List of (start_date, end_date) tuples."
25+
"Returns: Dictionary containing combined filters."
26+
)
2727
filters = build_filters(geojson_paths, date_ranges)
2828
logging.info(
29-
"Filters prepared for %d AOIs/date ranges", len(filters.get("config", []))
29+
"Filters prepared for %d AOIs/date ranges",
30+
len(filters.get("config", [])),
3031
)
3132
return filters
3233

3334

3435
def load_aois(geojson_paths: List[str]):
3536
(
36-
" Load AOIs from GeoJSON files. Args: geojson_paths: List of AOI geojson paths."
37-
"Returns: List of AOI geometries."
38-
)
37+
" Load AOIs from GeoJSON files. Args: geojson_paths: List of AOI geojson paths."
38+
"Returns: List of AOI geometries."
39+
)
3940
aois = [load_aoi(path) for path in geojson_paths]
4041
logging.info("Loaded %d AOIs", len(aois))
4142
return aois
4243

4344

4445
def run_client(geojson_paths: List[str], date_ranges: List[Tuple[str, str]]):
4546
(
46-
" Full client workflow: load AOIs, prepare filters, and return filters + AOIs."
47-
"Args: geojson_paths: List of AOI GeoJSON paths. date_ranges: List of"
48-
"(start_date, end_date) tuples. Returns: Tuple of (filters dict, list of AOI"
49-
"geometries)"
50-
)
47+
" Full client workflow: load AOIs, prepare filters, and return filters + AOIs."
48+
"Args: geojson_paths: List of AOI GeoJSON paths. date_ranges: List of"
49+
"(start_date, end_date) tuples. Returns: Tuple of (filters dict, list of AOI"
50+
"geometries)"
51+
)
5152
aois = load_aois(geojson_paths)
5253
filters = prepare_filters(geojson_paths, date_ranges)
5354
# Use filters downstream; previously 'combined_filter' was unused

src/planet_overlap/filters.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,22 @@
1010

1111
def geometry_filter(aoi: Polygon) -> Dict[str, Any]:
1212
(
13-
" Convert a shapely Polygon into a Planet GeometryFilter. Args: aoi (Polygon):"
14-
"The area of interest. Returns: dict: GeometryFilter for Planet API."
15-
)
16-
return {"type": "GeometryFilter", "field_name": "geometry", "config": mapping(aoi)}
13+
" Convert a shapely Polygon into a Planet GeometryFilter. Args: aoi (Polygon):"
14+
"The area of interest. Returns: dict: GeometryFilter for Planet API."
15+
)
16+
return {
17+
"type": "GeometryFilter",
18+
"field_name": "geometry",
19+
"config": mapping(aoi),
20+
}
1721

1822

1923
def date_range_filter(start: datetime, end: datetime) -> Dict[str, Any]:
2024
(
21-
" Convert a start/end datetime into a Planet DateRangeFilter. Args: start"
22-
"(datetime): Start date. end (datetime): End date. Returns: dict:"
23-
"DateRangeFilter for Planet API."
24-
)
25+
" Convert a start/end datetime into a Planet DateRangeFilter. Args: start"
26+
"(datetime): Start date. end (datetime): End date. Returns: dict:"
27+
"DateRangeFilter for Planet API."
28+
)
2529
return {
2630
"type": "DateRangeFilter",
2731
"field_name": "acquired",
@@ -34,9 +38,9 @@ def date_range_filter(start: datetime, end: datetime) -> Dict[str, Any]:
3438

3539
def cloud_cover_filter(max_cloud: float) -> Dict[str, Any]:
3640
(
37-
" Filter scenes by maximum cloud cover fraction. Args: max_cloud (float): Max"
38-
"cloud fraction (0.0-1.0). Returns: dict: RangeFilter for cloud_cover."
39-
)
41+
" Filter scenes by maximum cloud cover fraction. Args: max_cloud (float): Max"
42+
"cloud fraction (0.0-1.0). Returns: dict: RangeFilter for cloud_cover."
43+
)
4044
return {
4145
"type": "RangeFilter",
4246
"field_name": "cloud_cover",
@@ -46,9 +50,9 @@ def cloud_cover_filter(max_cloud: float) -> Dict[str, Any]:
4650

4751
def sun_angle_filter(min_sun_angle: float) -> Dict[str, Any]:
4852
(
49-
" Filter scenes by minimum sun angle. Args: min_sun_angle (float): Minimum sun"
50-
"angle in degrees. Returns: dict: RangeFilter for sun elevation."
51-
)
53+
" Filter scenes by minimum sun angle. Args: min_sun_angle (float): Minimum sun"
54+
"angle in degrees. Returns: dict: RangeFilter for sun elevation."
55+
)
5256
return {
5357
"type": "RangeFilter",
5458
"field_name": "sun_elevation",
@@ -63,30 +67,38 @@ def build_filters(
6367
min_sun_angle: float = 0.0,
6468
) -> Dict[str, Any]:
6569
(
66-
" Build a Planet API search filter combining multiple AOIs, date ranges, cloud"
67-
"cover, and sun angle constraints. Args: aois (List[Polygon]): List of AOI"
68-
"polygons. date_ranges (List[Tuple[datetime, datetime]]): List of start/end date"
69-
"tuples. max_cloud (float): Maximum cloud fraction. min_sun_angle (float):"
70-
"Minimum sun elevation in degrees. Returns: dict: Combined Planet API filter"
71-
"ready for pagination."
72-
)
70+
" Build a Planet API search filter combining multiple AOIs, date ranges, cloud"
71+
"cover, and sun angle constraints. Args: aois (List[Polygon]): List of AOI"
72+
"polygons. date_ranges (List[Tuple[datetime, datetime]]): List of start/end date"
73+
"tuples. max_cloud (float): Maximum cloud fraction. min_sun_angle (float):"
74+
"Minimum sun elevation in degrees. Returns: dict: Combined Planet API filter"
75+
"ready for pagination."
76+
)
7377
# Combine multiple AOIs with OrFilter
7478
if len(aois) == 1:
7579
geom_filter = geometry_filter(aois[0])
7680
else:
77-
geom_filter = {"type": "OrFilter", "config": [geometry_filter(a) for a in aois]}
81+
geom_filter = {
82+
"type": "OrFilter",
83+
"config": [geometry_filter(a) for a in aois],
84+
}
7885

7986
# Combine multiple date ranges with OrFilter
8087
if len(date_ranges) == 1:
8188
date_filter = date_range_filter(date_ranges[0][0], date_ranges[0][1])
8289
else:
8390
date_filter = {
8491
"type": "OrFilter",
85-
"config": [date_range_filter(start, end) for start, end in date_ranges],
92+
"config": [
93+
date_range_filter(start, end) for start, end in date_ranges
94+
],
8695
}
8796

8897
# Combine quality filters
89-
quality_filters = [cloud_cover_filter(max_cloud), sun_angle_filter(min_sun_angle)]
98+
quality_filters = [
99+
cloud_cover_filter(max_cloud),
100+
sun_angle_filter(min_sun_angle),
101+
]
90102

91103
# Combine everything with AndFilter
92104
combined_filter = {

src/planet_overlap/geometry.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616

1717
def load_aoi(paths: List[Union[str, Path]]) -> List[Polygon]:
1818
(
19-
" Load AOIs from multiple GeoJSON files or single polygons. Args: paths"
20-
"(List[str | Path]): List of GeoJSON file paths Returns: List[Polygon]: List of"
21-
"polygons representing AOIs"
22-
)
19+
" Load AOIs from multiple GeoJSON files or single polygons. Args: paths"
20+
"(List[str | Path]): List of GeoJSON file paths Returns: List[Polygon]: List of"
21+
"polygons representing AOIs"
22+
)
2323
aois: List[Polygon] = []
2424
for path in paths:
2525
path = Path(path)
@@ -38,13 +38,15 @@ def load_aoi(paths: List[Union[str, Path]]) -> List[Polygon]:
3838
return aois
3939

4040

41-
def buffer_points(points: List[Point], buffer_deg: float = 0.01) -> List[Polygon]:
41+
def buffer_points(
42+
points: List[Point], buffer_deg: float = 0.01
43+
) -> List[Polygon]:
4244
(
43-
" Converts points into small polygons (buffers) for Planet requests. Args:"
44-
"points (List[Point]): List of shapely Point objects buffer_deg (float): Buffer"
45-
"radius in degrees (default 0.01 ~1 km) Returns: List[Polygon]: Buffered"
46-
"polygons"
47-
)
45+
" Converts points into small polygons (buffers) for Planet requests. Args:"
46+
"points (List[Point]): List of shapely Point objects buffer_deg (float): Buffer"
47+
"radius in degrees (default 0.01 ~1 km) Returns: List[Polygon]: Buffered"
48+
"polygons"
49+
)
4850
buffered = [pt.buffer(buffer_deg) for pt in points]
4951
logger.info(
5052
f"Buffered {len(points)} points into polygons with {buffer_deg}° radius"
@@ -54,9 +56,9 @@ def buffer_points(points: List[Point], buffer_deg: float = 0.01) -> List[Polygon
5456

5557
def unify_aois(aois: List[Polygon]) -> Polygon:
5658
(
57-
" Merge multiple AOIs into a single polygon if needed. Args: aois"
58-
"(List[Polygon]): List of polygons Returns: Polygon: Single merged polygon"
59-
)
59+
" Merge multiple AOIs into a single polygon if needed. Args: aois"
60+
"(List[Polygon]): List of polygons Returns: Polygon: Single merged polygon"
61+
)
6062
merged = unary_union(aois)
6163
if isinstance(merged, Polygon):
6264
return merged

src/planet_overlap/logger.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@
33

44

55
def setup_logger(log_file: str | None = None):
6-
(
7-
" Configure logging for console and optional file output."
8-
)
6+
(" Configure logging for console and optional file output.")
97
handlers = [logging.StreamHandler(sys.stdout)]
108

119
if log_file:

src/planet_overlap/performance.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55

66

77
def track_performance(func):
8-
(
9-
" Decorator to track runtime and memory usage of functions."
10-
)
8+
(" Decorator to track runtime and memory usage of functions.")
119

1210
@wraps(func)
1311
def wrapper(*args, **kwargs):

src/planet_overlap/utils.py

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,38 @@
22

33

44
def estimate_scene_count(
5-
start_date: str, end_date: str, max_cloud: float, scenes_per_day: float = 1.5
5+
start_date: str,
6+
end_date: str,
7+
max_cloud: float,
8+
scenes_per_day: float = 1.5,
69
) -> int:
7-
(
8-
" Estimate number of scenes before execution."
9-
)
10+
(" Estimate number of scenes before execution.")
1011

11-
days = (datetime.fromisoformat(end_date) - datetime.fromisoformat(start_date)).days
12+
days = (
13+
datetime.fromisoformat(end_date) - datetime.fromisoformat(start_date)
14+
).days
1215

1316
estimated = int(days * scenes_per_day * (1 - max_cloud))
1417
return max(estimated, 0)
1518

1619

1720
def generate_monthly_ranges(start_date: str, end_date: str):
18-
(
19-
" Split date range into monthly windows."
20-
)
21+
(" Split date range into monthly windows.")
2122

2223
ranges = []
2324

2425
current = datetime.fromisoformat(start_date)
2526
end = datetime.fromisoformat(end_date)
2627

2728
while current < end:
28-
next_month = (current.replace(day=28) + timedelta(days=4)).replace(day=1)
29+
next_month = (current.replace(day=28) + timedelta(days=4)).replace(
30+
day=1
31+
)
2932
window_end = min(next_month, end)
3033

31-
ranges.append((current.date().isoformat(), window_end.date().isoformat()))
34+
ranges.append(
35+
(current.date().isoformat(), window_end.date().isoformat())
36+
)
3237

3338
current = window_end
3439

tests/test_cli.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33

44
def test_cli_defaults(tmp_path):
55
args = parse_args(
6-
["--output-dir", str(tmp_path), "--max-cloud", "0.3", "--min-sun-angle", "10"]
6+
[
7+
"--output-dir",
8+
str(tmp_path),
9+
"--max-cloud",
10+
"0.3",
11+
"--min-sun-angle",
12+
"10",
13+
]
714
)
815
assert args.output_dir == str(tmp_path)
916
assert args.max_cloud == 0.3

tests/test_filters.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ def test_single_geojson_and_single_date():
1414

1515
def test_multiple_geojson_and_multiple_date_ranges():
1616
"""Test multiple AOIs with multiple date ranges."""
17-
geojson_paths = ["tests/data/sample_aoi.geojson", "tests/data/sample_aoi2.geojson"]
17+
geojson_paths = [
18+
"tests/data/sample_aoi.geojson",
19+
"tests/data/sample_aoi2.geojson",
20+
]
1821
date_ranges = [("2023-01-01", "2023-01-15"), ("2023-02-01", "2023-02-10")]
1922
filters = build_filters(geojson_paths, date_ranges)
2023
# Ensure each AOI/date pair generates a config entry
@@ -26,7 +29,10 @@ def test_multiple_geojson_and_multiple_date_ranges():
2629

2730
def test_mixed_single_and_range_dates():
2831
"""Test handling of a mix of single dates and date ranges."""
29-
geojson_paths = ["tests/data/sample_aoi.geojson", "tests/data/sample_aoi2.geojson"]
32+
geojson_paths = [
33+
"tests/data/sample_aoi.geojson",
34+
"tests/data/sample_aoi2.geojson",
35+
]
3036
date_ranges = [
3137
("2023-01-01", "2023-01-01"), # single date as range
3238
("2023-02-01", "2023-02-10"),

0 commit comments

Comments
 (0)