pingmapper 5.4.6__tar.gz → 5.4.8__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.
- {pingmapper-5.4.6 → pingmapper-5.4.8}/PKG-INFO +44 -9
- {pingmapper-5.4.6 → pingmapper-5.4.8}/README.md +43 -8
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/class_portstarObj.py +21 -13
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/class_rectObj.py +2 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/self_check.py +6 -1
- pingmapper-5.4.8/pingmapper/test_cli_self_check.py +118 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/test_dq_filter.py +199 -0
- pingmapper-5.4.8/pingmapper/version.py +1 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper.egg-info/PKG-INFO +44 -9
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper.egg-info/SOURCES.txt +1 -0
- pingmapper-5.4.6/pingmapper/version.py +0 -1
- {pingmapper-5.4.6 → pingmapper-5.4.8}/LICENSE +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/__init__.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/__main__.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/class_mapSubstrateObj.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/class_sonObj.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/class_sonObj_nadirgaptest.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/default_params.json +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/doWork.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/funcs_common.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/funcs_model.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/funcs_rectify.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/gui_main.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/main_mapSubstrate.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/main_readFiles.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/main_rectify.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/nonGUI_batch_main.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/nonGui_main.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/processing_scripts/main_batchDirectory_2024-01-18_0926.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/processing_scripts/main_batchDirectory_2024-01-18_0929.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/scratch/funcs_pyhum_correct.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/scratch/main.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/scratch/main_batchDirectory.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/test_PINGMapper.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/test_time.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/avg_predictions_Mussel_WBL.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/gen_centerline.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/gen_centerline_from_bankline.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/gen_centerline_trkpnts_fitspline_DRAFT.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/testEXAMPLE_mosaic_logit.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/RawEGN_avg_predictions.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/00_substrate_logits_mosaic_transects.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/00_substrate_shps_mosaic_transects.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/01_gen_centerline_from_coverage.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/02_gen_summary_stamp_shps.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/03_gen_summary_shp.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/04_combine_summary_shp_csv.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/05_gen_summary_shp_plots.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/06_compare_raw-egn_volume.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/08_raw-egn_hardReacheFreq_hist.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/09_raw-egn_PatchSize_density.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/summarize_project_substrate.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/export_coverage.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/main_mosaic_transects.py +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper.egg-info/dependency_links.txt +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper.egg-info/requires.txt +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper.egg-info/top_level.txt +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/pyproject.toml +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/setup.cfg +0 -0
- {pingmapper-5.4.6 → pingmapper-5.4.8}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pingmapper
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.8
|
|
4
4
|
Summary: Open-source interface for processing recreation-grade side scan sonar datasets and reproducibly mapping benthic habitat
|
|
5
5
|
Author: Cameron Bodine, Daniel Buscombe, Iury T Simoes-Sousa
|
|
6
6
|
Author-email: bodine.cs@gmail.email
|
|
@@ -69,6 +69,15 @@ Dynamic: requires-python
|
|
|
69
69
|
|
|
70
70
|
`PINGMapper` is an open-source Python interface for reading and processing side scan sonar datasets and reproducibly mapping benthic habitat features. `PINGMapper` transforms recreation-grade sonar systems (i.e. fishfinders) into scientific data collectors, allowing researchers and citizens alike to reproducibly map their aquatic system with minimal expertise in data processing.
|
|
71
71
|
|
|
72
|
+
## PING Ecosystem
|
|
73
|
+
|
|
74
|
+
`PINGMapper` is part of the [**PING Ecosystem**](https://github.com/PINGEcosystem): a coordinated set of tools for installation, conversion, quality checks, and mapping workflows.
|
|
75
|
+
|
|
76
|
+
- [PINGMapper](https://github.com/CameronBodine/PINGMapper): Core sonar processing and mapping package
|
|
77
|
+
- [PINGInstaller](https://github.com/CameronBodine/PINGInstaller): Recommended installer and environment bootstrap
|
|
78
|
+
- [PINGWizard](https://github.com/CameronBodine/PINGWizard): Point-and-click interface for testing, updates, and routine processing
|
|
79
|
+
- [PINGVerter](https://github.com/CameronBodine/PINGVerter): Sonar data conversion utilities
|
|
80
|
+
|
|
72
81
|
## Learn More Now!
|
|
73
82
|
Check out PING-Mapper's [website](https://cameronbodine.github.io/PINGMapper/) for most up to date information:
|
|
74
83
|
|
|
@@ -128,7 +137,7 @@ A manuscript detailing the automated substrate mapping features made availabe in
|
|
|
128
137
|
|
|
129
138
|
### v3.0 - 4.0
|
|
130
139
|
|
|
131
|
-
Continued support for PINGMapper and tools in the [PING Ecosystem](
|
|
140
|
+
Continued support for PINGMapper and tools in the [PING Ecosystem](#ping-ecosystem) is made possible through mentorship, partnerships, and financial support listed below.
|
|
132
141
|
|
|
133
142
|
**Primary Developer:** [Dr. Cameron S. Bodine](https://github.com/CameronBodine)
|
|
134
143
|
|
|
@@ -142,7 +151,24 @@ Continued support for PINGMapper and tools in the [PING Ecosystem](./docs/PINGEc
|
|
|
142
151
|
|
|
143
152
|
## Quick Start
|
|
144
153
|
|
|
145
|
-
|
|
154
|
+
Recommended workflow: install Miniforge, use PINGInstaller to set up the `ping` environment, and launch PINGWizard for testing, updates, and routine processing.
|
|
155
|
+
|
|
156
|
+
### Recommended: Miniforge + PINGInstaller + PINGWizard
|
|
157
|
+
|
|
158
|
+
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions. In short:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install pinginstaller -U
|
|
162
|
+
python -m pinginstaller
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
After installation completes, launch PINGWizard using the shortcut created by PINGInstaller, or run:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
conda run -n ping python -m pingwizard
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Alternative: Direct conda environment
|
|
146
172
|
|
|
147
173
|
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions, or simply run:
|
|
148
174
|
|
|
@@ -152,9 +178,9 @@ conda activate ping
|
|
|
152
178
|
python -m pingmapper gui
|
|
153
179
|
```
|
|
154
180
|
|
|
155
|
-
###
|
|
181
|
+
### Optional: Pixi
|
|
156
182
|
|
|
157
|
-
[Pixi](https://pixi.sh)
|
|
183
|
+
[Pixi](https://pixi.sh) is available for users who prefer that workflow, but it is not the recommended installation path.
|
|
158
184
|
|
|
159
185
|
1. [Install pixi](https://pixi.sh)
|
|
160
186
|
2. Clone and run:
|
|
@@ -170,12 +196,18 @@ python -m pingmapper gui
|
|
|
170
196
|
|
|
171
197
|
### Verify Installation
|
|
172
198
|
|
|
173
|
-
|
|
199
|
+
Recommended routine verification is to run the included tests from PINGWizard. If you want a prompt-based check, run the lightweight self-check below:
|
|
174
200
|
|
|
175
201
|
```bash
|
|
176
202
|
python -m pingmapper check
|
|
177
203
|
```
|
|
178
204
|
|
|
205
|
+
Direct unit-test invocation (same lightweight suite run by `check`):
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
python -m unittest pingmapper.test_dq_filter pingmapper.test_cli_self_check -v
|
|
209
|
+
```
|
|
210
|
+
|
|
179
211
|
Optional longer end-to-end processing validation:
|
|
180
212
|
|
|
181
213
|
```bash
|
|
@@ -190,9 +222,12 @@ Follow the installation and testing instructions to [Get Started!](https://camer
|
|
|
190
222
|
|
|
191
223
|
If you are interested in partnering on future developments, please reach out to [Cameron Bodine](https://cameronbodine.github.io/).
|
|
192
224
|
|
|
193
|
-
# PING-Mapper is part of the
|
|
194
|
-
|
|
225
|
+
# PING-Mapper is part of the PING Ecosystem
|
|
226
|
+
|
|
195
227
|
|
|
196
|
-
|
|
228
|
+
PINGMapper is developed and distributed alongside companion PING tools (PINGInstaller, PINGWizard, and PINGVerter) to provide a complete end-to-end workflow.
|
|
197
229
|
|
|
230
|
+
PINGMapper also leverages components from the Doodleverse ecosystem for geoscientific image segmentation workflows. Learn more on [GitHub](https://github.com/Doodleverse).
|
|
231
|
+
|
|
232
|
+

|
|
198
233
|
|
|
@@ -31,6 +31,15 @@
|
|
|
31
31
|
|
|
32
32
|
`PINGMapper` is an open-source Python interface for reading and processing side scan sonar datasets and reproducibly mapping benthic habitat features. `PINGMapper` transforms recreation-grade sonar systems (i.e. fishfinders) into scientific data collectors, allowing researchers and citizens alike to reproducibly map their aquatic system with minimal expertise in data processing.
|
|
33
33
|
|
|
34
|
+
## PING Ecosystem
|
|
35
|
+
|
|
36
|
+
`PINGMapper` is part of the [**PING Ecosystem**](https://github.com/PINGEcosystem): a coordinated set of tools for installation, conversion, quality checks, and mapping workflows.
|
|
37
|
+
|
|
38
|
+
- [PINGMapper](https://github.com/CameronBodine/PINGMapper): Core sonar processing and mapping package
|
|
39
|
+
- [PINGInstaller](https://github.com/CameronBodine/PINGInstaller): Recommended installer and environment bootstrap
|
|
40
|
+
- [PINGWizard](https://github.com/CameronBodine/PINGWizard): Point-and-click interface for testing, updates, and routine processing
|
|
41
|
+
- [PINGVerter](https://github.com/CameronBodine/PINGVerter): Sonar data conversion utilities
|
|
42
|
+
|
|
34
43
|
## Learn More Now!
|
|
35
44
|
Check out PING-Mapper's [website](https://cameronbodine.github.io/PINGMapper/) for most up to date information:
|
|
36
45
|
|
|
@@ -90,7 +99,7 @@ A manuscript detailing the automated substrate mapping features made availabe in
|
|
|
90
99
|
|
|
91
100
|
### v3.0 - 4.0
|
|
92
101
|
|
|
93
|
-
Continued support for PINGMapper and tools in the [PING Ecosystem](
|
|
102
|
+
Continued support for PINGMapper and tools in the [PING Ecosystem](#ping-ecosystem) is made possible through mentorship, partnerships, and financial support listed below.
|
|
94
103
|
|
|
95
104
|
**Primary Developer:** [Dr. Cameron S. Bodine](https://github.com/CameronBodine)
|
|
96
105
|
|
|
@@ -104,7 +113,24 @@ Continued support for PINGMapper and tools in the [PING Ecosystem](./docs/PINGEc
|
|
|
104
113
|
|
|
105
114
|
## Quick Start
|
|
106
115
|
|
|
107
|
-
|
|
116
|
+
Recommended workflow: install Miniforge, use PINGInstaller to set up the `ping` environment, and launch PINGWizard for testing, updates, and routine processing.
|
|
117
|
+
|
|
118
|
+
### Recommended: Miniforge + PINGInstaller + PINGWizard
|
|
119
|
+
|
|
120
|
+
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions. In short:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
pip install pinginstaller -U
|
|
124
|
+
python -m pinginstaller
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
After installation completes, launch PINGWizard using the shortcut created by PINGInstaller, or run:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
conda run -n ping python -m pingwizard
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Alternative: Direct conda environment
|
|
108
134
|
|
|
109
135
|
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions, or simply run:
|
|
110
136
|
|
|
@@ -114,9 +140,9 @@ conda activate ping
|
|
|
114
140
|
python -m pingmapper gui
|
|
115
141
|
```
|
|
116
142
|
|
|
117
|
-
###
|
|
143
|
+
### Optional: Pixi
|
|
118
144
|
|
|
119
|
-
[Pixi](https://pixi.sh)
|
|
145
|
+
[Pixi](https://pixi.sh) is available for users who prefer that workflow, but it is not the recommended installation path.
|
|
120
146
|
|
|
121
147
|
1. [Install pixi](https://pixi.sh)
|
|
122
148
|
2. Clone and run:
|
|
@@ -132,12 +158,18 @@ python -m pingmapper gui
|
|
|
132
158
|
|
|
133
159
|
### Verify Installation
|
|
134
160
|
|
|
135
|
-
|
|
161
|
+
Recommended routine verification is to run the included tests from PINGWizard. If you want a prompt-based check, run the lightweight self-check below:
|
|
136
162
|
|
|
137
163
|
```bash
|
|
138
164
|
python -m pingmapper check
|
|
139
165
|
```
|
|
140
166
|
|
|
167
|
+
Direct unit-test invocation (same lightweight suite run by `check`):
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
python -m unittest pingmapper.test_dq_filter pingmapper.test_cli_self_check -v
|
|
171
|
+
```
|
|
172
|
+
|
|
141
173
|
Optional longer end-to-end processing validation:
|
|
142
174
|
|
|
143
175
|
```bash
|
|
@@ -152,9 +184,12 @@ Follow the installation and testing instructions to [Get Started!](https://camer
|
|
|
152
184
|
|
|
153
185
|
If you are interested in partnering on future developments, please reach out to [Cameron Bodine](https://cameronbodine.github.io/).
|
|
154
186
|
|
|
155
|
-
# PING-Mapper is part of the
|
|
156
|
-
|
|
187
|
+
# PING-Mapper is part of the PING Ecosystem
|
|
188
|
+
|
|
157
189
|
|
|
158
|
-
|
|
190
|
+
PINGMapper is developed and distributed alongside companion PING tools (PINGInstaller, PINGWizard, and PINGVerter) to provide a complete end-to-end workflow.
|
|
159
191
|
|
|
192
|
+
PINGMapper also leverages components from the Doodleverse ecosystem for geoscientific image segmentation workflows. Learn more on [GitHub](https://github.com/Doodleverse).
|
|
193
|
+
|
|
194
|
+

|
|
160
195
|
|
|
@@ -1981,26 +1981,34 @@ class portstarObj(object):
|
|
|
1981
1981
|
|
|
1982
1982
|
# If sides diverge strongly, invalidate the side farther from
|
|
1983
1983
|
# instrument depth so interpolation can recover continuity.
|
|
1984
|
-
|
|
1985
|
-
|
|
1984
|
+
# Port and star may have different ping counts; only compare the
|
|
1985
|
+
# overlapping rows.
|
|
1986
|
+
min_len = min(len(portArr), len(starArr))
|
|
1987
|
+
pA = portArr[:min_len]
|
|
1988
|
+
sA = starArr[:min_len]
|
|
1989
|
+
pI = portInst[:min_len]
|
|
1990
|
+
sI = starInst[:min_len]
|
|
1991
|
+
|
|
1992
|
+
pair_valid = np.isfinite(pA) & np.isfinite(sA) & (pA > 0) & (sA > 0)
|
|
1993
|
+
diverge = pair_valid & (np.abs(pA - sA) > 5.0)
|
|
1986
1994
|
if diverge.any():
|
|
1987
|
-
portErr = np.abs(
|
|
1988
|
-
starErr = np.abs(
|
|
1995
|
+
portErr = np.abs(pA - pI)
|
|
1996
|
+
starErr = np.abs(sA - sI)
|
|
1989
1997
|
|
|
1990
|
-
inst_pair_valid = np.isfinite(
|
|
1998
|
+
inst_pair_valid = np.isfinite(pI) & (pI > 0) & np.isfinite(sI) & (sI > 0)
|
|
1991
1999
|
choose_by_inst = diverge & inst_pair_valid
|
|
1992
|
-
portFlags |= choose_by_inst & (portErr >= starErr)
|
|
1993
|
-
starFlags |= choose_by_inst & (starErr > portErr)
|
|
2000
|
+
portFlags[:min_len] |= choose_by_inst & (portErr >= starErr)
|
|
2001
|
+
starFlags[:min_len] |= choose_by_inst & (starErr > portErr)
|
|
1994
2002
|
|
|
1995
2003
|
# Fallback for rows without valid instrument depth on one/both sides.
|
|
1996
2004
|
fallback = diverge & (~inst_pair_valid)
|
|
1997
2005
|
if fallback.any():
|
|
1998
|
-
pmed = _rolling_median(
|
|
1999
|
-
smed = _rolling_median(
|
|
2000
|
-
presid = np.abs(
|
|
2001
|
-
sresid = np.abs(
|
|
2002
|
-
portFlags |= fallback & (presid >= sresid)
|
|
2003
|
-
starFlags |= fallback & (sresid > presid)
|
|
2006
|
+
pmed = _rolling_median(pA)
|
|
2007
|
+
smed = _rolling_median(sA)
|
|
2008
|
+
presid = np.abs(pA - pmed)
|
|
2009
|
+
sresid = np.abs(sA - smed)
|
|
2010
|
+
portFlags[:min_len] |= fallback & (presid >= sresid)
|
|
2011
|
+
starFlags[:min_len] |= fallback & (sresid > presid)
|
|
2004
2012
|
|
|
2005
2013
|
portArr[portFlags] = np.nan
|
|
2006
2014
|
starArr[starFlags] = np.nan
|
|
@@ -2213,6 +2213,8 @@ class rectObj(sonObj):
|
|
|
2213
2213
|
crs='EPSG:4326',
|
|
2214
2214
|
).to_crs(self.humDat['epsg'])
|
|
2215
2215
|
|
|
2216
|
+
df[x_col] = df[x_col].astype(float)
|
|
2217
|
+
df[y_col] = df[y_col].astype(float)
|
|
2216
2218
|
df.loc[need_xy, x_col] = geo.geometry.x.to_numpy()
|
|
2217
2219
|
df.loc[need_xy, y_col] = geo.geometry.y.to_numpy()
|
|
2218
2220
|
return df
|
|
@@ -20,6 +20,11 @@ REQUIRED_MODULES = [
|
|
|
20
20
|
"pingverter",
|
|
21
21
|
]
|
|
22
22
|
|
|
23
|
+
UNIT_TEST_MODULES = [
|
|
24
|
+
"pingmapper.test_dq_filter",
|
|
25
|
+
"pingmapper.test_cli_self_check",
|
|
26
|
+
]
|
|
27
|
+
|
|
23
28
|
|
|
24
29
|
def _missing_required_modules() -> list[str]:
|
|
25
30
|
"""Return required modules that fail to import."""
|
|
@@ -46,7 +51,7 @@ def run_self_check(verbose: bool = True) -> int:
|
|
|
46
51
|
|
|
47
52
|
print("Dependency import checks passed.")
|
|
48
53
|
|
|
49
|
-
suite = unittest.defaultTestLoader.
|
|
54
|
+
suite = unittest.defaultTestLoader.loadTestsFromNames(UNIT_TEST_MODULES)
|
|
50
55
|
runner = unittest.TextTestRunner(verbosity=2 if verbose else 1)
|
|
51
56
|
result = runner.run(suite)
|
|
52
57
|
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Unit tests for CLI dispatch and self-check behavior."""
|
|
2
|
+
|
|
3
|
+
import importlib
|
|
4
|
+
import sys
|
|
5
|
+
import types
|
|
6
|
+
import unittest
|
|
7
|
+
from unittest import mock
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class TestCliDispatch(unittest.TestCase):
|
|
11
|
+
"""Validate command dispatch logic in pingmapper.__main__."""
|
|
12
|
+
|
|
13
|
+
def test_main_check_dispatches_to_self_check(self):
|
|
14
|
+
cli = importlib.import_module('pingmapper.__main__')
|
|
15
|
+
|
|
16
|
+
fake_mod = types.ModuleType('pingmapper.self_check')
|
|
17
|
+
fake_run = mock.Mock(return_value=7)
|
|
18
|
+
fake_mod.run_self_check = fake_run
|
|
19
|
+
|
|
20
|
+
with mock.patch.dict(sys.modules, {'pingmapper.self_check': fake_mod}):
|
|
21
|
+
result = cli.main('check')
|
|
22
|
+
|
|
23
|
+
self.assertEqual(result, 7)
|
|
24
|
+
fake_run.assert_called_once_with(verbose=True)
|
|
25
|
+
|
|
26
|
+
def test_main_test_unit_dispatches_to_self_check(self):
|
|
27
|
+
cli = importlib.import_module('pingmapper.__main__')
|
|
28
|
+
|
|
29
|
+
fake_mod = types.ModuleType('pingmapper.self_check')
|
|
30
|
+
fake_run = mock.Mock(return_value=3)
|
|
31
|
+
fake_mod.run_self_check = fake_run
|
|
32
|
+
|
|
33
|
+
with mock.patch.dict(sys.modules, {'pingmapper.self_check': fake_mod}):
|
|
34
|
+
result = cli.main('test_unit')
|
|
35
|
+
|
|
36
|
+
self.assertEqual(result, 3)
|
|
37
|
+
fake_run.assert_called_once_with(verbose=True)
|
|
38
|
+
|
|
39
|
+
def test_main_unknown_process_returns_zero(self):
|
|
40
|
+
cli = importlib.import_module('pingmapper.__main__')
|
|
41
|
+
self.assertEqual(cli.main('not-a-command'), 0)
|
|
42
|
+
|
|
43
|
+
def test_module_sets_default_process_to_gui_when_no_args(self):
|
|
44
|
+
cli = importlib.import_module('pingmapper.__main__')
|
|
45
|
+
|
|
46
|
+
with mock.patch.object(sys, 'argv', ['python']):
|
|
47
|
+
cli = importlib.reload(cli)
|
|
48
|
+
self.assertEqual(cli.to_do, 'gui')
|
|
49
|
+
|
|
50
|
+
def test_module_uses_first_arg_as_process(self):
|
|
51
|
+
cli = importlib.import_module('pingmapper.__main__')
|
|
52
|
+
|
|
53
|
+
with mock.patch.object(sys, 'argv', ['python', 'check']):
|
|
54
|
+
cli = importlib.reload(cli)
|
|
55
|
+
self.assertEqual(cli.to_do, 'check')
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class TestSelfCheck(unittest.TestCase):
|
|
59
|
+
"""Validate dependency-check and test-run exit code behavior."""
|
|
60
|
+
|
|
61
|
+
def test_missing_required_modules_collects_only_failures(self):
|
|
62
|
+
self_check = importlib.import_module('pingmapper.self_check')
|
|
63
|
+
|
|
64
|
+
def _fake_import(name):
|
|
65
|
+
if name in {'numpy', 'pingwizard'}:
|
|
66
|
+
raise ImportError('missing')
|
|
67
|
+
return object()
|
|
68
|
+
|
|
69
|
+
with mock.patch.object(self_check.importlib, 'import_module', side_effect=_fake_import):
|
|
70
|
+
missing = self_check._missing_required_modules()
|
|
71
|
+
|
|
72
|
+
self.assertEqual(missing, ['numpy', 'pingwizard'])
|
|
73
|
+
|
|
74
|
+
def test_run_self_check_returns_1_when_dependencies_missing(self):
|
|
75
|
+
self_check = importlib.import_module('pingmapper.self_check')
|
|
76
|
+
|
|
77
|
+
with mock.patch.object(self_check, '_missing_required_modules', return_value=['numpy']):
|
|
78
|
+
code = self_check.run_self_check(verbose=False)
|
|
79
|
+
|
|
80
|
+
self.assertEqual(code, 1)
|
|
81
|
+
|
|
82
|
+
def test_run_self_check_returns_1_when_tests_fail(self):
|
|
83
|
+
self_check = importlib.import_module('pingmapper.self_check')
|
|
84
|
+
|
|
85
|
+
fake_suite = object()
|
|
86
|
+
fake_result = types.SimpleNamespace(wasSuccessful=lambda: False)
|
|
87
|
+
fake_runner = mock.Mock()
|
|
88
|
+
fake_runner.run.return_value = fake_result
|
|
89
|
+
|
|
90
|
+
with mock.patch.object(self_check, '_missing_required_modules', return_value=[]), \
|
|
91
|
+
mock.patch.object(self_check.unittest.defaultTestLoader, 'loadTestsFromNames', return_value=fake_suite) as load_mock, \
|
|
92
|
+
mock.patch.object(self_check.unittest, 'TextTestRunner', return_value=fake_runner):
|
|
93
|
+
code = self_check.run_self_check(verbose=False)
|
|
94
|
+
|
|
95
|
+
self.assertEqual(code, 1)
|
|
96
|
+
load_mock.assert_called_once_with(self_check.UNIT_TEST_MODULES)
|
|
97
|
+
fake_runner.run.assert_called_once_with(fake_suite)
|
|
98
|
+
|
|
99
|
+
def test_run_self_check_returns_0_when_tests_pass(self):
|
|
100
|
+
self_check = importlib.import_module('pingmapper.self_check')
|
|
101
|
+
|
|
102
|
+
fake_suite = object()
|
|
103
|
+
fake_result = types.SimpleNamespace(wasSuccessful=lambda: True)
|
|
104
|
+
fake_runner = mock.Mock()
|
|
105
|
+
fake_runner.run.return_value = fake_result
|
|
106
|
+
|
|
107
|
+
with mock.patch.object(self_check, '_missing_required_modules', return_value=[]), \
|
|
108
|
+
mock.patch.object(self_check.unittest.defaultTestLoader, 'loadTestsFromNames', return_value=fake_suite) as load_mock, \
|
|
109
|
+
mock.patch.object(self_check.unittest, 'TextTestRunner', return_value=fake_runner):
|
|
110
|
+
code = self_check.run_self_check(verbose=False)
|
|
111
|
+
|
|
112
|
+
self.assertEqual(code, 0)
|
|
113
|
+
load_mock.assert_called_once_with(self_check.UNIT_TEST_MODULES)
|
|
114
|
+
fake_runner.run.assert_called_once_with(fake_suite)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == '__main__':
|
|
118
|
+
unittest.main()
|
|
@@ -199,5 +199,204 @@ class TestDQFilterEventStateBlocks(unittest.TestCase):
|
|
|
199
199
|
self.assertEqual(kept, [2, 3, 6])
|
|
200
200
|
|
|
201
201
|
|
|
202
|
+
class TestDQFilterValidation(unittest.TestCase):
|
|
203
|
+
"""Input validation and parsing error cases for DQ filtering."""
|
|
204
|
+
|
|
205
|
+
def test_missing_dq_time_field_raises(self):
|
|
206
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}])
|
|
207
|
+
path = _dq_csv([{'ts': 1.0, 'flag': 'Use'}])
|
|
208
|
+
|
|
209
|
+
with self.assertRaisesRegex(ValueError, 'dq_time_field is required'):
|
|
210
|
+
stub._filterDQ(
|
|
211
|
+
stub.sonMetaDF,
|
|
212
|
+
dq_table=path,
|
|
213
|
+
dq_time_field='',
|
|
214
|
+
dq_flag_field='flag',
|
|
215
|
+
dq_keep_values=['Use'],
|
|
216
|
+
dq_src_utc_offset=0.0,
|
|
217
|
+
dq_target_utc_offset=0.0,
|
|
218
|
+
dq_time_offset=0.0,
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
def test_missing_dq_flag_field_raises(self):
|
|
222
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}])
|
|
223
|
+
path = _dq_csv([{'ts': 1.0, 'flag': 'Use'}])
|
|
224
|
+
|
|
225
|
+
with self.assertRaisesRegex(ValueError, 'dq_flag_field is required'):
|
|
226
|
+
stub._filterDQ(
|
|
227
|
+
stub.sonMetaDF,
|
|
228
|
+
dq_table=path,
|
|
229
|
+
dq_time_field='ts',
|
|
230
|
+
dq_flag_field='',
|
|
231
|
+
dq_keep_values=['Use'],
|
|
232
|
+
dq_src_utc_offset=0.0,
|
|
233
|
+
dq_target_utc_offset=0.0,
|
|
234
|
+
dq_time_offset=0.0,
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
def test_missing_required_csv_column_raises(self):
|
|
238
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}])
|
|
239
|
+
path = _dq_csv([{'ts': 1.0, 'not_flag': 'Use'}])
|
|
240
|
+
|
|
241
|
+
with self.assertRaisesRegex(ValueError, 'dqLog missing required column'):
|
|
242
|
+
stub._filterDQ(
|
|
243
|
+
stub.sonMetaDF,
|
|
244
|
+
dq_table=path,
|
|
245
|
+
dq_time_field='ts',
|
|
246
|
+
dq_flag_field='flag',
|
|
247
|
+
dq_keep_values=['Use'],
|
|
248
|
+
dq_src_utc_offset=0.0,
|
|
249
|
+
dq_target_utc_offset=0.0,
|
|
250
|
+
dq_time_offset=0.0,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def test_timestamp_type_mismatch_raises(self):
|
|
254
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}, {'time_s': 3.0}])
|
|
255
|
+
path = _dq_csv([{'ts': '2024-01-01T00:00:00Z', 'flag': 'Use'}])
|
|
256
|
+
|
|
257
|
+
with self.assertRaisesRegex(ValueError, 'timestamp type'):
|
|
258
|
+
stub._filterDQ(
|
|
259
|
+
stub.sonMetaDF,
|
|
260
|
+
dq_table=path,
|
|
261
|
+
dq_time_field='ts',
|
|
262
|
+
dq_flag_field='flag',
|
|
263
|
+
dq_keep_values=['Use'],
|
|
264
|
+
dq_src_utc_offset=0.0,
|
|
265
|
+
dq_target_utc_offset=0.0,
|
|
266
|
+
dq_time_offset=0.0,
|
|
267
|
+
)
|
|
268
|
+
|
|
269
|
+
def test_empty_keep_values_raise(self):
|
|
270
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}])
|
|
271
|
+
path = _dq_csv([{'ts': 1.0, 'flag': 'Use'}])
|
|
272
|
+
|
|
273
|
+
with self.assertRaisesRegex(ValueError, 'dq_keep_values must contain at least one value'):
|
|
274
|
+
stub._filterDQ(
|
|
275
|
+
stub.sonMetaDF,
|
|
276
|
+
dq_table=path,
|
|
277
|
+
dq_time_field='ts',
|
|
278
|
+
dq_flag_field='flag',
|
|
279
|
+
dq_keep_values=[],
|
|
280
|
+
dq_src_utc_offset=0.0,
|
|
281
|
+
dq_target_utc_offset=0.0,
|
|
282
|
+
dq_time_offset=0.0,
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
class TestDQKeepValueNormalization(unittest.TestCase):
|
|
287
|
+
"""Normalization of dq_keep_values and DQ flag values."""
|
|
288
|
+
|
|
289
|
+
def test_keep_values_normalize_case_and_whitespace(self):
|
|
290
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}, {'time_s': 3.0}])
|
|
291
|
+
path = _dq_csv([
|
|
292
|
+
{'ts': 1.5, 'flag': ' usE '},
|
|
293
|
+
])
|
|
294
|
+
|
|
295
|
+
result = stub._filterDQ(
|
|
296
|
+
stub.sonMetaDF,
|
|
297
|
+
dq_table=path,
|
|
298
|
+
dq_time_field='ts',
|
|
299
|
+
dq_flag_field='flag',
|
|
300
|
+
dq_keep_values=' use , keep ',
|
|
301
|
+
dq_src_utc_offset=0.0,
|
|
302
|
+
dq_target_utc_offset=0.0,
|
|
303
|
+
dq_time_offset=0.0,
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
kept = list(result[result['filter_dq'] == True].index)
|
|
307
|
+
self.assertEqual(kept, [1, 2])
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
class TestDQUtcOffsetValidation(unittest.TestCase):
|
|
311
|
+
"""Validation around UTC offset parameters for datetime DQ logs."""
|
|
312
|
+
|
|
313
|
+
def test_setting_only_one_utc_offset_raises(self):
|
|
314
|
+
stub = _make_stub([
|
|
315
|
+
{'date': '2024-01-01', 'time': '00:00:01', 'time_s': 1.0},
|
|
316
|
+
{'date': '2024-01-01', 'time': '00:00:02', 'time_s': 2.0},
|
|
317
|
+
])
|
|
318
|
+
path = _dq_csv([
|
|
319
|
+
{'ts': '2024-01-01 00:00:00', 'flag': 'Use'},
|
|
320
|
+
])
|
|
321
|
+
|
|
322
|
+
with self.assertRaisesRegex(ValueError, 'must both be provided'):
|
|
323
|
+
stub._filterDQ(
|
|
324
|
+
stub.sonMetaDF,
|
|
325
|
+
dq_table=path,
|
|
326
|
+
dq_time_field='ts',
|
|
327
|
+
dq_flag_field='flag',
|
|
328
|
+
dq_keep_values=['Use'],
|
|
329
|
+
dq_src_utc_offset=0.0,
|
|
330
|
+
dq_target_utc_offset=None,
|
|
331
|
+
dq_time_offset=0.0,
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
def test_non_numeric_utc_offset_raises(self):
|
|
335
|
+
stub = _make_stub([
|
|
336
|
+
{'date': '2024-01-01', 'time': '00:00:01', 'time_s': 1.0},
|
|
337
|
+
{'date': '2024-01-01', 'time': '00:00:02', 'time_s': 2.0},
|
|
338
|
+
])
|
|
339
|
+
path = _dq_csv([
|
|
340
|
+
{'ts': '2024-01-01 00:00:00', 'flag': 'Use'},
|
|
341
|
+
])
|
|
342
|
+
|
|
343
|
+
with self.assertRaisesRegex(ValueError, 'must be a numeric UTC offset'):
|
|
344
|
+
stub._filterDQ(
|
|
345
|
+
stub.sonMetaDF,
|
|
346
|
+
dq_table=path,
|
|
347
|
+
dq_time_field='ts',
|
|
348
|
+
dq_flag_field='flag',
|
|
349
|
+
dq_keep_values=['Use'],
|
|
350
|
+
dq_src_utc_offset='east',
|
|
351
|
+
dq_target_utc_offset=0.0,
|
|
352
|
+
dq_time_offset=0.0,
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
class TestDQEventBoundaries(unittest.TestCase):
|
|
357
|
+
"""Boundary behavior around event timestamps and duplicate event rows."""
|
|
358
|
+
|
|
359
|
+
def test_ping_exactly_at_event_time_kept(self):
|
|
360
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}, {'time_s': 3.0}])
|
|
361
|
+
path = _dq_csv([
|
|
362
|
+
{'ts': 2.0, 'flag': 'Use'},
|
|
363
|
+
])
|
|
364
|
+
|
|
365
|
+
result = stub._filterDQ(
|
|
366
|
+
stub.sonMetaDF,
|
|
367
|
+
dq_table=path,
|
|
368
|
+
dq_time_field='ts',
|
|
369
|
+
dq_flag_field='flag',
|
|
370
|
+
dq_keep_values=['Use'],
|
|
371
|
+
dq_src_utc_offset=0.0,
|
|
372
|
+
dq_target_utc_offset=0.0,
|
|
373
|
+
dq_time_offset=0.0,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
kept = list(result[result['filter_dq'] == True].index)
|
|
377
|
+
self.assertEqual(kept, [1, 2])
|
|
378
|
+
|
|
379
|
+
def test_duplicate_event_timestamp_last_row_wins(self):
|
|
380
|
+
stub = _make_stub([{'time_s': 1.0}, {'time_s': 2.0}, {'time_s': 3.0}])
|
|
381
|
+
path = _dq_csv([
|
|
382
|
+
{'ts': 2.0, 'flag': 'Use'},
|
|
383
|
+
{'ts': 2.0, 'flag': 'NoUse'},
|
|
384
|
+
])
|
|
385
|
+
|
|
386
|
+
result = stub._filterDQ(
|
|
387
|
+
stub.sonMetaDF,
|
|
388
|
+
dq_table=path,
|
|
389
|
+
dq_time_field='ts',
|
|
390
|
+
dq_flag_field='flag',
|
|
391
|
+
dq_keep_values=['Use'],
|
|
392
|
+
dq_src_utc_offset=0.0,
|
|
393
|
+
dq_target_utc_offset=0.0,
|
|
394
|
+
dq_time_offset=0.0,
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
kept = list(result[result['filter_dq'] == True].index)
|
|
398
|
+
self.assertEqual(kept, [])
|
|
399
|
+
|
|
400
|
+
|
|
202
401
|
if __name__ == '__main__':
|
|
203
402
|
unittest.main()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '5.4.8'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pingmapper
|
|
3
|
-
Version: 5.4.
|
|
3
|
+
Version: 5.4.8
|
|
4
4
|
Summary: Open-source interface for processing recreation-grade side scan sonar datasets and reproducibly mapping benthic habitat
|
|
5
5
|
Author: Cameron Bodine, Daniel Buscombe, Iury T Simoes-Sousa
|
|
6
6
|
Author-email: bodine.cs@gmail.email
|
|
@@ -69,6 +69,15 @@ Dynamic: requires-python
|
|
|
69
69
|
|
|
70
70
|
`PINGMapper` is an open-source Python interface for reading and processing side scan sonar datasets and reproducibly mapping benthic habitat features. `PINGMapper` transforms recreation-grade sonar systems (i.e. fishfinders) into scientific data collectors, allowing researchers and citizens alike to reproducibly map their aquatic system with minimal expertise in data processing.
|
|
71
71
|
|
|
72
|
+
## PING Ecosystem
|
|
73
|
+
|
|
74
|
+
`PINGMapper` is part of the [**PING Ecosystem**](https://github.com/PINGEcosystem): a coordinated set of tools for installation, conversion, quality checks, and mapping workflows.
|
|
75
|
+
|
|
76
|
+
- [PINGMapper](https://github.com/CameronBodine/PINGMapper): Core sonar processing and mapping package
|
|
77
|
+
- [PINGInstaller](https://github.com/CameronBodine/PINGInstaller): Recommended installer and environment bootstrap
|
|
78
|
+
- [PINGWizard](https://github.com/CameronBodine/PINGWizard): Point-and-click interface for testing, updates, and routine processing
|
|
79
|
+
- [PINGVerter](https://github.com/CameronBodine/PINGVerter): Sonar data conversion utilities
|
|
80
|
+
|
|
72
81
|
## Learn More Now!
|
|
73
82
|
Check out PING-Mapper's [website](https://cameronbodine.github.io/PINGMapper/) for most up to date information:
|
|
74
83
|
|
|
@@ -128,7 +137,7 @@ A manuscript detailing the automated substrate mapping features made availabe in
|
|
|
128
137
|
|
|
129
138
|
### v3.0 - 4.0
|
|
130
139
|
|
|
131
|
-
Continued support for PINGMapper and tools in the [PING Ecosystem](
|
|
140
|
+
Continued support for PINGMapper and tools in the [PING Ecosystem](#ping-ecosystem) is made possible through mentorship, partnerships, and financial support listed below.
|
|
132
141
|
|
|
133
142
|
**Primary Developer:** [Dr. Cameron S. Bodine](https://github.com/CameronBodine)
|
|
134
143
|
|
|
@@ -142,7 +151,24 @@ Continued support for PINGMapper and tools in the [PING Ecosystem](./docs/PINGEc
|
|
|
142
151
|
|
|
143
152
|
## Quick Start
|
|
144
153
|
|
|
145
|
-
|
|
154
|
+
Recommended workflow: install Miniforge, use PINGInstaller to set up the `ping` environment, and launch PINGWizard for testing, updates, and routine processing.
|
|
155
|
+
|
|
156
|
+
### Recommended: Miniforge + PINGInstaller + PINGWizard
|
|
157
|
+
|
|
158
|
+
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions. In short:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
pip install pinginstaller -U
|
|
162
|
+
python -m pinginstaller
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
After installation completes, launch PINGWizard using the shortcut created by PINGInstaller, or run:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
conda run -n ping python -m pingwizard
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Alternative: Direct conda environment
|
|
146
172
|
|
|
147
173
|
Please see [Getting Started](https://cameronbodine.github.io/PINGMapper/docs/gettingstarted) for full instructions, or simply run:
|
|
148
174
|
|
|
@@ -152,9 +178,9 @@ conda activate ping
|
|
|
152
178
|
python -m pingmapper gui
|
|
153
179
|
```
|
|
154
180
|
|
|
155
|
-
###
|
|
181
|
+
### Optional: Pixi
|
|
156
182
|
|
|
157
|
-
[Pixi](https://pixi.sh)
|
|
183
|
+
[Pixi](https://pixi.sh) is available for users who prefer that workflow, but it is not the recommended installation path.
|
|
158
184
|
|
|
159
185
|
1. [Install pixi](https://pixi.sh)
|
|
160
186
|
2. Clone and run:
|
|
@@ -170,12 +196,18 @@ python -m pingmapper gui
|
|
|
170
196
|
|
|
171
197
|
### Verify Installation
|
|
172
198
|
|
|
173
|
-
|
|
199
|
+
Recommended routine verification is to run the included tests from PINGWizard. If you want a prompt-based check, run the lightweight self-check below:
|
|
174
200
|
|
|
175
201
|
```bash
|
|
176
202
|
python -m pingmapper check
|
|
177
203
|
```
|
|
178
204
|
|
|
205
|
+
Direct unit-test invocation (same lightweight suite run by `check`):
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
python -m unittest pingmapper.test_dq_filter pingmapper.test_cli_self_check -v
|
|
209
|
+
```
|
|
210
|
+
|
|
179
211
|
Optional longer end-to-end processing validation:
|
|
180
212
|
|
|
181
213
|
```bash
|
|
@@ -190,9 +222,12 @@ Follow the installation and testing instructions to [Get Started!](https://camer
|
|
|
190
222
|
|
|
191
223
|
If you are interested in partnering on future developments, please reach out to [Cameron Bodine](https://cameronbodine.github.io/).
|
|
192
224
|
|
|
193
|
-
# PING-Mapper is part of the
|
|
194
|
-
|
|
225
|
+
# PING-Mapper is part of the PING Ecosystem
|
|
226
|
+
|
|
195
227
|
|
|
196
|
-
|
|
228
|
+
PINGMapper is developed and distributed alongside companion PING tools (PINGInstaller, PINGWizard, and PINGVerter) to provide a complete end-to-end workflow.
|
|
197
229
|
|
|
230
|
+
PINGMapper also leverages components from the Doodleverse ecosystem for geoscientific image segmentation workflows. Learn more on [GitHub](https://github.com/Doodleverse).
|
|
231
|
+
|
|
232
|
+

|
|
198
233
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '5.4.6'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/avg_predictions_Mussel_WBL.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/DRAFT_Workflows/testEXAMPLE_mosaic_logit.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{pingmapper-5.4.6 → pingmapper-5.4.8}/pingmapper/utils/Substrate_Summaries/03_gen_summary_shp.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|