disscube 0.4.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.
- disscube-0.4.0/LICENSE +21 -0
- disscube-0.4.0/MANIFEST.in +3 -0
- disscube-0.4.0/PKG-INFO +368 -0
- disscube-0.4.0/README.md +310 -0
- disscube-0.4.0/disscube/__init__.py +19 -0
- disscube-0.4.0/disscube/catalog/__init__.py +5 -0
- disscube-0.4.0/disscube/catalog/json_store.py +94 -0
- disscube-0.4.0/disscube/catalog/protocol.py +22 -0
- disscube-0.4.0/disscube/catalog/sqlite_store.py +143 -0
- disscube-0.4.0/disscube/cli.py +144 -0
- disscube-0.4.0/disscube/client.py +521 -0
- disscube-0.4.0/disscube/data/bdc_grids/BDC_LG_V2.zip +0 -0
- disscube-0.4.0/disscube/data/bdc_grids/BDC_MD_V2.zip +0 -0
- disscube-0.4.0/disscube/data/bdc_grids/BDC_SM_V2.zip +0 -0
- disscube-0.4.0/disscube/data/bdc_grids/README.md +51 -0
- disscube-0.4.0/disscube/export.py +168 -0
- disscube-0.4.0/disscube/models/__init__.py +28 -0
- disscube-0.4.0/disscube/models/derivation.py +186 -0
- disscube-0.4.0/disscube/models/grid.py +240 -0
- disscube-0.4.0/disscube/models/variable.py +129 -0
- disscube-0.4.0/disscube/operators/__init__.py +20 -0
- disscube-0.4.0/disscube/operators/base.py +115 -0
- disscube-0.4.0/disscube/operators/proximity.py +170 -0
- disscube-0.4.0/disscube/operators/zonal.py +522 -0
- disscube-0.4.0/disscube/pipeline/__init__.py +41 -0
- disscube-0.4.0/disscube/pipeline/aggregator.py +152 -0
- disscube-0.4.0/disscube/pipeline/aligner.py +353 -0
- disscube-0.4.0/disscube/pipeline/context.py +24 -0
- disscube-0.4.0/disscube/pipeline/normalizer.py +59 -0
- disscube-0.4.0/disscube/pipeline/runner.py +693 -0
- disscube-0.4.0/disscube/pipeline/schema.py +212 -0
- disscube-0.4.0/disscube/pipeline/writer.py +144 -0
- disscube-0.4.0/disscube/sources/__init__.py +43 -0
- disscube-0.4.0/disscube/sources/_categorical.py +89 -0
- disscube-0.4.0/disscube/sources/_raster.py +303 -0
- disscube-0.4.0/disscube/sources/bdc.py +286 -0
- disscube-0.4.0/disscube/sources/classified.py +80 -0
- disscube-0.4.0/disscube/sources/mapbiomas.py +162 -0
- disscube-0.4.0/disscube/sources/prodes.py +254 -0
- disscube-0.4.0/disscube/storage.py +32 -0
- disscube-0.4.0/disscube/utils.py +150 -0
- disscube-0.4.0/disscube.egg-info/PKG-INFO +368 -0
- disscube-0.4.0/disscube.egg-info/SOURCES.txt +76 -0
- disscube-0.4.0/disscube.egg-info/dependency_links.txt +1 -0
- disscube-0.4.0/disscube.egg-info/entry_points.txt +2 -0
- disscube-0.4.0/disscube.egg-info/requires.txt +40 -0
- disscube-0.4.0/disscube.egg-info/top_level.txt +1 -0
- disscube-0.4.0/pyproject.toml +144 -0
- disscube-0.4.0/setup.cfg +4 -0
- disscube-0.4.0/tests/test_aggregator.py +129 -0
- disscube-0.4.0/tests/test_aligner.py +111 -0
- disscube-0.4.0/tests/test_aligner_resampling.py +246 -0
- disscube-0.4.0/tests/test_anchoring.py +76 -0
- disscube-0.4.0/tests/test_bdc_bundled_grids.py +105 -0
- disscube-0.4.0/tests/test_bdc_master_grids.py +195 -0
- disscube-0.4.0/tests/test_classified.py +78 -0
- disscube-0.4.0/tests/test_derivation.py +173 -0
- disscube-0.4.0/tests/test_distance_operator.py +73 -0
- disscube-0.4.0/tests/test_error_fallbacks.py +70 -0
- disscube-0.4.0/tests/test_examples.py +31 -0
- disscube-0.4.0/tests/test_export.py +218 -0
- disscube-0.4.0/tests/test_fetch.py +111 -0
- disscube-0.4.0/tests/test_geographic_grid.py +64 -0
- disscube-0.4.0/tests/test_geometry.py +42 -0
- disscube-0.4.0/tests/test_grid_relations.py +113 -0
- disscube-0.4.0/tests/test_mapbiomas.py +94 -0
- disscube-0.4.0/tests/test_models.py +52 -0
- disscube-0.4.0/tests/test_mutation.py +66 -0
- disscube-0.4.0/tests/test_nodata.py +104 -0
- disscube-0.4.0/tests/test_percentage_purity.py +196 -0
- disscube-0.4.0/tests/test_pipeline_file.py +375 -0
- disscube-0.4.0/tests/test_pipeline_options.py +407 -0
- disscube-0.4.0/tests/test_prodes.py +158 -0
- disscube-0.4.0/tests/test_roundtrip.py +213 -0
- disscube-0.4.0/tests/test_source_checksum.py +106 -0
- disscube-0.4.0/tests/test_sources.py +433 -0
- disscube-0.4.0/tests/test_spec_hash.py +113 -0
- disscube-0.4.0/tests/test_temporal.py +211 -0
disscube-0.4.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sérgio Costa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
disscube-0.4.0/PKG-INFO
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: disscube
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: Declarative spatial data cubes: describe sources, grid and derived variables in TOML; get a cataloged, reproducible cube.
|
|
5
|
+
Author: Sérgio Souza Costa
|
|
6
|
+
Maintainer: Sérgio Souza Costa
|
|
7
|
+
License: MIT
|
|
8
|
+
Project-URL: Homepage, https://github.com/DisSModel/disscube
|
|
9
|
+
Project-URL: Repository, https://github.com/DisSModel/disscube
|
|
10
|
+
Project-URL: Documentation, https://dissmodel.github.io/disscube/
|
|
11
|
+
Project-URL: Issues, https://github.com/DisSModel/disscube/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/DisSModel/disscube/blob/main/CHANGELOG.md
|
|
13
|
+
Keywords: spatial data cube,geospatial,land use and land cover change,brazil data cube,reproducibility
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: pydantic>=2.0
|
|
24
|
+
Requires-Dist: xarray
|
|
25
|
+
Requires-Dist: zarr
|
|
26
|
+
Requires-Dist: rasterio
|
|
27
|
+
Requires-Dist: geopandas
|
|
28
|
+
Requires-Dist: shapely
|
|
29
|
+
Requires-Dist: scipy
|
|
30
|
+
Requires-Dist: numpy
|
|
31
|
+
Requires-Dist: pandas
|
|
32
|
+
Requires-Dist: pyproj
|
|
33
|
+
Requires-Dist: fsspec
|
|
34
|
+
Requires-Dist: toml
|
|
35
|
+
Requires-Dist: rioxarray
|
|
36
|
+
Requires-Dist: affine
|
|
37
|
+
Requires-Dist: pooch>=1.8.0
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
41
|
+
Requires-Dist: mypy>=1.13; extra == "dev"
|
|
42
|
+
Requires-Dist: ruff<0.17,>=0.16; extra == "dev"
|
|
43
|
+
Requires-Dist: ipykernel; extra == "dev"
|
|
44
|
+
Provides-Extra: bdc
|
|
45
|
+
Requires-Dist: fiona; extra == "bdc"
|
|
46
|
+
Requires-Dist: pystac-client; extra == "bdc"
|
|
47
|
+
Provides-Extra: s3
|
|
48
|
+
Requires-Dist: s3fs; extra == "s3"
|
|
49
|
+
Provides-Extra: netcdf
|
|
50
|
+
Requires-Dist: h5netcdf; extra == "netcdf"
|
|
51
|
+
Requires-Dist: h5py; extra == "netcdf"
|
|
52
|
+
Provides-Extra: dissmodel
|
|
53
|
+
Requires-Dist: dissmodel<0.7.0,>=0.6.0; extra == "dissmodel"
|
|
54
|
+
Provides-Extra: docs
|
|
55
|
+
Requires-Dist: mkdocs<2,>=1.6; extra == "docs"
|
|
56
|
+
Requires-Dist: mkdocs-material>=9.5; extra == "docs"
|
|
57
|
+
Dynamic: license-file
|
|
58
|
+
|
|
59
|
+
# DisSCube
|
|
60
|
+
|
|
61
|
+
[](https://github.com/DisSModel/disscube/actions/workflows/ci.yml)
|
|
62
|
+
[](https://dissmodel.github.io/disscube/)
|
|
63
|
+
[](https://opensource.org/licenses/MIT)
|
|
64
|
+
|
|
65
|
+
> **Status: Alpha — stable APIs for the core pipeline; declarative models still evolving.**
|
|
66
|
+
|
|
67
|
+
DisSCube is the spatial data cube engine of the **DisSModel** ecosystem. It converts raw geospatial sources (rasters, vectors) into derived variables aligned to LUCC (Land Use and Cover Change) modeling grids, ready for Cellular Automata models and spatio-temporal analysis.
|
|
68
|
+
|
|
69
|
+
📖 **Documentation:** <https://dissmodel.github.io/disscube/>
|
|
70
|
+
|
|
71
|
+
## Core concept
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
SpatialSource → Derivation → Variable → DerivedVariable (Zarr)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A **source** (`SpatialSource`) goes through a **derivation** (`SpatialDerivation` or `Derivation`) that applies an **operator** on a **grid** (`GridSpec`), producing a **derived variable** registered in the SQLite catalog and stored in Zarr.
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone https://github.com/DisSModel/disscube.git
|
|
83
|
+
cd disscube
|
|
84
|
+
python -m venv .venv && source .venv/bin/activate
|
|
85
|
+
pip install -e .
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Basic usage
|
|
89
|
+
|
|
90
|
+
### 1. Initialize the catalog and register a grid
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from disscube.client import CubeClient
|
|
94
|
+
from disscube.utils.grids import register_local_grid
|
|
95
|
+
|
|
96
|
+
cube = CubeClient(catalog="catalog.db", store="./data/")
|
|
97
|
+
|
|
98
|
+
grid = register_local_grid(
|
|
99
|
+
cube,
|
|
100
|
+
name="AC",
|
|
101
|
+
bbox_geo=(-73.99, -11.15, -66.62, -7.11),
|
|
102
|
+
resolution=5_000.0,
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. Register a source
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from disscube.models import SpatialSource
|
|
110
|
+
|
|
111
|
+
cube.register_spatial_source(SpatialSource(
|
|
112
|
+
id="mapbiomas_2020",
|
|
113
|
+
name="MapBiomas Acre 2020",
|
|
114
|
+
format="raster",
|
|
115
|
+
asset_url="data/raw/mapbiomas_2020.tif",
|
|
116
|
+
crs="EPSG:4326",
|
|
117
|
+
time=2020,
|
|
118
|
+
))
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Derive — declarative mode (recommended)
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from disscube.derivation import Derivation
|
|
125
|
+
|
|
126
|
+
d = Derivation(
|
|
127
|
+
target="forest_pct",
|
|
128
|
+
source_id="mapbiomas_2020",
|
|
129
|
+
operator="percentage",
|
|
130
|
+
class_code=3,
|
|
131
|
+
role="driver",
|
|
132
|
+
valid_from="2020",
|
|
133
|
+
valid_until="2020",
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
cube.derive_declarative(d, grid_id="AC/5km")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 4. Derive — direct mode
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from disscube.models import SpatialDerivation, Variable
|
|
143
|
+
|
|
144
|
+
cube.derive(SpatialDerivation(
|
|
145
|
+
source_id="mapbiomas_2020",
|
|
146
|
+
grid_id="AC/5km",
|
|
147
|
+
role="driver",
|
|
148
|
+
variables=[Variable(name="forest_pct", operator="percentage", class_code=3)],
|
|
149
|
+
valid_from="2020",
|
|
150
|
+
valid_until="2020",
|
|
151
|
+
))
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### 5. Load the result
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
da = cube.load("forest_pct", grid_id="AC/5km")
|
|
158
|
+
print(da.shape) # (rows, cols)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 6. Get the cube out
|
|
162
|
+
|
|
163
|
+
```python
|
|
164
|
+
ds = cube.to_dataset(["forest_pct", "dist_roads"], grid_id="AC/5km", period=("2015", "2020"))
|
|
165
|
+
# xarray.Dataset: (y, x) static and (time, y, x) temporal variables, CRS and transform via ds.rio
|
|
166
|
+
|
|
167
|
+
cube.export_geotiff(["forest_pct"], "forest.tif", grid_id="AC/5km") # one band per variable and year
|
|
168
|
+
cube.export_netcdf(["forest_pct"], "cube.nc", grid_id="AC/5km") # CF-1.8; pip install "disscube[netcdf]"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Exports carry their provenance: each GeoTIFF band and netCDF variable records the
|
|
172
|
+
`spec_hash`, the `content_hash` of the stored data and the `source_checksum` of the
|
|
173
|
+
input it came from (`cube.provenance("forest_pct")` lists them per year).
|
|
174
|
+
|
|
175
|
+
DisSCube does not need DisSModel. To hand a cube to a DisSModel model, install
|
|
176
|
+
`disscube[dissmodel]` and use `cube.to_raster_backend(...)`, which returns a `RasterBackend`.
|
|
177
|
+
|
|
178
|
+
## Pipeline files (TOML)
|
|
179
|
+
|
|
180
|
+
A whole data preparation — grid, sources, derived variables — can be declared
|
|
181
|
+
in one TOML file, the counterpart of a TerraME `fill` script, and run from the
|
|
182
|
+
command line:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
disscube validate examples/pipelines/quickstart.toml # no downloads
|
|
186
|
+
disscube run examples/pipelines/quickstart.toml --workspace outputs/quickstart
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
```toml
|
|
190
|
+
schema = 1
|
|
191
|
+
name = "Quickstart"
|
|
192
|
+
|
|
193
|
+
[grid]
|
|
194
|
+
name = "demo/300m"
|
|
195
|
+
crs = "EPSG:31983"
|
|
196
|
+
bbox = [570000.0, 9708000.0, 582000.0, 9720000.0]
|
|
197
|
+
resolution = 300
|
|
198
|
+
|
|
199
|
+
[[source]]
|
|
200
|
+
id = "landuse"
|
|
201
|
+
type = "file"
|
|
202
|
+
path = "../data/quickstart/landuse.tif"
|
|
203
|
+
crs = "EPSG:31983"
|
|
204
|
+
|
|
205
|
+
[[derive]]
|
|
206
|
+
target = "forest_pct"
|
|
207
|
+
source = "landuse"
|
|
208
|
+
operator = "percentage"
|
|
209
|
+
class_code = 3
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
See [`docs/guides/pipeline_files.md`](docs/guides/pipeline_files.md) and
|
|
213
|
+
[`examples/pipelines/`](examples/pipelines/).
|
|
214
|
+
|
|
215
|
+
## Examples
|
|
216
|
+
|
|
217
|
+
[`examples/`](examples/) has runnable, self-contained examples that run offline in seconds:
|
|
218
|
+
|
|
219
|
+
- **01–03, synthetic data** — a quickstart with raster operators, vector drivers, and time series handed off to DisSModel.
|
|
220
|
+
- **quickstart.toml** — declarative pipeline equivalent to example 01.
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
python examples/01_quickstart.py
|
|
224
|
+
disscube run examples/pipelines/quickstart.toml
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Real data workflows, TerraME parity benchmarks, and large-scale case studies are maintained in
|
|
228
|
+
[**LambdaGeo/disscube-recipes**](https://github.com/LambdaGeo/disscube-recipes) (`cases/terrame_fill`, `cases/ilha_maranhao`, `cases/prodes_br163`, `cases/luccme_br`).
|
|
229
|
+
|
|
230
|
+
See [`examples/README.md`](examples/README.md) for the full list, and
|
|
231
|
+
[`docs/terrame_fill_correspondence.md`](docs/terrame_fill_correspondence.md)
|
|
232
|
+
for how DisSCube's operators relate to TerraME's *Fill*.
|
|
233
|
+
|
|
234
|
+
## Available operators
|
|
235
|
+
|
|
236
|
+
| Operator | Type | Resampling | Requires `class_code` |
|
|
237
|
+
|---|---|---|---|
|
|
238
|
+
| `mean` | zonal | average | no |
|
|
239
|
+
| `sum` | zonal | sum | no |
|
|
240
|
+
| `std` | zonal | nearest | no |
|
|
241
|
+
| `min` | zonal | min | no |
|
|
242
|
+
| `max` | zonal | max | no |
|
|
243
|
+
| `majority` | zonal | nearest¹ | no |
|
|
244
|
+
| `minority` | zonal | nearest¹ | no |
|
|
245
|
+
| `percentage` | zonal | nearest¹ | **yes** |
|
|
246
|
+
| `attribute` | zonal | nearest | no |
|
|
247
|
+
| `presence` | zonal | nearest | no |
|
|
248
|
+
| `distance` | proximity (exact, cell centre → nearest feature, source not clipped) | — | no |
|
|
249
|
+
| `min_distance` | proximity (raster approximation, features inside the grid) | nearest | no |
|
|
250
|
+
| `count` | proximity | nearest | no |
|
|
251
|
+
| `area` | polygons (exact share of the cell covered) | — | no |
|
|
252
|
+
|
|
253
|
+
`distance` takes `params = {crs = …}` to measure in another CRS (metres on a
|
|
254
|
+
geographic grid); the ¹ operators take `params = {subcells = n}` to cap the
|
|
255
|
+
fine pixels per cell. Any derivation takes `fill = "nearest"`.
|
|
256
|
+
|
|
257
|
+
> ¹ These use `needs_fine_alignment=True`: GridAligner resamples with `nearest` at high resolution; the actual reduction (per-window counting) is done by the operator.
|
|
258
|
+
|
|
259
|
+
## Pipeline
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
SpatialSource
|
|
263
|
+
│
|
|
264
|
+
▼
|
|
265
|
+
Normalizer — validates / loads a GeoDataFrame (vector) or opens the raster
|
|
266
|
+
│
|
|
267
|
+
▼
|
|
268
|
+
GridAligner — reprojects per variable with the operator's Resampling
|
|
269
|
+
│
|
|
270
|
+
▼
|
|
271
|
+
Aggregator — delegates to operator.compute() → one xr.DataArray per variable
|
|
272
|
+
│
|
|
273
|
+
▼
|
|
274
|
+
VariableWriter — writes Zarr + registers the DerivedVariable in the catalog
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## Storage layout
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
data/derived/{grid_id}/{partition}/{spec_hash}/{variable_name}.zarr
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
- `partition` = `tile_id`, or `global` for untiled derivations.
|
|
284
|
+
- `spec_hash` = SHA-256 of the derivation (source + grid + variables + time window, plus the source's `checksum` when it has one — replacing a source file and registering its new checksum recomputes instead of returning a stale product).
|
|
285
|
+
|
|
286
|
+
## Project structure
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
disscube/
|
|
290
|
+
├── client.py CubeClient — public entry point
|
|
291
|
+
├── models/ GridSpec, SpatialSource, SpatialDerivation, Variable, Derivation…
|
|
292
|
+
├── operators/ Operators as classes (self-registered via __init_subclass__)
|
|
293
|
+
│ ├── base.py Operator ABC + OPERATOR_REGISTRY
|
|
294
|
+
│ ├── zonal.py mean, sum, majority, percentage, attribute, presence…
|
|
295
|
+
│ └── proximity.py distance, min_distance, count
|
|
296
|
+
├── pipeline/ Pipeline execution & planning (schema, runner) + internal stages
|
|
297
|
+
├── catalog/ CatalogStore (Protocol) + SQLite and JSON implementations
|
|
298
|
+
├── storage.py AssetStore (fsspec — local and S3)
|
|
299
|
+
├── cli.py `disscube validate` / `disscube run` / `disscube export`
|
|
300
|
+
├── sources/ Adapters that bring external data in as SpatialSources,
|
|
301
|
+
│ │ each with a checksum and a provenance.json sidecar
|
|
302
|
+
│ ├── _raster.py Window2D, windowed reads, composites, mosaics, register_raster
|
|
303
|
+
│ ├── bdc.py Brazil Data Cube cubes via STAC (`bdc` extra)
|
|
304
|
+
│ ├── _categorical.py legends (.qml/.json/.csv) and reclassification
|
|
305
|
+
│ ├── mapbiomas.py MapBiomas annual land-cover maps (Collection 11, 10 m series)
|
|
306
|
+
│ ├── prodes.py PRODES deforestation (download + cache, legend from the .qml)
|
|
307
|
+
│ └── classified.py any classified map with its legend, e.g. from SITS
|
|
308
|
+
└── utils.py Checksums (sha256_file) and BDC tile importer (import_bdc_grids)
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Adding a new operator
|
|
312
|
+
|
|
313
|
+
Create a subclass of `Operator` in any module imported at startup:
|
|
314
|
+
|
|
315
|
+
```python
|
|
316
|
+
from rasterio.warp import Resampling
|
|
317
|
+
from disscube.operators.base import Operator
|
|
318
|
+
|
|
319
|
+
class WeightedMeanOperator(Operator):
|
|
320
|
+
name = "weighted_mean"
|
|
321
|
+
_resampling = Resampling.average
|
|
322
|
+
|
|
323
|
+
def compute(self, data, var, grid):
|
|
324
|
+
# data is an xr.DataArray (raster) or a GeoDataFrame (vector)
|
|
325
|
+
...
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
The operator is registered automatically and accepted by `Derivation` / `SpatialDerivation` with no other change.
|
|
329
|
+
|
|
330
|
+
## Known limitations
|
|
331
|
+
|
|
332
|
+
The limitations below are scope decisions for the current version, not bugs. They are documented so that users and reviewers understand what is implemented versus what is planned.
|
|
333
|
+
|
|
334
|
+
**In-memory, single-tile processing**
|
|
335
|
+
Each call to `derive()` loads a tile's full data into memory. There is no lazy (Dask) or distributed processing. For continental-scale grids (e.g. `BR/1km`), use the tile loop — each tile is processed and saved independently.
|
|
336
|
+
|
|
337
|
+
**Vector aggregation by rasterization (not area-weighted)**
|
|
338
|
+
Operators over vector sources (`majority`, `percentage`, `attribute`, `presence`, `minority`) convert geometries to raster before aggregating pixels. For the share of each cell covered by polygons, use `area`, which intersects the polygons with the cells exactly.
|
|
339
|
+
|
|
340
|
+
**Tile disambiguation in `load()`**
|
|
341
|
+
`CubeClient.load(name)` without `tile_id` raises `ValueError` when multiple tiles of the same variable exist on the same grid. Automatic mosaicking is not implemented. **Always pass `tile_id` in multi-tile workloads.**
|
|
342
|
+
|
|
343
|
+
**`SpatialRelation` does not act in the pipeline**
|
|
344
|
+
The `SpatialRelation` model is persisted in the catalog, but no pipeline stage uses relations during derivation — which is why they are **excluded from `spec_hash`**. Including them would make the cache key sensitive to metadata that does not affect the result, breaking the reproducibility guarantee. Integration with hierarchical grid strategies is reserved for a future version.
|
|
345
|
+
|
|
346
|
+
**`purity_threshold` reserved**
|
|
347
|
+
The `purity_threshold` field on `Derivation` is included in `spec_hash` but is not applied to the output — purity masking is not implemented. Setting `purity_threshold` changes the cache key without changing the result.
|
|
348
|
+
|
|
349
|
+
**STAC: reading only**
|
|
350
|
+
`disscube.sources.bdc` reads Brazil Data Cube cubes through their STAC catalog (search, windowed reads, per-tile composites, mosaics) and writes local GeoTIFFs that are registered as ordinary sources. Derived variables are not published back as STAC, and the `valid_from`/`valid_until` and `bbox` fields on `Derivation` only follow STAC naming conventions.
|
|
351
|
+
|
|
352
|
+
## Citation
|
|
353
|
+
|
|
354
|
+
If you use DisSCube in your research, dynamic modeling, or spatial data pipelines, please cite it using the metadata from [`CITATION.cff`](CITATION.cff) or the following BibTeX entry:
|
|
355
|
+
|
|
356
|
+
```bibtex
|
|
357
|
+
@software{costa_disscube_2026,
|
|
358
|
+
author = {Costa, S{\'e}rgio Souza},
|
|
359
|
+
title = {{DisSCube: Declarative spatial data cubes}},
|
|
360
|
+
year = {2026},
|
|
361
|
+
version = {0.4.0},
|
|
362
|
+
url = {https://github.com/DisSModel/disscube}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## License
|
|
367
|
+
|
|
368
|
+
DisSCube is part of the DisSModel ecosystem and is released under the MIT License. See [LICENSE](LICENSE) for details.
|