mounts-project 0.1.0__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.
@@ -0,0 +1,403 @@
1
+ Metadata-Version: 2.4
2
+ Name: mounts-project
3
+ Version: 0.1.0
4
+ Summary: Unofficial package for MOUNTS | Monitoring Unrest From Space
5
+ Keywords: volcano,volcanology,volcanoes,thermal,remote sensing
6
+ Author: Martanto
7
+ Author-email: Martanto <martanto@live.com>
8
+ License-Expression: MIT
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Dist: click>=8.0
16
+ Requires-Dist: loguru>=0.7.3
17
+ Requires-Dist: openpyxl>=3.1.5
18
+ Requires-Dist: pandas>=3.0.3
19
+ Requires-Dist: requests>=2.34.2
20
+ Requires-Dist: streamlit>=1.40 ; extra == 'dashboard'
21
+ Requires-Dist: plotly>=5.24 ; extra == 'dashboard'
22
+ Requires-Python: >=3.11
23
+ Project-URL: Homepage, https://github.com/martanto/mounts-project
24
+ Project-URL: Issues, https://github.com/martanto/mounts-project/issues
25
+ Provides-Extra: dashboard
26
+ Description-Content-Type: text/markdown
27
+
28
+ # mounts-project
29
+
30
+ ![Version](https://img.shields.io/badge/version-0.1.0-blue)
31
+ ![Python](https://img.shields.io/badge/python-3.11%2B-blue)
32
+ ![License](https://img.shields.io/badge/license-MIT-green)
33
+ ![Status](https://img.shields.io/badge/status-active%20development-orange)
34
+
35
+ Unofficial Python package
36
+ for [MOUNTS — Monitoring Unrest From Space](http://www.mounts-project.com).
37
+ Scrapes SO2 and thermal timeseries from the public MOUNTS pages and exposes them as pandas
38
+ DataFrames, ready to be written to CSV or XLSX.
39
+
40
+ <table align="center">
41
+ <tr>
42
+ <td align="center"><img src="https://raw.githubusercontent.com/martanto/mounts-project/main/assets/dashboard-1.jpg" alt="Dashboard overview" /></td>
43
+ <td align="center"><img src="https://raw.githubusercontent.com/martanto/mounts-project/main/assets/dashboard-2.jpg" alt="Dashboard detail" /></td>
44
+ </tr>
45
+ </table>
46
+
47
+ ## Disclaimer
48
+
49
+ This is an **unofficial** client and is not affiliated with the MOUNTS project. The information
50
+ presented within the MOUNTS website is provided "as is" and users bear all responsibility and
51
+ liability for their use of data and images, and for any indirect, incidental or consequential
52
+ damages arising out of any use of, or inability to use, the data.
53
+
54
+ ## Table of Contents
55
+
56
+ - [Requirements](#requirements)
57
+ - [Installation](#installation)
58
+ - [Quick Start](#quick-start)
59
+ - [Command-line interface](#command-line-interface)
60
+ - [Dashboard](#dashboard)
61
+ - [About the project](#about-the-project)
62
+ - [Publications](#publications)
63
+ - [Credits & Acknowledgements](#credits--acknowledgements)
64
+ - [Use of the data](#use-of-the-data)
65
+ - [API Reference](#api-reference)
66
+ - [`MountsProject`](#mountsprojectfilter_values01-output_dirnone-overwritefalse-verbosefalse)
67
+ - [Utility functions](#utility-functions)
68
+ - [Logging helpers](#logging-helpers)
69
+
70
+ ## Requirements
71
+
72
+ - **Python** `>=3.11`
73
+ - **uv** — Python package
74
+ manager ([installation guide](https://docs.astral.sh/uv/getting-started/installation/))
75
+
76
+ ## Installation
77
+
78
+ Install from PyPI:
79
+
80
+ ```bash
81
+ uv add mounts-project
82
+ ```
83
+
84
+ Or install the latest from GitHub:
85
+
86
+ ```bash
87
+ uv add git+https://github.com/martanto/mounts-project
88
+ ```
89
+
90
+ Or, to work on the source:
91
+
92
+ ```bash
93
+ git clone https://github.com/martanto/mounts-project
94
+ cd mounts-project
95
+ uv sync
96
+ ```
97
+
98
+ ## Quick Start
99
+
100
+ Minimal example (see [`main.py`](main.py)):
101
+
102
+ ```python
103
+ from mounts_project import MountsProject
104
+
105
+
106
+ def main():
107
+ mounts = MountsProject(verbose=True)
108
+
109
+ # Scrape every volcano in the built-in catalog
110
+ mounts.extract()
111
+
112
+ # Access the per-volcano DataFrames
113
+ data = mounts.data
114
+
115
+ # Export to ./output/xlsx/<volcano>.xlsx + ./output/all-volcanoes.xlsx
116
+ mounts.save(filetype="xlsx")
117
+
118
+
119
+ if __name__ == "__main__":
120
+ main()
121
+ ```
122
+
123
+ Run it:
124
+
125
+ ```bash
126
+ uv run python main.py
127
+ ```
128
+
129
+ The full pipeline is chainable:
130
+
131
+ ```python
132
+ MountsProject(verbose=True).extract().save(filetype="csv")
133
+ ```
134
+
135
+ Outputs land under `./output/`:
136
+
137
+ ```
138
+ output/
139
+ ├── all-volcanoes.csv
140
+ ├── csv/
141
+ │ ├── lewotobi-laki-laki.csv
142
+ │ ├── marapi.csv
143
+ │ └── ...
144
+ └── json/ # cached raw scrape; reused on subsequent runs
145
+ ├── lewotobi-laki-laki-264180.json
146
+ └── ...
147
+ ```
148
+
149
+ To monitor your own list of volcanoes instead of the built-in Indonesian catalog, pass them to
150
+ `extract()`:
151
+
152
+ ```python
153
+ volcanoes = [
154
+ {"name": "Etna", "code": "211060"},
155
+ {"name": "Stromboli", "code": "211040"},
156
+ ]
157
+ MountsProject().extract(volcanoes=volcanoes).save()
158
+ ```
159
+
160
+ ## Command-line interface
161
+
162
+ Installing the package registers a `mounts` console script:
163
+
164
+ ```bash
165
+ uv run mounts --help
166
+ uv run mounts save --help
167
+ ```
168
+
169
+ ### `mounts save`
170
+
171
+ Extract every volcano in the default catalog and write the result.
172
+
173
+ ```bash
174
+ uv run mounts save --type csv # → ./output/csv/*.csv + all-volcanoes.csv
175
+ uv run mounts save --type xlsx --output-dir data # → ./data/xlsx/*.xlsx + all-volcanoes.xlsx
176
+ uv run mounts save --overwrite -v # force re-fetch + verbose logs
177
+ ```
178
+
179
+ | Option | Default | Description |
180
+ |----------------|------------|----------------------------------------------------|
181
+ | `--type` | `csv` | Output format (`csv` or `xlsx`). |
182
+ | `--output-dir` | `./output` | Override the output directory. |
183
+ | `--overwrite` | off | Re-fetch from MOUNTS even when cached JSON exists. |
184
+ | `--verbose` | off | Emit per-volcano info logs during extraction. |
185
+
186
+ ### `mounts dashboard`
187
+
188
+ Launch the Streamlit dashboard. Any extra arguments are forwarded to
189
+ `streamlit run`:
190
+
191
+ ```bash
192
+ uv run mounts dashboard
193
+ uv run mounts dashboard --server.port 9000 --server.headless true
194
+ ```
195
+
196
+ ## Dashboard
197
+
198
+ `mounts dashboard` opens a Streamlit app that groups the extracted data by
199
+ volcano and by data type (SO2 / Thermal). Install the extras first:
200
+
201
+ ```bash
202
+ uv sync --extra dashboard
203
+ uv run mounts dashboard
204
+ ```
205
+
206
+ The dashboard reads `output/all-volcanoes.csv` from the current working
207
+ directory. If it does not exist yet, click **Refresh data** in the sidebar
208
+ or run `uv run mounts save --type csv` once to populate it.
209
+
210
+ ## About the project
211
+
212
+ MOUNTS is a project conceptualized and led by Sébastien Valade since April 2017. Its aim is
213
+ to develop an operational monitoring system for volcanoes worldwide using satellite imagery.
214
+ It currently focuses on processing of Sentinel-1 (SAR), Sentinel-2 (SWIR), and Sentinel-5P (TROPOMI)
215
+ data.
216
+ Artificial intelligence "plugins" are developed and implemented in the processing chain to assist
217
+ monitoring tasks.
218
+
219
+ The project was from April 2017 to October 2019 funded by GEO.X and carried at TU-Berlin
220
+ (Computer Vision & Remote Sensing group, Prof. O. Hellwich) and GFZ
221
+ (Physics of Earthquakes and Volcanoes section, Priv. Doz. T. Walter).
222
+ Since March 2020, the project is carried at UNAM (Instituto de Geofísica, Mexico City).
223
+ The server running both the system and website is however still hosted at CV TU-Berlin,
224
+ with the kind agreement of Prof. Hellwich.
225
+
226
+ MOUNTS is strongly inspired by the operating MIROVA system,
227
+ with which tight collaborations are ongoing.
228
+
229
+ ## Publications
230
+
231
+ ### System description and recent eruptive events
232
+
233
+ - Valade, S., Ley, A., Massimetti, F., D'Hondt, O., Laiolo, M., Coppola, D., Loibl, D., Hellwich,
234
+ O., Walter, T.R., Towards Global Volcano Monitoring Using Multisensor Sentinel Missions and
235
+ Artificial Intelligence: The MOUNTS Monitoring System, *Remote Sens.*, 2019, 11, 1528
236
+
237
+ ### Algorithm used to analyze Sentinel-2 images
238
+
239
+ - Massimetti, F., Coppola, D., Laiolo, M., Valade, S., Cigolini, C., Ripepe M., Volcanic Hot-Spot
240
+ Detection Using SENTINEL-2: A Comparison with MODIS–MIROVA Thermal Data Series, *Remote Sens.*,
241
+ 2020, 12(5), 820
242
+
243
+ ### Algorithm used to filter speckle from Sentinel-1 images
244
+
245
+ - Davis, T., Jain, V., Ley, A., D'Hondt, O., Valade, S., Hellwich, O., Reference-free despeckling of
246
+ Synthetic-Aperture Radar images using a deep convolutional network, IGARSS 2020
247
+
248
+ ### Algorithms developed to improve analysis of Sentinel-5P images
249
+
250
+ - Markus, B., Valade, S., Wöllhaf, M., Hellwich, O., Automatic retrieval of volcanic SO2 emission
251
+ source from TROPOMI products, *Front. Earth Sci.*, 2023, 10
252
+
253
+ ### Volcanological studies using data and analysis from MOUNTS (selection)
254
+
255
+ - Valade S., Coppola D., Campion R., Ley A., Boulesteix T., Taquet N., Legrand D., Laiolo M., Walter
256
+ T. R. and De la Cruz-Reyna S. Lava dome cycles reveal rise and fall of magma column at
257
+ Popocatépetl volcano, *Nature Communications*, 2023
258
+ - Coppola D., Valade S., Masias P., Laiolo M., Massimetti F., Campus A., Aguilar R., Anccasi R.,
259
+ Apaza F., Ccallata B., Cigolini C., Cruz L. F., Finizola A., Gonzales K., Macedo O., Miranda R.,
260
+ Ortega M., Paxi R., Taipe E., and Valdivia D. Shallow magma convection evidenced by excess
261
+ degassing and thermal radiation during the dome-forming sabancaya eruption (2012–2020), *Bulletin
262
+ of Volcanology*, 2022
263
+ - Burgi P.-Y., Valade, S., Coppola D., Boudoire G., Mavonga G., Rufino F., and Tedesco D.,
264
+ Unconventional filling dynamics of a pit crater, *EPSL*, 2021
265
+
266
+ ## Credits & Acknowledgements
267
+
268
+ ### Funding sources
269
+
270
+ - 2017-2019: GEO.X 2-year postdoc fundings for the bottom-up project MOUNTS
271
+ - 2019: GEO.X Seed Funding 6-months postdoc for the project MOUNTS-AI dedicated to investigating
272
+ Artificial Intelligence strategies for volcano monitoring.
273
+ - 2021-2023: PAPIIT project IA102221, 2-year project with part of the fundings dedicated to the
274
+ purchase of new hardware for MOUNTS.
275
+
276
+ ### TU-Berlin
277
+
278
+ - Andreas Ley developed and trained the convolutional neural network used by MOUNTS to detect ground
279
+ deformation from Sentinel-1 interferograms.
280
+ - Olivier D'Hondt developed the NDSAR toolkit for SAR speckle filtering used in Valade et al. (
281
+ 2019).
282
+ - Timothy Davis & Vinit Jain, under the supervision of Andreas Ley & Sébastien Valade, developed and
283
+ trained the convolutional neural network used by MOUNTS to despeckle Sentinel-1 SAR amplitude
284
+ images: Davis et al. 2020 (IGARSS).
285
+ - Manuel Wöllhaf is contributing to the development of the new backend architecture of MOUNTS. He
286
+ co-supervised Balazs Markus, whose research project focused on the automatic retrieval of volcanic
287
+ SO2 emission source from TROPOMI products (Markus et al. 2023).
288
+ - MIROVA: members of MIROVA developed the algorithm used to detect hot pixels within the Sentinel-2
289
+ SWIR bands (Massimetti et al., 2020). MIROVA is a collaborative project between the Universities
290
+ of Turin and Firenze (Italy). Developments are underway to increase the interactivity between
291
+ MOUNTS and MIROVA.
292
+ - LGS (University of Firenze): many thanks to friends and former colleagues of the Laboratorio di
293
+ Geofisica Sperimentale (LGS), from whom much was learnt. This website is inspired by the unique
294
+ interaction of research and monitoring that is achieved in this group.
295
+ - Sentinel data are freely available through ESA's Copernicus Open Access Hub, and are partially
296
+ processed with the free SNAP toolboxes. Earthquake catalogs are provided by GEOFON (GFZ Potsdam)
297
+ and USGS, and interrogated using the Pyrocko Toolbox.
298
+
299
+ ## Use of the data
300
+
301
+ The products available on the MOUNTS website are value-added products created from freely available
302
+ Sentinel data provided by ESA. The products are released under the following conditions: permission
303
+ to freely copy, share and quote for non-commercial purposes, with attribution to MOUNTS and ESA as
304
+ the original source. If used for academic purposes, contacting Sébastien Valade (
305
+ valade@igeofisica.unam.mx) and citing the above-mentioned publication (Valade et al. 2019, *Remote
306
+ Sensing*) is kindly appreciated.
307
+
308
+ ## API Reference
309
+
310
+ ### `MountsProject(filter_values=0.1, output_dir=None, overwrite=False, verbose=False)`
311
+
312
+ Orchestrator that holds the scraped data and drives the
313
+ `extract() → save()` pipeline.
314
+
315
+ **Constructor parameters**
316
+
317
+ | Parameter | Type | Default | Description |
318
+ |-----------------|-----------------|----------------|----------------------------------------------------------------------------------------------------------------------------------------|
319
+ | `filter_values` | `float \| None` | `0.1` | Lower bound applied to the `value` column after extraction. Rows with `value <= filter_values` are dropped. `None` disables filtering. |
320
+ | `output_dir` | `str \| None` | `<cwd>/output` | Root directory for cached JSON and exported CSV/XLSX files. |
321
+ | `overwrite` | `bool` | `False` | Force re-fetching from MOUNTS even when a cached JSON file exists. |
322
+ | `verbose` | `bool` | `False` | Emit per-volcano info logs during fetch. |
323
+
324
+ **Attributes**
325
+
326
+ | Attribute | Type | Description |
327
+ |------------|-------------------------------|-------------------------------------------------------------------------------|
328
+ | `data` | `dict[str, pandas.DataFrame]` | Per-volcano DataFrames keyed by volcano name. Populated by `extract()`. |
329
+ | `catalogs` | `list[dict[str, Any]]` | Per-volcano metadata: `name`, `code`, `updated_at`. Populated by `extract()`. |
330
+ | `files` | `list[str]` | Paths of files written by `save()`. |
331
+
332
+ **Methods**
333
+
334
+ #### `extract(volcanoes=None) -> Self`
335
+
336
+ Fetch timeseries for a list of volcanoes and populate `self.data` and `self.catalogs`.
337
+
338
+ | Parameter | Type | Default | Description |
339
+ |-------------|--------------------------------|------------------|------------------------------------------------------------------------------------------------------------|
340
+ | `volcanoes` | `list[dict[str, str]] \| None` | built-in catalog | List of `{"name": ..., "code": ...}` entries. When `None`, uses the bundled 12-volcano Indonesian catalog. |
341
+
342
+ Returns `self` for chaining.
343
+
344
+ #### `extract_single_volcano(name, code) -> pandas.DataFrame`
345
+
346
+ Fetch and assemble the combined SO2 + thermal DataFrame for one volcano. Used internally by
347
+ `extract()`; call it directly if you want a single DataFrame without populating `self.data`.
348
+
349
+ | Parameter | Type | Description |
350
+ |-----------|-------|---------------------------------------------------------------|
351
+ | `name` | `str` | Volcano name (used for the `name` column and cache filename). |
352
+ | `code` | `str` | MOUNTS volcano code (used in the URL and the `code` column). |
353
+
354
+ Returns a DataFrame indexed by `datetime`, with columns `value`, `graph`, `type` (`"SO2"` or
355
+ `"Thermal"`), `date`, `time`, `code`, `name`.
356
+
357
+ #### `save(filetype="csv", merge=True) -> Self`
358
+
359
+ Write per-volcano files plus a merged `all-volcanoes` export. Calls `extract()` automatically when
360
+ `self.data` is empty.
361
+
362
+ | Parameter | Type | Default | Description |
363
+ |------------|--------------------------|---------|-----------------------------------------------------------------------|
364
+ | `filetype` | `Literal["csv", "xlsx"]` | `"csv"` | Output format. |
365
+ | `merge` | `bool` | `True` | Reserved for future use; the merged file is currently always written. |
366
+
367
+ Writes:
368
+
369
+ - `<output_dir>/<filetype>/<slug>.<filetype>` per volcano
370
+ - `<output_dir>/all-volcanoes.<filetype>` (concatenated)
371
+
372
+ Returns `self` for chaining.
373
+
374
+ ### Utility functions
375
+
376
+ From `mounts_project.utils`:
377
+
378
+ | Function | Description |
379
+ |--------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------|
380
+ | `get_so2_values(graph_json)` | Extract the SO2 timeseries from a MOUNTS Plotly graph payload (`data[2]`). Returns a DataFrame with `datetime`, `value`, `graph`, `type="SO2"`. |
381
+ | `get_thermal_values(graph_json)` | Extract the thermal timeseries from a MOUNTS Plotly graph payload (`data[0]`). Returns a DataFrame with `datetime`, `value`, `graph`, `type="Thermal"`. |
382
+ | `get_json_from_javascript(response)` | Regex-extract and parse the `var graph = {...}` JavaScript blob from a MOUNTS HTTP response. Raises `ValueError` if not found. |
383
+ | `slugify(text, hyphen="-")` | Convert arbitrary text into a safe filename slug. |
384
+ | `ensure_dir(path)` | Create a directory (and any missing parents) and return it as a `pathlib.Path`. |
385
+
386
+ ### Logging helpers
387
+
388
+ The package configures [loguru](https://loguru.readthedocs.io/) on import, writing a console stream
389
+ plus daily-rotated `logs/mounts_YYYY-MM-DD.log` and `logs/errors_YYYY-MM-DD.log` files in the
390
+ current working directory.
391
+
392
+ From `mounts_project.logger`:
393
+
394
+ | Function | Description |
395
+ |------------------------------|-------------------------------------------------------------------------------------------|
396
+ | `get_logger()` | Return the package-wide loguru `logger` instance. |
397
+ | `set_log_level(level)` | Change the console log level (`"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"`, `"CRITICAL"`). |
398
+ | `set_log_directory(log_dir)` | Change where log files are written. |
399
+ | `disable_logging()` | Remove all handlers. |
400
+ | `enable_logging()` | Restore handlers after `disable_logging()`. |
401
+
402
+ Set the environment variable `DISABLE_LOGGING=1` before import to skip handler setup entirely (
403
+ useful for subprocess workers).