openforis-whisp 2.0.0b2__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/datasets.py +201 -216
- openforis_whisp/stats.py +211 -53
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-2.0.0b3.dist-info}/METADATA +1 -1
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-2.0.0b3.dist-info}/RECORD +6 -6
- {openforis_whisp-2.0.0b2.dist-info → openforis_whisp-2.0.0b3.dist-info}/LICENSE +0 -0
- {openforis_whisp-2.0.0b2.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,7 +349,7 @@ 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
|
|
@@ -353,7 +366,7 @@ def g_esri_2020_2023_crop_prep():
|
|
|
353
366
|
|
|
354
367
|
newCrop = esri_lulc10_crop_2023.And(esri_lulc10_crop_2020.Not())
|
|
355
368
|
|
|
356
|
-
return newCrop.rename("ESRI_crop_gain_2020_2023")
|
|
369
|
+
return newCrop.rename("ESRI_crop_gain_2020_2023").selfMask()
|
|
357
370
|
|
|
358
371
|
|
|
359
372
|
#### disturbances by year
|
|
@@ -363,23 +376,13 @@ def g_radd_year_prep():
|
|
|
363
376
|
from datetime import datetime
|
|
364
377
|
|
|
365
378
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
366
|
-
|
|
367
379
|
radd_date = (
|
|
368
380
|
radd.filterMetadata("layer", "contains", "alert").select("Date").mosaic()
|
|
369
381
|
)
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
current_year = (
|
|
374
|
-
datetime.now().year
|
|
375
|
-
% 100
|
|
376
|
-
# NB the % 100 part gets last two digits needed
|
|
377
|
-
)
|
|
382
|
+
start_year = 19
|
|
383
|
+
current_year = datetime.now().year % 100
|
|
378
384
|
|
|
379
|
-
|
|
380
|
-
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to <current year>
|
|
381
|
-
for year in range(start_year, current_year + 1):
|
|
382
|
-
# 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):
|
|
383
386
|
start = year * 1000
|
|
384
387
|
end = year * 1000 + 365
|
|
385
388
|
radd_year = (
|
|
@@ -388,12 +391,35 @@ def g_radd_year_prep():
|
|
|
388
391
|
.gt(0)
|
|
389
392
|
.rename("RADD_year_" + "20" + str(year))
|
|
390
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
|
+
)
|
|
391
407
|
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
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)
|
|
420
|
+
|
|
421
|
+
img_stack = years.slice(1).iterate(make_band, first_band)
|
|
422
|
+
return ee.Image(img_stack)
|
|
397
423
|
|
|
398
424
|
|
|
399
425
|
# TMF_def_2000 to TMF_def_2023
|
|
@@ -403,7 +429,9 @@ def g_tmf_def_per_year_prep():
|
|
|
403
429
|
img_stack = None
|
|
404
430
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
405
431
|
for i in range(0, 24 + 1):
|
|
406
|
-
|
|
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)
|
|
407
435
|
if img_stack is None:
|
|
408
436
|
img_stack = tmf_def_year
|
|
409
437
|
else:
|
|
@@ -418,7 +446,9 @@ def g_tmf_deg_per_year_prep():
|
|
|
418
446
|
img_stack = None
|
|
419
447
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
420
448
|
for i in range(0, 24 + 1):
|
|
421
|
-
|
|
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)
|
|
422
452
|
if img_stack is None:
|
|
423
453
|
img_stack = tmf_def_year
|
|
424
454
|
else:
|
|
@@ -433,10 +463,12 @@ def g_glad_gfc_loss_per_year_prep():
|
|
|
433
463
|
img_stack = None
|
|
434
464
|
# Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
|
|
435
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"))
|
|
436
468
|
gfc_loss_year = (
|
|
437
469
|
gfc.select(["lossyear"]).eq(i).And(gfc.select(["treecover2000"]).gt(10))
|
|
438
470
|
)
|
|
439
|
-
gfc_loss_year = gfc_loss_year.rename(
|
|
471
|
+
gfc_loss_year = gfc_loss_year.rename(band_name)
|
|
440
472
|
if img_stack is None:
|
|
441
473
|
img_stack = gfc_loss_year
|
|
442
474
|
else:
|
|
@@ -457,6 +489,8 @@ def g_modis_fire_prep():
|
|
|
457
489
|
img_stack = None
|
|
458
490
|
|
|
459
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"))
|
|
460
494
|
date_st = f"{year}-01-01"
|
|
461
495
|
date_ed = f"{year}-12-31"
|
|
462
496
|
modis_year = (
|
|
@@ -464,7 +498,7 @@ def g_modis_fire_prep():
|
|
|
464
498
|
.mosaic()
|
|
465
499
|
.select(["BurnDate"])
|
|
466
500
|
.gte(0)
|
|
467
|
-
.rename(
|
|
501
|
+
.rename(band_name)
|
|
468
502
|
)
|
|
469
503
|
img_stack = modis_year if img_stack is None else img_stack.addBands(modis_year)
|
|
470
504
|
|
|
@@ -484,6 +518,8 @@ def g_esa_fire_prep():
|
|
|
484
518
|
img_stack = None
|
|
485
519
|
|
|
486
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"))
|
|
487
523
|
date_st = f"{year}-01-01"
|
|
488
524
|
date_ed = f"{year}-12-31"
|
|
489
525
|
esa_year = (
|
|
@@ -491,107 +527,17 @@ def g_esa_fire_prep():
|
|
|
491
527
|
.mosaic()
|
|
492
528
|
.select(["BurnDate"])
|
|
493
529
|
.gte(0)
|
|
494
|
-
.rename(
|
|
530
|
+
.rename(band_name)
|
|
495
531
|
)
|
|
496
532
|
img_stack = esa_year if img_stack is None else img_stack.addBands(esa_year)
|
|
497
533
|
|
|
498
534
|
return img_stack
|
|
499
535
|
|
|
500
536
|
|
|
501
|
-
# # DIST_alert_2024 to DIST_alert_< current year >
|
|
502
|
-
# # Notes:
|
|
503
|
-
# # 1) so far only available for 2024 onwards in GEE
|
|
504
|
-
# # TO DO - see if gee asset for pre 2020-2024 is available from GLAD team, else download from nasa and put in Whisp assets
|
|
505
|
-
# # 2) masked alerts (as dist alerts are for all vegetation) to JRC EUFO 2020 layer, as close to EUDR definition
|
|
506
|
-
# # TO DO - ask opinions on if others (such as treecover data from GLAD team) should be used instead
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
# def glad_dist_year_prep():
|
|
510
|
-
|
|
511
|
-
# # Load the vegetation disturbance collections
|
|
512
|
-
|
|
513
|
-
# # Vegetation disturbance status (0-8, class flag, 8-bit)
|
|
514
|
-
# VEGDISTSTATUS = ee.ImageCollection(
|
|
515
|
-
# "projects/glad/HLSDIST/current/VEG-DIST-STATUS"
|
|
516
|
-
# ).mosaic()
|
|
517
|
-
# # Initial vegetation disturbance date (>0: days since 2020-12-31, 16-bit)
|
|
518
|
-
# VEGDISTDATE = ee.ImageCollection(
|
|
519
|
-
# "projects/glad/HLSDIST/current/VEG-DIST-DATE"
|
|
520
|
-
# ).mosaic()
|
|
521
|
-
|
|
522
|
-
# # 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)
|
|
523
|
-
|
|
524
|
-
# # Key for high-confidence alerts (values 3, 6, 7, 8)
|
|
525
|
-
# high_conf_values = [3, 6, 7, 8]
|
|
526
|
-
# # where:
|
|
527
|
-
# # 3 = <50% loss, high confidence, ongoing
|
|
528
|
-
# # 6 = ≥50% loss, high confidence, ongoing
|
|
529
|
-
# # 7 = <50% loss, high confidence, finished
|
|
530
|
-
# # 8 = ≥50% loss, high confidence, finished
|
|
531
|
-
# # Note could use <50% loss (i.e. only 6 and 7) for if want to be more strict
|
|
532
|
-
|
|
533
|
-
# # Create high-confidence mask
|
|
534
|
-
# dist_high_conf = VEGDISTSTATUS.remap(
|
|
535
|
-
# high_conf_values, [1] * len(high_conf_values), 0
|
|
536
|
-
# )
|
|
537
|
-
|
|
538
|
-
# # Determine start year and current year dynamically
|
|
539
|
-
# start_year = 2024 # Set the first year of interest
|
|
540
|
-
# current_year = datetime.now().year
|
|
541
|
-
|
|
542
|
-
# # Calculate days since December 31, 2020 for start and end dates (server-side)
|
|
543
|
-
# start_of_2020 = ee.Date("2020-12-31").millis().divide(86400000).int()
|
|
544
|
-
|
|
545
|
-
# # Create a list to hold the yearly images
|
|
546
|
-
# yearly_images = []
|
|
547
|
-
|
|
548
|
-
# for year in range(start_year, current_year + 1):
|
|
549
|
-
# start_of_year = (
|
|
550
|
-
# ee.Date(f"{year}-01-01")
|
|
551
|
-
# .millis()
|
|
552
|
-
# .divide(86400000)
|
|
553
|
-
# .int()
|
|
554
|
-
# .subtract(start_of_2020)
|
|
555
|
-
# )
|
|
556
|
-
# start_of_next_year = (
|
|
557
|
-
# ee.Date(f"{year + 1}-01-01")
|
|
558
|
-
# .millis()
|
|
559
|
-
# .divide(86400000)
|
|
560
|
-
# .int()
|
|
561
|
-
# .subtract(start_of_2020)
|
|
562
|
-
# )
|
|
563
|
-
|
|
564
|
-
# # Filter VEG-DIST-DATE for the selected year
|
|
565
|
-
# dist_year = VEGDISTDATE.gte(start_of_year).And(
|
|
566
|
-
# VEGDISTDATE.lt(start_of_next_year)
|
|
567
|
-
# )
|
|
568
|
-
|
|
569
|
-
# # Apply high-confidence mask and rename the band
|
|
570
|
-
# high_conf_year = dist_year.updateMask(dist_high_conf).rename(
|
|
571
|
-
# f"DIST_year_{year}"
|
|
572
|
-
# )
|
|
573
|
-
|
|
574
|
-
# # Append the year's data to the list
|
|
575
|
-
# yearly_images.append(high_conf_year)
|
|
576
|
-
|
|
577
|
-
# # Combine all yearly images into a single image
|
|
578
|
-
# img_stack = ee.Image.cat(yearly_images)
|
|
579
|
-
|
|
580
|
-
# # Rename the bands correctly
|
|
581
|
-
# band_names = [f"DIST_year_{year}" for year in range(start_year, current_year + 1)]
|
|
582
|
-
# img_stack = img_stack.select(img_stack.bandNames(), band_names)
|
|
583
|
-
|
|
584
|
-
# return img_stack.updateMask(
|
|
585
|
-
# jrc_gfc_2020_prep()
|
|
586
|
-
# ) # mask yearly dist alerts to forest cover in 2020
|
|
587
|
-
|
|
588
|
-
|
|
589
537
|
#### disturbances combined (split into before and after 2020)
|
|
590
538
|
|
|
591
539
|
# RADD_after_2020
|
|
592
540
|
def g_radd_after_2020_prep():
|
|
593
|
-
from datetime import datetime
|
|
594
|
-
|
|
595
541
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
596
542
|
|
|
597
543
|
radd_date = (
|
|
@@ -600,9 +546,8 @@ def g_radd_after_2020_prep():
|
|
|
600
546
|
# date of avaialbility
|
|
601
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)
|
|
602
548
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
) # 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
|
|
606
551
|
start = start_year * 1000
|
|
607
552
|
end = current_year * 1000 + 365
|
|
608
553
|
return (
|
|
@@ -610,13 +555,11 @@ def g_radd_after_2020_prep():
|
|
|
610
555
|
.updateMask(radd_date.lte(end))
|
|
611
556
|
.gt(0)
|
|
612
557
|
.rename("RADD_after_2020")
|
|
613
|
-
)
|
|
558
|
+
).selfMask()
|
|
614
559
|
|
|
615
560
|
|
|
616
561
|
# RADD_before_2020
|
|
617
562
|
def g_radd_before_2020_prep():
|
|
618
|
-
from datetime import datetime
|
|
619
|
-
|
|
620
563
|
radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
|
|
621
564
|
|
|
622
565
|
radd_date = (
|
|
@@ -625,8 +568,6 @@ def g_radd_before_2020_prep():
|
|
|
625
568
|
# date of avaialbility
|
|
626
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)
|
|
627
570
|
|
|
628
|
-
# current_year = datetime.now().year % 100 # NB the % 100 part gets last two digits needed
|
|
629
|
-
|
|
630
571
|
start = start_year * 1000
|
|
631
572
|
end = 20 * 1000 + 365
|
|
632
573
|
return (
|
|
@@ -634,7 +575,7 @@ def g_radd_before_2020_prep():
|
|
|
634
575
|
.updateMask(radd_date.lte(end))
|
|
635
576
|
.gt(0)
|
|
636
577
|
.rename("RADD_before_2020")
|
|
637
|
-
)
|
|
578
|
+
).selfMask()
|
|
638
579
|
|
|
639
580
|
|
|
640
581
|
# # DIST_after_2020
|
|
@@ -662,25 +603,35 @@ def g_radd_before_2020_prep():
|
|
|
662
603
|
# TMF_deg_before_2020
|
|
663
604
|
def g_tmf_deg_before_2020_prep():
|
|
664
605
|
tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
|
|
665
|
-
return (
|
|
606
|
+
return (
|
|
607
|
+
(tmf_deg.lte(2020))
|
|
608
|
+
.And(tmf_deg.gte(2000))
|
|
609
|
+
.rename("TMF_deg_before_2020")
|
|
610
|
+
.selfMask()
|
|
611
|
+
)
|
|
666
612
|
|
|
667
613
|
|
|
668
614
|
# TMF_deg_after_2020
|
|
669
615
|
def g_tmf_deg_after_2020_prep():
|
|
670
616
|
tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
|
|
671
|
-
return tmf_deg.gt(2020).rename("TMF_deg_after_2020")
|
|
617
|
+
return tmf_deg.gt(2020).rename("TMF_deg_after_2020").selfMask()
|
|
672
618
|
|
|
673
619
|
|
|
674
620
|
# tmf_def_before_2020
|
|
675
621
|
def g_tmf_def_before_2020_prep():
|
|
676
622
|
tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
|
|
677
|
-
return (
|
|
623
|
+
return (
|
|
624
|
+
(tmf_def.lte(2020))
|
|
625
|
+
.And(tmf_def.gte(2000))
|
|
626
|
+
.rename("TMF_def_before_2020")
|
|
627
|
+
.selfMask()
|
|
628
|
+
)
|
|
678
629
|
|
|
679
630
|
|
|
680
631
|
# tmf_def_after_2020
|
|
681
632
|
def g_tmf_def_after_2020_prep():
|
|
682
633
|
tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
|
|
683
|
-
return tmf_def.gt(2020).rename("TMF_def_after_2020")
|
|
634
|
+
return tmf_def.gt(2020).rename("TMF_def_after_2020").selfMask()
|
|
684
635
|
|
|
685
636
|
|
|
686
637
|
# GFC_loss_before_2020 (loss within 10 percent cover; includes 2020; correct for version 11)
|
|
@@ -690,7 +641,7 @@ def g_glad_gfc_loss_before_2020_prep():
|
|
|
690
641
|
gfc_loss = (
|
|
691
642
|
gfc.select(["lossyear"]).lte(20).And(gfc.select(["treecover2000"]).gt(10))
|
|
692
643
|
)
|
|
693
|
-
return gfc_loss.rename("GFC_loss_before_2020")
|
|
644
|
+
return gfc_loss.rename("GFC_loss_before_2020").selfMask()
|
|
694
645
|
|
|
695
646
|
|
|
696
647
|
# GFC_loss_after_2020 (loss within 10 percent cover; correct for version 11)
|
|
@@ -698,7 +649,7 @@ def g_glad_gfc_loss_after_2020_prep():
|
|
|
698
649
|
# Load the Global Forest Change dataset
|
|
699
650
|
gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
|
|
700
651
|
gfc_loss = gfc.select(["lossyear"]).gt(20).And(gfc.select(["treecover2000"]).gt(10))
|
|
701
|
-
return gfc_loss.rename("GFC_loss_after_2020")
|
|
652
|
+
return gfc_loss.rename("GFC_loss_after_2020").selfMask()
|
|
702
653
|
|
|
703
654
|
|
|
704
655
|
# MODIS_fire_before_2020
|
|
@@ -714,14 +665,15 @@ def g_modis_fire_before_2020_prep():
|
|
|
714
665
|
.select(["BurnDate"])
|
|
715
666
|
.gte(0)
|
|
716
667
|
.rename("MODIS_fire_before_2020")
|
|
717
|
-
)
|
|
668
|
+
).selfMask()
|
|
718
669
|
|
|
719
670
|
|
|
720
671
|
# MODIS_fire_after_2020
|
|
721
672
|
def g_modis_fire_after_2020_prep():
|
|
722
673
|
modis_fire = ee.ImageCollection("MODIS/061/MCD64A1")
|
|
723
674
|
start_year = 2021
|
|
724
|
-
|
|
675
|
+
# Use pre-calculated current year (avoids repeated datetime calls)
|
|
676
|
+
end_year = CURRENT_YEAR - 1 # Use year - 1 to ensure data availability
|
|
725
677
|
date_st = str(start_year) + "-01-01"
|
|
726
678
|
date_ed = str(end_year) + "-12-31"
|
|
727
679
|
return (
|
|
@@ -730,7 +682,7 @@ def g_modis_fire_after_2020_prep():
|
|
|
730
682
|
.select(["BurnDate"])
|
|
731
683
|
.gte(0)
|
|
732
684
|
.rename("MODIS_fire_after_2020")
|
|
733
|
-
)
|
|
685
|
+
).selfMask()
|
|
734
686
|
|
|
735
687
|
|
|
736
688
|
# ESA_fire_before_2020
|
|
@@ -746,7 +698,7 @@ def g_esa_fire_before_2020_prep():
|
|
|
746
698
|
.select(["BurnDate"])
|
|
747
699
|
.gte(0)
|
|
748
700
|
.rename("ESA_fire_before_2020")
|
|
749
|
-
)
|
|
701
|
+
).selfMask()
|
|
750
702
|
|
|
751
703
|
|
|
752
704
|
#########################logging concessions
|
|
@@ -792,7 +744,7 @@ def g_logging_concessions_before_2020_prep():
|
|
|
792
744
|
]
|
|
793
745
|
).mosaic()
|
|
794
746
|
|
|
795
|
-
return logging_concessions_binary.rename("GFW_logging_before_2020")
|
|
747
|
+
return logging_concessions_binary.rename("GFW_logging_before_2020").selfMask()
|
|
796
748
|
|
|
797
749
|
|
|
798
750
|
#########################national datasets
|
|
@@ -810,7 +762,7 @@ def g_logging_concessions_before_2020_prep():
|
|
|
810
762
|
def nbr_terraclass_amz20_primary_prep():
|
|
811
763
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
812
764
|
tcamz20_f = tcamz20.eq(1)
|
|
813
|
-
return tcamz20_f.rename("nBR_INPE_TC_primary_forest_Amazon_2020")
|
|
765
|
+
return tcamz20_f.rename("nBR_INPE_TC_primary_forest_Amazon_2020").selfMask()
|
|
814
766
|
|
|
815
767
|
|
|
816
768
|
# [Official NFMS dataset] Brazilian Forest Service dataset on natural forest cover from PRODES and TerraClass data, base year 2022
|
|
@@ -824,7 +776,7 @@ def nbr_bfs_ptn_f20_prep():
|
|
|
824
776
|
bfs_fptn20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_ptn_2020")
|
|
825
777
|
|
|
826
778
|
bfs_fptn20_binary = ee.Image().paint(bfs_fptn20, 1)
|
|
827
|
-
return bfs_fptn20_binary.rename("nBR_BFS_primary_forest_Pantanal_2020")
|
|
779
|
+
return bfs_fptn20_binary.rename("nBR_BFS_primary_forest_Pantanal_2020").selfMask()
|
|
828
780
|
|
|
829
781
|
|
|
830
782
|
# Caatinga - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
@@ -832,35 +784,39 @@ def nbr_bfs_ptn_f20_prep():
|
|
|
832
784
|
def nbr_bfs_caat_f20_prep():
|
|
833
785
|
bfs_fcaat20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_caat_2020")
|
|
834
786
|
bfs_fcaat20_binary = ee.Image().paint(bfs_fcaat20, 1)
|
|
835
|
-
return bfs_fcaat20_binary.rename("nBR_BFS_primary_forest_Caatinga_2020")
|
|
787
|
+
return bfs_fcaat20_binary.rename("nBR_BFS_primary_forest_Caatinga_2020").selfMask()
|
|
836
788
|
|
|
837
789
|
|
|
838
790
|
# Atlantic Forest - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
839
791
|
def nbr_bfs_atlf_f20_prep():
|
|
840
792
|
bfs_fatlf20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_atlf_2020")
|
|
841
793
|
bfs_fatlf20_binary = ee.Image().paint(bfs_fatlf20, 1)
|
|
842
|
-
return bfs_fatlf20_binary.rename(
|
|
794
|
+
return bfs_fatlf20_binary.rename(
|
|
795
|
+
"nBR_BFS_primary_forest_AtlanticForest_2020"
|
|
796
|
+
).selfMask()
|
|
843
797
|
|
|
844
798
|
|
|
845
799
|
# Pampa - filtered in QGIS to save some storage space
|
|
846
800
|
def nbr_bfs_pmp_f20_prep():
|
|
847
801
|
bfs_fpmp20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_pmp_2020")
|
|
848
802
|
bfs_fpmp20_binary = ee.Image().paint(bfs_fpmp20, 1)
|
|
849
|
-
return bfs_fpmp20_binary.rename("nBR_BFS_primary_forest_Pampa_2020")
|
|
803
|
+
return bfs_fpmp20_binary.rename("nBR_BFS_primary_forest_Pampa_2020").selfMask()
|
|
850
804
|
|
|
851
805
|
|
|
852
806
|
##########################secondary forests###############################################
|
|
853
807
|
def nbr_terraclass_amz20_secondary_prep():
|
|
854
808
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
855
809
|
tcamz20_f = tcamz20.eq(2)
|
|
856
|
-
return tcamz20_f.rename("nBR_INPE_TC_secondary_forest_Amazon_2020")
|
|
810
|
+
return tcamz20_f.rename("nBR_INPE_TC_secondary_forest_Amazon_2020").selfMask()
|
|
857
811
|
|
|
858
812
|
|
|
859
813
|
# Cerrado - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
|
|
860
814
|
def nbr_bfs_cer_f20_prep():
|
|
861
815
|
bfs_fcer20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_cerr_2020")
|
|
862
816
|
bfs_fcer20_binary = ee.Image().paint(bfs_fcer20, 1)
|
|
863
|
-
return bfs_fcer20_binary.rename(
|
|
817
|
+
return bfs_fcer20_binary.rename(
|
|
818
|
+
"nBR_BFS_primary_and_secondary_forest_Cerrado_2020"
|
|
819
|
+
).selfMask()
|
|
864
820
|
|
|
865
821
|
|
|
866
822
|
# %%
|
|
@@ -879,7 +835,9 @@ def nbr_mapbiomasc9_f20_prep():
|
|
|
879
835
|
.Or(mapbiomasc9_20.eq(6))
|
|
880
836
|
.Or(mapbiomasc9_20.eq(49))
|
|
881
837
|
)
|
|
882
|
-
return mapbiomasc9_20_forest.rename(
|
|
838
|
+
return mapbiomasc9_20_forest.rename(
|
|
839
|
+
"nBR_MapBiomas_col9_forest_Brazil_2020"
|
|
840
|
+
).selfMask()
|
|
883
841
|
|
|
884
842
|
|
|
885
843
|
# ### ########################NBR plantation forest in 2020:#######################################
|
|
@@ -890,7 +848,7 @@ def nbr_mapbiomasc9_f20_prep():
|
|
|
890
848
|
def nbr_terraclass_amz20_silv_prep():
|
|
891
849
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
892
850
|
tcamz20_silviculture = tcamz20.eq(9)
|
|
893
|
-
return tcamz20_silviculture.rename("nBR_INPE_TCsilviculture_Amazon_2020")
|
|
851
|
+
return tcamz20_silviculture.rename("nBR_INPE_TCsilviculture_Amazon_2020").selfMask()
|
|
894
852
|
|
|
895
853
|
|
|
896
854
|
# [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
|
|
@@ -899,7 +857,9 @@ def nbr_terraclass_amz20_silv_prep():
|
|
|
899
857
|
def nbr_terraclass_silv_cer20_prep():
|
|
900
858
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
901
859
|
tccer20_silviculture = tccer20.eq(9)
|
|
902
|
-
return tccer20_silviculture.rename(
|
|
860
|
+
return tccer20_silviculture.rename(
|
|
861
|
+
"nBR_INPE_TCsilviculture_Cerrado_2020"
|
|
862
|
+
).selfMask()
|
|
903
863
|
|
|
904
864
|
|
|
905
865
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -913,7 +873,7 @@ def nbr_mapbiomasc9_silv20_prep():
|
|
|
913
873
|
mapbiomasc9_20_silviculture = mapbiomasc9_20.eq(9)
|
|
914
874
|
return mapbiomasc9_20_silviculture.rename(
|
|
915
875
|
"nBR_MapBiomas_col9_silviculture_Brazil_2020"
|
|
916
|
-
)
|
|
876
|
+
).selfMask()
|
|
917
877
|
|
|
918
878
|
|
|
919
879
|
################ ### NBR Disturbances before 2020:########################################
|
|
@@ -958,8 +918,9 @@ def nbr_prodes_before_2020_prep():
|
|
|
958
918
|
prodes_before_20_mask = prodes.remap(
|
|
959
919
|
prodes_before_20_dn, [1] * len(prodes_before_20_dn)
|
|
960
920
|
) # .eq(1)
|
|
961
|
-
|
|
962
|
-
|
|
921
|
+
return prodes_before_20_mask.rename(
|
|
922
|
+
"nBR_PRODES_deforestation_Brazil_before_2020"
|
|
923
|
+
).selfMask()
|
|
963
924
|
|
|
964
925
|
|
|
965
926
|
## Caution: 1) includes deforestation and conversion of other wooded land and grassland
|
|
@@ -984,7 +945,9 @@ def nbr_deter_amazon_before_2020_prep():
|
|
|
984
945
|
).filter(ee.Filter.lt("formatted_date", ee.Date("2020-12-31")))
|
|
985
946
|
|
|
986
947
|
deter_deg_binary = ee.Image().paint(deter_deg, 1)
|
|
987
|
-
return deter_deg_binary.rename(
|
|
948
|
+
return deter_deg_binary.rename(
|
|
949
|
+
"nBR_DETER_forestdegradation_Amazon_before_2020"
|
|
950
|
+
).selfMask()
|
|
988
951
|
|
|
989
952
|
|
|
990
953
|
################ ### NBR Disturbances after 2020:########################################
|
|
@@ -1001,7 +964,9 @@ def nbr_prodes_after_2020_prep():
|
|
|
1001
964
|
prodes_after_20_dn, [1] * len(prodes_after_20_dn)
|
|
1002
965
|
) # .eq(1)
|
|
1003
966
|
prodes_after_20 = prodes_after_20_mask.selfMask()
|
|
1004
|
-
return prodes_after_20.rename(
|
|
967
|
+
return prodes_after_20.rename(
|
|
968
|
+
"nBR_PRODES_deforestation_Brazil_after_2020"
|
|
969
|
+
).selfMask()
|
|
1005
970
|
|
|
1006
971
|
|
|
1007
972
|
# %%
|
|
@@ -1023,7 +988,9 @@ def nbr_deter_amazon_after_2020_prep():
|
|
|
1023
988
|
).filter(ee.Filter.gt("formatted_date", ee.Date("2021-01-01")))
|
|
1024
989
|
|
|
1025
990
|
deter_deg_binary = ee.Image().paint(deter_deg, 1)
|
|
1026
|
-
return deter_deg_binary.rename(
|
|
991
|
+
return deter_deg_binary.rename(
|
|
992
|
+
"nBR_DETER_forestdegradation_Amazon_after_2020"
|
|
993
|
+
).selfMask()
|
|
1027
994
|
|
|
1028
995
|
|
|
1029
996
|
# ########################## NBR commodities - permanent/perennial crops in 2020:###############################
|
|
@@ -1037,7 +1004,7 @@ def nbr_terraclass_amz_cer20_pc_prep():
|
|
|
1037
1004
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1038
1005
|
tccer20_pc = tccer20.eq(12).Or(tccer20.eq(13))
|
|
1039
1006
|
tc_pc = ee.ImageCollection([tcamz20_pc, tccer20_pc]).mosaic()
|
|
1040
|
-
return tc_pc.rename("nBR_INPE_TCamz_cer_perennial_2020")
|
|
1007
|
+
return tc_pc.rename("nBR_INPE_TCamz_cer_perennial_2020").selfMask()
|
|
1041
1008
|
|
|
1042
1009
|
|
|
1043
1010
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1049,7 +1016,7 @@ def nbr_mapbiomasc9_cof_prep():
|
|
|
1049
1016
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1050
1017
|
).select("classification_2020")
|
|
1051
1018
|
mapbiomasc9_20_coffee = mapbiomasc9_20.eq(46)
|
|
1052
|
-
return mapbiomasc9_20_coffee.rename("nBR_MapBiomas_col9_coffee_2020")
|
|
1019
|
+
return mapbiomasc9_20_coffee.rename("nBR_MapBiomas_col9_coffee_2020").selfMask()
|
|
1053
1020
|
|
|
1054
1021
|
|
|
1055
1022
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1061,7 +1028,7 @@ def nbr_mapbiomasc9_po_prep():
|
|
|
1061
1028
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1062
1029
|
).select("classification_2020")
|
|
1063
1030
|
mapbiomasc9_20_palm = mapbiomasc9_20.eq(35)
|
|
1064
|
-
return mapbiomasc9_20_palm.rename("nBR_MapBiomas_col9_palmoil_2020")
|
|
1031
|
+
return mapbiomasc9_20_palm.rename("nBR_MapBiomas_col9_palmoil_2020").selfMask()
|
|
1065
1032
|
|
|
1066
1033
|
|
|
1067
1034
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1073,7 +1040,7 @@ def nbr_mapbiomasc9_pc_prep():
|
|
|
1073
1040
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1074
1041
|
).select("classification_2020")
|
|
1075
1042
|
mapbiomasc9_20_pc = mapbiomasc9_20.eq(35).Or(mapbiomasc9_20.eq(46))
|
|
1076
|
-
return mapbiomasc9_20_pc.rename("nBR_MapBiomas_col9_pc_2020")
|
|
1043
|
+
return mapbiomasc9_20_pc.rename("nBR_MapBiomas_col9_pc_2020").selfMask()
|
|
1077
1044
|
|
|
1078
1045
|
|
|
1079
1046
|
# ######################## NBR commodities - annual crops in 2020:##############################
|
|
@@ -1089,7 +1056,7 @@ def nbr_terraclass_amz_cer20_ac_prep():
|
|
|
1089
1056
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1090
1057
|
tccer20_ac = tccer20.eq(14).Or(tccer20.eq(15))
|
|
1091
1058
|
tc_ac = ee.ImageCollection([tcamz20_ac, tccer20_ac]).mosaic()
|
|
1092
|
-
return tc_ac.rename("nBR_INPE_TCamz_cer_annual_2020")
|
|
1059
|
+
return tc_ac.rename("nBR_INPE_TCamz_cer_annual_2020").selfMask()
|
|
1093
1060
|
|
|
1094
1061
|
|
|
1095
1062
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1101,7 +1068,7 @@ def nbr_mapbiomasc9_soy_prep():
|
|
|
1101
1068
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1102
1069
|
).select("classification_2020")
|
|
1103
1070
|
mapbiomasc9_20_soy = mapbiomasc9_20.eq(39)
|
|
1104
|
-
return mapbiomasc9_20_soy.rename("nBR_MapBiomas_col9_soy_2020")
|
|
1071
|
+
return mapbiomasc9_20_soy.rename("nBR_MapBiomas_col9_soy_2020").selfMask()
|
|
1105
1072
|
|
|
1106
1073
|
|
|
1107
1074
|
# [non-official dataset by MapBiomas multisector initiative]
|
|
@@ -1121,7 +1088,7 @@ def nbr_mapbiomasc9_ac_prep():
|
|
|
1121
1088
|
.Or(mapbiomasc9_20.eq(40))
|
|
1122
1089
|
.Or(mapbiomasc9_20.eq(62))
|
|
1123
1090
|
)
|
|
1124
|
-
return mapbiomasc9_20_ac.rename("nBR_MapBiomas_col9_annual_crops_2020")
|
|
1091
|
+
return mapbiomasc9_20_ac.rename("nBR_MapBiomas_col9_annual_crops_2020").selfMask()
|
|
1125
1092
|
|
|
1126
1093
|
|
|
1127
1094
|
# ################################### NBR commodities - pasture/livestock in 2020:##############################
|
|
@@ -1134,7 +1101,7 @@ def nbr_mapbiomasc9_ac_prep():
|
|
|
1134
1101
|
def nbr_terraclass_amz20_pasture_prep():
|
|
1135
1102
|
tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
|
|
1136
1103
|
tcamz20_pasture = tcamz20.eq(10).Or(tcamz20.eq(11))
|
|
1137
|
-
return tcamz20_pasture.rename("nBR_INPE_TCamz_pasture_2020")
|
|
1104
|
+
return tcamz20_pasture.rename("nBR_INPE_TCamz_pasture_2020").selfMask()
|
|
1138
1105
|
|
|
1139
1106
|
|
|
1140
1107
|
# %%
|
|
@@ -1146,7 +1113,7 @@ def nbr_terraclass_amz20_pasture_prep():
|
|
|
1146
1113
|
def nbr_terraclass_cer20_ac_prep():
|
|
1147
1114
|
tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
|
|
1148
1115
|
tccer20_pasture = tccer20.eq(11)
|
|
1149
|
-
return tccer20_pasture.rename("nBR_INPE_TCcer_pasture_2020")
|
|
1116
|
+
return tccer20_pasture.rename("nBR_INPE_TCcer_pasture_2020").selfMask()
|
|
1150
1117
|
|
|
1151
1118
|
|
|
1152
1119
|
# %%
|
|
@@ -1159,7 +1126,7 @@ def nbr_mapbiomasc9_pasture_prep():
|
|
|
1159
1126
|
"projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
|
|
1160
1127
|
).select("classification_2020")
|
|
1161
1128
|
mapbiomasc9_20_pasture = mapbiomasc9_20.eq(15)
|
|
1162
|
-
return mapbiomasc9_20_pasture.rename("nBR_MapBiomas_col9_pasture_2020")
|
|
1129
|
+
return mapbiomasc9_20_pasture.rename("nBR_MapBiomas_col9_pasture_2020").selfMask()
|
|
1163
1130
|
|
|
1164
1131
|
|
|
1165
1132
|
###################################################################
|
|
@@ -1169,13 +1136,13 @@ def nbr_mapbiomasc9_pasture_prep():
|
|
|
1169
1136
|
def nco_ideam_forest_2020_prep():
|
|
1170
1137
|
ideam_forest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo")
|
|
1171
1138
|
ideam_forest = ideam_forest_raw.eq(1) # get forest class
|
|
1172
|
-
return ideam_forest.rename("nCO_ideam_forest_2020")
|
|
1139
|
+
return ideam_forest.rename("nCO_ideam_forest_2020").selfMask()
|
|
1173
1140
|
|
|
1174
1141
|
|
|
1175
1142
|
def nco_ideam_eufo_commission_2020_prep():
|
|
1176
1143
|
ideam_agroforest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo_EUFO")
|
|
1177
1144
|
ideam_agroforest = ideam_agroforest_raw.eq(4) # get forest class
|
|
1178
|
-
return ideam_agroforest.rename("nCO_ideam_eufo_commission_2020")
|
|
1145
|
+
return ideam_agroforest.rename("nCO_ideam_eufo_commission_2020").selfMask()
|
|
1179
1146
|
|
|
1180
1147
|
|
|
1181
1148
|
# Cocoa_bnetd
|
|
@@ -1185,43 +1152,61 @@ def nci_ocs2020_prep():
|
|
|
1185
1152
|
.select("classification")
|
|
1186
1153
|
.eq(9)
|
|
1187
1154
|
.rename("nCI_Cocoa_bnetd")
|
|
1188
|
-
) # cocoa from national land cover map for Côte d'Ivoire
|
|
1155
|
+
).selfMask() # cocoa from national land cover map for Côte d'Ivoire
|
|
1189
1156
|
|
|
1190
1157
|
|
|
1191
1158
|
###Combining datasets
|
|
1192
1159
|
|
|
1193
1160
|
|
|
1194
|
-
def combine_datasets(national_codes=None):
|
|
1195
|
-
"""
|
|
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
|
+
"""
|
|
1196
1178
|
img_combined = ee.Image(1).rename(geometry_area_column)
|
|
1197
1179
|
|
|
1198
1180
|
# Combine images directly
|
|
1199
1181
|
for img in [func() for func in list_functions(national_codes=national_codes)]:
|
|
1200
1182
|
try:
|
|
1201
1183
|
img_combined = img_combined.addBands(img)
|
|
1184
|
+
# img_combined = img_combined.addBands(img)
|
|
1202
1185
|
except ee.EEException as e:
|
|
1203
1186
|
# logger.error(f"Error adding image: {e}")
|
|
1204
1187
|
print(f"Error adding image: {e}")
|
|
1205
1188
|
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
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)
|
|
1225
1210
|
|
|
1226
1211
|
img_combined = img_combined.multiply(ee.Image.pixelArea())
|
|
1227
1212
|
print("Whisp multiband image compiled")
|