pymast 0.0.6__py3-none-any.whl → 1.0.1__py3-none-any.whl
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.
- pymast/__init__.py +31 -2
- pymast/fish_history.py +59 -6
- pymast/formatter.py +886 -548
- pymast/logger.py +58 -0
- pymast/naive_bayes.py +116 -9
- pymast/overlap_removal.py +2327 -490
- pymast/parsers.py +1091 -208
- pymast/predictors.py +302 -116
- pymast/radio_project.py +1382 -512
- pymast/validation.py +224 -0
- pymast-1.0.1.dist-info/METADATA +636 -0
- pymast-1.0.1.dist-info/RECORD +15 -0
- {pymast-0.0.6.dist-info → pymast-1.0.1.dist-info}/WHEEL +1 -1
- pymast/table_merge.py +0 -154
- pymast-0.0.6.dist-info/METADATA +0 -19
- pymast-0.0.6.dist-info/RECORD +0 -14
- {pymast-0.0.6.dist-info → pymast-1.0.1.dist-info/licenses}/LICENSE.txt +0 -0
- {pymast-0.0.6.dist-info → pymast-1.0.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,636 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pymast
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Movement Analysis Software for Telemetry (MAST) - False positive removal and movement analysis for radio telemetry data
|
|
5
|
+
Author: Theodore Castro-Santos
|
|
6
|
+
Author-email: "Kevin P. Nebiolo" <kevin.nebiolo@kleinschmidtgroup.com>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/knebiolo/mast
|
|
9
|
+
Project-URL: Documentation, https://github.com/knebiolo/mast/blob/main/README.md
|
|
10
|
+
Project-URL: Repository, https://github.com/knebiolo/mast
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/knebiolo/mast/issues
|
|
12
|
+
Keywords: telemetry,radio-tracking,fish,wildlife,movement-ecology,false-positive
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE.txt
|
|
24
|
+
Requires-Dist: numpy>=1.20.0
|
|
25
|
+
Requires-Dist: pandas>=1.3.0
|
|
26
|
+
Requires-Dist: matplotlib>=3.4.0
|
|
27
|
+
Requires-Dist: statsmodels>=0.12.0
|
|
28
|
+
Requires-Dist: networkx>=2.5
|
|
29
|
+
Requires-Dist: scipy>=1.7.1
|
|
30
|
+
Requires-Dist: scikit-learn>=0.24.0
|
|
31
|
+
Requires-Dist: h5py>=3.0.0
|
|
32
|
+
Requires-Dist: dask>=2021.3.0
|
|
33
|
+
Requires-Dist: dask-ml>=1.9.0
|
|
34
|
+
Requires-Dist: distributed>=2021.3.0
|
|
35
|
+
Requires-Dist: numba>=0.53.0
|
|
36
|
+
Requires-Dist: tables>=3.8.0
|
|
37
|
+
Requires-Dist: intervaltree>=3.1.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
41
|
+
Requires-Dist: black; extra == "dev"
|
|
42
|
+
Requires-Dist: flake8; extra == "dev"
|
|
43
|
+
Requires-Dist: sphinx; extra == "dev"
|
|
44
|
+
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
|
45
|
+
Dynamic: license-file
|
|
46
|
+
|
|
47
|
+
# PyMAST - Movement Analysis Software for Telemetry
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<img src="pymast_logo.png" alt="PyMAST Logo" width="400"/>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"/></a>
|
|
55
|
+
<a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="Python 3.8+"/></a>
|
|
56
|
+
</p>
|
|
57
|
+
|
|
58
|
+
**PyMAST** (Movement Analysis Software for Telemetry) is a Python toolkit for processing, analyzing, and modeling radio telemetry data. From data import to statistical model export, PyMAST provides a complete solution for aquatic telemetry studies.
|
|
59
|
+
|
|
60
|
+
## Key Features
|
|
61
|
+
|
|
62
|
+
- **Multi-Manufacturer Support** - Import from Lotek (SRX600/800/1200), Orion, ARES, and VR2 receivers
|
|
63
|
+
- **Automated Classification** - Naive Bayes classifier removes false positives
|
|
64
|
+
- **Bout Detection** - DBSCAN clustering identifies continuous presence periods
|
|
65
|
+
- **Overlap Resolution** - Signal quality comparison resolves spatial ambiguity
|
|
66
|
+
- **Movement Filtering** - Adjacency filter removes impossible transitions
|
|
67
|
+
- **Statistical Export** - CJS, LRDR, and Time-to-Event formats for Program MARK/R
|
|
68
|
+
- **HDF5 Database** - Fast queries and efficient storage for large datasets
|
|
69
|
+
- **Comprehensive Documentation** - All modules accessible via Python `help()` system
|
|
70
|
+
- **Visualization Suite** - Network graphs, bout distributions, overlap analysis, 3D fish tracks
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
**New users: Start with [GETTING_STARTED.md](GETTING_STARTED.md) for a complete walkthrough.**
|
|
77
|
+
|
|
78
|
+
### Installation
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install pymast
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or from source:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
cd mast
|
|
88
|
+
pip install -e .
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 30-Second Example
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from pymast.radio_project import radio_project
|
|
95
|
+
import pandas as pd
|
|
96
|
+
|
|
97
|
+
# Initialize project
|
|
98
|
+
proj = radio_project(
|
|
99
|
+
project_dir='C:/my_study',
|
|
100
|
+
db_name='study.h5',
|
|
101
|
+
tag_list=pd.read_csv('tags.csv'),
|
|
102
|
+
rec_list=pd.read_csv('receivers.csv')
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Import receiver data
|
|
106
|
+
proj.import_data(
|
|
107
|
+
file_name='receiver_001.csv',
|
|
108
|
+
receiver_make='srx1200',
|
|
109
|
+
rec_id='REC001',
|
|
110
|
+
scan_time=2.5,
|
|
111
|
+
channels=1
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Process and analyze
|
|
115
|
+
proj.make_recaptures_table()
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
See [GETTING_STARTED.md](GETTING_STARTED.md) for complete workflows.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Documentation
|
|
123
|
+
|
|
124
|
+
| Document | Description |
|
|
125
|
+
|----------|-------------|
|
|
126
|
+
| **[GETTING_STARTED.md](GETTING_STARTED.md)** | **Start here!** Complete setup guide |
|
|
127
|
+
| [ARCHITECTURE.md](ARCHITECTURE.md) | System design, database structure, workflow |
|
|
128
|
+
| [docs/TUTORIAL.md](docs/TUTORIAL.md) | Step-by-step analysis examples |
|
|
129
|
+
| [docs/API_REFERENCE.md](docs/API_REFERENCE.md) | Detailed function documentation |
|
|
130
|
+
| [CHANGELOG.md](CHANGELOG.md) | Version history and updates |
|
|
131
|
+
|
|
132
|
+
### In-Code Documentation
|
|
133
|
+
|
|
134
|
+
All modules support Python's `help()` system:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import pymast
|
|
138
|
+
help(pymast.parsers) # Module overview
|
|
139
|
+
help(pymast.overlap_removal.bout) # Class documentation
|
|
140
|
+
help(pymast.naive_bayes.calculate_likelihood) # Function details
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## System Architecture
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Raw receiver files
|
|
149
|
+
-> Parsers (HDF5 import)
|
|
150
|
+
-> Classification (false positive removal)
|
|
151
|
+
-> Recaptures (link detections to locations)
|
|
152
|
+
-> Bout detection (presence periods)
|
|
153
|
+
-> Overlap resolution (multi-receiver conflicts)
|
|
154
|
+
-> Adjacency filter (movement constraints)
|
|
155
|
+
-> Formatter (CJS/LRDR/TTE)
|
|
156
|
+
-> Program MARK / R analysis
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for details.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## System Requirements
|
|
164
|
+
|
|
165
|
+
- **Python**: 3.8 or higher
|
|
166
|
+
- **RAM**: 8+ GB recommended for large datasets
|
|
167
|
+
- **Storage**: HDF5 database typically 20-50% of raw data size
|
|
168
|
+
- **Disk Space**: 10+ GB for large projects with beacon tags
|
|
169
|
+
- **Operating System**: Windows, macOS, or Linux
|
|
170
|
+
|
|
171
|
+
### Required Input Files
|
|
172
|
+
|
|
173
|
+
MAST requires three CSV files to initialize a project:
|
|
174
|
+
|
|
175
|
+
#### 1. Master Tag File (`tblMasterTag.csv`)
|
|
176
|
+
|
|
177
|
+
| Field | Type | Required | Description |
|
|
178
|
+
|------------|----------|----------|------------------------------------------------|
|
|
179
|
+
| freq_code | string | Yes | Unique frequency-code combination |
|
|
180
|
+
| pulse_rate | float | Yes | Seconds between tag pulses |
|
|
181
|
+
| tag_type | string | Yes | 'study', 'BEACON', or 'TEST' |
|
|
182
|
+
| rel_date | datetime | Yes | Release date and time (YYYY-MM-DD HH:MM:SS) |
|
|
183
|
+
| rel_loc | string | Yes | Release location |
|
|
184
|
+
| cap_loc | string | Yes | Capture location |
|
|
185
|
+
| mort_rate | float | No | Mortality pulse rate (if equipped) |
|
|
186
|
+
| length | int | No | Fish length (mm) |
|
|
187
|
+
| weight | float | No | Fish weight (g) |
|
|
188
|
+
| species | string | No | Species name |
|
|
189
|
+
| sex | string | No | 'M' or 'F' |
|
|
190
|
+
|
|
191
|
+
**Example:**
|
|
192
|
+
```csv
|
|
193
|
+
freq_code,pulse_rate,tag_type,rel_date,rel_loc,cap_loc,length,species
|
|
194
|
+
164.123 45,3.0,study,2024-05-15 08:30:00,Release Site 1,Capture Site A,450,Atlantic Salmon
|
|
195
|
+
164.234 12,5.0,BEACON,2024-05-01 00:00:00,Beacon Location,Beacon Location,NA,NA
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### 2. Master Receiver File (`tblMasterReceiver.csv`)
|
|
199
|
+
|
|
200
|
+
| Field | Type | Required | Description |
|
|
201
|
+
|----------|--------|----------|-----------------------------------------------|
|
|
202
|
+
| rec_id | string | Yes | Unique receiver identifier |
|
|
203
|
+
| rec_type | string | Yes | 'srx600', 'srx800', 'srx1200', 'orion', 'ares', 'VR2' |
|
|
204
|
+
| node | string | Yes | Network node identifier |
|
|
205
|
+
| name | string | No | Common name for receiver location |
|
|
206
|
+
|
|
207
|
+
**Example:**
|
|
208
|
+
```csv
|
|
209
|
+
rec_id,rec_type,node,name
|
|
210
|
+
R01,srx800,N01,Downstream Array
|
|
211
|
+
R02,srx800,N02,Fishway Entrance
|
|
212
|
+
R03,orion,N03,Upstream Release
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
#### 3. Nodes File (`tblNodes.csv`)
|
|
216
|
+
|
|
217
|
+
| Field | Type | Required | Description |
|
|
218
|
+
|-------|--------|----------|--------------------------------------|
|
|
219
|
+
| node | string | Yes | Unique node identifier (matches receivers) |
|
|
220
|
+
| reach | string | No | Common name for river reach |
|
|
221
|
+
| X | int | Yes | Arbitrary X coordinate for visualization |
|
|
222
|
+
| Y | int | Yes | Arbitrary Y coordinate for visualization |
|
|
223
|
+
|
|
224
|
+
**Note:** Use arbitrary coordinates for visualization, not actual lat/lon. This creates clearer network diagrams for sinuous river systems.
|
|
225
|
+
|
|
226
|
+
**Example:**
|
|
227
|
+
```csv
|
|
228
|
+
node,reach,X,Y
|
|
229
|
+
N01,Lower River,100,100
|
|
230
|
+
N02,Fishway,200,150
|
|
231
|
+
N03,Upper River,300,200
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Project Directory Structure
|
|
235
|
+
|
|
236
|
+
When you create a project, MAST automatically creates this structure:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
your_project/
|
|
240
|
+
Data/
|
|
241
|
+
tblMasterTag.csv
|
|
242
|
+
tblMasterReceiver.csv
|
|
243
|
+
tblNodes.csv
|
|
244
|
+
Training_Files/
|
|
245
|
+
[raw receiver files]
|
|
246
|
+
Output/
|
|
247
|
+
Figures/
|
|
248
|
+
recaptures.csv
|
|
249
|
+
your_database.h5
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
## Workflow Steps
|
|
255
|
+
|
|
256
|
+
### 1. Project Initialization
|
|
257
|
+
|
|
258
|
+
```python
|
|
259
|
+
from pymast.radio_project import radio_project
|
|
260
|
+
import pandas as pd
|
|
261
|
+
import os
|
|
262
|
+
|
|
263
|
+
project_dir = r"C:\MyProject"
|
|
264
|
+
db_name = 'my_study'
|
|
265
|
+
|
|
266
|
+
# Load input files
|
|
267
|
+
tags = pd.read_csv(os.path.join(project_dir, 'tblMasterTag.csv'))
|
|
268
|
+
receivers = pd.read_csv(os.path.join(project_dir, 'tblMasterReceiver.csv'))
|
|
269
|
+
nodes = pd.read_csv(os.path.join(project_dir, 'tblNodes.csv'))
|
|
270
|
+
|
|
271
|
+
# Create project (detection_count and duration are classifier parameters)
|
|
272
|
+
project = radio_project(
|
|
273
|
+
project_dir=project_dir,
|
|
274
|
+
db_name=db_name,
|
|
275
|
+
detection_count=5, # Number of detections in detection history window
|
|
276
|
+
duration=1, # Duration (minutes) for noise ratio calculation
|
|
277
|
+
tag_data=tags,
|
|
278
|
+
receiver_data=receivers,
|
|
279
|
+
nodes_data=nodes
|
|
280
|
+
)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 2. Import Raw Data
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
# Import data from one receiver
|
|
287
|
+
project.telem_data_import(
|
|
288
|
+
rec_id='R01', # Receiver ID from tblMasterReceiver
|
|
289
|
+
rec_type='srx800', # Receiver type
|
|
290
|
+
file_dir=os.path.join(project_dir, 'Data', 'Training_Files'),
|
|
291
|
+
db_dir=os.path.join(project_dir, f'{db_name}.h5'),
|
|
292
|
+
scan_time=1, # Channel scan time (seconds) for Orion/Ares
|
|
293
|
+
channels=1, # Number of channels for Orion/Ares
|
|
294
|
+
ant_to_rec_dict={'A0': 'R01'} # Antenna to receiver mapping
|
|
295
|
+
)
|
|
296
|
+
|
|
297
|
+
# Undo import if needed
|
|
298
|
+
# project.undo_import('R01')
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### 3. Train Classifier
|
|
302
|
+
|
|
303
|
+
Training creates a dataset of known true and false positive detections using beacon tags and miscoded detections.
|
|
304
|
+
|
|
305
|
+
```python
|
|
306
|
+
rec_id = 'R01'
|
|
307
|
+
rec_type = 'srx800'
|
|
308
|
+
|
|
309
|
+
# Get all fish detected at this receiver
|
|
310
|
+
fishes = project.get_fish(rec_id=rec_id)
|
|
311
|
+
|
|
312
|
+
# Train on each fish
|
|
313
|
+
for fish in fishes:
|
|
314
|
+
project.train(fish, rec_id)
|
|
315
|
+
|
|
316
|
+
# Generate training summary with visualization
|
|
317
|
+
project.training_summary(rec_type, site=[rec_id])
|
|
318
|
+
|
|
319
|
+
# Undo training if needed
|
|
320
|
+
# project.undo_training(rec_id)
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 4. Classify Detections
|
|
324
|
+
|
|
325
|
+
Apply the Naive Bayes classifier to identify false positives.
|
|
326
|
+
|
|
327
|
+
```python
|
|
328
|
+
project.reclassify(
|
|
329
|
+
project=project,
|
|
330
|
+
rec_id='R01',
|
|
331
|
+
rec_type='srx800',
|
|
332
|
+
threshold_ratio=1.0, # 1.0 = MAP hypothesis, >1.0 = more strict, <1.0 = less strict
|
|
333
|
+
likelihood_model=['hit_ratio', 'cons_length', 'noise_ratio', 'power', 'lag_diff']
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
# Undo classification if needed
|
|
337
|
+
# project.undo_classification('R01')
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Available Likelihood Predictors:**
|
|
341
|
+
- `hit_ratio`: Proportion of expected pulses detected
|
|
342
|
+
- `cons_length`: Maximum consecutive detections
|
|
343
|
+
- `noise_ratio`: Ratio of miscoded to correct detections
|
|
344
|
+
- `power`: Signal strength
|
|
345
|
+
- `lag_diff`: Second-order difference in detection intervals
|
|
346
|
+
|
|
347
|
+
### 5. Bout Detection (Optional)
|
|
348
|
+
|
|
349
|
+
Identify discrete presence events at receivers.
|
|
350
|
+
|
|
351
|
+
```python
|
|
352
|
+
import pymast
|
|
353
|
+
|
|
354
|
+
node = 'N01'
|
|
355
|
+
bout = pymast.bout(project, node, lag_window=2, time_limit=21600)
|
|
356
|
+
|
|
357
|
+
# Fit processes to find optimal threshold
|
|
358
|
+
threshold = bout.fit_processes()
|
|
359
|
+
|
|
360
|
+
# Calculate presences using fitted threshold
|
|
361
|
+
bout.presence(threshold)
|
|
362
|
+
|
|
363
|
+
# Or use a manual threshold (seconds)
|
|
364
|
+
# bout.presence(120)
|
|
365
|
+
|
|
366
|
+
# Undo if needed
|
|
367
|
+
# project.undo_bouts(node)
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### 6. Overlap Removal (Optional)
|
|
371
|
+
|
|
372
|
+
Remove detections from parent receivers when fish is present at nested child receivers.
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
import pymast
|
|
376
|
+
|
|
377
|
+
# Define parent:child relationships (large:small detection zones)
|
|
378
|
+
edges = [
|
|
379
|
+
('R01', 'R02'), # R01 overlaps R02
|
|
380
|
+
('R01', 'R03'), # R01 overlaps R03
|
|
381
|
+
('R02', 'R04'), # R02 overlaps R04
|
|
382
|
+
]
|
|
383
|
+
|
|
384
|
+
nodes = ['R01', 'R02', 'R03', 'R04']
|
|
385
|
+
|
|
386
|
+
# Create overlap object and apply nested doll algorithm
|
|
387
|
+
doll = pymast.overlap_reduction(nodes, edges, project)
|
|
388
|
+
doll.nested_doll()
|
|
389
|
+
|
|
390
|
+
# Alternative: unsupervised removal (uses clustering)
|
|
391
|
+
# doll.unsupervised_removal()
|
|
392
|
+
|
|
393
|
+
# Undo if needed
|
|
394
|
+
# project.undo_overlap()
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### 7. Create Recaptures Table
|
|
398
|
+
|
|
399
|
+
Compile all classified, de-overlapped detections into a final recaptures table.
|
|
400
|
+
|
|
401
|
+
```python
|
|
402
|
+
# Create and export recaptures table
|
|
403
|
+
project.make_recaptures_table(export=True)
|
|
404
|
+
|
|
405
|
+
# Output will be saved to: Output/recaptures.csv
|
|
406
|
+
|
|
407
|
+
# Undo if needed
|
|
408
|
+
# project.undo_recaptures()
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
---
|
|
412
|
+
|
|
413
|
+
## Statistical Data Formatting
|
|
414
|
+
|
|
415
|
+
### Cormack-Jolly-Seber (CJS) Format
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
from pymast.formatter import cjs_data_prep
|
|
419
|
+
|
|
420
|
+
# Define receiver to recapture occasion mapping
|
|
421
|
+
receiver_to_recap = {
|
|
422
|
+
'R01': 'R00', # Release
|
|
423
|
+
'R02': 'R01', # First recapture
|
|
424
|
+
'R03': 'R02', # Second recapture
|
|
425
|
+
'R04': 'R03', # Third recapture
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
# Create CJS formatted data
|
|
429
|
+
cjs = cjs_data_prep(
|
|
430
|
+
receiver_to_recap=receiver_to_recap,
|
|
431
|
+
project=project,
|
|
432
|
+
rel_loc='Release Site 1', # Optional filter
|
|
433
|
+
initial_recap_release=False # True if starting from first recapture
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
# Export to .inp file for Program MARK
|
|
437
|
+
cjs.input_file('my_model', project.output_dir)
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
### Competing Risks / Time-to-Event Format
|
|
441
|
+
|
|
442
|
+
```python
|
|
443
|
+
from pymast.formatter import time_to_event
|
|
444
|
+
|
|
445
|
+
# Define node to state mapping
|
|
446
|
+
node_to_state = {
|
|
447
|
+
'N01': 1, # Downstream
|
|
448
|
+
'N02': 2, # Fishway
|
|
449
|
+
'N03': 3, # Upstream
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
# Create time-to-event data
|
|
453
|
+
tte = time_to_event(
|
|
454
|
+
node_to_state=node_to_state,
|
|
455
|
+
project=project,
|
|
456
|
+
bucket_length_min=15 # Time bin size in minutes
|
|
457
|
+
)
|
|
458
|
+
|
|
459
|
+
# Export for survival analysis in R
|
|
460
|
+
tte.to_csv(os.path.join(project.output_dir, 'time_to_event.csv'))
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Visualization
|
|
466
|
+
|
|
467
|
+
### Fish Movement History
|
|
468
|
+
|
|
469
|
+
```python
|
|
470
|
+
from pymast.fish_history import fish_history
|
|
471
|
+
|
|
472
|
+
# Create fish history object
|
|
473
|
+
fh = fish_history(
|
|
474
|
+
projectDB=project.db,
|
|
475
|
+
filtered=True, # Use classified data
|
|
476
|
+
overlapping=False # Exclude overlapping detections
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
# Plot a specific fish in 3D space-time
|
|
480
|
+
fh.fish_plot('164.123 45')
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## Supported Receiver Types
|
|
486
|
+
|
|
487
|
+
| Manufacturer | Model | Code | Notes |
|
|
488
|
+
|--------------|-----------------|------------|---------------------------------|
|
|
489
|
+
| Lotek | SRX600 | `srx600` | Standard format |
|
|
490
|
+
| Lotek | SRX800 | `srx800` | Standard format |
|
|
491
|
+
| Lotek | SRX1200 | `srx1200` | Standard format |
|
|
492
|
+
| SigmaEight | Orion | `orion` | Supports multi-channel/antenna |
|
|
493
|
+
| SigmaEight | Ares | `ares` | Multiple firmware versions |
|
|
494
|
+
| Vemco | VR2 | `VR2` | Standard format |
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Scientific Background
|
|
499
|
+
|
|
500
|
+
PyMAST implements validated algorithms for radio telemetry data processing, peer-reviewed and published in *Animal Biotelemetry*:
|
|
501
|
+
|
|
502
|
+
> **Nebiolo, K.P., & Castro-Santos, T.** (2024). MAST: Movement Analysis Software for Telemetry data. Part I: the semi-automated removal of false positives from radio telemetry data. *Animal Biotelemetry*, 12(1), 11. https://doi.org/10.1186/s40317-024-00358-1
|
|
503
|
+
|
|
504
|
+
### False Positive Detection Algorithm
|
|
505
|
+
|
|
506
|
+
MAST uses a **Naive Bayes classifier** with the conditional independence assumption:
|
|
507
|
+
|
|
508
|
+
```
|
|
509
|
+
P(True|X) = P(True) * P(Xi|True)
|
|
510
|
+
P(False|X) = P(False) * P(Xi|False)
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Where X represents the vector of predictor variables. The classifier computes the posterior probability for each detection and classifies using the Maximum A Posteriori (MAP) hypothesis.
|
|
514
|
+
|
|
515
|
+
**Key Innovation:** Laplace smoothing (add-one smoothing) prevents zero probabilities for unseen feature combinations, making the classifier robust to novel detection patterns.
|
|
516
|
+
|
|
517
|
+
### Bout Detection Algorithm
|
|
518
|
+
|
|
519
|
+
Fits a **three-process broken-stick model** (piecewise exponential decay) to inter-detection intervals:
|
|
520
|
+
|
|
521
|
+
1. **Process 1**: Continuous presence (seconds to minutes)
|
|
522
|
+
2. **Process 2**: Edge milling behavior (minutes to hours)
|
|
523
|
+
3. **Process 3**: True departure and return (hours to days)
|
|
524
|
+
|
|
525
|
+
The knot locations determine threshold values for classifying detection gaps.
|
|
526
|
+
|
|
527
|
+
### Nested Doll Overlap Removal
|
|
528
|
+
|
|
529
|
+
Uses a **directed acyclic graph** (DAG) representing parent:child relationships between receivers. If a fish is present at a child receiver (small detection zone) while also detected at a parent receiver (large detection zone), the algorithm removes the overlapping parent detections.
|
|
530
|
+
|
|
531
|
+
**Analogy:** Like nested Russian dolls - if you can place an object in the innermost doll, you know it is not in the outer dolls.
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Examples
|
|
536
|
+
|
|
537
|
+
See the following for complete examples:
|
|
538
|
+
|
|
539
|
+
- **`MAST_Project.ipynb`** - Interactive Jupyter notebook with full workflow
|
|
540
|
+
- **`scripts/mast_complete_project.py`** - Python script implementation
|
|
541
|
+
- **Sample data** - Check `data/` folder for example file formats
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Contributing
|
|
546
|
+
|
|
547
|
+
We welcome contributions. Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
548
|
+
|
|
549
|
+
**Quick Development Setup:**
|
|
550
|
+
|
|
551
|
+
```bash
|
|
552
|
+
git clone https://github.com/knebiolo/mast.git
|
|
553
|
+
cd mast
|
|
554
|
+
python -m venv venv
|
|
555
|
+
venv\Scripts\activate # Windows
|
|
556
|
+
# source venv/bin/activate # macOS/Linux
|
|
557
|
+
pip install -e .
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
---
|
|
561
|
+
|
|
562
|
+
## Citation
|
|
563
|
+
|
|
564
|
+
If you use PyMAST in your research, please cite:
|
|
565
|
+
|
|
566
|
+
```bibtex
|
|
567
|
+
@article{nebiolo2024mast,
|
|
568
|
+
author = {Nebiolo, Kevin P. and Castro-Santos, Theodore},
|
|
569
|
+
title = {MAST: Movement Analysis Software for Telemetry data. Part I: the semi-automated removal of false positives from radio telemetry data},
|
|
570
|
+
journal = {Animal Biotelemetry},
|
|
571
|
+
year = {2024},
|
|
572
|
+
volume = {12},
|
|
573
|
+
number = {1},
|
|
574
|
+
pages = {11},
|
|
575
|
+
doi = {10.1186/s40317-024-00358-1},
|
|
576
|
+
url = {https://doi.org/10.1186/s40317-024-00358-1}
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Software Citation:**
|
|
581
|
+
|
|
582
|
+
```bibtex
|
|
583
|
+
@software{nebiolo2025pymast,
|
|
584
|
+
author = {Nebiolo, Kevin P. and Castro-Santos, Theodore},
|
|
585
|
+
title = {PyMAST: Movement Analysis Software for Telemetry},
|
|
586
|
+
year = {2025},
|
|
587
|
+
publisher = {GitHub},
|
|
588
|
+
url = {https://github.com/knebiolo/mast}
|
|
589
|
+
}
|
|
590
|
+
```
|
|
591
|
+
|
|
592
|
+
**Additional Key Publications:**
|
|
593
|
+
|
|
594
|
+
- Beeman, J.W., & Perry, R.W. (2012). *Bias from False-Positive Detections and Strategies for their Removal in Studies Using Telemetry.* American Fisheries Society.
|
|
595
|
+
- Sibly, R.M., Nott, H.M., & Fletcher, D.J. (1990). *Splitting Behavior into Bouts.* Animal Behavior.
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
## License
|
|
600
|
+
|
|
601
|
+
This project is licensed under the MIT License - see [LICENSE.txt](LICENSE.txt) for details.
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
## Authors and Acknowledgments
|
|
606
|
+
|
|
607
|
+
**Development Team:**
|
|
608
|
+
- **Kevin P. Nebiolo** - Lead Developer (Kleinschmidt Associates)
|
|
609
|
+
- **Theodore Castro-Santos** - Co-Developer (USGS)
|
|
610
|
+
|
|
611
|
+
**Institutional Support:**
|
|
612
|
+
- Kleinschmidt Associates
|
|
613
|
+
- U.S. Geological Survey (USGS)
|
|
614
|
+
|
|
615
|
+
**Community:**
|
|
616
|
+
- Thanks to the aquatic telemetry community for feedback and testing
|
|
617
|
+
|
|
618
|
+
---
|
|
619
|
+
|
|
620
|
+
## Support
|
|
621
|
+
|
|
622
|
+
- **Issues**: [GitHub Issues](https://github.com/knebiolo/mast/issues)
|
|
623
|
+
- **Email**: kevin.nebiolo@kleinschmidtgroup.com
|
|
624
|
+
- **Documentation**: See [CHANGELOG.md](CHANGELOG.md) for version history
|
|
625
|
+
|
|
626
|
+
---
|
|
627
|
+
|
|
628
|
+
## Additional Resources
|
|
629
|
+
|
|
630
|
+
- [HDF5 Documentation](https://www.hdfgroup.org/)
|
|
631
|
+
- [Program MARK](http://www.phidot.org/software/mark/)
|
|
632
|
+
- [R survival package](https://cran.r-project.org/web/packages/survival/)
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
Happy fish tracking!
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
pymast/__init__.py,sha256=m9EZlhddHgq9C0jKet_DhwTAdtcHl4PDMZ8uhkBaEQE,1187
|
|
2
|
+
pymast/fish_history.py,sha256=K0L6IdenGH7TxfSXs9G9oGpEJqi_EZtZUd-9AorEsm0,8494
|
|
3
|
+
pymast/formatter.py,sha256=unv3AJZK3vRJ5jXnO4SArqnCWDdrPn3Y4fpSvHwbmtI,68892
|
|
4
|
+
pymast/logger.py,sha256=V0bFw3UU-gvlAacfB3sroz_SJaTQJsqrM_BxJVkpAoE,1511
|
|
5
|
+
pymast/naive_bayes.py,sha256=hWe8fOLhQRxcRdx9FudS5TF2kEqkazmKEK-EqbPw8-s,10761
|
|
6
|
+
pymast/overlap_removal.py,sha256=bO-9USgyn2nLrEvmjdbB7e7EA2Qy0VUWUL1kewQvSxM,117272
|
|
7
|
+
pymast/parsers.py,sha256=aTHcgyn3uiEqavFRauUntcsbojjBARZv0CKDFNT2HNQ,91329
|
|
8
|
+
pymast/predictors.py,sha256=UGLSxygtwrGSmPi8qMbM1tFvgdt14SswgArY1--8KiY,12346
|
|
9
|
+
pymast/radio_project.py,sha256=Z74KXlnyoL0JDmL4R5xeO3oQqdr13wjvkDbFj6rWW1A,99295
|
|
10
|
+
pymast/validation.py,sha256=qFAsCyaD5xxZJPFxyIK9FqWxGM4f3oOw3YFQ-yyCYGU,6409
|
|
11
|
+
pymast-1.0.1.dist-info/licenses/LICENSE.txt,sha256=CX_nvzXXwOA7SPq4-ivN4Q9NIK2PfK-KGHt3ZQKldsw,1143
|
|
12
|
+
pymast-1.0.1.dist-info/METADATA,sha256=SsgJdMStBjkTW6mvKqI4r1sGfpFu-Qf6nfv1ghFXrrw,20131
|
|
13
|
+
pymast-1.0.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
14
|
+
pymast-1.0.1.dist-info/top_level.txt,sha256=LDZpLLge9zI4yvuMYoABLrsOrZzE3bYDRULmHoZQc4k,7
|
|
15
|
+
pymast-1.0.1.dist-info/RECORD,,
|