coastseg 0.0.65.dev4__tar.gz → 0.0.66.dev1__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.
- {coastseg-0.0.65.dev4/src/coastseg.egg-info → coastseg-0.0.66.dev1}/PKG-INFO +1 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/pyproject.toml +5 -3
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bbox.py +2 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/coastseg_map.py +210 -186
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/common.py +105 -56
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/downloads.py +0 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/extracted_shoreline.py +46 -15
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/map_UI.py +68 -79
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/models_UI.py +2 -2
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/settings_UI.py +0 -6
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/shoreline.py +0 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects.py +1 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/watchable_slider.py +2 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/zoo_model.py +102 -86
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1/src/coastseg.egg-info}/PKG-INFO +1 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg.egg-info/requires.txt +3 -1
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/LICENSE +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/MANIFEST.in +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/README.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/config.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/extract_shorelines.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/change_layer_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/colab_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/colab_downloads_location.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/create_rois_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/extract_shorelines_and_transects.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/gee_auth_tutorial.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/generate_rois_and_display_area.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/load_config_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/load_geojson_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/load_geojson_files_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/load_shoreline_transect_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/gifs/settings_demo.gif +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/map_guide.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/models.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/roi.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/settings.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/docs/transect_time_series.md +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/setup.cfg +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/setup.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/__init__.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/shorelines_bounding_boxes.csv +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/transects_bounding_boxes.csv +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/usa_shorelines_bounding_boxes.csv +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/usa_shorelines_bounding_boxes.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/world_reference_shorelines_bboxes.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/bounding_boxes/world_shorelines_bounding_boxes.csv +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/coastseg_logs.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/exception_handler.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/exceptions.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/factory.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/observable.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/roi.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/sessions.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/BarterIslandAlaskaTransects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/CA_USA_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/Chile_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/E_aus_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/Gulf_USA_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/Japan_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/Mexico_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/NE_TWL_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/NE_usa_DSAS.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/NZ_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/N_AK_DSAS.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/PNW_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/Peru_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/PuertoRico_TWL_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/SE_USA_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/SFlorida_TWL_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/all_HI_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/mergedBI_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/usa_southeast_transects_DE.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/transects/usa_southeast_transects_MD.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg/upload_feature_widget.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg.egg-info/SOURCES.txt +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg.egg-info/dependency_links.txt +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/src/coastseg.egg-info/top_level.txt +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/__init__.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/conftest.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_bbox.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_coastseg_map.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_common.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/config.json +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/config_gdf_id_2.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/config_id_2.json +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/transect_compatible_bbox.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/transect_compatible_rois.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/transect_compatible_shoreline.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/transect_compatible_transects.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/valid_bbox.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_data/valid_rois.geojson +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_extracted_shoreline.py +0 -0
- {coastseg-0.0.65.dev4 → coastseg-0.0.66.dev1}/tests/test_roi.py +0 -0
|
@@ -5,14 +5,14 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coastseg"
|
|
7
7
|
dynamic = ["readme"]
|
|
8
|
-
version = "0.0.
|
|
8
|
+
version = "0.0.66dev1"
|
|
9
9
|
authors = [
|
|
10
10
|
{ name=" Sharon Fitzpatrick", email="sharon.fitzpatrick23@gmail.com" },
|
|
11
11
|
]
|
|
12
12
|
# find` directive with `include` or `exclude`
|
|
13
13
|
description = "An interactive jupyter notebook for downloading satellite imagery"
|
|
14
14
|
dependencies = [
|
|
15
|
-
"coastsat-package>=0.1.
|
|
15
|
+
"coastsat-package>=0.1.12",
|
|
16
16
|
"area",
|
|
17
17
|
"doodleverse-utils>=0.0.29",
|
|
18
18
|
"ipyfilechooser>=0.6.0",
|
|
@@ -22,7 +22,9 @@ dependencies = [
|
|
|
22
22
|
"aiohttp",
|
|
23
23
|
"nest-asyncio",
|
|
24
24
|
"tensorflow",
|
|
25
|
-
"dask"
|
|
25
|
+
"dask",
|
|
26
|
+
"xarray",
|
|
27
|
+
"pyTMD"]
|
|
26
28
|
license = { file="LICENSE" }
|
|
27
29
|
requires-python = ">=3.8"
|
|
28
30
|
classifiers = [
|
|
@@ -79,7 +79,8 @@ class Bounding_Box:
|
|
|
79
79
|
crs (str, optional): coordinate reference system string. Defaults to 'EPSG:4326'.
|
|
80
80
|
|
|
81
81
|
Returns:
|
|
82
|
-
gpd.GeoDataFrame: geodataframe with geometry column = rectangle and given crs
|
|
82
|
+
gpd.GeoDataFrame: geodataframe with geometry column = rectangle and given crs
|
|
83
|
+
"""
|
|
83
84
|
geom = [shape(rectangle)]
|
|
84
85
|
geojson_bbox = gpd.GeoDataFrame({"geometry": geom})
|
|
85
86
|
geojson_bbox.crs = crs
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import datetime
|
|
1
2
|
import os
|
|
2
3
|
import json
|
|
3
4
|
import logging
|
|
@@ -19,7 +20,6 @@ from coastseg.observable import Observable
|
|
|
19
20
|
|
|
20
21
|
from coastsat import (
|
|
21
22
|
SDS_download,
|
|
22
|
-
SDS_transects,
|
|
23
23
|
)
|
|
24
24
|
import pandas as pd
|
|
25
25
|
import geopandas as gpd
|
|
@@ -195,11 +195,31 @@ class CoastSeg_Map:
|
|
|
195
195
|
file_path = os.path.join(dir_path, file_name)
|
|
196
196
|
if not os.path.isfile(file_path):
|
|
197
197
|
continue
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
198
|
+
if file_name == "shoreline_settings.json":
|
|
199
|
+
keys = [
|
|
200
|
+
"cloud_thresh",
|
|
201
|
+
"cloud_mask_issue",
|
|
202
|
+
"min_beach_area",
|
|
203
|
+
"min_length_sl",
|
|
204
|
+
"output_epsg",
|
|
205
|
+
"sand_color",
|
|
206
|
+
"pan_off",
|
|
207
|
+
"max_dist_ref",
|
|
208
|
+
"dist_clouds",
|
|
209
|
+
"percent_no_data",
|
|
210
|
+
]
|
|
211
|
+
self.load_settings(file_path, keys)
|
|
212
|
+
elif file_name == "transects_settings.json":
|
|
213
|
+
keys = [
|
|
214
|
+
"max_std",
|
|
215
|
+
"min_points",
|
|
216
|
+
"along_dist",
|
|
217
|
+
"max_range",
|
|
218
|
+
"min_chainage",
|
|
219
|
+
"multiple_inter",
|
|
220
|
+
"prc_multiple",
|
|
221
|
+
]
|
|
222
|
+
self.load_settings(file_path, keys)
|
|
203
223
|
if not config_loaded:
|
|
204
224
|
logger.info(f"Not all config files not found at {dir_path}")
|
|
205
225
|
|
|
@@ -281,38 +301,13 @@ class CoastSeg_Map:
|
|
|
281
301
|
# update observable list of ROI ids with extracted shorelines
|
|
282
302
|
self.roi_ids_with_extracted_shorelines.set(ids_with_extracted_shorelines)
|
|
283
303
|
|
|
284
|
-
def load_settings(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
new_settings: A dictionary of new settings to apply.
|
|
292
|
-
|
|
293
|
-
Returns:
|
|
294
|
-
None.
|
|
295
|
-
"""
|
|
296
|
-
new_settings = common.read_json_file(filepath, raise_error=False)
|
|
297
|
-
if new_settings is None:
|
|
298
|
-
new_settings = {}
|
|
299
|
-
# load in transect settings if found
|
|
300
|
-
transect_keys = [
|
|
301
|
-
"max_std",
|
|
302
|
-
"min_points",
|
|
303
|
-
"along_dist",
|
|
304
|
-
"max_range",
|
|
305
|
-
"min_chainage",
|
|
306
|
-
"multiple_inter",
|
|
307
|
-
"prc_multiple",
|
|
308
|
-
]
|
|
309
|
-
transect_settings = common.filter_dict_by_keys(new_settings, keys=transect_keys)
|
|
310
|
-
if transect_settings != {}:
|
|
311
|
-
logger.info(f"Loading transect_settings: {transect_settings}")
|
|
312
|
-
self.set_settings(**transect_settings)
|
|
313
|
-
logger.info(f"Loaded transect_settings from {filepath}")
|
|
314
|
-
|
|
315
|
-
shoreline_keys = [
|
|
304
|
+
def load_settings(
|
|
305
|
+
self,
|
|
306
|
+
filepath: str = "",
|
|
307
|
+
keys: set = (
|
|
308
|
+
"sat_list",
|
|
309
|
+
"dates",
|
|
310
|
+
"sand_color",
|
|
316
311
|
"cloud_thresh",
|
|
317
312
|
"cloud_mask_issue",
|
|
318
313
|
"min_beach_area",
|
|
@@ -323,18 +318,74 @@ class CoastSeg_Map:
|
|
|
323
318
|
"max_dist_ref",
|
|
324
319
|
"dist_clouds",
|
|
325
320
|
"percent_no_data",
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
321
|
+
"max_std",
|
|
322
|
+
"min_points",
|
|
323
|
+
"along_dist",
|
|
324
|
+
"max_range",
|
|
325
|
+
"min_chainage",
|
|
326
|
+
"multiple_inter",
|
|
327
|
+
"prc_multiple",
|
|
328
|
+
),
|
|
329
|
+
load_nested_settings:bool=True,
|
|
330
|
+
):
|
|
331
|
+
"""
|
|
332
|
+
Loads settings from a JSON file and applies them to the object.
|
|
333
|
+
|
|
334
|
+
Args:
|
|
335
|
+
filepath (str, optional): The filepath to the JSON file containing the settings. Defaults to an empty string.
|
|
336
|
+
load_nested_setting (bool, optional): Load settings from a nest subdictionary 'settings' or not.
|
|
337
|
+
keys (list or set, optional): A list of keys specifying which settings to load from the JSON file. If empty, no settings are loaded. Defaults to a set with the following
|
|
338
|
+
"sat_list",
|
|
339
|
+
"dates",
|
|
340
|
+
"cloud_thresh",
|
|
341
|
+
"cloud_mask_issue",
|
|
342
|
+
"min_beach_area",
|
|
343
|
+
"min_length_sl",
|
|
344
|
+
"output_epsg",
|
|
345
|
+
"sand_color",
|
|
346
|
+
"pan_off",
|
|
347
|
+
"max_dist_ref",
|
|
348
|
+
"dist_clouds",
|
|
349
|
+
"percent_no_data",
|
|
350
|
+
"max_std",
|
|
351
|
+
"min_points",
|
|
352
|
+
"along_dist",
|
|
353
|
+
"max_range",
|
|
354
|
+
"min_chainage",
|
|
355
|
+
"multiple_inter",
|
|
356
|
+
"prc_multiple".
|
|
357
|
+
|
|
358
|
+
Returns:
|
|
359
|
+
None
|
|
360
|
+
|
|
361
|
+
"""
|
|
362
|
+
# Convert keys to a list if a set is passed
|
|
363
|
+
if isinstance(keys, set):
|
|
364
|
+
keys = list(keys)
|
|
333
365
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
366
|
+
new_settings = common.read_json_file(filepath, raise_error=False)
|
|
367
|
+
logger.info(f"all of new settings read from file : {filepath} \n {new_settings}")
|
|
368
|
+
|
|
369
|
+
nested_settings = new_settings.get('settings',{})
|
|
370
|
+
logger.info(f"all of new nested settings read from file : {filepath} \n {nested_settings }")
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
if new_settings is None:
|
|
374
|
+
new_settings = {}
|
|
375
|
+
|
|
376
|
+
# Load only settings with provided keys
|
|
377
|
+
if keys:
|
|
378
|
+
new_settings = {k: new_settings[k] for k in keys if k in new_settings}
|
|
379
|
+
if nested_settings:
|
|
380
|
+
nested_settings = {k: nested_settings[k] for k in keys if k in nested_settings}
|
|
381
|
+
|
|
382
|
+
if new_settings != {}:
|
|
383
|
+
self.set_settings(**new_settings)
|
|
384
|
+
if nested_settings != {} and load_nested_settings:
|
|
385
|
+
self.set_settings(**nested_settings)
|
|
386
|
+
logger.info(
|
|
387
|
+
f"Loaded new_settings from {filepath}:\n new self.settings {self.settings}"
|
|
388
|
+
)
|
|
338
389
|
|
|
339
390
|
def load_gdf_config(self, filepath: str) -> None:
|
|
340
391
|
"""Load features from geodataframe located in geojson file at filepath onto map.
|
|
@@ -457,55 +508,62 @@ class CoastSeg_Map:
|
|
|
457
508
|
It replaces the coastseg_map.settings with the settings from the config file,
|
|
458
509
|
and replaces the roi_settings for each ROI with the contents of the json_data.
|
|
459
510
|
Finally, it saves the input dictionaries for all ROIs.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
511
|
+
|
|
512
|
+
Args:
|
|
513
|
+
self (object): CoastsegMap instance
|
|
514
|
+
filepath (str): The filepath to the json config file
|
|
515
|
+
datapath (str): Full path to the coastseg data directory
|
|
516
|
+
|
|
464
517
|
Returns:
|
|
465
518
|
None
|
|
519
|
+
|
|
520
|
+
Raises:
|
|
521
|
+
FileNotFoundError: If the config file is not found
|
|
522
|
+
MissingDirectoriesError: If one or more directories specified in the config file are missing
|
|
523
|
+
|
|
466
524
|
"""
|
|
467
525
|
logger.info(f"filepath: {filepath}")
|
|
468
526
|
exception_handler.check_if_None(self.rois)
|
|
527
|
+
|
|
469
528
|
json_data = common.read_json_file(filepath, raise_error=True)
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
#
|
|
473
|
-
self.set_settings(**json_data
|
|
474
|
-
|
|
529
|
+
json_data = json_data or {}
|
|
530
|
+
|
|
531
|
+
# Replace coastseg_map.settings with settings from config file
|
|
532
|
+
self.set_settings(**json_data.get("settings", {}))
|
|
533
|
+
|
|
534
|
+
# Replace roi_settings for each ROI with contents of json_data
|
|
475
535
|
roi_settings = {}
|
|
476
|
-
# flag raised if a single directory is missing
|
|
477
536
|
missing_directories = []
|
|
537
|
+
fields_of_interest = [
|
|
538
|
+
"dates",
|
|
539
|
+
"sitename",
|
|
540
|
+
"polygon",
|
|
541
|
+
"roi_id",
|
|
542
|
+
"sat_list",
|
|
543
|
+
"sitename",
|
|
544
|
+
"landsat_collection",
|
|
545
|
+
"filepath",
|
|
546
|
+
]
|
|
547
|
+
|
|
478
548
|
logger.info(f"json_data: {json_data}\n")
|
|
479
|
-
|
|
549
|
+
|
|
550
|
+
for roi_id in json_data.get("roi_ids", []):
|
|
480
551
|
logger.info(f"roi_id: {roi_id}")
|
|
481
|
-
#
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
"sitename",
|
|
485
|
-
"polygon",
|
|
486
|
-
"roi_id",
|
|
487
|
-
"sat_list",
|
|
488
|
-
"sitename",
|
|
489
|
-
"landsat_collection",
|
|
490
|
-
"filepath",
|
|
491
|
-
]
|
|
492
|
-
roi_data = common.extract_fields(json_data, roi_id, fields_of_interest)
|
|
493
|
-
if not roi_data:
|
|
494
|
-
logger.error(f"json_data: {json_data}")
|
|
495
|
-
raise Exception(
|
|
496
|
-
f"Invalid config.json file detected. Please add the correct roi ids to the config.json file's 'roi_ids' and try again.\nContents of config.json file's 'roi_ids':{json_data['roi_ids']}"
|
|
497
|
-
)
|
|
498
|
-
# update the roi location to be one relevant to the current computer
|
|
552
|
+
# get the fields of interest from an roi with a matching id
|
|
553
|
+
roi_data = common.extract_roi_data(json_data, roi_id, fields_of_interest)
|
|
554
|
+
|
|
499
555
|
sitename = roi_data.get("sitename", "")
|
|
500
556
|
roi_path = os.path.join(data_path, sitename)
|
|
501
557
|
roi_data["filepath"] = data_path
|
|
558
|
+
|
|
502
559
|
if not os.path.exists(roi_path):
|
|
503
560
|
missing_directories.append(sitename)
|
|
504
|
-
|
|
561
|
+
|
|
505
562
|
roi_settings[str(roi_id)] = roi_data
|
|
506
563
|
|
|
507
564
|
# if any directories are missing tell the user list of missing directories
|
|
508
565
|
exception_handler.check_if_dirs_missing(missing_directories)
|
|
566
|
+
|
|
509
567
|
# Save input dictionaries for all ROIs
|
|
510
568
|
self.rois.roi_settings = roi_settings
|
|
511
569
|
logger.info(f"roi_settings: {roi_settings}")
|
|
@@ -523,8 +581,9 @@ class CoastSeg_Map:
|
|
|
523
581
|
# check if config files exist
|
|
524
582
|
config_geojson_path = os.path.join(dir_path, "config_gdf.geojson")
|
|
525
583
|
config_json_path = os.path.join(dir_path, "config.json")
|
|
526
|
-
logger.info(
|
|
527
|
-
|
|
584
|
+
logger.info(
|
|
585
|
+
f"config_gdf.geojson: {config_geojson_path} \n config.json location: {config_json_path}"
|
|
586
|
+
)
|
|
528
587
|
# cannot load config.json file if config_gdf.geojson file is missing
|
|
529
588
|
if not os.path.exists(config_geojson_path):
|
|
530
589
|
logger.warning(f"config_gdf.geojson file missing at {config_geojson_path}")
|
|
@@ -590,7 +649,11 @@ class CoastSeg_Map:
|
|
|
590
649
|
if not selected_rois.empty:
|
|
591
650
|
epsg_code = selected_rois.crs
|
|
592
651
|
config_gdf = common.create_config_gdf(
|
|
593
|
-
selected_rois,
|
|
652
|
+
selected_rois,
|
|
653
|
+
shorelines_gdf=shorelines_gdf,
|
|
654
|
+
transects_gdf=transects_gdf,
|
|
655
|
+
bbox_gdf=bbox_gdf,
|
|
656
|
+
epsg_code=epsg_code,
|
|
594
657
|
)
|
|
595
658
|
logger.info(f"config_gdf: {config_gdf} ")
|
|
596
659
|
is_downloaded = common.were_rois_downloaded(self.rois.roi_settings, roi_ids)
|
|
@@ -636,9 +699,10 @@ class CoastSeg_Map:
|
|
|
636
699
|
Returns:
|
|
637
700
|
None
|
|
638
701
|
"""
|
|
702
|
+
logger.info(f"New Settings: {kwargs}")
|
|
639
703
|
# Check if any of the keys are missing
|
|
640
704
|
# if any keys are missing set the default value
|
|
641
|
-
default_settings = {
|
|
705
|
+
self.default_settings = {
|
|
642
706
|
"landsat_collection": "C02",
|
|
643
707
|
"dates": ["2017-12-01", "2018-01-01"],
|
|
644
708
|
"sat_list": ["L8"],
|
|
@@ -651,7 +715,6 @@ class CoastSeg_Map:
|
|
|
651
715
|
# if True, allows user to adjust the position of each shoreline by changing the threshold
|
|
652
716
|
"adjust_detection": False,
|
|
653
717
|
"save_figure": True, # if True, saves a figure showing the mapped shoreline for each image
|
|
654
|
-
# [ONLY FOR ADVANCED USERS] shoreline detection parameters:
|
|
655
718
|
# minimum area (in metres^2) for an object to be labelled as a beach
|
|
656
719
|
"min_beach_area": 4500,
|
|
657
720
|
# minimum length (in metres) of shoreline perimeter to be valid
|
|
@@ -670,45 +733,79 @@ class CoastSeg_Map:
|
|
|
670
733
|
"multiple_inter": "auto", # mode for removing outliers ('auto', 'nan', 'max')
|
|
671
734
|
"prc_multiple": 0.1, # percentage of the time that multiple intersects are present to use the max
|
|
672
735
|
}
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
736
|
+
self.settings.update(kwargs)
|
|
737
|
+
if "dates" in kwargs.keys():
|
|
738
|
+
updated_dates = []
|
|
739
|
+
self.settings["dates"] = kwargs['dates']
|
|
740
|
+
for date_str in kwargs['dates']:
|
|
741
|
+
try:
|
|
742
|
+
dt = datetime.strptime(date_str, '%Y-%m-%dT%H:%M:%S')
|
|
743
|
+
except ValueError:
|
|
744
|
+
dt = datetime.strptime(date_str, '%Y-%m-%d')
|
|
745
|
+
updated_dates.append(dt.strftime('%Y-%m-%d'))
|
|
746
|
+
self.settings["dates"] = updated_dates
|
|
747
|
+
|
|
748
|
+
for key, value in self.default_settings.items():
|
|
749
|
+
self.settings.setdefault(key, value)
|
|
750
|
+
|
|
682
751
|
logger.info(f"Settings: {self.settings}")
|
|
683
752
|
|
|
684
753
|
def get_settings(self):
|
|
754
|
+
"""
|
|
755
|
+
Retrieves the current settings.
|
|
756
|
+
|
|
757
|
+
Returns:
|
|
758
|
+
dict: A dictionary containing the current settings.
|
|
759
|
+
|
|
760
|
+
Raises:
|
|
761
|
+
Exception: If no settings are found. Click save settings or load a config file.
|
|
762
|
+
|
|
763
|
+
"""
|
|
685
764
|
SETTINGS_NOT_FOUND = (
|
|
686
765
|
"No settings found. Click save settings or load a config file."
|
|
687
766
|
)
|
|
688
767
|
logger.info(f"self.settings: {self.settings}")
|
|
689
768
|
if self.settings is None or self.settings == {}:
|
|
690
769
|
raise Exception(SETTINGS_NOT_FOUND)
|
|
691
|
-
|
|
692
|
-
self.settings.setdefault("cloud_mask_issue", False)
|
|
693
|
-
self.settings.setdefault("cloud_thresh", 99.9)
|
|
694
770
|
return self.settings
|
|
695
771
|
|
|
696
|
-
def update_transects_html(self, feature, **kwargs):
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
772
|
+
def update_transects_html(self, feature: dict, **kwargs):
|
|
773
|
+
"""
|
|
774
|
+
Modifies the HTML when a transect is hovered over.
|
|
775
|
+
|
|
776
|
+
Args:
|
|
777
|
+
feature (dict): The transect feature.
|
|
778
|
+
**kwargs: Additional keyword arguments.
|
|
779
|
+
|
|
780
|
+
Returns:
|
|
781
|
+
None
|
|
782
|
+
|
|
783
|
+
"""
|
|
784
|
+
properties = feature["properties"]
|
|
785
|
+
transect_id = properties.get("id", "unknown")
|
|
786
|
+
slope = properties.get("slope", "unknown")
|
|
787
|
+
|
|
788
|
+
self.feature_html.value = (
|
|
789
|
+
"<div style='max-width: 230px; max-height: 200px; overflow-x: auto; overflow-y: auto'>"
|
|
790
|
+
"<b>Transect</b>"
|
|
791
|
+
f"<p>Id: {transect_id}</p>"
|
|
792
|
+
f"<p>Slope: {slope}</p>"
|
|
707
793
|
)
|
|
708
794
|
|
|
709
795
|
def update_extracted_shoreline_html(self, feature, **kwargs):
|
|
796
|
+
"""
|
|
797
|
+
Modifies the HTML content when an extracted shoreline is hovered over.
|
|
798
|
+
|
|
799
|
+
Args:
|
|
800
|
+
feature (dict): The extracted shoreline feature.
|
|
801
|
+
**kwargs: Additional keyword arguments.
|
|
802
|
+
|
|
803
|
+
Returns:
|
|
804
|
+
None
|
|
805
|
+
|
|
806
|
+
"""
|
|
710
807
|
# Modifies html when extracted shoreline is hovered over
|
|
711
|
-
|
|
808
|
+
properties = defaultdict(lambda: "unknown", feature["properties"])
|
|
712
809
|
self.feature_html.value = """
|
|
713
810
|
<div style='max-width: 230px; max-height: 200px; overflow-x: auto; overflow-y: auto'>
|
|
714
811
|
<b>Extracted Shoreline</b>
|
|
@@ -717,10 +814,10 @@ class CoastSeg_Map:
|
|
|
717
814
|
<p>Cloud Cover: {}</p>
|
|
718
815
|
<p>Satellite Name: {}</p>
|
|
719
816
|
""".format(
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
817
|
+
properties["date"],
|
|
818
|
+
properties["geoaccuracy"],
|
|
819
|
+
properties["cloud_cover"],
|
|
820
|
+
properties["satname"],
|
|
724
821
|
)
|
|
725
822
|
|
|
726
823
|
def update_roi_html(self, feature, **kwargs):
|
|
@@ -1045,7 +1142,6 @@ class CoastSeg_Map:
|
|
|
1045
1142
|
selected_rois_gdf = self.rois.gdf[self.rois.gdf["id"].isin(roi_ids)]
|
|
1046
1143
|
return selected_rois_gdf
|
|
1047
1144
|
|
|
1048
|
-
|
|
1049
1145
|
def get_cross_distance(
|
|
1050
1146
|
self,
|
|
1051
1147
|
roi_id: str,
|
|
@@ -1110,78 +1206,6 @@ class CoastSeg_Map:
|
|
|
1110
1206
|
|
|
1111
1207
|
return cross_distance, failure_reason
|
|
1112
1208
|
|
|
1113
|
-
# def get_cross_distance(self,
|
|
1114
|
-
# roi_id: str,
|
|
1115
|
-
# transects_in_roi_gdf:gpd.GeoDataFrame,
|
|
1116
|
-
# settings: dict,
|
|
1117
|
-
# output_epsg: str):
|
|
1118
|
-
# """
|
|
1119
|
-
# Compute the cross shore distance of transects and extracted shorelines for a given ROI.
|
|
1120
|
-
|
|
1121
|
-
# Parameters:
|
|
1122
|
-
# -----------
|
|
1123
|
-
# roi_id : str
|
|
1124
|
-
# The ID of the ROI to compute the cross shore distance for.
|
|
1125
|
-
# transects_in_roi_gdf : gpd.GeoDataFrame
|
|
1126
|
-
# All the transects in the ROI.
|
|
1127
|
-
# Must contain the columns ["id", "geometry"]
|
|
1128
|
-
# settings : dict
|
|
1129
|
-
# A dictionary of settings to be used in the computation.
|
|
1130
|
-
# output_epsg : str
|
|
1131
|
-
# The EPSG code of the output projection.
|
|
1132
|
-
|
|
1133
|
-
# Returns:
|
|
1134
|
-
# --------
|
|
1135
|
-
# float
|
|
1136
|
-
# The computed cross shore distance, or 0 if there was an issue in the computation.
|
|
1137
|
-
|
|
1138
|
-
# Raises:
|
|
1139
|
-
# -------
|
|
1140
|
-
# exceptions.No_Extracted_Shoreline
|
|
1141
|
-
# Raised if no shorelines were extracted for the ROI with roi_id
|
|
1142
|
-
|
|
1143
|
-
# Usage:
|
|
1144
|
-
# ------
|
|
1145
|
-
# cross_distance = get_cross_distance(roi_id, settings, output_epsg)
|
|
1146
|
-
# """
|
|
1147
|
-
# failure_reason = None
|
|
1148
|
-
# cross_distance = 0
|
|
1149
|
-
|
|
1150
|
-
# # get extracted shorelines object for the currently selected ROI
|
|
1151
|
-
# roi_extracted_shoreline = self.rois.get_extracted_shoreline(roi_id)
|
|
1152
|
-
|
|
1153
|
-
# # transects_in_roi_gdf = transects_in_roi_gdf[["id", "geometry"]]
|
|
1154
|
-
# transects_in_roi_gdf = transects_in_roi_gdf.loc[:, ["id", "geometry"]]
|
|
1155
|
-
|
|
1156
|
-
# if roi_extracted_shoreline is None:
|
|
1157
|
-
# failure_reason = "No extracted shorelines were found"
|
|
1158
|
-
# elif transects_in_roi_gdf.empty:
|
|
1159
|
-
# failure_reason = "No transects intersected the ROI"
|
|
1160
|
-
# else:
|
|
1161
|
-
# extracted_shoreline_x_transect = transects_in_roi_gdf[
|
|
1162
|
-
# transects_in_roi_gdf.intersects(roi_extracted_shoreline.gdf.unary_union)
|
|
1163
|
-
# ]
|
|
1164
|
-
# if extracted_shoreline_x_transect.empty:
|
|
1165
|
-
# cross_distance = 0
|
|
1166
|
-
# failure_reason = "No extracted shorelines intersected transects"
|
|
1167
|
-
# else:
|
|
1168
|
-
# # convert transects_in_roi_gdf to output_crs from settings
|
|
1169
|
-
# transects_in_roi_gdf = transects_in_roi_gdf.to_crs(output_epsg)
|
|
1170
|
-
# # compute cross shore distance of transects and extracted shorelines
|
|
1171
|
-
# extracted_shorelines_dict = roi_extracted_shoreline.dictionary
|
|
1172
|
-
# cross_distance = self.compute_transects_from_roi(
|
|
1173
|
-
# roi_id,
|
|
1174
|
-
# extracted_shorelines_dict,
|
|
1175
|
-
# transects_in_roi_gdf,
|
|
1176
|
-
# settings,
|
|
1177
|
-
# )
|
|
1178
|
-
|
|
1179
|
-
# if cross_distance == 0:
|
|
1180
|
-
# logger.warning(f"{failure_reason} for ROI {roi_id}")
|
|
1181
|
-
# print(f"{failure_reason} for ROI {roi_id}")
|
|
1182
|
-
|
|
1183
|
-
# return cross_distance
|
|
1184
|
-
|
|
1185
1209
|
def save_timeseries_csv(self, session_path: str, roi_id: str, rois: ROI) -> None:
|
|
1186
1210
|
"""Saves cross distances of transects and
|
|
1187
1211
|
extracted shorelines in ROI to csv file within each ROI's directory.
|
|
@@ -1961,7 +1985,7 @@ class CoastSeg_Map:
|
|
|
1961
1985
|
):
|
|
1962
1986
|
"""
|
|
1963
1987
|
Save a geographical feature (Bounding_Box, Shoreline, Transects, ROI) as a GeoJSON file.
|
|
1964
|
-
|
|
1988
|
+
|
|
1965
1989
|
Args:
|
|
1966
1990
|
feature (Union[Bounding_Box, Shoreline, Transects, ROI]): The geographical feature to save.
|
|
1967
1991
|
feature_type (str, optional): The type of the feature, e.g. Bounding_Box, Shoreline, Transects, or ROI.
|