openforis-whisp 2.0.0b1__py3-none-any.whl → 2.0.0b3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openforis_whisp/__init__.py +2 -1
- openforis_whisp/data_conversion.py +11 -0
- openforis_whisp/datasets.py +207 -247
- openforis_whisp/parameters/lookup_gee_datasets.csv +2 -5
- openforis_whisp/risk.py +29 -29
- openforis_whisp/stats.py +297 -47
- openforis_whisp/utils.py +298 -5
- {openforis_whisp-2.0.0b1.dist-info → openforis_whisp-2.0.0b3.dist-info}/METADATA +1 -1
- openforis_whisp-2.0.0b3.dist-info/RECORD +16 -0
- openforis_whisp/parameters/__init__.py +0 -15
- openforis_whisp-2.0.0b1.dist-info/RECORD +0 -17
- {openforis_whisp-2.0.0b1.dist-info → openforis_whisp-2.0.0b3.dist-info}/LICENSE +0 -0
- {openforis_whisp-2.0.0b1.dist-info → openforis_whisp-2.0.0b3.dist-info}/WHEEL +0 -0
openforis_whisp/datasets.py
CHANGED
|
@@ -7,8 +7,10 @@
|
|
|
7
7
|
# b) a prefix of "nXX_" if it is national/sub-national dataset (where XX is replaced by that country code), or a prefix of 'g_' if it covers more than one country.
|
|
8
8
|
# c) a name for your image, defined by ".rename('add_your_image_name_here')". This becomes the column header in the output table.
|
|
9
9
|
|
|
10
|
-
#
|
|
11
|
-
#
|
|
10
|
+
# Tips:
|
|
11
|
+
# -Avoid getInfo() and for loops to speed up processing by keeping everything in the Earth Engine API.
|
|
12
|
+
# -For all the above you will need to be running the package in editable mode for these local changes to take effect.
|
|
13
|
+
# Editable mode runs the package locally and thus changes to any files are reflected immediately.
|
|
12
14
|
|
|
13
15
|
import ee
|
|
14
16
|
|
|
@@ -24,6 +26,11 @@ from datetime import datetime
|
|
|
24
26
|
# defining here instead of importing from config_runtime, to allow functioning as more of a standalone script
|
|
25
27
|
geometry_area_column = "Area"
|
|
26
28
|
|
|
29
|
+
# Calculate current year once at module load time (not in functions)
|
|
30
|
+
# This avoids repeated datetime calls and potential .getInfo() calls
|
|
31
|
+
CURRENT_YEAR = datetime.now().year
|
|
32
|
+
CURRENT_YEAR_2DIGIT = CURRENT_YEAR % 100 # Last two digits for RADD datasets
|
|
33
|
+
|
|
27
34
|
import inspect
|
|
28
35
|
|
|
29
36
|
import logging
|
|
@@ -49,13 +56,13 @@ def g_esa_worldcover_trees_prep():
|
|
|
49
56
|
esa_worldcover_trees_2020 = esa_worldcover_2020_raw.eq(95).Or(
|
|
50
57
|
esa_worldcover_2020_raw.eq(10)
|
|
51
58
|
) # get trees and mnangroves
|
|
52
|
-
return esa_worldcover_trees_2020.rename("ESA_TC_2020")
|
|
59
|
+
return esa_worldcover_trees_2020.rename("ESA_TC_2020").selfMask()
|
|
53
60
|
|
|
54
61
|
|
|
55
62
|
# EUFO_2020
|
|
56
63
|
def g_jrc_gfc_2020_prep():
|
|
57
64
|
jrc_gfc2020_raw = ee.ImageCollection("JRC/GFC2020/V2")
|
|
58
|
-
return jrc_gfc2020_raw.mosaic().rename("EUFO_2020")
|
|
65
|
+
return jrc_gfc2020_raw.mosaic().rename("EUFO_2020").selfMask()
|
|
59
66
|
|
|
60
67
|
|
|
61
68
|
# GFC_TC_2020
|
|
@@ -64,7 +71,7 @@ def g_glad_gfc_10pc_prep():
|
|
|
64
71
|
gfc_treecover2000 = gfc.select(["treecover2000"])
|
|
65
72
|
gfc_loss2001_2020 = gfc.select(["lossyear"]).lte(20)
|
|
66
73
|
gfc_treecover2020 = gfc_treecover2000.where(gfc_loss2001_2020.eq(1), 0)
|
|
67
|
-
return gfc_treecover2020.gt(10).rename("GFC_TC_2020")
|
|
74
|
+
return gfc_treecover2020.gt(10).rename("GFC_TC_2020").selfMask()
|
|
68
75
|
|
|
69
76
|
|
|
70
77
|
# GLAD_Primary
|
|
@@ -77,8 +84,10 @@ def g_glad_pht_prep():
|
|
|
77
84
|
)
|
|
78
85
|
gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
|
|
79
86
|
gfc_loss2001_2020 = gfc.select(["lossyear"]).lte(20)
|
|
80
|
-
return
|
|
81
|
-
|
|
87
|
+
return (
|
|
88
|
+
primary_ht_forests2001.where(gfc_loss2001_2020.eq(1), 0)
|
|
89
|
+
.rename("GLAD_Primary")
|
|
90
|
+
.selfMask()
|
|
82
91
|
)
|
|
83
92
|
|
|
84
93
|
|
|
@@ -90,7 +99,7 @@ def g_jrc_tmf_undisturbed_prep():
|
|
|
90
99
|
.mosaic()
|
|
91
100
|
.eq(1)
|
|
92
101
|
) # update from https://github.com/forestdatapartnership/whisp/issues/42
|
|
93
|
-
return TMF_undist_2020.rename("TMF_undist")
|
|
102
|
+
return TMF_undist_2020.rename("TMF_undist").selfMask()
|
|
94
103
|
|
|
95
104
|
|
|
96
105
|
# Forest Persistence FDaP
|
|
@@ -99,7 +108,7 @@ def g_fdap_forest_prep():
|
|
|
99
108
|
"projects/forestdatapartnership/assets/community_forests/ForestPersistence_2020"
|
|
100
109
|
)
|
|
101
110
|
fdap_forest = fdap_forest_raw.gt(0.75)
|
|
102
|
-
return fdap_forest.rename("Forest_FDaP")
|
|
111
|
+
return fdap_forest.rename("Forest_FDaP").selfMask()
|
|
103
112
|
|
|
104
113
|
|
|
105
114
|
#########################primary forest
|
|
@@ -107,27 +116,27 @@ def g_fdap_forest_prep():
|
|
|
107
116
|
def g_gft_primary_prep():
|
|
108
117
|
gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
|
|
109
118
|
gft_primary = gft_raw.eq(10)
|
|
110
|
-
return gft_primary.rename("GFT_primary")
|
|
119
|
+
return gft_primary.rename("GFT_primary").selfMask()
|
|
111
120
|
|
|
112
121
|
|
|
113
122
|
# Intact Forest Landscape 2020
|
|
114
123
|
def g_ifl_2020_prep():
|
|
115
124
|
IFL_2020 = ee.Image("users/potapovpeter/IFL_2020")
|
|
116
|
-
return IFL_2020.rename("IFL_2020")
|
|
125
|
+
return IFL_2020.rename("IFL_2020").selfMask()
|
|
117
126
|
|
|
118
127
|
|
|
119
128
|
# European Primary Forest Dataset
|
|
120
129
|
def g_epfd_prep():
|
|
121
130
|
EPFD = ee.FeatureCollection("HU_BERLIN/EPFD/V2/polygons")
|
|
122
131
|
EPFD_binary = ee.Image().paint(EPFD, 1)
|
|
123
|
-
return EPFD_binary.rename("European_Primary_Forest")
|
|
132
|
+
return EPFD_binary.rename("European_Primary_Forest").selfMask()
|
|
124
133
|
|
|
125
134
|
|
|
126
135
|
# EUFO JRC Global forest type - naturally regenerating planted/plantation forests
|
|
127
136
|
def g_gft_nat_reg_prep():
|
|
128
137
|
gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
|
|
129
138
|
gft_nat_reg = gft_raw.eq(1)
|
|
130
|
-
return gft_nat_reg.rename("GFT_naturally_regenerating")
|
|
139
|
+
return gft_nat_reg.rename("GFT_naturally_regenerating").selfMask()
|
|
131
140
|
|
|
132
141
|
|
|
133
142
|
#########################planted and plantation forests
|
|
@@ -136,13 +145,13 @@ def g_gft_nat_reg_prep():
|
|
|
136
145
|
def g_gft_plantation_prep():
|
|
137
146
|
gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
|
|
138
147
|
gft_plantation = gft_raw.eq(20)
|
|
139
|
-
return gft_plantation.rename("GFT_planted_plantation")
|
|
148
|
+
return gft_plantation.rename("GFT_planted_plantation").selfMask()
|
|
140
149
|
|
|
141
150
|
|
|
142
151
|
def g_iiasa_planted_prep():
|
|
143
152
|
iiasa = ee.Image("projects/sat-io/open-datasets/GFM/FML_v3-2")
|
|
144
153
|
iiasa_PL = iiasa.eq(31).Or(iiasa.eq(32))
|
|
145
|
-
return iiasa_PL.rename("IIASA_planted_plantation")
|
|
154
|
+
return iiasa_PL.rename("IIASA_planted_plantation").selfMask()
|
|
146
155
|
|
|
147
156
|
|
|
148
157
|
#########################TMF regrowth in 2023
|
|
@@ -151,7 +160,7 @@ def g_tmf_regrowth_prep():
|
|
|
151
160
|
TMF_AC = ee.ImageCollection("projects/JRC/TMF/v1_2024/AnnualChanges").mosaic()
|
|
152
161
|
TMF_AC_2023 = TMF_AC.select("Dec2023")
|
|
153
162
|
Regrowth_TMF = TMF_AC_2023.eq(4)
|
|
154
|
-
return Regrowth_TMF.rename("TMF_regrowth_2023")
|
|
163
|
+
return Regrowth_TMF.rename("TMF_regrowth_2023").selfMask()
|
|
155
164
|
|
|
156
165
|
|
|
157
166
|
############tree crops
|
|
@@ -181,20 +190,22 @@ def g_creaf_descals_palm_prep():
|
|
|
181
190
|
)
|
|
182
191
|
.mosaic()
|
|
183
192
|
.select("minNBR_date")
|
|
184
|
-
)
|
|
193
|
+
).selfMask()
|
|
185
194
|
|
|
186
195
|
# Calculate the year of plantation and select all below and including 2020
|
|
187
196
|
oil_palm_plantation_year = img.divide(365).add(1970).floor().lte(2020)
|
|
188
197
|
|
|
189
198
|
# Create a mask for plantations in the year 2020 or earlier
|
|
190
|
-
plantation_2020 = oil_palm_plantation_year.lte(2020)
|
|
191
|
-
return plantation_2020.rename("Oil_palm_Descals")
|
|
199
|
+
plantation_2020 = oil_palm_plantation_year.lte(2020)
|
|
200
|
+
return plantation_2020.rename("Oil_palm_Descals").selfMask()
|
|
192
201
|
|
|
193
202
|
|
|
194
203
|
# Cocoa_ETH
|
|
195
204
|
def g_eth_kalischek_cocoa_prep():
|
|
196
|
-
return
|
|
197
|
-
"
|
|
205
|
+
return (
|
|
206
|
+
ee.Image("projects/ee-nk-cocoa/assets/cocoa_map_threshold_065")
|
|
207
|
+
.rename("Cocoa_ETH")
|
|
208
|
+
.selfMask()
|
|
198
209
|
)
|
|
199
210
|
|
|
200
211
|
|
|
@@ -212,7 +223,7 @@ def g_fdap_palm_prep():
|
|
|
212
223
|
.mosaic()
|
|
213
224
|
.gt(0.88) # Precision and recall ~78% at 0.88 threshold.
|
|
214
225
|
)
|
|
215
|
-
return fdap_palm.rename("Oil_palm_FDaP")
|
|
226
|
+
return fdap_palm.rename("Oil_palm_FDaP").selfMask()
|
|
216
227
|
|
|
217
228
|
|
|
218
229
|
def g_fdap_palm_2023_prep():
|
|
@@ -224,7 +235,7 @@ def g_fdap_palm_2023_prep():
|
|
|
224
235
|
.mosaic()
|
|
225
236
|
.gt(0.88) # Precision and recall ~78% at 0.88 threshold.
|
|
226
237
|
)
|
|
227
|
-
return fdap_palm.rename("Oil_palm_2023_FDaP")
|
|
238
|
+
return fdap_palm.rename("Oil_palm_2023_FDaP").selfMask()
|
|
228
239
|
|
|
229
240
|
|
|
230
241
|
# Cocoa FDaP
|
|
@@ -237,7 +248,7 @@ def g_fdap_cocoa_prep():
|
|
|
237
248
|
.mosaic()
|
|
238
249
|
.gt(0.96) # Precision and recall ~87% 0.96 threshold.
|
|
239
250
|
)
|
|
240
|
-
return fdap_cocoa.rename("Cocoa_FDaP")
|
|
251
|
+
return fdap_cocoa.rename("Cocoa_FDaP").selfMask()
|
|
241
252
|
|
|
242
253
|
|
|
243
254
|
def g_fdap_cocoa_2023_prep():
|
|
@@ -249,7 +260,7 @@ def g_fdap_cocoa_2023_prep():
|
|
|
249
260
|
.mosaic()
|
|
250
261
|
.gt(0.96) # Precision and recall ~87% 0.96 threshold.
|
|
251
262
|
)
|
|
252
|
-
return fdap_cocoa.rename("Cocoa_2023_FDaP")
|
|
263
|
+
return fdap_cocoa.rename("Cocoa_2023_FDaP").selfMask()
|
|
253
264
|
|
|
254
265
|
|
|
255
266
|
# Rubber FDaP
|
|
@@ -262,7 +273,7 @@ def g_fdap_rubber_prep():
|
|
|
262
273
|
.mosaic()
|
|
263
274
|
.gt(0.59) # Precision and recall ~80% 0.59 threshold.
|
|
264
275
|
)
|
|
265
|
-
return fdap_rubber.rename("Rubber_FDaP")
|
|
276
|
+
return fdap_rubber.rename("Rubber_FDaP").selfMask()
|
|
266
277
|
|
|
267
278
|
|
|
268
279
|
def g_fdap_rubber_2023_prep():
|
|
@@ -274,7 +285,7 @@ def g_fdap_rubber_2023_prep():
|
|
|
274
285
|
.mosaic()
|
|
275
286
|
.gt(0.59) # Threshold for Rubber
|
|
276
287
|
)
|
|
277
|
-
return fdap_rubber.rename("Rubber_2023_FDaP")
|
|
288
|
+
return fdap_rubber.rename("Rubber_2023_FDaP").selfMask()
|
|
278
289
|
|
|
279
290
|
|
|
280
291
|
# # Coffee FDaP
|
|
@@ -291,7 +302,7 @@ def g_fdap_coffee_2020_prep():
|
|
|
291
302
|
.gt(0.99) # Precision and recall ~54% 0.99 threshold.
|
|
292
303
|
)
|
|
293
304
|
|
|
294
|
-
return coffee_2020.rename("Coffee_FDaP")
|
|
305
|
+
return coffee_2020.rename("Coffee_FDaP").selfMask()
|
|
295
306
|
|
|
296
307
|
|
|
297
308
|
def g_fdap_coffee_2023_prep():
|
|
@@ -306,7 +317,7 @@ def g_fdap_coffee_2023_prep():
|
|
|
306
317
|
.mosaic()
|
|
307
318
|
.gt(0.99) # Precision and recall ~54% 0.99 threshold.
|
|
308
319
|
)
|
|
309
|
-
return coffee_2023.rename("Coffee_FDaP_2023")
|
|
320
|
+
return coffee_2023.rename("Coffee_FDaP_2023").selfMask()
|
|
310
321
|
|
|
311
322
|
|
|
312
323
|
# Rubber_RBGE - from Royal Botanical Gardens of Edinburgh (RBGE) NB for 2021
|
|
@@ -315,14 +326,16 @@ def g_rbge_rubber_prep():
|
|
|
315
326
|
ee.Image(
|
|
316
327
|
"users/wangyxtina/MapRubberPaper/rRubber10m202122_perc1585DifESAdist5pxPF"
|
|
317
328
|
)
|
|
318
|
-
.unmask()
|
|
319
329
|
.rename("Rubber_RBGE")
|
|
330
|
+
.selfMask()
|
|
320
331
|
)
|
|
321
332
|
|
|
322
333
|
|
|
323
334
|
# soy 2020 South America
|
|
324
335
|
def g_soy_song_2020_prep():
|
|
325
|
-
return
|
|
336
|
+
return (
|
|
337
|
+
ee.Image("projects/glad/soy_annual_SA/2020").rename("Soy_Song_2020").selfMask()
|
|
338
|
+
)
|
|
326
339
|
|
|
327
340
|
|
|
328
341
|
##############
|
|
@@ -336,49 +349,24 @@ def g_esri_2023_tc_prep():
|
|
|
336
349
|
esri_lulc10_TC = (
|
|
337
350
|
esri_lulc10_raw.filterDate("2023-01-01", "2023-12-31").mosaic().eq(2)
|
|
338
351
|
)
|
|
339
|
-
return esri_lulc10_TC.rename("ESRI_2023_TC")
|
|
352
|
+
return esri_lulc10_TC.rename("ESRI_2023_TC").selfMask()
|
|
340
353
|
|
|
341
354
|
|
|
342
355
|
# ESRI 2023 - Crop
|
|
343
|
-
def
|
|
356
|
+
def g_esri_2020_2023_crop_prep():
|
|
344
357
|
esri_lulc10_raw = ee.ImageCollection(
|
|
345
358
|
"projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS"
|
|
346
359
|
)
|
|
347
|
-
|
|
348
|
-
esri_lulc10_raw.filterDate("
|
|
360
|
+
esri_lulc10_crop_2020 = (
|
|
361
|
+
esri_lulc10_raw.filterDate("2020-01-01", "2020-12-31").mosaic().eq(5)
|
|
349
362
|
)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
# GLC_FCS30D 2022
|
|
354
|
-
|
|
355
|
-
# GLC_FCS30D Tree Cover
|
|
356
|
-
# forest classes + swamp + mangrove / what to do with shrubland?
|
|
357
|
-
def g_glc_fcs30d_tc_2022_prep():
|
|
358
|
-
GLC_FCS30D = (
|
|
359
|
-
ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual")
|
|
360
|
-
.mosaic()
|
|
361
|
-
.select(22)
|
|
362
|
-
)
|
|
363
|
-
GLC_FCS30D_TC = (
|
|
364
|
-
(GLC_FCS30D.gte(51))
|
|
365
|
-
.And(GLC_FCS30D.lte(92))
|
|
366
|
-
.Or(GLC_FCS30D.eq(181))
|
|
367
|
-
.Or(GLC_FCS30D.eq(185))
|
|
363
|
+
esri_lulc10_crop_2023 = (
|
|
364
|
+
esri_lulc10_raw.filterDate("2023-01-01", "2023-12-31").mosaic().eq(5)
|
|
368
365
|
)
|
|
369
|
-
return GLC_FCS30D_TC.rename("GLC_FCS30D_TC_2022")
|
|
370
366
|
|
|
367
|
+
newCrop = esri_lulc10_crop_2023.And(esri_lulc10_crop_2020.Not())
|
|
371
368
|
|
|
372
|
-
|
|
373
|
-
# 10 Rainfed cropland; 11 Herbaceous cover; 12 Tree or shrub cover (Orchard); 20 Irrigated cropland
|
|
374
|
-
def g_glc_fcs30d_crop_2022_prep():
|
|
375
|
-
GLC_FCS30D = (
|
|
376
|
-
ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual")
|
|
377
|
-
.mosaic()
|
|
378
|
-
.select(22)
|
|
379
|
-
)
|
|
380
|
-
GLC_FCS30D_crop = GLC_FCS30D.gte(10).And(GLC_FCS30D.lte(20))
|
|
381
|
-
return GLC_FCS30D_crop.rename("GLC_FCS30D_crop_2022")
|
|
369
|
+
return newCrop.rename("ESRI_crop_gain_2020_2023").selfMask()
|
|
382
370
|
|
|
383
371
|
|
|
384
372
|
#### disturbances by year
|
|
@@ -388,23 +376,13 @@ def g_radd_year_prep():
|
|
|
388
376
|
from datetime import datetime
|
|
389
377
|
|
|
390
378
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
391
|
-
|
|
392
379
|
radd_date = (
|
|
393
380
|
radd.filterMetadata("layer", "contains", "alert").select("Date").mosaic()
|
|
394
381
|
)
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
current_year = (
|
|
399
|
-
datetime.now().year
|
|
400
|
-
% 100
|
|
401
|
-
# NB the % 100 part gets last two digits needed
|
|
402
|
-
)
|
|
382
|
+
start_year = 19
|
|
383
|
+
current_year = datetime.now().year % 100
|
|
403
384
|
|
|
404
|
-
|
|
405
|
-
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to <current year>
|
|
406
|
-
for year in range(start_year, current_year + 1):
|
|
407
|
-
# gfc_loss_year = gfc.select(['lossyear']).eq(i).And(gfc.select(['treecover2000']).gt(10)) # use any definition of loss
|
|
385
|
+
def make_band(year, img_stack):
|
|
408
386
|
start = year * 1000
|
|
409
387
|
end = year * 1000 + 365
|
|
410
388
|
radd_year = (
|
|
@@ -413,12 +391,35 @@ def g_radd_year_prep():
|
|
|
413
391
|
.gt(0)
|
|
414
392
|
.rename("RADD_year_" + "20" + str(year))
|
|
415
393
|
)
|
|
394
|
+
return ee.Image(img_stack).addBands(radd_year)
|
|
395
|
+
|
|
396
|
+
years = ee.List.sequence(start_year, current_year)
|
|
397
|
+
first_year = ee.Number(years.get(0))
|
|
398
|
+
start = first_year.multiply(1000)
|
|
399
|
+
end = first_year.multiply(1000).add(365)
|
|
400
|
+
band_name = ee.String("RADD_year_").cat("20").cat(first_year.format("%02d"))
|
|
401
|
+
first_band = (
|
|
402
|
+
radd_date.updateMask(radd_date.gte(start))
|
|
403
|
+
.updateMask(radd_date.lte(end))
|
|
404
|
+
.gt(0)
|
|
405
|
+
.rename(band_name)
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
def make_band(year, img_stack):
|
|
409
|
+
year_num = ee.Number(year)
|
|
410
|
+
start = year_num.multiply(1000)
|
|
411
|
+
end = year_num.multiply(1000).add(365)
|
|
412
|
+
band_name = ee.String("RADD_year_").cat("20").cat(year_num.format("%02d"))
|
|
413
|
+
radd_year = (
|
|
414
|
+
radd_date.updateMask(radd_date.gte(start))
|
|
415
|
+
.updateMask(radd_date.lte(end))
|
|
416
|
+
.gt(0)
|
|
417
|
+
.rename(band_name)
|
|
418
|
+
)
|
|
419
|
+
return ee.Image(img_stack).addBands(radd_year)
|
|
416
420
|
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
else:
|
|
420
|
-
img_stack = img_stack.addBands(radd_year)
|
|
421
|
-
return img_stack
|
|
421
|
+
img_stack = years.slice(1).iterate(make_band, first_band)
|
|
422
|
+
return ee.Image(img_stack)
|
|
422
423
|
|
|
423
424
|
|
|
424
425
|
# TMF_def_2000 to TMF_def_2023
|
|
@@ -428,7 +429,9 @@ def g_tmf_def_per_year_prep():
|
|
|
428
429
|
img_stack = None
|
|
429
430
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
430
431
|
for i in range(0, 24 + 1):
|
|
431
|
-
|
|
432
|
+
year_num = ee.Number(2000 + i)
|
|
433
|
+
band_name = ee.String("TMF_def_").cat(year_num.format("%d"))
|
|
434
|
+
tmf_def_year = tmf_def.eq(year_num).rename(band_name)
|
|
432
435
|
if img_stack is None:
|
|
433
436
|
img_stack = tmf_def_year
|
|
434
437
|
else:
|
|
@@ -443,7 +446,9 @@ def g_tmf_deg_per_year_prep():
|
|
|
443
446
|
img_stack = None
|
|
444
447
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
445
448
|
for i in range(0, 24 + 1):
|
|
446
|
-
|
|
449
|
+
year_num = ee.Number(2000 + i)
|
|
450
|
+
band_name = ee.String("TMF_deg_").cat(year_num.format("%d"))
|
|
451
|
+
tmf_def_year = tmf_def.eq(year_num).rename(band_name)
|
|
447
452
|
if img_stack is None:
|
|
448
453
|
img_stack = tmf_def_year
|
|
449
454
|
else:
|
|
@@ -458,10 +463,12 @@ def g_glad_gfc_loss_per_year_prep():
|
|
|
458
463
|
img_stack = None
|
|
459
464
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
460
465
|
for i in range(1, 24 + 1):
|
|
466
|
+
year_num = ee.Number(2000 + i)
|
|
467
|
+
band_name = ee.String("GFC_loss_year_").cat(year_num.format("%d"))
|
|
461
468
|
gfc_loss_year = (
|
|
462
469
|
gfc.select(["lossyear"]).eq(i).And(gfc.select(["treecover2000"]).gt(10))
|
|
463
470
|
)
|
|
464
|
-
gfc_loss_year = gfc_loss_year.rename(
|
|
471
|
+
gfc_loss_year = gfc_loss_year.rename(band_name)
|
|
465
472
|
if img_stack is None:
|
|
466
473
|
img_stack = gfc_loss_year
|
|
467
474
|
else:
|
|
@@ -482,6 +489,8 @@ def g_modis_fire_prep():
|
|
|
482
489
|
img_stack = None
|
|
483
490
|
|
|
484
491
|
for year in range(start_year, end_year + 1):
|
|
492
|
+
year_num = ee.Number(year)
|
|
493
|
+
band_name = ee.String("MODIS_fire_").cat(year_num.format("%d"))
|
|
485
494
|
date_st = f"{year}-01-01"
|
|
486
495
|
date_ed = f"{year}-12-31"
|
|
487
496
|
modis_year = (
|
|
@@ -489,7 +498,7 @@ def g_modis_fire_prep():
|
|
|
489
498
|
.mosaic()
|
|
490
499
|
.select(["BurnDate"])
|
|
491
500
|
.gte(0)
|
|
492
|
-
.rename(
|
|
501
|
+
.rename(band_name)
|
|
493
502
|
)
|
|
494
503
|
img_stack = modis_year if img_stack is None else img_stack.addBands(modis_year)
|
|
495
504
|
|
|
@@ -509,6 +518,8 @@ def g_esa_fire_prep():
|
|
|
509
518
|
img_stack = None
|
|
510
519
|
|
|
511
520
|
for year in range(start_year, end_year + 1):
|
|
521
|
+
year_num = ee.Number(year)
|
|
522
|
+
band_name = ee.String("ESA_fire_").cat(year_num.format("%d"))
|
|
512
523
|
date_st = f"{year}-01-01"
|
|
513
524
|
date_ed = f"{year}-12-31"
|
|
514
525
|
esa_year = (
|
|
@@ -516,107 +527,17 @@ def g_esa_fire_prep():
|
|
|
516
527
|
.mosaic()
|
|
517
528
|
.select(["BurnDate"])
|
|
518
529
|
.gte(0)
|
|
519
|
-
.rename(
|
|
530
|
+
.rename(band_name)
|
|
520
531
|
)
|
|
521
532
|
img_stack = esa_year if img_stack is None else img_stack.addBands(esa_year)
|
|
522
533
|
|
|
523
534
|
return img_stack
|
|
524
535
|
|
|
525
536
|
|
|
526
|
-
# # DIST_alert_2024 to DIST_alert_< current year >
|
|
527
|
-
# # Notes:
|
|
528
|
-
# # 1) so far only available for 2024 onwards in GEE
|
|
529
|
-
# # TO DO - see if gee asset for pre 2020-2024 is available from GLAD team, else download from nasa and put in Whisp assets
|
|
530
|
-
# # 2) masked alerts (as dist alerts are for all vegetation) to JRC EUFO 2020 layer, as close to EUDR definition
|
|
531
|
-
# # TO DO - ask opinions on if others (such as treecover data from GLAD team) should be used instead
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
# def glad_dist_year_prep():
|
|
535
|
-
|
|
536
|
-
# # Load the vegetation disturbance collections
|
|
537
|
-
|
|
538
|
-
# # Vegetation disturbance status (0-8, class flag, 8-bit)
|
|
539
|
-
# VEGDISTSTATUS = ee.ImageCollection(
|
|
540
|
-
# "projects/glad/HLSDIST/current/VEG-DIST-STATUS"
|
|
541
|
-
# ).mosaic()
|
|
542
|
-
# # Initial vegetation disturbance date (>0: days since 2020-12-31, 16-bit)
|
|
543
|
-
# VEGDISTDATE = ee.ImageCollection(
|
|
544
|
-
# "projects/glad/HLSDIST/current/VEG-DIST-DATE"
|
|
545
|
-
# ).mosaic()
|
|
546
|
-
|
|
547
|
-
# # NB relies on initial date of disturbance - consider if last date needed? : VEGLASTDATE = ee.ImageCollection("projects/glad/HLSDIST/current/VEG-LAST-DATE").mosaic(); # Last assessed observation date (≥1, days, 16-bit)
|
|
548
|
-
|
|
549
|
-
# # Key for high-confidence alerts (values 3, 6, 7, 8)
|
|
550
|
-
# high_conf_values = [3, 6, 7, 8]
|
|
551
|
-
# # where:
|
|
552
|
-
# # 3 = <50% loss, high confidence, ongoing
|
|
553
|
-
# # 6 = ≥50% loss, high confidence, ongoing
|
|
554
|
-
# # 7 = <50% loss, high confidence, finished
|
|
555
|
-
# # 8 = ≥50% loss, high confidence, finished
|
|
556
|
-
# # Note could use <50% loss (i.e. only 6 and 7) for if want to be more strict
|
|
557
|
-
|
|
558
|
-
# # Create high-confidence mask
|
|
559
|
-
# dist_high_conf = VEGDISTSTATUS.remap(
|
|
560
|
-
# high_conf_values, [1] * len(high_conf_values), 0
|
|
561
|
-
# )
|
|
562
|
-
|
|
563
|
-
# # Determine start year and current year dynamically
|
|
564
|
-
# start_year = 2024 # Set the first year of interest
|
|
565
|
-
# current_year = datetime.now().year
|
|
566
|
-
|
|
567
|
-
# # Calculate days since December 31, 2020 for start and end dates (server-side)
|
|
568
|
-
# start_of_2020 = ee.Date("2020-12-31").millis().divide(86400000).int()
|
|
569
|
-
|
|
570
|
-
# # Create a list to hold the yearly images
|
|
571
|
-
# yearly_images = []
|
|
572
|
-
|
|
573
|
-
# for year in range(start_year, current_year + 1):
|
|
574
|
-
# start_of_year = (
|
|
575
|
-
# ee.Date(f"{year}-01-01")
|
|
576
|
-
# .millis()
|
|
577
|
-
# .divide(86400000)
|
|
578
|
-
# .int()
|
|
579
|
-
# .subtract(start_of_2020)
|
|
580
|
-
# )
|
|
581
|
-
# start_of_next_year = (
|
|
582
|
-
# ee.Date(f"{year + 1}-01-01")
|
|
583
|
-
# .millis()
|
|
584
|
-
# .divide(86400000)
|
|
585
|
-
# .int()
|
|
586
|
-
# .subtract(start_of_2020)
|
|
587
|
-
# )
|
|
588
|
-
|
|
589
|
-
# # Filter VEG-DIST-DATE for the selected year
|
|
590
|
-
# dist_year = VEGDISTDATE.gte(start_of_year).And(
|
|
591
|
-
# VEGDISTDATE.lt(start_of_next_year)
|
|
592
|
-
# )
|
|
593
|
-
|
|
594
|
-
# # Apply high-confidence mask and rename the band
|
|
595
|
-
# high_conf_year = dist_year.updateMask(dist_high_conf).rename(
|
|
596
|
-
# f"DIST_year_{year}"
|
|
597
|
-
# )
|
|
598
|
-
|
|
599
|
-
# # Append the year's data to the list
|
|
600
|
-
# yearly_images.append(high_conf_year)
|
|
601
|
-
|
|
602
|
-
# # Combine all yearly images into a single image
|
|
603
|
-
# img_stack = ee.Image.cat(yearly_images)
|
|
604
|
-
|
|
605
|
-
# # Rename the bands correctly
|
|
606
|
-
# band_names = [f"DIST_year_{year}" for year in range(start_year, current_year + 1)]
|
|
607
|
-
# img_stack = img_stack.select(img_stack.bandNames(), band_names)
|
|
608
|
-
|
|
609
|
-
# return img_stack.updateMask(
|
|
610
|
-
# jrc_gfc_2020_prep()
|
|
611
|
-
# ) # mask yearly dist alerts to forest cover in 2020
|
|
612
|
-
|
|
613
|
-
|
|
614
537
|
#### disturbances combined (split into before and after 2020)
|
|
615
538
|
|
|
616
539
|
# RADD_after_2020
|
|
617
540
|
def g_radd_after_2020_prep():
|
|
618
|
-
from datetime import datetime
|
|
619
|
-
|
|
620
541
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
621
542
|
|
|
622
543
|
radd_date = (
|
|
@@ -625,9 +546,8 @@ def g_radd_after_2020_prep():
|
|
|
625
546
|
# date of avaialbility
|
|
626
547
|
start_year = 21 ## (starts 2019 in Africa, then 2020 for S America and Asia: https://data.globalforestwatch.org/datasets/gfw::deforestation-alerts-radd/about)
|
|
627
548
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
) # NB the % 100 part gets last two digits needed
|
|
549
|
+
# Use pre-calculated current year (avoids repeated datetime calls)
|
|
550
|
+
current_year = CURRENT_YEAR_2DIGIT
|
|
631
551
|
start = start_year * 1000
|
|
632
552
|
end = current_year * 1000 + 365
|
|
633
553
|
return (
|
|
@@ -635,13 +555,11 @@ def g_radd_after_2020_prep():
|
|
|
635
555
|
.updateMask(radd_date.lte(end))
|
|
636
556
|
.gt(0)
|
|
637
557
|
.rename("RADD_after_2020")
|
|
638
|
-
)
|
|
558
|
+
).selfMask()
|
|
639
559
|
|
|
640
560
|
|
|
641
561
|
# RADD_before_2020
|
|
642
562
|
def g_radd_before_2020_prep():
|
|
643
|
-
from datetime import datetime
|
|
644
|
-
|
|
645
563
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
646
564
|
|
|
647
565
|
radd_date = (
|
|
@@ -650,8 +568,6 @@ def g_radd_before_2020_prep():
|
|
|
650
568
|
# date of avaialbility
|
|
651
569
|
start_year = 19 ## (starts 2019 in Africa, then 2020 for S America and Asia: https://data.globalforestwatch.org/datasets/gfw::deforestation-alerts-radd/about)
|
|
652
570
|
|
|
653
|
-
# current_year = datetime.now().year % 100 # NB the % 100 part gets last two digits needed
|
|
654
|
-
|
|
655
571
|
start = start_year * 1000
|
|
656
572
|
end = 20 * 1000 + 365
|
|
657
573
|
return (
|
|
@@ -659,7 +575,7 @@ def g_radd_before_2020_prep():
|
|
|
659
575
|
.updateMask(radd_date.lte(end))
|
|
660
576
|
.gt(0)
|
|
661
577
|
.rename("RADD_before_2020")
|
|
662
|
-
)
|
|
578
|
+
).selfMask()
|
|
663
579
|
|
|
664
580
|
|
|
665
581
|
# # DIST_after_2020
|
|
@@ -687,25 +603,35 @@ def g_radd_before_2020_prep():
|
|
|
687
603
|
# TMF_deg_before_2020
|
|
688
604
|
def g_tmf_deg_before_2020_prep():
|
|
689
605
|
tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
|
|
690
|
-
return (
|
|
606
|
+
return (
|
|
607
|
+
(tmf_deg.lte(2020))
|
|
608
|
+
.And(tmf_deg.gte(2000))
|
|
609
|
+
.rename("TMF_deg_before_2020")
|
|
610
|
+
.selfMask()
|
|
611
|
+
)
|
|
691
612
|
|
|
692
613
|
|
|
693
614
|
# TMF_deg_after_2020
|
|
694
615
|
def g_tmf_deg_after_2020_prep():
|
|
695
616
|
tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
|
|
696
|
-
return tmf_deg.gt(2020).rename("TMF_deg_after_2020")
|
|
617
|
+
return tmf_deg.gt(2020).rename("TMF_deg_after_2020").selfMask()
|
|
697
618
|
|
|
698
619
|
|
|
699
620
|
# tmf_def_before_2020
|
|
700
621
|
def g_tmf_def_before_2020_prep():
|
|
701
622
|
tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
|
|
702
|
-
return (
|
|
623
|
+
return (
|
|
624
|
+
(tmf_def.lte(2020))
|
|
625
|
+
.And(tmf_def.gte(2000))
|
|
626
|
+
.rename("TMF_def_before_2020")
|
|
627
|
+
.selfMask()
|
|
628
|
+
)
|
|
703
629
|
|
|
704
630
|
|
|
705
631
|
# tmf_def_after_2020
|
|
706
632
|
def g_tmf_def_after_2020_prep():
|
|
707
633
|
tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
|
|
708
|
-
return tmf_def.gt(2020).rename("TMF_def_after_2020")
|
|
634
|
+
return tmf_def.gt(2020).rename("TMF_def_after_2020").selfMask()
|
|
709
635
|
|
|
710
636
|
|
|
711
637
|
# GFC_loss_before_2020 (loss within 10 percent cover; includes 2020; correct for version 11)
|
|
@@ -715,7 +641,7 @@ def g_glad_gfc_loss_before_2020_prep():
|
|
|
715
641
|
gfc_loss = (
|
|
716
642
|
gfc.select(["lossyear"]).lte(20).And(gfc.select(["treecover2000"]).gt(10))
|
|
717
643
|
)
|
|
718
|
-
return gfc_loss.rename("GFC_loss_before_2020")
|
|
644
|
+
return gfc_loss.rename("GFC_loss_before_2020").selfMask()
|
|
719
645
|
|
|
720
646
|
|
|
721
647
|
# GFC_loss_after_2020 (loss within 10 percent cover; correct for version 11)
|
|
@@ -723,7 +649,7 @@ def g_glad_gfc_loss_after_2020_prep():
|
|
|
723
649
|
# Load the Global Forest Change dataset
|
|
724
650
|
gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
|
|
725
651
|
gfc_loss = gfc.select(["lossyear"]).gt(20).And(gfc.select(["treecover2000"]).gt(10))
|
|
726
|
-
return gfc_loss.rename("GFC_loss_after_2020")
|
|
652
|
+
return gfc_loss.rename("GFC_loss_after_2020").selfMask()
|
|
727
653
|
|
|
728
654
|
|
|
729
655
|
# MODIS_fire_before_2020
|
|
@@ -739,14 +665,15 @@ def g_modis_fire_before_2020_prep():
|
|
|
739
665
|
.select(["BurnDate"])
|
|
740
666
|
.gte(0)
|
|
741
667
|
.rename("MODIS_fire_before_2020")
|
|
742
|
-
)
|
|
668
|
+
).selfMask()
|
|
743
669
|
|
|
744
670
|
|
|
745
671
|
# MODIS_fire_after_2020
|
|
746
672
|
def g_modis_fire_after_2020_prep():
|
|
747
673
|
modis_fire = ee.ImageCollection("MODIS/061/MCD64A1")
|
|
748
674
|
start_year = 2021
|
|
749
|
-
|
|
675
|
+
# Use pre-calculated current year (avoids repeated datetime calls)
|
|
676
|
+
end_year = CURRENT_YEAR - 1 # Use year - 1 to ensure data availability
|
|
750
677
|
date_st = str(start_year) + "-01-01"
|
|
751
678
|
date_ed = str(end_year) + "-12-31"
|
|
752
679
|
return (
|
|
@@ -755,7 +682,7 @@ def g_modis_fire_after_2020_prep():
|
|
|
755
682
|
.select(["BurnDate"])
|
|
756
683
|
.gte(0)
|
|
757
684
|
.rename("MODIS_fire_after_2020")
|
|
758
|
-
)
|
|
685
|
+
).selfMask()
|
|
759
686
|
|
|
760
687
|
|
|
761
688
|
# ESA_fire_before_2020
|
|
@@ -771,7 +698,7 @@ def g_esa_fire_before_2020_prep():
|
|
|
771
698
|
.select(["BurnDate"])
|
|
772
699
|
.gte(0)
|
|
773
700
|
.rename("ESA_fire_before_2020")
|
|
774
|
-
)
|
|
701
|
+
).selfMask()
|
|
775
702
|
|
|
776
703
|
|
|
777
704
|
#########################logging concessions
|
|
@@ -817,7 +744,7 @@ def g_logging_concessions_before_2020_prep():
|
|
|
817
744
|
]
|
|
818
745
|
).mosaic()
|
|
819
746
|
|
|
820
|
-
return logging_concessions_binary.rename("GFW_logging_before_2020")
|
|
747
|
+
return logging_concessions_binary.rename("GFW_logging_before_2020").selfMask()
|
|
821
748
|
|
|
822
749
|
|
|
823
750
|
#########################national datasets
|
|
@@ -835,7 +762,7 @@ def g_logging_concessions_before_2020_prep():
|
|
|
835
762
|
def nbr_terraclass_amz20_primary_prep():
|
|
836
763
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
837
764
|
tcamz20_f = tcamz20.eq(1)
|
|
838
|
-
return tcamz20_f.rename("nBR_INPE_TC_primary_forest_Amazon_2020")
|
|
765
|
+
return tcamz20_f.rename("nBR_INPE_TC_primary_forest_Amazon_2020").selfMask()
|
|
839
766
|
|
|
840
767
|
|
|
841
768
|
# [Official NFMS dataset] Brazilian Forest Service dataset on natural forest cover from PRODES and TerraClass data, base year 2022
|
|
@@ -849,7 +776,7 @@ def nbr_bfs_ptn_f20_prep():
|
|
|
849
776
|
bfs_fptn20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_ptn_2020")
|
|
850
777
|
|
|
851
778
|
bfs_fptn20_binary = ee.Image().paint(bfs_fptn20, 1)
|
|
852
|
-
return bfs_fptn20_binary.rename("nBR_BFS_primary_forest_Pantanal_2020")
|
|
779
|
+
return bfs_fptn20_binary.rename("nBR_BFS_primary_forest_Pantanal_2020").selfMask()
|
|
853
780
|
|
|
854
781
|
|
|
855
782
|
# Caatinga - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
@@ -857,35 +784,39 @@ def nbr_bfs_ptn_f20_prep():
|
|
|
857
784
|
def nbr_bfs_caat_f20_prep():
|
|
858
785
|
bfs_fcaat20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_caat_2020")
|
|
859
786
|
bfs_fcaat20_binary = ee.Image().paint(bfs_fcaat20, 1)
|
|
860
|
-
return bfs_fcaat20_binary.rename("nBR_BFS_primary_forest_Caatinga_2020")
|
|
787
|
+
return bfs_fcaat20_binary.rename("nBR_BFS_primary_forest_Caatinga_2020").selfMask()
|
|
861
788
|
|
|
862
789
|
|
|
863
790
|
# Atlantic Forest - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
864
791
|
def nbr_bfs_atlf_f20_prep():
|
|
865
792
|
bfs_fatlf20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_atlf_2020")
|
|
866
793
|
bfs_fatlf20_binary = ee.Image().paint(bfs_fatlf20, 1)
|
|
867
|
-
return bfs_fatlf20_binary.rename(
|
|
794
|
+
return bfs_fatlf20_binary.rename(
|
|
795
|
+
"nBR_BFS_primary_forest_AtlanticForest_2020"
|
|
796
|
+
).selfMask()
|
|
868
797
|
|
|
869
798
|
|
|
870
799
|
# Pampa - filtered in QGIS to save some storage space
|
|
871
800
|
def nbr_bfs_pmp_f20_prep():
|
|
872
801
|
bfs_fpmp20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_pmp_2020")
|
|
873
802
|
bfs_fpmp20_binary = ee.Image().paint(bfs_fpmp20, 1)
|
|
874
|
-
return bfs_fpmp20_binary.rename("nBR_BFS_primary_forest_Pampa_2020")
|
|
803
|
+
return bfs_fpmp20_binary.rename("nBR_BFS_primary_forest_Pampa_2020").selfMask()
|
|
875
804
|
|
|
876
805
|
|
|
877
806
|
##########################secondary forests###############################################
|
|
878
807
|
def nbr_terraclass_amz20_secondary_prep():
|
|
879
808
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
880
809
|
tcamz20_f = tcamz20.eq(2)
|
|
881
|
-
return tcamz20_f.rename("nBR_INPE_TC_secondary_forest_Amazon_2020")
|
|
810
|
+
return tcamz20_f.rename("nBR_INPE_TC_secondary_forest_Amazon_2020").selfMask()
|
|
882
811
|
|
|
883
812
|
|
|
884
813
|
# Cerrado - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
885
814
|
def nbr_bfs_cer_f20_prep():
|
|
886
815
|
bfs_fcer20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_cerr_2020")
|
|
887
816
|
bfs_fcer20_binary = ee.Image().paint(bfs_fcer20, 1)
|
|
888
|
-
return bfs_fcer20_binary.rename(
|
|
817
|
+
return bfs_fcer20_binary.rename(
|
|
818
|
+
"nBR_BFS_primary_and_secondary_forest_Cerrado_2020"
|
|
819
|
+
).selfMask()
|
|
889
820
|
|
|
890
821
|
|
|
891
822
|
# %%
|
|
@@ -904,7 +835,9 @@ def nbr_mapbiomasc9_f20_prep():
|
|
|
904
835
|
.Or(mapbiomasc9_20.eq(6))
|
|
905
836
|
.Or(mapbiomasc9_20.eq(49))
|
|
906
837
|
)
|
|
907
|
-
return mapbiomasc9_20_forest.rename(
|
|
838
|
+
return mapbiomasc9_20_forest.rename(
|
|
839
|
+
"nBR_MapBiomas_col9_forest_Brazil_2020"
|
|
840
|
+
).selfMask()
|
|
908
841
|
|
|
909
842
|
|
|
910
843
|
# ### ########################NBR plantation forest in 2020:#######################################
|
|
@@ -915,7 +848,7 @@ def nbr_mapbiomasc9_f20_prep():
|
|
|
915
848
|
def nbr_terraclass_amz20_silv_prep():
|
|
916
849
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
917
850
|
tcamz20_silviculture = tcamz20.eq(9)
|
|
918
|
-
return tcamz20_silviculture.rename("nBR_INPE_TCsilviculture_Amazon_2020")
|
|
851
|
+
return tcamz20_silviculture.rename("nBR_INPE_TCsilviculture_Amazon_2020").selfMask()
|
|
919
852
|
|
|
920
853
|
|
|
921
854
|
# [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
|
|
@@ -924,7 +857,9 @@ def nbr_terraclass_amz20_silv_prep():
|
|
|
924
857
|
def nbr_terraclass_silv_cer20_prep():
|
|
925
858
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
926
859
|
tccer20_silviculture = tccer20.eq(9)
|
|
927
|
-
return tccer20_silviculture.rename(
|
|
860
|
+
return tccer20_silviculture.rename(
|
|
861
|
+
"nBR_INPE_TCsilviculture_Cerrado_2020"
|
|
862
|
+
).selfMask()
|
|
928
863
|
|
|
929
864
|
|
|
930
865
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -938,7 +873,7 @@ def nbr_mapbiomasc9_silv20_prep():
|
|
|
938
873
|
mapbiomasc9_20_silviculture = mapbiomasc9_20.eq(9)
|
|
939
874
|
return mapbiomasc9_20_silviculture.rename(
|
|
940
875
|
"nBR_MapBiomas_col9_silviculture_Brazil_2020"
|
|
941
|
-
)
|
|
876
|
+
).selfMask()
|
|
942
877
|
|
|
943
878
|
|
|
944
879
|
################ ### NBR Disturbances before 2020:########################################
|
|
@@ -983,8 +918,9 @@ def nbr_prodes_before_2020_prep():
|
|
|
983
918
|
prodes_before_20_mask = prodes.remap(
|
|
984
919
|
prodes_before_20_dn, [1] * len(prodes_before_20_dn)
|
|
985
920
|
) # .eq(1)
|
|
986
|
-
|
|
987
|
-
|
|
921
|
+
return prodes_before_20_mask.rename(
|
|
922
|
+
"nBR_PRODES_deforestation_Brazil_before_2020"
|
|
923
|
+
).selfMask()
|
|
988
924
|
|
|
989
925
|
|
|
990
926
|
## Caution: 1) includes deforestation and conversion of other wooded land and grassland
|
|
@@ -1009,7 +945,9 @@ def nbr_deter_amazon_before_2020_prep():
|
|
|
1009
945
|
).filter(ee.Filter.lt("formatted_date", ee.Date("2020-12-31")))
|
|
1010
946
|
|
|
1011
947
|
deter_deg_binary = ee.Image().paint(deter_deg, 1)
|
|
1012
|
-
return deter_deg_binary.rename(
|
|
948
|
+
return deter_deg_binary.rename(
|
|
949
|
+
"nBR_DETER_forestdegradation_Amazon_before_2020"
|
|
950
|
+
).selfMask()
|
|
1013
951
|
|
|
1014
952
|
|
|
1015
953
|
################ ### NBR Disturbances after 2020:########################################
|
|
@@ -1026,7 +964,9 @@ def nbr_prodes_after_2020_prep():
|
|
|
1026
964
|
prodes_after_20_dn, [1] * len(prodes_after_20_dn)
|
|
1027
965
|
) # .eq(1)
|
|
1028
966
|
prodes_after_20 = prodes_after_20_mask.selfMask()
|
|
1029
|
-
return prodes_after_20.rename(
|
|
967
|
+
return prodes_after_20.rename(
|
|
968
|
+
"nBR_PRODES_deforestation_Brazil_after_2020"
|
|
969
|
+
).selfMask()
|
|
1030
970
|
|
|
1031
971
|
|
|
1032
972
|
# %%
|
|
@@ -1048,7 +988,9 @@ def nbr_deter_amazon_after_2020_prep():
|
|
|
1048
988
|
).filter(ee.Filter.gt("formatted_date", ee.Date("2021-01-01")))
|
|
1049
989
|
|
|
1050
990
|
deter_deg_binary = ee.Image().paint(deter_deg, 1)
|
|
1051
|
-
return deter_deg_binary.rename(
|
|
991
|
+
return deter_deg_binary.rename(
|
|
992
|
+
"nBR_DETER_forestdegradation_Amazon_after_2020"
|
|
993
|
+
).selfMask()
|
|
1052
994
|
|
|
1053
995
|
|
|
1054
996
|
# ########################## NBR commodities - permanent/perennial crops in 2020:###############################
|
|
@@ -1062,7 +1004,7 @@ def nbr_terraclass_amz_cer20_pc_prep():
|
|
|
1062
1004
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1063
1005
|
tccer20_pc = tccer20.eq(12).Or(tccer20.eq(13))
|
|
1064
1006
|
tc_pc = ee.ImageCollection([tcamz20_pc, tccer20_pc]).mosaic()
|
|
1065
|
-
return tc_pc.rename("nBR_INPE_TCamz_cer_perennial_2020")
|
|
1007
|
+
return tc_pc.rename("nBR_INPE_TCamz_cer_perennial_2020").selfMask()
|
|
1066
1008
|
|
|
1067
1009
|
|
|
1068
1010
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1074,7 +1016,7 @@ def nbr_mapbiomasc9_cof_prep():
|
|
|
1074
1016
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1075
1017
|
).select("classification_2020")
|
|
1076
1018
|
mapbiomasc9_20_coffee = mapbiomasc9_20.eq(46)
|
|
1077
|
-
return mapbiomasc9_20_coffee.rename("nBR_MapBiomas_col9_coffee_2020")
|
|
1019
|
+
return mapbiomasc9_20_coffee.rename("nBR_MapBiomas_col9_coffee_2020").selfMask()
|
|
1078
1020
|
|
|
1079
1021
|
|
|
1080
1022
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1086,7 +1028,7 @@ def nbr_mapbiomasc9_po_prep():
|
|
|
1086
1028
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1087
1029
|
).select("classification_2020")
|
|
1088
1030
|
mapbiomasc9_20_palm = mapbiomasc9_20.eq(35)
|
|
1089
|
-
return mapbiomasc9_20_palm.rename("nBR_MapBiomas_col9_palmoil_2020")
|
|
1031
|
+
return mapbiomasc9_20_palm.rename("nBR_MapBiomas_col9_palmoil_2020").selfMask()
|
|
1090
1032
|
|
|
1091
1033
|
|
|
1092
1034
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1098,7 +1040,7 @@ def nbr_mapbiomasc9_pc_prep():
|
|
|
1098
1040
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1099
1041
|
).select("classification_2020")
|
|
1100
1042
|
mapbiomasc9_20_pc = mapbiomasc9_20.eq(35).Or(mapbiomasc9_20.eq(46))
|
|
1101
|
-
return mapbiomasc9_20_pc.rename("nBR_MapBiomas_col9_pc_2020")
|
|
1043
|
+
return mapbiomasc9_20_pc.rename("nBR_MapBiomas_col9_pc_2020").selfMask()
|
|
1102
1044
|
|
|
1103
1045
|
|
|
1104
1046
|
# ######################## NBR commodities - annual crops in 2020:##############################
|
|
@@ -1114,7 +1056,7 @@ def nbr_terraclass_amz_cer20_ac_prep():
|
|
|
1114
1056
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1115
1057
|
tccer20_ac = tccer20.eq(14).Or(tccer20.eq(15))
|
|
1116
1058
|
tc_ac = ee.ImageCollection([tcamz20_ac, tccer20_ac]).mosaic()
|
|
1117
|
-
return tc_ac.rename("nBR_INPE_TCamz_cer_annual_2020")
|
|
1059
|
+
return tc_ac.rename("nBR_INPE_TCamz_cer_annual_2020").selfMask()
|
|
1118
1060
|
|
|
1119
1061
|
|
|
1120
1062
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1126,7 +1068,7 @@ def nbr_mapbiomasc9_soy_prep():
|
|
|
1126
1068
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1127
1069
|
).select("classification_2020")
|
|
1128
1070
|
mapbiomasc9_20_soy = mapbiomasc9_20.eq(39)
|
|
1129
|
-
return mapbiomasc9_20_soy.rename("nBR_MapBiomas_col9_soy_2020")
|
|
1071
|
+
return mapbiomasc9_20_soy.rename("nBR_MapBiomas_col9_soy_2020").selfMask()
|
|
1130
1072
|
|
|
1131
1073
|
|
|
1132
1074
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1146,7 +1088,7 @@ def nbr_mapbiomasc9_ac_prep():
|
|
|
1146
1088
|
.Or(mapbiomasc9_20.eq(40))
|
|
1147
1089
|
.Or(mapbiomasc9_20.eq(62))
|
|
1148
1090
|
)
|
|
1149
|
-
return mapbiomasc9_20_ac.rename("nBR_MapBiomas_col9_annual_crops_2020")
|
|
1091
|
+
return mapbiomasc9_20_ac.rename("nBR_MapBiomas_col9_annual_crops_2020").selfMask()
|
|
1150
1092
|
|
|
1151
1093
|
|
|
1152
1094
|
# ################################### NBR commodities - pasture/livestock in 2020:##############################
|
|
@@ -1159,7 +1101,7 @@ def nbr_mapbiomasc9_ac_prep():
|
|
|
1159
1101
|
def nbr_terraclass_amz20_pasture_prep():
|
|
1160
1102
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
1161
1103
|
tcamz20_pasture = tcamz20.eq(10).Or(tcamz20.eq(11))
|
|
1162
|
-
return tcamz20_pasture.rename("nBR_INPE_TCamz_pasture_2020")
|
|
1104
|
+
return tcamz20_pasture.rename("nBR_INPE_TCamz_pasture_2020").selfMask()
|
|
1163
1105
|
|
|
1164
1106
|
|
|
1165
1107
|
# %%
|
|
@@ -1171,7 +1113,7 @@ def nbr_terraclass_amz20_pasture_prep():
|
|
|
1171
1113
|
def nbr_terraclass_cer20_ac_prep():
|
|
1172
1114
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1173
1115
|
tccer20_pasture = tccer20.eq(11)
|
|
1174
|
-
return tccer20_pasture.rename("nBR_INPE_TCcer_pasture_2020")
|
|
1116
|
+
return tccer20_pasture.rename("nBR_INPE_TCcer_pasture_2020").selfMask()
|
|
1175
1117
|
|
|
1176
1118
|
|
|
1177
1119
|
# %%
|
|
@@ -1184,7 +1126,7 @@ def nbr_mapbiomasc9_pasture_prep():
|
|
|
1184
1126
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1185
1127
|
).select("classification_2020")
|
|
1186
1128
|
mapbiomasc9_20_pasture = mapbiomasc9_20.eq(15)
|
|
1187
|
-
return mapbiomasc9_20_pasture.rename("nBR_MapBiomas_col9_pasture_2020")
|
|
1129
|
+
return mapbiomasc9_20_pasture.rename("nBR_MapBiomas_col9_pasture_2020").selfMask()
|
|
1188
1130
|
|
|
1189
1131
|
|
|
1190
1132
|
###################################################################
|
|
@@ -1194,13 +1136,13 @@ def nbr_mapbiomasc9_pasture_prep():
|
|
|
1194
1136
|
def nco_ideam_forest_2020_prep():
|
|
1195
1137
|
ideam_forest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo")
|
|
1196
1138
|
ideam_forest = ideam_forest_raw.eq(1) # get forest class
|
|
1197
|
-
return ideam_forest.rename("nCO_ideam_forest_2020")
|
|
1139
|
+
return ideam_forest.rename("nCO_ideam_forest_2020").selfMask()
|
|
1198
1140
|
|
|
1199
1141
|
|
|
1200
1142
|
def nco_ideam_eufo_commission_2020_prep():
|
|
1201
1143
|
ideam_agroforest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo_EUFO")
|
|
1202
1144
|
ideam_agroforest = ideam_agroforest_raw.eq(4) # get forest class
|
|
1203
|
-
return ideam_agroforest.rename("nCO_ideam_eufo_commission_2020")
|
|
1145
|
+
return ideam_agroforest.rename("nCO_ideam_eufo_commission_2020").selfMask()
|
|
1204
1146
|
|
|
1205
1147
|
|
|
1206
1148
|
# Cocoa_bnetd
|
|
@@ -1210,43 +1152,61 @@ def nci_ocs2020_prep():
|
|
|
1210
1152
|
.select("classification")
|
|
1211
1153
|
.eq(9)
|
|
1212
1154
|
.rename("nCI_Cocoa_bnetd")
|
|
1213
|
-
) # cocoa from national land cover map for Côte d'Ivoire
|
|
1155
|
+
).selfMask() # cocoa from national land cover map for Côte d'Ivoire
|
|
1214
1156
|
|
|
1215
1157
|
|
|
1216
1158
|
###Combining datasets
|
|
1217
1159
|
|
|
1218
1160
|
|
|
1219
|
-
def combine_datasets(national_codes=None):
|
|
1220
|
-
"""
|
|
1161
|
+
def combine_datasets(national_codes=None, validate_bands=False):
|
|
1162
|
+
"""
|
|
1163
|
+
Combines datasets into a single multiband image, with fallback if assets are missing.
|
|
1164
|
+
|
|
1165
|
+
Parameters
|
|
1166
|
+
----------
|
|
1167
|
+
national_codes : list, optional
|
|
1168
|
+
List of ISO2 country codes to include national datasets
|
|
1169
|
+
validate_bands : bool, optional
|
|
1170
|
+
If True, validates band names with a slow .getInfo() call (default: False)
|
|
1171
|
+
Only enable for debugging. Normal operation relies on exception handling.
|
|
1172
|
+
|
|
1173
|
+
Returns
|
|
1174
|
+
-------
|
|
1175
|
+
ee.Image
|
|
1176
|
+
Combined multiband image with all datasets
|
|
1177
|
+
"""
|
|
1221
1178
|
img_combined = ee.Image(1).rename(geometry_area_column)
|
|
1222
1179
|
|
|
1223
1180
|
# Combine images directly
|
|
1224
1181
|
for img in [func() for func in list_functions(national_codes=national_codes)]:
|
|
1225
1182
|
try:
|
|
1226
1183
|
img_combined = img_combined.addBands(img)
|
|
1184
|
+
# img_combined = img_combined.addBands(img)
|
|
1227
1185
|
except ee.EEException as e:
|
|
1228
1186
|
# logger.error(f"Error adding image: {e}")
|
|
1229
1187
|
print(f"Error adding image: {e}")
|
|
1230
1188
|
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
img_combined =
|
|
1189
|
+
# OPTIMIZATION: Removed slow .getInfo() call for band validation
|
|
1190
|
+
# The validation is now optional and disabled by default
|
|
1191
|
+
# Image processing will fail downstream if there's an issue, which is handled by exception blocks
|
|
1192
|
+
if validate_bands:
|
|
1193
|
+
try:
|
|
1194
|
+
# This is SLOW - only use for debugging
|
|
1195
|
+
img_combined.bandNames().getInfo()
|
|
1196
|
+
except ee.EEException as e:
|
|
1197
|
+
# logger.error(f"Error validating band names: {e}")
|
|
1198
|
+
# logger.info("Running code for filtering to only valid datasets due to error in input")
|
|
1199
|
+
print("using valid datasets filter due to error in validation")
|
|
1200
|
+
# Validate images
|
|
1201
|
+
images_to_test = [
|
|
1202
|
+
func() for func in list_functions(national_codes=national_codes)
|
|
1203
|
+
]
|
|
1204
|
+
valid_imgs = keep_valid_images(images_to_test) # Validate images
|
|
1205
|
+
|
|
1206
|
+
# Retry combining images after validation
|
|
1207
|
+
img_combined = ee.Image(1).rename(geometry_area_column)
|
|
1208
|
+
for img in valid_imgs:
|
|
1209
|
+
img_combined = img_combined.addBands(img)
|
|
1250
1210
|
|
|
1251
1211
|
img_combined = img_combined.multiply(ee.Image.pixelArea())
|
|
1252
1212
|
print("Whisp multiband image compiled")
|