cryoswath 0.2.1.post4__tar.gz → 0.2.2.dev0__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.
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/.gitignore +1 -0
- cryoswath-0.2.2.dev0/.readthedocs.yaml +25 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/LICENSE.txt +2 -1
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/PKG-INFO +55 -38
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/README.md +47 -32
- cryoswath-0.2.2.dev0/cryoswath/__init__.py +22 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/cryoswath/gis.py +105 -46
- cryoswath-0.2.2.dev0/cryoswath/l1b.py +1249 -0
- cryoswath-0.2.2.dev0/cryoswath/l2.py +616 -0
- cryoswath-0.2.2.dev0/cryoswath/l3.py +548 -0
- cryoswath-0.2.2.dev0/cryoswath/l4.py +1317 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/cryoswath/misc.py +1044 -475
- cryoswath-0.2.2.dev0/cryoswath/test_plots/maps.py +65 -0
- cryoswath-0.2.2.dev0/cryoswath/test_plots/timeseries.py +71 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/conf.py +72 -7
- cryoswath-0.2.2.dev0/docs/prerequisites.rst +61 -0
- cryoswath-0.2.2.dev0/docs/requirements.in +2 -0
- cryoswath-0.2.2.dev0/docs/requirements.txt +59 -0
- cryoswath-0.2.2.dev0/docs/tests.rst +25 -0
- cryoswath-0.2.2.dev0/docs/tutorials.rst +27 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/pyproject.toml +10 -6
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/l1b_swath_start.ipynb +2 -2
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/l1b_waveform.ipynb +2 -2
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/l2_tested_data_comparison.ipynb +2 -2
- cryoswath-0.2.2.dev0/tests/test_l1b.py +25 -0
- cryoswath-0.2.1.post4/cryoswath/__init__.py +0 -6
- cryoswath-0.2.1.post4/cryoswath/l1b.py +0 -903
- cryoswath-0.2.1.post4/cryoswath/l2.py +0 -424
- cryoswath-0.2.1.post4/cryoswath/l3.py +0 -641
- cryoswath-0.2.1.post4/cryoswath/l4.py +0 -197
- cryoswath-0.2.1.post4/cryoswath/test_plots/maps.py +0 -41
- cryoswath-0.2.1.post4/cryoswath/test_plots/timeseries.py +0 -55
- cryoswath-0.2.1.post4/docs/prerequisites.rst +0 -50
- cryoswath-0.2.1.post4/docs/tests.rst +0 -15
- cryoswath-0.2.1.post4/docs/tutorials.rst +0 -23
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/.gitattributes +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/.github/ISSUE_TEMPLATE/question.md +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/cryoswath/test_plots/__init__.py +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/cryoswath/test_plots/waveform.py +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docker/Dockerfile +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/Makefile +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.gis.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.l1b.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.l2.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.l3.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.l4.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.misc.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/cryoswath.test_plots.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/getting_started.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/docs/index.rst +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/requirements.txt +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/.gitignore +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/l2_dem_comparison.ipynb +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/reference_data/L2_reference_data_20220521T110815.csv +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/reports/reference_figures/waveform_2014-05-17T22:54:51.839752960.png +0 -0
- {cryoswath-0.2.1.post4 → cryoswath-0.2.2.dev0}/tests/void_filling_results_smell_test.ipynb +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Read the Docs configuration file
|
|
2
|
+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
|
3
|
+
|
|
4
|
+
# Required
|
|
5
|
+
version: 2
|
|
6
|
+
|
|
7
|
+
# Set the OS, Python version, and other tools you might need
|
|
8
|
+
build:
|
|
9
|
+
os: ubuntu-24.04
|
|
10
|
+
tools:
|
|
11
|
+
python: "3.13"
|
|
12
|
+
|
|
13
|
+
# Build documentation in the "docs/" directory with Sphinx
|
|
14
|
+
sphinx:
|
|
15
|
+
configuration: docs/conf.py
|
|
16
|
+
|
|
17
|
+
# Optionally, but recommended,
|
|
18
|
+
# declare the Python requirements required to build your documentation
|
|
19
|
+
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
|
20
|
+
python:
|
|
21
|
+
install:
|
|
22
|
+
- requirements: docs/requirements.txt
|
|
23
|
+
- method: pip
|
|
24
|
+
path: .
|
|
25
|
+
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
|
-
Copyright (c) 2023 Delft University of Technology
|
|
2
|
+
Copyright (c) 2023-2024 Delft University of Technology
|
|
3
|
+
Copyright (c) 2024-2025 Jan Haacker
|
|
3
4
|
|
|
4
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
6
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: cryoswath
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2.dev0
|
|
4
4
|
Summary: Swath processing toolbox for CryoSat-2
|
|
5
5
|
Keywords: glacier,altimetry,swath,cryosat
|
|
6
6
|
Author-email: Jan Haacker <j.m.haacker@tudelft.nl>
|
|
@@ -9,9 +9,10 @@ Description-Content-Type: text/markdown
|
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
10
|
Classifier: Operating System :: OS Independent
|
|
11
11
|
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Requires-Dist: Bottleneck
|
|
12
13
|
Requires-Dist: dask
|
|
13
14
|
Requires-Dist: defusedxml
|
|
14
|
-
Requires-Dist: geopandas
|
|
15
|
+
Requires-Dist: geopandas>=1.0.1
|
|
15
16
|
Requires-Dist: gitpython
|
|
16
17
|
Requires-Dist: h5netcdf
|
|
17
18
|
Requires-Dist: h5py
|
|
@@ -33,20 +34,21 @@ Requires-Dist: statsmodels
|
|
|
33
34
|
Requires-Dist: tqdm
|
|
34
35
|
Requires-Dist: xarray
|
|
35
36
|
Requires-Dist: zarr
|
|
36
|
-
Requires-Dist:
|
|
37
|
+
Requires-Dist: black ; extra == "dev"
|
|
38
|
+
Requires-Dist: sphinx ; extra == "dev"
|
|
39
|
+
Requires-Dist: sphinx-rtd-theme ; extra == "dev"
|
|
37
40
|
Requires-Dist: ipykernel ; extra == "notebooks"
|
|
38
|
-
Project-URL: Documentation, https://
|
|
39
|
-
Project-URL: Homepage, https://github.com/j-haacker/cryoswath
|
|
41
|
+
Project-URL: Documentation, https://cryoswath.readthedocs.io/
|
|
40
42
|
Project-URL: Issues, https://github.com/j-haacker/cryoswath/issues
|
|
41
43
|
Project-URL: Repository, https://github.com/j-haacker/cryoswath.git
|
|
42
|
-
Provides-Extra:
|
|
44
|
+
Provides-Extra: dev
|
|
43
45
|
Provides-Extra: notebooks
|
|
44
46
|
|
|
45
47
|
# cryoswath
|
|
46
48
|
|
|
47
49
|

|
|
48
|
-

|
|
51
|
+
[](https://doi.org/10.5281/zenodo.14825358)
|
|
50
52
|

|
|
51
53
|
|
|
52
54
|
cryoswath is a python package containing processing pipelines, a tool
|
|
@@ -59,11 +61,11 @@ changing the concerned function or adding a new one.
|
|
|
59
61
|
|
|
60
62
|
## 🌱 state
|
|
61
63
|
|
|
62
|
-
cryoswath is being developed. Branch `main`
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
cryoswath is being developed. Branch `main` is the release branch,
|
|
65
|
+
`scripts` contains tutorials, and `data` contains auxiliary data and the
|
|
66
|
+
required directory structure. You can have everything setup
|
|
67
|
+
automatically (see "getting started"). Other branches are for
|
|
68
|
+
development.
|
|
67
69
|
|
|
68
70
|
## ✨ features
|
|
69
71
|
|
|
@@ -81,16 +83,26 @@ instructions for UNIX systems. Make sure to use python 3.11 or higher.
|
|
|
81
83
|
Further, I recommend to use a virtual environment and will involve
|
|
82
84
|
python-venv in the instructions (however, conda works similar).
|
|
83
85
|
|
|
86
|
+
All of the following instructions consist of three main steps:
|
|
87
|
+
|
|
88
|
+
1. making cryoswath available
|
|
89
|
+
2. setting up a project directory
|
|
90
|
+
3. initializing cryoswath
|
|
91
|
+
|
|
92
|
+
The instructions will use the variable `$proj_dir` for the project
|
|
93
|
+
directory. Please set it to a path that suits you like
|
|
94
|
+
`proj_dir=altimetry-project`.
|
|
95
|
+
|
|
96
|
+
In all cases, consider to download the data dependencies ArcticDEM and
|
|
97
|
+
the RGI glacier and complex shape files into the
|
|
98
|
+
`$proj_dir/data/auxiliary/DEM` and `$proj_dir/data/auxiliary/RGI`
|
|
99
|
+
directories (more in the [docs](https://j-haacker.github.io/cryoswath/prerequisites.html)).
|
|
100
|
+
|
|
84
101
|
### with git 🐙
|
|
85
102
|
|
|
86
103
|
advantage: easy pulling bugfixes
|
|
87
104
|
|
|
88
|
-
Set up a project directory, pull this repo, create virtual
|
|
89
|
-
environment, initialize, and download ArcticDEM and the RGI glacier and complex
|
|
90
|
-
shape files into the `data/auxiliary/DEM` and -`RGI` directories.
|
|
91
|
-
|
|
92
105
|
```sh
|
|
93
|
-
proj_dir=altimetry-project
|
|
94
106
|
git clone https://github.com/j-haacker/cryoswath.git $proj_dir
|
|
95
107
|
cd $proj_dir
|
|
96
108
|
python3.11 -m venv .venv
|
|
@@ -103,13 +115,7 @@ cryoswath-init
|
|
|
103
115
|
|
|
104
116
|
advantage: easy installation
|
|
105
117
|
|
|
106
|
-
Set up a project directory, create virtual environment, install
|
|
107
|
-
cryoswath, initialize, and download ArcticDEM and the RGI glacier and
|
|
108
|
-
complex shape files into the `data/auxiliary/DEM` and -`RGI`
|
|
109
|
-
directories.
|
|
110
|
-
|
|
111
118
|
```sh
|
|
112
|
-
proj_dir=altimetry-project
|
|
113
119
|
mkdir $proj_dir
|
|
114
120
|
cd $proj_dir
|
|
115
121
|
python3.11 -m venv .venv
|
|
@@ -118,30 +124,40 @@ pip install cryoswath
|
|
|
118
124
|
cryoswath-init
|
|
119
125
|
```
|
|
120
126
|
|
|
127
|
+
### with conda 🐍
|
|
128
|
+
|
|
129
|
+
advantage: most stable dependency resolution
|
|
130
|
+
|
|
131
|
+
First, choose an environment name and either define `$env_name`, e.g.,
|
|
132
|
+
`env_name=cryoswath`, or adapt the create and activate commands
|
|
133
|
+
accordingly.
|
|
134
|
+
|
|
135
|
+
```sh
|
|
136
|
+
conda create -n $env_name conda-forge::cryoswath
|
|
137
|
+
conda activate $env_name
|
|
138
|
+
mkdir $proj_dir
|
|
139
|
+
cd $proj_dir
|
|
140
|
+
cryoswath-init
|
|
141
|
+
```
|
|
142
|
+
|
|
121
143
|
### with Docker 🐳
|
|
122
144
|
|
|
123
145
|
advantage: will almost always work
|
|
124
146
|
|
|
125
147
|
*note*: the first time running the docker image require to download ~ 1 Gb
|
|
126
148
|
|
|
127
|
-
1.
|
|
128
|
-
2.
|
|
129
|
-
3.
|
|
130
|
-
4. Open
|
|
131
|
-
5. Open the scripts folder in the explorer and select one of the notebooks or create your own (inside the scripts folder)
|
|
132
|
-
|
|
133
|
-
### conda
|
|
134
|
-
|
|
135
|
-
New setup instructions coming soon.
|
|
149
|
+
1. `docker run -it -p 8888:8888 -v $proj_dir$:/home/jovyan cryoswath/jupyterlab:v0.2.1`
|
|
150
|
+
2. You will receive an address including a token with which you can connect to the jupyterlab using your browser
|
|
151
|
+
3. In jupyterlab, open a regular shell and execute `cryoswath-init`
|
|
152
|
+
4. Open the scripts folder in the explorer and select one of the notebooks or create your own (inside the scripts folder)
|
|
136
153
|
|
|
137
154
|
### multiple projects
|
|
138
155
|
|
|
139
|
-
|
|
140
|
-
in a neutral directory. For each project, run `cryoswath-init`.
|
|
156
|
+
For each project, run `cryoswath-init` from the project directory.
|
|
141
157
|
|
|
142
158
|
## 📖 documentation
|
|
143
159
|
|
|
144
|
-
[j-haacker.github.io/cryoswath](https://
|
|
160
|
+
[j-haacker.github.io/cryoswath](https://cryoswath.readthedocs.io/)
|
|
145
161
|
|
|
146
162
|
## dependencies
|
|
147
163
|
|
|
@@ -153,6 +169,7 @@ cryoswath will point you to the required resources.
|
|
|
153
169
|
|
|
154
170
|
## 🐛 known issues
|
|
155
171
|
|
|
172
|
+
- ESA's data server is not available from all internet service providers
|
|
156
173
|
- projected RGI basins sometimes "invalid"
|
|
157
174
|
-> add `.make_valid()` if it is missing somewhere
|
|
158
175
|
- it has mostly been tested for the Arctic
|
|
@@ -166,11 +183,11 @@ You can cite this package using bibtex:
|
|
|
166
183
|
```bibtex
|
|
167
184
|
@software{cryoswath,
|
|
168
185
|
author = {Haacker, Jan},
|
|
169
|
-
title = {cryoswath: v0.2.
|
|
186
|
+
title = {cryoswath: v0.2.2},
|
|
170
187
|
month = feb,
|
|
171
188
|
year = 2025,
|
|
172
189
|
publisher = {Zenodo},
|
|
173
|
-
version = {v0.2.
|
|
190
|
+
version = {v0.2.2},
|
|
174
191
|
doi = {10.5281/zenodo.14837018}
|
|
175
192
|
}
|
|
176
193
|
```
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# cryoswath
|
|
2
2
|
|
|
3
3
|

|
|
4
|
-

|
|
5
|
+
[](https://doi.org/10.5281/zenodo.14825358)
|
|
6
6
|

|
|
7
7
|
|
|
8
8
|
cryoswath is a python package containing processing pipelines, a tool
|
|
@@ -15,11 +15,11 @@ changing the concerned function or adding a new one.
|
|
|
15
15
|
|
|
16
16
|
## 🌱 state
|
|
17
17
|
|
|
18
|
-
cryoswath is being developed. Branch `main`
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
cryoswath is being developed. Branch `main` is the release branch,
|
|
19
|
+
`scripts` contains tutorials, and `data` contains auxiliary data and the
|
|
20
|
+
required directory structure. You can have everything setup
|
|
21
|
+
automatically (see "getting started"). Other branches are for
|
|
22
|
+
development.
|
|
23
23
|
|
|
24
24
|
## ✨ features
|
|
25
25
|
|
|
@@ -37,16 +37,26 @@ instructions for UNIX systems. Make sure to use python 3.11 or higher.
|
|
|
37
37
|
Further, I recommend to use a virtual environment and will involve
|
|
38
38
|
python-venv in the instructions (however, conda works similar).
|
|
39
39
|
|
|
40
|
+
All of the following instructions consist of three main steps:
|
|
41
|
+
|
|
42
|
+
1. making cryoswath available
|
|
43
|
+
2. setting up a project directory
|
|
44
|
+
3. initializing cryoswath
|
|
45
|
+
|
|
46
|
+
The instructions will use the variable `$proj_dir` for the project
|
|
47
|
+
directory. Please set it to a path that suits you like
|
|
48
|
+
`proj_dir=altimetry-project`.
|
|
49
|
+
|
|
50
|
+
In all cases, consider to download the data dependencies ArcticDEM and
|
|
51
|
+
the RGI glacier and complex shape files into the
|
|
52
|
+
`$proj_dir/data/auxiliary/DEM` and `$proj_dir/data/auxiliary/RGI`
|
|
53
|
+
directories (more in the [docs](https://j-haacker.github.io/cryoswath/prerequisites.html)).
|
|
54
|
+
|
|
40
55
|
### with git 🐙
|
|
41
56
|
|
|
42
57
|
advantage: easy pulling bugfixes
|
|
43
58
|
|
|
44
|
-
Set up a project directory, pull this repo, create virtual
|
|
45
|
-
environment, initialize, and download ArcticDEM and the RGI glacier and complex
|
|
46
|
-
shape files into the `data/auxiliary/DEM` and -`RGI` directories.
|
|
47
|
-
|
|
48
59
|
```sh
|
|
49
|
-
proj_dir=altimetry-project
|
|
50
60
|
git clone https://github.com/j-haacker/cryoswath.git $proj_dir
|
|
51
61
|
cd $proj_dir
|
|
52
62
|
python3.11 -m venv .venv
|
|
@@ -59,13 +69,7 @@ cryoswath-init
|
|
|
59
69
|
|
|
60
70
|
advantage: easy installation
|
|
61
71
|
|
|
62
|
-
Set up a project directory, create virtual environment, install
|
|
63
|
-
cryoswath, initialize, and download ArcticDEM and the RGI glacier and
|
|
64
|
-
complex shape files into the `data/auxiliary/DEM` and -`RGI`
|
|
65
|
-
directories.
|
|
66
|
-
|
|
67
72
|
```sh
|
|
68
|
-
proj_dir=altimetry-project
|
|
69
73
|
mkdir $proj_dir
|
|
70
74
|
cd $proj_dir
|
|
71
75
|
python3.11 -m venv .venv
|
|
@@ -74,30 +78,40 @@ pip install cryoswath
|
|
|
74
78
|
cryoswath-init
|
|
75
79
|
```
|
|
76
80
|
|
|
81
|
+
### with conda 🐍
|
|
82
|
+
|
|
83
|
+
advantage: most stable dependency resolution
|
|
84
|
+
|
|
85
|
+
First, choose an environment name and either define `$env_name`, e.g.,
|
|
86
|
+
`env_name=cryoswath`, or adapt the create and activate commands
|
|
87
|
+
accordingly.
|
|
88
|
+
|
|
89
|
+
```sh
|
|
90
|
+
conda create -n $env_name conda-forge::cryoswath
|
|
91
|
+
conda activate $env_name
|
|
92
|
+
mkdir $proj_dir
|
|
93
|
+
cd $proj_dir
|
|
94
|
+
cryoswath-init
|
|
95
|
+
```
|
|
96
|
+
|
|
77
97
|
### with Docker 🐳
|
|
78
98
|
|
|
79
99
|
advantage: will almost always work
|
|
80
100
|
|
|
81
101
|
*note*: the first time running the docker image require to download ~ 1 Gb
|
|
82
102
|
|
|
83
|
-
1.
|
|
84
|
-
2.
|
|
85
|
-
3.
|
|
86
|
-
4. Open
|
|
87
|
-
5. Open the scripts folder in the explorer and select one of the notebooks or create your own (inside the scripts folder)
|
|
88
|
-
|
|
89
|
-
### conda
|
|
90
|
-
|
|
91
|
-
New setup instructions coming soon.
|
|
103
|
+
1. `docker run -it -p 8888:8888 -v $proj_dir$:/home/jovyan cryoswath/jupyterlab:v0.2.1`
|
|
104
|
+
2. You will receive an address including a token with which you can connect to the jupyterlab using your browser
|
|
105
|
+
3. In jupyterlab, open a regular shell and execute `cryoswath-init`
|
|
106
|
+
4. Open the scripts folder in the explorer and select one of the notebooks or create your own (inside the scripts folder)
|
|
92
107
|
|
|
93
108
|
### multiple projects
|
|
94
109
|
|
|
95
|
-
|
|
96
|
-
in a neutral directory. For each project, run `cryoswath-init`.
|
|
110
|
+
For each project, run `cryoswath-init` from the project directory.
|
|
97
111
|
|
|
98
112
|
## 📖 documentation
|
|
99
113
|
|
|
100
|
-
[j-haacker.github.io/cryoswath](https://
|
|
114
|
+
[j-haacker.github.io/cryoswath](https://cryoswath.readthedocs.io/)
|
|
101
115
|
|
|
102
116
|
## dependencies
|
|
103
117
|
|
|
@@ -109,6 +123,7 @@ cryoswath will point you to the required resources.
|
|
|
109
123
|
|
|
110
124
|
## 🐛 known issues
|
|
111
125
|
|
|
126
|
+
- ESA's data server is not available from all internet service providers
|
|
112
127
|
- projected RGI basins sometimes "invalid"
|
|
113
128
|
-> add `.make_valid()` if it is missing somewhere
|
|
114
129
|
- it has mostly been tested for the Arctic
|
|
@@ -122,11 +137,11 @@ You can cite this package using bibtex:
|
|
|
122
137
|
```bibtex
|
|
123
138
|
@software{cryoswath,
|
|
124
139
|
author = {Haacker, Jan},
|
|
125
|
-
title = {cryoswath: v0.2.
|
|
140
|
+
title = {cryoswath: v0.2.2},
|
|
126
141
|
month = feb,
|
|
127
142
|
year = 2025,
|
|
128
143
|
publisher = {Zenodo},
|
|
129
|
-
version = {v0.2.
|
|
144
|
+
version = {v0.2.2},
|
|
130
145
|
doi = {10.5281/zenodo.14837018}
|
|
131
146
|
}
|
|
132
147
|
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
__all__ = [
|
|
2
|
+
"__version__",
|
|
3
|
+
"misc",
|
|
4
|
+
"gis",
|
|
5
|
+
"l1b",
|
|
6
|
+
"l2",
|
|
7
|
+
"l3",
|
|
8
|
+
"l4",
|
|
9
|
+
"test_plots", # subpackage
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
from importlib.metadata import version as _version
|
|
13
|
+
from . import gis, misc, l1b, l2, l3, l4, test_plots
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# copied from xarray
|
|
17
|
+
try:
|
|
18
|
+
__version__ = _version("cryoswath")
|
|
19
|
+
except Exception:
|
|
20
|
+
# Local copy or not installed with setuptools.
|
|
21
|
+
# Disable minimum version checks on downstream libraries.
|
|
22
|
+
__version__ = "9999"
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
"""Geospatial processing focused helper functions"""
|
|
2
|
+
|
|
3
|
+
__all__ = [
|
|
4
|
+
"find_planar_crs",
|
|
5
|
+
"buffer_4326_shp",
|
|
6
|
+
"simplify_4326_shp",
|
|
7
|
+
"get_4326_to_dem_Transformer",
|
|
8
|
+
"ensure_pyproj_crs",
|
|
9
|
+
"points_on_glacier",
|
|
10
|
+
"subdivide_region",
|
|
11
|
+
"esri_to_feather",
|
|
12
|
+
"get_lon_origin",
|
|
13
|
+
]
|
|
14
|
+
|
|
1
15
|
import geopandas as gpd
|
|
2
16
|
import numpy as np
|
|
3
17
|
import os
|
|
@@ -8,27 +22,37 @@ import rasterio
|
|
|
8
22
|
import shapely
|
|
9
23
|
import warnings
|
|
10
24
|
|
|
11
|
-
from .misc import
|
|
12
|
-
|
|
13
|
-
|
|
25
|
+
from .misc import (
|
|
26
|
+
load_glacier_outlines,
|
|
27
|
+
rgi_path,
|
|
28
|
+
)
|
|
14
29
|
|
|
15
30
|
# ! tbi:
|
|
16
31
|
rgi_o1_epsg_dict = dict()
|
|
17
32
|
|
|
18
33
|
|
|
19
|
-
def buffer_4326_shp(
|
|
34
|
+
def buffer_4326_shp(
|
|
35
|
+
shp: shapely.Geometry, radius: float, simplify: bool = True
|
|
36
|
+
) -> shapely.MultiPolygon:
|
|
20
37
|
# the algorithm splits a multi-geomerty like MultiPolygon into its
|
|
21
38
|
# parts, simplifies them if requested, buffers them, and joins them
|
|
22
39
|
# finally.
|
|
23
40
|
# the splitting is necessary to work around issue #13
|
|
24
|
-
if
|
|
25
|
-
|
|
41
|
+
if (
|
|
42
|
+
shp is None
|
|
43
|
+
): # this will occasionally fail, as it will be 'GEOMETRYCOLLECTION EMPTY'
|
|
44
|
+
warnings.warn(
|
|
45
|
+
"shp=None passed to buffer_4326_shp, returning empty MultiPolygon."
|
|
46
|
+
)
|
|
26
47
|
return shapely.MultiPolygon()
|
|
27
48
|
# # below does not take the geopandas detour. while more straight forward,
|
|
28
49
|
# # geopandas used to be more stable. however the below was improved and
|
|
29
50
|
# # may be equally good now.
|
|
30
51
|
# transformer = Transformer.from_crs("EPSG:4326", planar_crs)
|
|
31
|
-
# shp = shapely.ops.transform(transformer.invert().transform,
|
|
52
|
+
# shp = shapely.ops.transform(transformer.invert().transform,
|
|
53
|
+
# shapely.ops.transform(
|
|
54
|
+
# transformer.transform, shp
|
|
55
|
+
# ).simplify(100).buffer(radius)).make_valid()
|
|
32
56
|
if isinstance(shp, shapely.geometry.base.BaseMultipartGeometry):
|
|
33
57
|
shp = list(shp.geoms)
|
|
34
58
|
elif isinstance(shp, shapely.geometry.base.BaseGeometry):
|
|
@@ -45,13 +69,17 @@ def buffer_4326_shp(shp: shapely.Geometry, radius: float, simplify: bool = True)
|
|
|
45
69
|
buffered_planar = []
|
|
46
70
|
for poly in shp:
|
|
47
71
|
buffered_planar.append(
|
|
48
|
-
gpd.GeoSeries(poly, crs=4326)
|
|
72
|
+
gpd.GeoSeries(poly, crs=4326)
|
|
73
|
+
.to_crs(planar_crs)
|
|
74
|
+
.make_valid()
|
|
75
|
+
.simplify(100)
|
|
76
|
+
.buffer(radius)
|
|
77
|
+
)
|
|
49
78
|
buffered_planar = pd.concat(buffered_planar)
|
|
50
79
|
if simplify:
|
|
51
|
-
buffered_planar = buffered_planar.simplify(radius/3)
|
|
80
|
+
buffered_planar = buffered_planar.simplify(radius / 3)
|
|
52
81
|
buffered_planar = buffered_planar.to_crs(4326)
|
|
53
82
|
return shapely.make_valid(buffered_planar.union_all(method="unary"))
|
|
54
|
-
__all__.append("buffer_4326_shp")
|
|
55
83
|
|
|
56
84
|
|
|
57
85
|
def ensure_pyproj_crs(crs: CRS) -> CRS:
|
|
@@ -64,17 +92,21 @@ def ensure_pyproj_crs(crs: CRS) -> CRS:
|
|
|
64
92
|
epsg = crs
|
|
65
93
|
crs = CRS.from_epsg(epsg)
|
|
66
94
|
return crs
|
|
67
|
-
__all__.append("ensure_pyproj_crs")
|
|
68
95
|
|
|
69
96
|
|
|
70
97
|
def esri_to_feather(file_path: str = None) -> None:
|
|
71
98
|
if file_path.split(os.path.extsep)[-1].lower() == "shp":
|
|
72
99
|
basename = os.path.extsep.join(file_path.split(os.path.extsep)[:-1])
|
|
73
|
-
gpd.read_file(file_path).to_feather(basename+os.path.extsep+"feather")
|
|
74
|
-
__all__.append("esri_to_feather")
|
|
100
|
+
gpd.read_file(file_path).to_feather(basename + os.path.extsep + "feather")
|
|
75
101
|
|
|
76
102
|
|
|
77
|
-
def find_planar_crs(
|
|
103
|
+
def find_planar_crs(
|
|
104
|
+
*,
|
|
105
|
+
shp: shapely.Geometry = None,
|
|
106
|
+
lat: float = None,
|
|
107
|
+
lon: float = None,
|
|
108
|
+
region_id: str = None,
|
|
109
|
+
):
|
|
78
110
|
if region_id is not None:
|
|
79
111
|
with warnings.catch_warnings(action="ignore"):
|
|
80
112
|
shp = load_glacier_outlines(region_id)
|
|
@@ -87,57 +119,74 @@ def find_planar_crs(*, shp: shapely.Geometry = None, lat: float = None, lon: flo
|
|
|
87
119
|
return CRS.from_epsg(3976)
|
|
88
120
|
else:
|
|
89
121
|
return gpd.GeoSeries(shp, crs=4326).to_frame().estimate_utm_crs()
|
|
90
|
-
|
|
122
|
+
|
|
91
123
|
|
|
92
124
|
def get_lon_origin(crs):
|
|
93
125
|
# Extract Longitude of origin
|
|
94
126
|
# May turn out not to be very robust.
|
|
95
127
|
return ensure_pyproj_crs(crs).coordinate_operation.params[1].value
|
|
96
|
-
|
|
97
|
-
|
|
128
|
+
|
|
98
129
|
|
|
99
130
|
def get_4326_to_dem_Transformer(dem_reader: rasterio.DatasetReader) -> Transformer:
|
|
100
131
|
return Transformer.from_crs("EPSG:4326", ensure_pyproj_crs(dem_reader.crs))
|
|
101
|
-
__all__.append("get_4326_to_dem_Transformer")
|
|
102
132
|
|
|
103
133
|
|
|
104
134
|
def points_on_glacier(points: gpd.GeoSeries) -> pd.Index:
|
|
105
|
-
o2regions = gpd.read_feather(
|
|
106
|
-
|
|
107
|
-
|
|
135
|
+
o2regions = gpd.read_feather(
|
|
136
|
+
os.path.join(rgi_path, "RGI2000-v7.0-o2regions.feather")
|
|
137
|
+
)
|
|
138
|
+
o2code = o2regions[o2regions.geometry.contains(shapely.box(*points.total_bounds))][
|
|
139
|
+
"o2region"
|
|
140
|
+
].values[0]
|
|
141
|
+
buffered_glaciered_area_polygon = load_glacier_outlines(o2code)
|
|
108
142
|
import time
|
|
143
|
+
|
|
109
144
|
print(time.time(), "building union")
|
|
110
145
|
union = buffered_glaciered_area_polygon.unary_union
|
|
111
146
|
print(time.time(), "building geoseries")
|
|
112
|
-
buffered_glaciered_area_polygon = gpd.GeoSeries(
|
|
113
|
-
|
|
114
|
-
|
|
147
|
+
buffered_glaciered_area_polygon = gpd.GeoSeries(
|
|
148
|
+
union,
|
|
149
|
+
# ! the buffering below works only for the arctic
|
|
150
|
+
crs=buffered_glaciered_area_polygon.crs,
|
|
151
|
+
)
|
|
115
152
|
print(time.time(), "buffering")
|
|
116
|
-
buffered_glaciered_area_polygon = buffered_glaciered_area_polygon.to_crs(
|
|
153
|
+
buffered_glaciered_area_polygon = buffered_glaciered_area_polygon.to_crs(
|
|
154
|
+
3413
|
|
155
|
+
).buffer(30_000)
|
|
117
156
|
print(time.time(), "simplifying")
|
|
118
|
-
buffered_glaciered_area_polygon = buffered_glaciered_area_polygon.simplify(
|
|
157
|
+
buffered_glaciered_area_polygon = buffered_glaciered_area_polygon.simplify(
|
|
158
|
+
1000
|
|
159
|
+
).to_crs(4326)
|
|
119
160
|
return points[points.within(buffered_glaciered_area_polygon[0])].index
|
|
120
|
-
__all__.append("points_on_glacier")
|
|
121
161
|
|
|
122
162
|
|
|
123
|
-
def simplify_4326_shp(
|
|
163
|
+
def simplify_4326_shp(
|
|
164
|
+
shp: shapely.Geometry, tolerance: float = None
|
|
165
|
+
) -> shapely.Geometry:
|
|
124
166
|
if tolerance is None:
|
|
125
|
-
if shp.length >= 20_000:
|
|
167
|
+
if shp.length >= 20_000: # 5 x 5 km
|
|
126
168
|
tolerance = 1000
|
|
127
169
|
else:
|
|
128
170
|
tolerance = 300
|
|
129
171
|
planar_crs = find_planar_crs(shp=shp)
|
|
130
|
-
# simplify can create holes outside of the polygon. this is fixed by
|
|
172
|
+
# simplify can create holes outside of the polygon. this is fixed by
|
|
173
|
+
# buffer(0) or make_valid()
|
|
131
174
|
if isinstance(shp, shapely.Geometry):
|
|
132
175
|
shp = gpd.GeoSeries(shp, crs=4326)
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
return (
|
|
177
|
+
shp.to_crs(planar_crs)
|
|
178
|
+
.simplify(tolerance)
|
|
179
|
+
.to_crs(4326)
|
|
180
|
+
.make_valid()
|
|
181
|
+
.union_all(method="unary")
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def subdivide_region(
|
|
186
|
+
basin_gdf: gpd.GeoDataFrame,
|
|
187
|
+
lat_bin_width_degree: float = 1,
|
|
188
|
+
lon_bin_width_degree: float = 1,
|
|
189
|
+
) -> list[gpd.GeoDataFrame]:
|
|
141
190
|
"""Devides GeoDataFrame of basins into smaller GeoDataFrame based on
|
|
142
191
|
their central lat/lon coords.
|
|
143
192
|
|
|
@@ -153,15 +202,25 @@ def subdivide_region(basin_gdf: gpd.GeoDataFrame,
|
|
|
153
202
|
"""
|
|
154
203
|
return_list = []
|
|
155
204
|
# cut latitude into degree slices
|
|
156
|
-
n_lat_bins = max(
|
|
205
|
+
n_lat_bins = max(
|
|
206
|
+
1,
|
|
207
|
+
round((basin_gdf.cenlat.max() - basin_gdf.cenlat.min()) / lat_bin_width_degree),
|
|
208
|
+
)
|
|
157
209
|
# below, `observed=True` to grant compatibility with future pandas versions.
|
|
158
|
-
for lat_label, lat_group in basin_gdf.groupby(
|
|
210
|
+
for lat_label, lat_group in basin_gdf.groupby(
|
|
211
|
+
pd.cut(basin_gdf.cenlat, bins=n_lat_bins), observed=True
|
|
212
|
+
):
|
|
159
213
|
# similarly, cut longitude
|
|
160
|
-
n_lon_bins = max(
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
214
|
+
n_lon_bins = max(
|
|
215
|
+
1,
|
|
216
|
+
round(
|
|
217
|
+
(lat_group.cenlon.max() - lat_group.cenlon.min())
|
|
218
|
+
/ lon_bin_width_degree
|
|
219
|
+
* np.cos(np.deg2rad(lat_label.mid))
|
|
220
|
+
),
|
|
221
|
+
)
|
|
222
|
+
for _, lon_group in lat_group.groupby(
|
|
223
|
+
pd.cut(lat_group.cenlon, bins=n_lon_bins), observed=True
|
|
224
|
+
):
|
|
164
225
|
return_list.append(lon_group)
|
|
165
226
|
return return_list
|
|
166
|
-
__all__.append("subdivide_region")
|
|
167
|
-
|