pysits 1.5.3.dev2__tar.gz → 2.0.0.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.
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/PKG-INFO +12 -9
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/README.md +8 -8
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pyproject.toml +6 -3
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/__init__.py +35 -10
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/backend/functions.py +10 -1
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/backend/loaders.py +39 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/common.py +21 -0
- pysits-2.0.0.dev0/pysits/conversions/stac.py +233 -0
- pysits-2.0.0.dev0/pysits/conversions/tibble.py +698 -0
- pysits-2.0.0.dev0/pysits/conversions/xarray.py +699 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/cube.py +17 -9
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/ts.py +7 -8
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/tuning.py +2 -7
- pysits-2.0.0.dev0/pysits/models/frame.py +37 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/ml.py +4 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/settings.py +2 -2
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/config.py +51 -0
- pysits-2.0.0.dev0/pysits/sits/exporters/xarray.py +131 -0
- pysits-2.0.0.dev0/pysits/sits/impute.py +28 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/ml.py +18 -1
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/segment.py +1 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/tiles.py +0 -6
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/ts.py +6 -15
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/visualization.py +8 -1
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/visualization/base.py +7 -1
- pysits-2.0.0.dev0/tests/test_config.py +81 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_conversions.py +167 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_cube.py +72 -2
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_data.py +34 -1
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_indexing.py +100 -26
- pysits-2.0.0.dev0/tests/test_resolver.py +82 -0
- pysits-2.0.0.dev0/tests/test_rl_models.py +81 -0
- pysits-2.0.0.dev0/tests/test_tiles.py +121 -0
- pysits-2.0.0.dev0/tests/test_tuning.py +106 -0
- pysits-2.0.0.dev0/tests/test_validation.py +137 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_visualization.py +7 -1
- pysits-2.0.0.dev0/tests/test_xarray.py +497 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/uv.lock +1005 -5
- pysits-1.5.3.dev2/pysits/conversions/tibble.py +0 -444
- pysits-1.5.3.dev2/pysits/conversions/tibble_arrow.py +0 -473
- pysits-1.5.3.dev2/pysits/conversions/xarray.py +0 -207
- pysits-1.5.3.dev2/pysits/models/frame.py +0 -191
- pysits-1.5.3.dev2/pysits/sits/exporters/xarray.py +0 -65
- pysits-1.5.3.dev2/pysits/sits/impute.py +0 -38
- pysits-1.5.3.dev2/tests/test_tiles.py +0 -56
- pysits-1.5.3.dev2/tests/test_validation.py +0 -50
- pysits-1.5.3.dev2/tests/test_xarray.py +0 -52
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/.gitattributes +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/.github/workflows/ruff.yaml +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/.gitignore +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/.pre-commit-config.yaml +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/LICENSE +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/conda/meta.yaml +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/backend/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/backend/pkgs.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/clojure.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/decorators.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/dsl/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/dsl/base.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/dsl/mask.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/dsl/tuning.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/conversions/vector.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/docs/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/docs/content/sits_get_data.md +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/docs/decorators.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/extras/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/extras/earthdatalogin.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/extras/torch.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/jinja.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/base.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/accuracy.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/base.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/frame.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/frame_accessor.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/matrix.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/table.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/data/vector.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/models/resolver.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/classification.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/colors.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/context.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/cube.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/data.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/exporters/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/exporters/files.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/exporters/sf.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/tuning.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/sits/utils.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/templates/cube.html +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/templates/tuning.html +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/visualization/__init__.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/visualization/image.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/visualization/leaflet.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/pysits/visualization/tmap.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/conftest.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_classification.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_dsl.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_extras.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_geopandas.py +0 -0
- /pysits-1.5.3.dev2/tests/test_models.py → /pysits-2.0.0.dev0/tests/test_ml_models.py +0 -0
- {pysits-1.5.3.dev2 → pysits-2.0.0.dev0}/tests/test_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pysits
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0.dev0
|
|
4
4
|
Summary: Python wrapper for the sits R package
|
|
5
5
|
Project-URL: Homepage, https://github.com/e-sensing/pysits
|
|
6
6
|
Project-URL: Issue Tracker, https://github.com/e-sensing/pysits/issues
|
|
@@ -34,6 +34,9 @@ Requires-Dist: ruff>=0.11.12; extra == 'dev'
|
|
|
34
34
|
Provides-Extra: xarray
|
|
35
35
|
Requires-Dist: affine>=2.4.0; extra == 'xarray'
|
|
36
36
|
Requires-Dist: dask>=2025.3.0; extra == 'xarray'
|
|
37
|
+
Requires-Dist: odc-stac>=0.5.3; extra == 'xarray'
|
|
38
|
+
Requires-Dist: planetary-computer>=1.0.0; extra == 'xarray'
|
|
39
|
+
Requires-Dist: pystac>=1.15.0; extra == 'xarray'
|
|
37
40
|
Requires-Dist: rioxarray>=0.18.2; extra == 'xarray'
|
|
38
41
|
Requires-Dist: xarray>=2025.3.0; extra == 'xarray'
|
|
39
42
|
Description-Content-Type: text/markdown
|
|
@@ -42,7 +45,7 @@ Description-Content-Type: text/markdown
|
|
|
42
45
|
|
|
43
46
|
Python wrapper for the [sits](https://github.com/e-sensing/sits) R package.
|
|
44
47
|
|
|
45
|
-
##
|
|
48
|
+
## Installation
|
|
46
49
|
|
|
47
50
|
To install `pysits` with pip:
|
|
48
51
|
|
|
@@ -58,7 +61,7 @@ pip install git+https://github.com/e-sensing/pysits.git
|
|
|
58
61
|
|
|
59
62
|
> To use `pysits`, you must have [sits](https://github.com/e-sensing/sits) installed. For more information, refer to the [official sits documentation](https://e-sensing.github.io/sitsbook/setup.html).
|
|
60
63
|
|
|
61
|
-
##
|
|
64
|
+
## Development setup (for contributors)
|
|
62
65
|
|
|
63
66
|
To set up a local development environment:
|
|
64
67
|
|
|
@@ -82,7 +85,7 @@ source .venv/bin/activate # or .venv\Scripts\activate on Windows
|
|
|
82
85
|
uv pip install -e ".[dev]"
|
|
83
86
|
```
|
|
84
87
|
|
|
85
|
-
###
|
|
88
|
+
### Run tests
|
|
86
89
|
|
|
87
90
|
We use `pytest` for testing:
|
|
88
91
|
|
|
@@ -90,7 +93,7 @@ We use `pytest` for testing:
|
|
|
90
93
|
pytest
|
|
91
94
|
```
|
|
92
95
|
|
|
93
|
-
###
|
|
96
|
+
### Code formatting
|
|
94
97
|
|
|
95
98
|
To keep the codebase clean and consistent we use [ruff](https://github.com/astral-sh/ruff):
|
|
96
99
|
|
|
@@ -98,7 +101,7 @@ To keep the codebase clean and consistent we use [ruff](https://github.com/astra
|
|
|
98
101
|
ruff format .
|
|
99
102
|
```
|
|
100
103
|
|
|
101
|
-
###
|
|
104
|
+
### Linting
|
|
102
105
|
|
|
103
106
|
We use [ruff](https://github.com/astral-sh/ruff) for static analysis:
|
|
104
107
|
|
|
@@ -108,11 +111,11 @@ ruff check .
|
|
|
108
111
|
|
|
109
112
|
> The `examples/` directory is excluded from linting.
|
|
110
113
|
|
|
111
|
-
##
|
|
114
|
+
## Learn more
|
|
112
115
|
|
|
113
116
|
To learn all about `sits`, including its concepts, API, and real-world examples, we recommend accessing the [official sits book](https://e-sensing.github.io/sitsbook/). The book provides examples in both R and Python.
|
|
114
117
|
|
|
115
|
-
##
|
|
118
|
+
## Contributing
|
|
116
119
|
|
|
117
120
|
We welcome contributions! Please:
|
|
118
121
|
|
|
@@ -120,6 +123,6 @@ We welcome contributions! Please:
|
|
|
120
123
|
- Create a feature branch
|
|
121
124
|
- Submit a pull request with a clear description
|
|
122
125
|
|
|
123
|
-
##
|
|
126
|
+
## License
|
|
124
127
|
|
|
125
128
|
`pysits` is distributed under the GPL-2.0 license. See [LICENSE](./LICENSE) for more details.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Python wrapper for the [sits](https://github.com/e-sensing/sits) R package.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
To install `pysits` with pip:
|
|
8
8
|
|
|
@@ -18,7 +18,7 @@ pip install git+https://github.com/e-sensing/pysits.git
|
|
|
18
18
|
|
|
19
19
|
> To use `pysits`, you must have [sits](https://github.com/e-sensing/sits) installed. For more information, refer to the [official sits documentation](https://e-sensing.github.io/sitsbook/setup.html).
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Development setup (for contributors)
|
|
22
22
|
|
|
23
23
|
To set up a local development environment:
|
|
24
24
|
|
|
@@ -42,7 +42,7 @@ source .venv/bin/activate # or .venv\Scripts\activate on Windows
|
|
|
42
42
|
uv pip install -e ".[dev]"
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
###
|
|
45
|
+
### Run tests
|
|
46
46
|
|
|
47
47
|
We use `pytest` for testing:
|
|
48
48
|
|
|
@@ -50,7 +50,7 @@ We use `pytest` for testing:
|
|
|
50
50
|
pytest
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
###
|
|
53
|
+
### Code formatting
|
|
54
54
|
|
|
55
55
|
To keep the codebase clean and consistent we use [ruff](https://github.com/astral-sh/ruff):
|
|
56
56
|
|
|
@@ -58,7 +58,7 @@ To keep the codebase clean and consistent we use [ruff](https://github.com/astra
|
|
|
58
58
|
ruff format .
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
###
|
|
61
|
+
### Linting
|
|
62
62
|
|
|
63
63
|
We use [ruff](https://github.com/astral-sh/ruff) for static analysis:
|
|
64
64
|
|
|
@@ -68,11 +68,11 @@ ruff check .
|
|
|
68
68
|
|
|
69
69
|
> The `examples/` directory is excluded from linting.
|
|
70
70
|
|
|
71
|
-
##
|
|
71
|
+
## Learn more
|
|
72
72
|
|
|
73
73
|
To learn all about `sits`, including its concepts, API, and real-world examples, we recommend accessing the [official sits book](https://e-sensing.github.io/sitsbook/). The book provides examples in both R and Python.
|
|
74
74
|
|
|
75
|
-
##
|
|
75
|
+
## Contributing
|
|
76
76
|
|
|
77
77
|
We welcome contributions! Please:
|
|
78
78
|
|
|
@@ -80,6 +80,6 @@ We welcome contributions! Please:
|
|
|
80
80
|
- Create a feature branch
|
|
81
81
|
- Submit a pull request with a clear description
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## License
|
|
84
84
|
|
|
85
85
|
`pysits` is distributed under the GPL-2.0 license. See [LICENSE](./LICENSE) for more details.
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
[project]
|
|
19
19
|
name = "pysits"
|
|
20
|
-
version = "
|
|
20
|
+
version = "2.0.0.dev0"
|
|
21
21
|
description = "Python wrapper for the sits R package"
|
|
22
22
|
readme = "README.md"
|
|
23
23
|
requires-python = ">=3.10,<4"
|
|
@@ -77,7 +77,10 @@ xarray = [
|
|
|
77
77
|
"xarray>=2025.3.0",
|
|
78
78
|
"dask>=2025.3.0",
|
|
79
79
|
"rioxarray>=0.18.2",
|
|
80
|
-
"affine>=2.4.0"
|
|
80
|
+
"affine>=2.4.0",
|
|
81
|
+
"odc-stac>=0.5.3",
|
|
82
|
+
"pystac>=1.15.0",
|
|
83
|
+
"planetary-computer>=1.0.0"
|
|
81
84
|
]
|
|
82
85
|
|
|
83
86
|
dev = [
|
|
@@ -93,7 +96,7 @@ dev = [
|
|
|
93
96
|
exclude = ["examples", "_resources"]
|
|
94
97
|
|
|
95
98
|
[tool.ruff.lint]
|
|
96
|
-
ignore = ["PLC0415"]
|
|
99
|
+
ignore = ["PLC0415", "PLW0108"]
|
|
97
100
|
select = [
|
|
98
101
|
"E", # pycodestyle
|
|
99
102
|
"F", # pyflakes
|
|
@@ -27,7 +27,13 @@ from .sits.colors import (
|
|
|
27
27
|
sits_colors_set,
|
|
28
28
|
sits_colors_show,
|
|
29
29
|
)
|
|
30
|
-
from .sits.config import
|
|
30
|
+
from .sits.config import (
|
|
31
|
+
sits_config,
|
|
32
|
+
sits_config_show,
|
|
33
|
+
sits_config_user_file,
|
|
34
|
+
sits_config_value,
|
|
35
|
+
sits_parallel,
|
|
36
|
+
)
|
|
31
37
|
from .sits.context import (
|
|
32
38
|
cerrado_2classes,
|
|
33
39
|
point_mt_6bands,
|
|
@@ -67,8 +73,15 @@ from .sits.data import (
|
|
|
67
73
|
)
|
|
68
74
|
from .sits.data import sits_summary as summary
|
|
69
75
|
from .sits.exporters import sits_as_geopandas, sits_as_xarray, sits_to_csv, sits_to_xlsx
|
|
70
|
-
from .sits.impute import
|
|
76
|
+
from .sits.impute import (
|
|
77
|
+
impute_linear,
|
|
78
|
+
impute_mean,
|
|
79
|
+
impute_mean_window,
|
|
80
|
+
impute_median,
|
|
81
|
+
)
|
|
71
82
|
from .sits.ml import (
|
|
83
|
+
sits_barlow_twins,
|
|
84
|
+
sits_contrastive_learning,
|
|
72
85
|
sits_formula_linear,
|
|
73
86
|
sits_formula_logref,
|
|
74
87
|
sits_kfold_validate,
|
|
@@ -76,20 +89,25 @@ from .sits.ml import (
|
|
|
76
89
|
sits_lighttae,
|
|
77
90
|
sits_mlp,
|
|
78
91
|
sits_model_export,
|
|
92
|
+
sits_pre_train,
|
|
79
93
|
sits_resnet,
|
|
80
94
|
sits_rfor,
|
|
95
|
+
sits_ssl_lejepa,
|
|
96
|
+
sits_ssl_mae,
|
|
97
|
+
sits_ssl_vicreg,
|
|
81
98
|
sits_svm,
|
|
82
99
|
sits_tae,
|
|
83
100
|
sits_tempcnn,
|
|
84
101
|
sits_train,
|
|
85
102
|
sits_xgboost,
|
|
86
103
|
)
|
|
87
|
-
from .sits.segment import sits_segment, sits_slic
|
|
88
|
-
from .sits.tiles import
|
|
104
|
+
from .sits.segment import sits_segment, sits_slic, sits_snic
|
|
105
|
+
from .sits.tiles import sits_roi_to_tiles, sits_tiles_to_roi
|
|
89
106
|
from .sits.ts import (
|
|
90
107
|
sits_cluster_clean,
|
|
91
108
|
sits_cluster_dendro,
|
|
92
109
|
sits_cluster_frequency,
|
|
110
|
+
sits_encode,
|
|
93
111
|
sits_geo_dist,
|
|
94
112
|
sits_get_class,
|
|
95
113
|
sits_get_data,
|
|
@@ -103,7 +121,6 @@ from .sits.ts import (
|
|
|
103
121
|
sits_reduce_imbalance,
|
|
104
122
|
sits_sample,
|
|
105
123
|
sits_sampling_design,
|
|
106
|
-
sits_sgolay,
|
|
107
124
|
sits_show_prediction,
|
|
108
125
|
sits_som_clean_samples,
|
|
109
126
|
sits_som_evaluate_cluster,
|
|
@@ -111,7 +128,6 @@ from .sits.ts import (
|
|
|
111
128
|
sits_stats,
|
|
112
129
|
sits_stratified_sampling,
|
|
113
130
|
sits_validate,
|
|
114
|
-
sits_whittaker,
|
|
115
131
|
)
|
|
116
132
|
from .sits.tuning import sits_tuning, sits_tuning_hparams
|
|
117
133
|
from .sits.utils import (
|
|
@@ -152,6 +168,8 @@ __all__ = (
|
|
|
152
168
|
"sits_config",
|
|
153
169
|
"sits_config_show",
|
|
154
170
|
"sits_config_user_file",
|
|
171
|
+
"sits_config_value",
|
|
172
|
+
"sits_parallel",
|
|
155
173
|
# Data management
|
|
156
174
|
"sits_bands",
|
|
157
175
|
"sits_timeline",
|
|
@@ -184,13 +202,19 @@ __all__ = (
|
|
|
184
202
|
"sits_model_export",
|
|
185
203
|
"sits_formula_linear",
|
|
186
204
|
"sits_formula_logref",
|
|
205
|
+
"sits_ssl_mae",
|
|
206
|
+
"sits_ssl_lejepa",
|
|
207
|
+
"sits_ssl_vicreg",
|
|
208
|
+
"sits_barlow_twins",
|
|
209
|
+
"sits_contrastive_learning",
|
|
210
|
+
"sits_pre_train",
|
|
187
211
|
# Impute
|
|
188
|
-
"sits_impute",
|
|
189
212
|
"impute_linear",
|
|
213
|
+
"impute_mean",
|
|
214
|
+
"impute_median",
|
|
215
|
+
"impute_mean_window",
|
|
190
216
|
# Time-series
|
|
191
217
|
"sits_show_prediction",
|
|
192
|
-
"sits_sgolay",
|
|
193
|
-
"sits_whittaker",
|
|
194
218
|
"sits_get_data",
|
|
195
219
|
"sits_get_class",
|
|
196
220
|
"sits_get_probs",
|
|
@@ -210,13 +234,14 @@ __all__ = (
|
|
|
210
234
|
"sits_reduce_imbalance",
|
|
211
235
|
"sits_sampling_design",
|
|
212
236
|
"sits_stratified_sampling",
|
|
237
|
+
"sits_encode",
|
|
213
238
|
# Tiles
|
|
214
|
-
"sits_mgrs_to_roi",
|
|
215
239
|
"sits_tiles_to_roi",
|
|
216
240
|
"sits_roi_to_tiles",
|
|
217
241
|
# Segments
|
|
218
242
|
"sits_segment",
|
|
219
243
|
"sits_slic",
|
|
244
|
+
"sits_snic",
|
|
220
245
|
# Apply
|
|
221
246
|
"sits_apply",
|
|
222
247
|
# Exporters
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
"""backend functions."""
|
|
19
19
|
|
|
20
|
-
from pysits.backend.loaders import
|
|
20
|
+
from pysits.backend.loaders import (
|
|
21
|
+
load_function_from_package,
|
|
22
|
+
load_internal_function_from_package,
|
|
23
|
+
)
|
|
21
24
|
|
|
22
25
|
# Base - plot
|
|
23
26
|
r_fnc_plot = load_function_from_package("base::plot")
|
|
@@ -40,6 +43,9 @@ r_fnc_set_seed = load_function_from_package("base::set_seed")
|
|
|
40
43
|
# Base - class (base)
|
|
41
44
|
r_fnc_class = load_function_from_package("base::class")
|
|
42
45
|
|
|
46
|
+
# Base - eval (base)
|
|
47
|
+
r_fnc_eval = load_function_from_package("base::eval")
|
|
48
|
+
|
|
43
49
|
# Base - as.data.frame (base)
|
|
44
50
|
r_fnc_as_data_frame = load_function_from_package("base::as_data_frame")
|
|
45
51
|
|
|
@@ -48,3 +54,6 @@ r_fnc_colnames = load_function_from_package("base::colnames")
|
|
|
48
54
|
|
|
49
55
|
# Base - rownames (base)
|
|
50
56
|
r_fnc_rownames = load_function_from_package("base::rownames")
|
|
57
|
+
|
|
58
|
+
# sits - configuration (internal)
|
|
59
|
+
r_fnc_sits_conf = load_internal_function_from_package("sits:::.conf")
|
|
@@ -105,3 +105,42 @@ def load_function_from_package(name: str) -> Callable[..., Any]:
|
|
|
105
105
|
|
|
106
106
|
# Return function
|
|
107
107
|
return getattr(pkg, func_name)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def load_internal_function_from_package(name: str) -> Callable[..., Any]:
|
|
111
|
+
"""Load an internal R function from a specified package.
|
|
112
|
+
|
|
113
|
+
Internal functions are those not exported by a package. They are addressed
|
|
114
|
+
in R with the ``package:::function`` notation.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
name (str): The fully qualified name of the R function in the format
|
|
118
|
+
'package:::function'. For example, 'sits:::.conf'.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Callable[..., Any]: A Python callable that wraps the R function.
|
|
122
|
+
The exact signature depends on the underlying R function.
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
ValueError: If the ``name`` doesn't follow the 'package:::function' format.
|
|
126
|
+
|
|
127
|
+
PackageNotFoundError: If the specified R package is not installed.
|
|
128
|
+
|
|
129
|
+
Examples:
|
|
130
|
+
>>> conf = load_internal_function_from_package('sits:::.conf')
|
|
131
|
+
>>> scale = conf('sources', 'BDC', 'collections', 'MOD13Q1-6.1')
|
|
132
|
+
"""
|
|
133
|
+
# Parse package and function
|
|
134
|
+
package_name, _, func_name = name.partition(":::")
|
|
135
|
+
|
|
136
|
+
if not package_name or not func_name:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"Invalid function name format: {name}. "
|
|
139
|
+
"Expected format: 'package:::function'"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Import the package
|
|
143
|
+
importr(package_name, on_conflict="warn")
|
|
144
|
+
|
|
145
|
+
# Return function
|
|
146
|
+
return rpy2_r_interface(name)
|
|
@@ -25,8 +25,10 @@ from geopandas import GeoDataFrame as GeoPandasDataFrame
|
|
|
25
25
|
from pandas import DataFrame as PandasDataFrame
|
|
26
26
|
from rpy2.rinterface_lib.sexp import NULLType
|
|
27
27
|
from rpy2.robjects import pandas2ri
|
|
28
|
+
from rpy2.robjects.language import LangVector
|
|
28
29
|
from rpy2.robjects.robject import RObjectMixin
|
|
29
30
|
|
|
31
|
+
from pysits.backend.functions import r_fnc_eval
|
|
30
32
|
from pysits.backend.pkgs import r_pkg_tibble
|
|
31
33
|
from pysits.conversions.dsl.base import DSLObject
|
|
32
34
|
from pysits.conversions.tibble import geopandas_to_tibble, pandas_to_tibble
|
|
@@ -179,6 +181,22 @@ def convert_to_r(obj):
|
|
|
179
181
|
raise TypeError(f"Cannot convert object of type {obj_type} to R format")
|
|
180
182
|
|
|
181
183
|
|
|
184
|
+
def eval_r_language(obj):
|
|
185
|
+
"""Evaluate an unevaluated R expression.
|
|
186
|
+
|
|
187
|
+
Args:
|
|
188
|
+
obj: The R object to evaluate.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
The evaluated R object. Objects that are not R expressions are returned
|
|
192
|
+
unchanged.
|
|
193
|
+
"""
|
|
194
|
+
if isinstance(obj, LangVector):
|
|
195
|
+
return r_fnc_eval(obj)
|
|
196
|
+
|
|
197
|
+
return obj
|
|
198
|
+
|
|
199
|
+
|
|
182
200
|
def convert_to_python(obj, as_type="str"):
|
|
183
201
|
"""Convert an R object to a Python representation.
|
|
184
202
|
|
|
@@ -206,6 +224,9 @@ def convert_to_python(obj, as_type="str"):
|
|
|
206
224
|
def _convert(value, type_):
|
|
207
225
|
result = []
|
|
208
226
|
|
|
227
|
+
# R expressions must be evaluated to be converted
|
|
228
|
+
value = eval_r_language(value)
|
|
229
|
+
|
|
209
230
|
if isinstance(value, ro.ListVector):
|
|
210
231
|
for k, v in value.items():
|
|
211
232
|
result.append(
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2025 sits developers.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software; you can redistribute it and/or modify it
|
|
5
|
+
# under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation; either version 2 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
#
|
|
17
|
+
|
|
18
|
+
"""STAC conversions."""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from urllib.parse import urlparse, urlunparse
|
|
23
|
+
|
|
24
|
+
import pystac
|
|
25
|
+
from affine import Affine
|
|
26
|
+
from numpy import datetime64
|
|
27
|
+
from odc.geo.geobox import GeoBox
|
|
28
|
+
from odc.geo.geom import CRS
|
|
29
|
+
from pandas import DataFrame as PandasDataFrame
|
|
30
|
+
from rasterio.warp import transform_bounds
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# Prefix used by GDAL to read files through HTTP
|
|
34
|
+
#
|
|
35
|
+
VSICURL_PREFIX = "/vsicurl/"
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Host used by Microsoft Planetary Computer to store data
|
|
39
|
+
#
|
|
40
|
+
MPC_HOST_SUFFIX = "blob.core.windows.net"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
#
|
|
44
|
+
# Grid operations
|
|
45
|
+
#
|
|
46
|
+
def files_geobox(files: PandasDataFrame) -> GeoBox:
|
|
47
|
+
"""Create the geobox covering all files of a grid group.
|
|
48
|
+
|
|
49
|
+
The geobox uses the native resolution and CRS of the files, so data is read
|
|
50
|
+
without resampling.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
files (PandasDataFrame): Files of a single grid group.
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
GeoBox: Geobox covering all files.
|
|
57
|
+
"""
|
|
58
|
+
xres = float(files["xres"].iloc[0])
|
|
59
|
+
yres = float(files["yres"].iloc[0])
|
|
60
|
+
|
|
61
|
+
# Extent covering all files of the group
|
|
62
|
+
xmin = float(files["xmin"].min())
|
|
63
|
+
xmax = float(files["xmax"].max())
|
|
64
|
+
ymin = float(files["ymin"].min())
|
|
65
|
+
ymax = float(files["ymax"].max())
|
|
66
|
+
|
|
67
|
+
# Shape (rounded, as files of a group share the same grid)
|
|
68
|
+
width = int(round((xmax - xmin) / xres))
|
|
69
|
+
height = int(round((ymax - ymin) / yres))
|
|
70
|
+
|
|
71
|
+
return GeoBox(
|
|
72
|
+
shape=(height, width),
|
|
73
|
+
affine=Affine(xres, 0.0, xmin, 0.0, -yres, ymax),
|
|
74
|
+
crs=CRS(str(files["crs"].iloc[0])),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def grid_group_name(files: PandasDataFrame, index: int) -> str:
|
|
79
|
+
"""Create a name for a grid group.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
files (PandasDataFrame): Files of a single grid group.
|
|
83
|
+
|
|
84
|
+
index (int): Position of the group, used when the CRS has no EPSG code.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
str: Group name (e.g., ``epsg32720-10m``).
|
|
88
|
+
"""
|
|
89
|
+
crs = CRS(str(files["crs"].iloc[0]))
|
|
90
|
+
resolution = float(files["xres"].iloc[0])
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
crs_name = f"epsg{crs.epsg}" if crs.epsg else f"grid{index}"
|
|
94
|
+
|
|
95
|
+
except Exception:
|
|
96
|
+
crs_name = f"grid{index}"
|
|
97
|
+
|
|
98
|
+
return f"{crs_name}-{resolution:g}m"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# STAC items
|
|
103
|
+
#
|
|
104
|
+
def stac_items_from_files(files: PandasDataFrame) -> list[pystac.Item]:
|
|
105
|
+
"""Create STAC Items from cube files.
|
|
106
|
+
|
|
107
|
+
One item is created for each ``(tile, date)``, with one asset per band. All
|
|
108
|
+
item properties come from the cube metadata: no file is read.
|
|
109
|
+
|
|
110
|
+
Cubes can have more than one file for the same tile, date and band, as
|
|
111
|
+
collections may have multiple versions of an acquisition. Each version is
|
|
112
|
+
described as its own item, so all of them are used when data is read.
|
|
113
|
+
|
|
114
|
+
Args:
|
|
115
|
+
files (PandasDataFrame): Files of a single grid group.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
list[pystac.Item]: Items describing the files.
|
|
119
|
+
"""
|
|
120
|
+
items = []
|
|
121
|
+
|
|
122
|
+
# Files of the same tile, date and band are versions of an acquisition
|
|
123
|
+
files = files.copy()
|
|
124
|
+
files["version"] = files.groupby(["tile", "date", "band"]).cumcount()
|
|
125
|
+
|
|
126
|
+
for (tile, date, version), group in files.groupby(
|
|
127
|
+
["tile", "date", "version"], sort=True
|
|
128
|
+
):
|
|
129
|
+
crs = str(group["crs"].iloc[0])
|
|
130
|
+
assets = {}
|
|
131
|
+
|
|
132
|
+
for _, file in group.iterrows():
|
|
133
|
+
transform = Affine(
|
|
134
|
+
a=float(file["xres"]),
|
|
135
|
+
b=0.0,
|
|
136
|
+
c=float(file["xmin"]),
|
|
137
|
+
d=0.0,
|
|
138
|
+
e=-float(file["yres"]),
|
|
139
|
+
f=float(file["ymax"]),
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Create asset
|
|
143
|
+
asset = pystac.Asset(
|
|
144
|
+
href=str(file["path"]),
|
|
145
|
+
roles=["data"],
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
# Define extra fields
|
|
149
|
+
asset.extra_fields.update(
|
|
150
|
+
{
|
|
151
|
+
"proj:wkt2": crs,
|
|
152
|
+
"proj:shape": [int(file["nrows"]), int(file["ncols"])],
|
|
153
|
+
"proj:transform": [*list(transform)[:6], 0.0, 0.0, 1.0],
|
|
154
|
+
}
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
# Save band
|
|
158
|
+
assets[str(file["band"])] = asset
|
|
159
|
+
|
|
160
|
+
# Footprint, in geographic coordinates (required by STAC)
|
|
161
|
+
bbox = list(
|
|
162
|
+
transform_bounds(
|
|
163
|
+
src_crs=crs,
|
|
164
|
+
dst_crs="EPSG:4326",
|
|
165
|
+
left=float(group["xmin"].min()),
|
|
166
|
+
bottom=float(group["ymin"].min()),
|
|
167
|
+
right=float(group["xmax"].max()),
|
|
168
|
+
top=float(group["ymax"].max()),
|
|
169
|
+
)
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
# Create item
|
|
173
|
+
item = pystac.Item(
|
|
174
|
+
id=f"{tile}_{date}_{version}",
|
|
175
|
+
geometry={
|
|
176
|
+
"type": "Polygon",
|
|
177
|
+
"coordinates": [
|
|
178
|
+
[
|
|
179
|
+
[bbox[0], bbox[1]],
|
|
180
|
+
[bbox[2], bbox[1]],
|
|
181
|
+
[bbox[2], bbox[3]],
|
|
182
|
+
[bbox[0], bbox[3]],
|
|
183
|
+
[bbox[0], bbox[1]],
|
|
184
|
+
]
|
|
185
|
+
],
|
|
186
|
+
},
|
|
187
|
+
bbox=bbox,
|
|
188
|
+
datetime=datetime64(str(date)).astype("datetime64[s]").item(),
|
|
189
|
+
properties={"tile": tile},
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Add assets
|
|
193
|
+
for band, asset in assets.items():
|
|
194
|
+
item.add_asset(band, asset)
|
|
195
|
+
|
|
196
|
+
# Save item
|
|
197
|
+
items.append(item)
|
|
198
|
+
|
|
199
|
+
# Return!
|
|
200
|
+
return items
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
#
|
|
204
|
+
# Data access
|
|
205
|
+
#
|
|
206
|
+
def signature_file_url(url: str) -> str:
|
|
207
|
+
"""Refresh the credentials of a file URL.
|
|
208
|
+
|
|
209
|
+
Cubes store the credentials available when they were created. As these
|
|
210
|
+
credentials expire, they are refreshed before data is read.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
url (str): File URL.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
str: URL with refreshed credentials, if required.
|
|
217
|
+
"""
|
|
218
|
+
prefix = VSICURL_PREFIX if url.startswith(VSICURL_PREFIX) else ""
|
|
219
|
+
address = url[len(prefix) :]
|
|
220
|
+
|
|
221
|
+
parsed = urlparse(address)
|
|
222
|
+
|
|
223
|
+
# Only data with expiring credentials is refreshed
|
|
224
|
+
if not parsed.netloc.endswith(MPC_HOST_SUFFIX) or not parsed.query:
|
|
225
|
+
return url
|
|
226
|
+
|
|
227
|
+
try:
|
|
228
|
+
from planetary_computer import sign
|
|
229
|
+
|
|
230
|
+
except ImportError:
|
|
231
|
+
return url
|
|
232
|
+
|
|
233
|
+
return prefix + sign(urlunparse(parsed._replace(query="")))
|