openforis-whisp 1.0.0a1__py3-none-any.whl → 2.0.0a2__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.
@@ -1,3 +1,15 @@
1
+ # This file contains python code for the Google Earth Engine datasets used in the Whisp pacakge.
2
+
3
+ # If you are running a bespoke analysis including your own datasets see also the main README.md file.
4
+
5
+ # Key aspects to include in the code for each function are:
6
+ # a) a suffix of ' _prep' and
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
+ # c) a name for your image, defined by ".rename('add_your_image_name_here')". This becomes the column header in the output table.
9
+
10
+ # NB for all the above you will need to be running the package in editable mode for these local changes to take effect.
11
+ # Editable mode runs the package locally and thus changes to any files are reflected immediately.
12
+
1
13
  import ee
2
14
 
3
15
  # ee.Authenticate()
@@ -32,7 +44,7 @@ def get_logger(name):
32
44
 
33
45
 
34
46
  # ESA_TC_2020
35
- def esa_worldcover_trees_prep():
47
+ def g_esa_worldcover_trees_prep():
36
48
  esa_worldcover_2020_raw = ee.Image("ESA/WorldCover/v100/2020")
37
49
  esa_worldcover_trees_2020 = esa_worldcover_2020_raw.eq(95).Or(
38
50
  esa_worldcover_2020_raw.eq(10)
@@ -41,25 +53,27 @@ def esa_worldcover_trees_prep():
41
53
 
42
54
 
43
55
  # EUFO_2020
44
- def jrc_gfc_2020_prep():
56
+ def g_jrc_gfc_2020_prep():
45
57
  jrc_gfc2020_raw = ee.ImageCollection("JRC/GFC2020/V2")
46
58
  return jrc_gfc2020_raw.mosaic().rename("EUFO_2020")
47
59
 
48
60
 
49
- # JAXA_FNF_2020
50
- def jaxa_forest_prep():
51
- jaxa_forest_non_forest_raw = ee.ImageCollection("JAXA/ALOS/PALSAR/YEARLY/FNF4")
52
- jaxa_forest_non_forest_2020 = (
53
- jaxa_forest_non_forest_raw.filterDate("2020-01-01", "2020-12-31")
54
- .select("fnf")
55
- .mosaic()
56
- )
57
- return jaxa_forest_non_forest_2020.lte(2).rename("JAXA_FNF_2020")
61
+ ## removing JAXA product due to repeat errors of commission being noted by users, compared to other datasets
62
+
63
+ # # JAXA_FNF_2020
64
+ # def g_jaxa_forest_prep():
65
+ # jaxa_forest_non_forest_raw = ee.ImageCollection("JAXA/ALOS/PALSAR/YEARLY/FNF4")
66
+ # jaxa_forest_non_forest_2020 = (
67
+ # jaxa_forest_non_forest_raw.filterDate("2020-01-01", "2020-12-31")
68
+ # .select("fnf")
69
+ # .mosaic()
70
+ # )
71
+ # return jaxa_forest_non_forest_2020.lte(2).rename("JAXA_FNF_2020")
58
72
 
59
73
 
60
74
  # GFC_TC_2020
61
- def glad_gfc_10pc_prep():
62
- gfc = ee.Image("UMD/hansen/global_forest_change_2023_v1_11")
75
+ def g_glad_gfc_10pc_prep():
76
+ gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
63
77
  gfc_treecover2000 = gfc.select(["treecover2000"])
64
78
  gfc_loss2001_2020 = gfc.select(["lossyear"]).lte(20)
65
79
  gfc_treecover2020 = gfc_treecover2000.where(gfc_loss2001_2020.eq(1), 0)
@@ -67,14 +81,14 @@ def glad_gfc_10pc_prep():
67
81
 
68
82
 
69
83
  # GLAD_Primary
70
- def glad_pht_prep():
84
+ def g_glad_pht_prep():
71
85
  primary_ht_forests2001_raw = ee.ImageCollection(
72
86
  "UMD/GLAD/PRIMARY_HUMID_TROPICAL_FORESTS/v1"
73
87
  )
74
88
  primary_ht_forests2001 = (
75
89
  primary_ht_forests2001_raw.select("Primary_HT_forests").mosaic().selfMask()
76
90
  )
77
- gfc = ee.Image("UMD/hansen/global_forest_change_2023_v1_11")
91
+ gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
78
92
  gfc_loss2001_2020 = gfc.select(["lossyear"]).lte(20)
79
93
  return primary_ht_forests2001.where(gfc_loss2001_2020.eq(1), 0).rename(
80
94
  "GLAD_Primary"
@@ -82,9 +96,9 @@ def glad_pht_prep():
82
96
 
83
97
 
84
98
  # TMF_undist (undistrubed forest in 2020)
85
- def jrc_tmf_undisturbed_prep():
99
+ def g_jrc_tmf_undisturbed_prep():
86
100
  TMF_undist_2020 = (
87
- ee.ImageCollection("projects/JRC/TMF/v1_2023/AnnualChanges")
101
+ ee.ImageCollection("projects/JRC/TMF/v1_2024/AnnualChanges")
88
102
  .select("Dec2020")
89
103
  .mosaic()
90
104
  .eq(1)
@@ -93,33 +107,37 @@ def jrc_tmf_undisturbed_prep():
93
107
 
94
108
 
95
109
  # Forest Persistence FDaP
96
- def fdap_forest_prep():
110
+ def g_fdap_forest_prep():
97
111
  fdap_forest_raw = ee.Image(
98
112
  "projects/forestdatapartnership/assets/community_forests/ForestPersistence_2020"
99
113
  )
100
114
  fdap_forest = fdap_forest_raw.gt(0.75)
101
115
  return fdap_forest.rename("Forest_FDaP")
102
116
 
117
+
103
118
  #########################primary forest
104
119
  # EUFO JRC Global forest type - primary
105
- def gft_primary_prep():
120
+ def g_gft_primary_prep():
106
121
  gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
107
122
  gft_primary = gft_raw.eq(10)
108
123
  return gft_primary.rename("GFT_primary")
109
-
124
+
125
+
110
126
  # Intact Forest Landscape 2020
111
- def IFL_2020_prep():
112
- IFL_2020 = ee.Image('users/potapovpeter/IFL_2020')
127
+ def g_ifl_2020_prep():
128
+ IFL_2020 = ee.Image("users/potapovpeter/IFL_2020")
113
129
  return IFL_2020.rename("IFL_2020")
114
130
 
131
+
115
132
  # European Primary Forest Dataset
116
- def EPFD_prep():
117
- EPFD=ee.FeatureCollection("HU_BERLIN/EPFD/V2/polygons")
118
- EPFD_binary = ee.Image().paint(EPFD,1)
119
- return EPFD_binary.rename('European_Primary_Forest')
120
-
133
+ def g_epfd_prep():
134
+ EPFD = ee.FeatureCollection("HU_BERLIN/EPFD/V2/polygons")
135
+ EPFD_binary = ee.Image().paint(EPFD, 1)
136
+ return EPFD_binary.rename("European_Primary_Forest")
137
+
138
+
121
139
  # EUFO JRC Global forest type - naturally regenerating planted/plantation forests
122
- def gft_nat_reg_prep():
140
+ def g_gft_nat_reg_prep():
123
141
  gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
124
142
  gft_nat_reg = gft_raw.eq(1)
125
143
  return gft_nat_reg.rename("GFT_naturally_regenerating")
@@ -128,33 +146,36 @@ def gft_nat_reg_prep():
128
146
  #########################planted and plantation forests
129
147
 
130
148
  # EUFO JRC Global forest type - planted/plantation forests
131
- def gft_plantation_prep():
149
+ def g_gft_plantation_prep():
132
150
  gft_raw = ee.ImageCollection("JRC/GFC2020_subtypes/V0").mosaic()
133
151
  gft_plantation = gft_raw.eq(20)
134
152
  return gft_plantation.rename("GFT_planted_plantation")
135
-
136
- def IIASA_planted_prep():
137
- iiasa = ee.Image('projects/sat-io/open-datasets/GFM/FML_v3-2');
153
+
154
+
155
+ def g_iiasa_planted_prep():
156
+ iiasa = ee.Image("projects/sat-io/open-datasets/GFM/FML_v3-2")
138
157
  iiasa_PL = iiasa.eq(31).Or(iiasa.eq(32))
139
- return iiasa_PL.rename('IIASA_planted_plantation')
140
-
158
+ return iiasa_PL.rename("IIASA_planted_plantation")
159
+
160
+
141
161
  #########################TMF regrowth in 2023
142
- def tmf_regrowth_prep():
162
+ def g_tmf_regrowth_prep():
143
163
  # Load the TMF Degradation annual product
144
- TMF_AC=ee.ImageCollection('projects/JRC/TMF/v1_2023/AnnualChanges').mosaic()
145
- TMF_AC_2023=TMF_AC.select('Dec2023')
164
+ TMF_AC = ee.ImageCollection("projects/JRC/TMF/v1_2024/AnnualChanges").mosaic()
165
+ TMF_AC_2023 = TMF_AC.select("Dec2023")
146
166
  Regrowth_TMF = TMF_AC_2023.eq(4)
147
- return Regrowth_TMF.rename('TMF_regrowth_2023')
148
-
167
+ return Regrowth_TMF.rename("TMF_regrowth_2023")
168
+
169
+
149
170
  ############tree crops
150
171
 
151
172
  # TMF_plant (plantations in 2020)
152
- def jrc_tmf_plantation_prep():
173
+ def g_jrc_tmf_plantation_prep():
153
174
  transition = ee.ImageCollection(
154
- "projects/JRC/TMF/v1_2023/TransitionMap_Subtypes"
175
+ "projects/JRC/TMF/v1_2024/TransitionMap_Subtypes"
155
176
  ).mosaic()
156
177
  deforestation_year = ee.ImageCollection(
157
- "projects/JRC/TMF/v1_2023/DeforestationYear"
178
+ "projects/JRC/TMF/v1_2024/DeforestationYear"
158
179
  ).mosaic()
159
180
  plantation = (transition.gte(81)).And(transition.lte(86))
160
181
  plantation_2020 = plantation.where(
@@ -165,7 +186,7 @@ def jrc_tmf_plantation_prep():
165
186
 
166
187
  # # Oil_palm_Descals
167
188
  # NB updated to Descals et al 2024 paper (as opposed to Descals et al 2021 paper)
168
- def creaf_descals_palm_prep():
189
+ def g_creaf_descals_palm_prep():
169
190
  # Load the Global Oil Palm Year of Plantation image and mosaic it
170
191
  img = (
171
192
  ee.ImageCollection(
@@ -182,103 +203,127 @@ def creaf_descals_palm_prep():
182
203
  plantation_2020 = oil_palm_plantation_year.lte(2020).selfMask()
183
204
  return plantation_2020.rename("Oil_palm_Descals")
184
205
 
185
- # Calculate the year of plantation
186
- oil_palm_plantation_year = img.divide(365).add(1970).floor().lte(2020)
187
-
188
- # Create a mask for plantations in the year 2020 or earlier
189
- plantation_2020 = oil_palm_plantation_year.lte(2020).selfMask()
190
- return plantation_2020.rename("Oil_palm_Descals")
191
-
192
206
 
193
207
  # Cocoa_ETH
194
- def eth_kalischek_cocoa_prep():
208
+ def g_eth_kalischek_cocoa_prep():
195
209
  return ee.Image("projects/ee-nk-cocoa/assets/cocoa_map_threshold_065").rename(
196
210
  "Cocoa_ETH"
197
211
  )
198
212
 
199
213
 
214
+ # fdap datasets
215
+
216
+ # Thresholds and model info here https://github.com/google/forest-data-partnership/blob/main/models/README.md
217
+
200
218
  # Oil Palm FDaP
201
- def fdap_palm_prep():
219
+ def g_fdap_palm_prep():
202
220
  fdap_palm2020_model_raw = ee.ImageCollection(
203
- "projects/forestdatapartnership/assets/palm/model_2024a"
221
+ "projects/forestdatapartnership/assets/palm/model_2025a"
204
222
  )
205
223
  fdap_palm = (
206
224
  fdap_palm2020_model_raw.filterDate("2020-01-01", "2020-12-31")
207
225
  .mosaic()
208
- .gt(0.83) # Threshold for Oil Palm
226
+ .gt(0.88) # Precision and recall ~78% at 0.88 threshold.
209
227
  )
210
228
  return fdap_palm.rename("Oil_palm_FDaP")
211
229
 
212
- def fdap_palm_2023_prep():
213
- fdap_palm2020_model_raw = ee.ImageCollection("projects/forestdatapartnership/assets/palm/model_2024a")
230
+
231
+ def g_fdap_palm_2023_prep():
232
+ fdap_palm2020_model_raw = ee.ImageCollection(
233
+ "projects/forestdatapartnership/assets/palm/model_2025a"
234
+ )
214
235
  fdap_palm = (
215
- fdap_palm2020_model_raw
216
- .filterDate('2023-01-01', '2023-12-31')
236
+ fdap_palm2020_model_raw.filterDate("2023-01-01", "2023-12-31")
217
237
  .mosaic()
218
- .gt(0.83) # Threshold for Oil Palm
219
-
238
+ .gt(0.88) # Precision and recall ~78% at 0.88 threshold.
220
239
  )
221
240
  return fdap_palm.rename("Oil_palm_2023_FDaP")
222
241
 
223
242
 
243
+ # Cocoa FDaP
244
+ def g_fdap_cocoa_prep():
245
+ fdap_cocoa2020_model_raw = ee.ImageCollection(
246
+ "projects/forestdatapartnership/assets/cocoa/model_2025a"
247
+ )
248
+ fdap_cocoa = (
249
+ fdap_cocoa2020_model_raw.filterDate("2020-01-01", "2020-12-31")
250
+ .mosaic()
251
+ .gt(0.96) # Precision and recall ~87% 0.96 threshold.
252
+ )
253
+ return fdap_cocoa.rename("Cocoa_FDaP")
254
+
255
+
256
+ def g_fdap_cocoa_2023_prep():
257
+ fdap_cocoa2020_model_raw = ee.ImageCollection(
258
+ "projects/forestdatapartnership/assets/cocoa/model_2025a"
259
+ )
260
+ fdap_cocoa = (
261
+ fdap_cocoa2020_model_raw.filterDate("2023-01-01", "2023-12-31")
262
+ .mosaic()
263
+ .gt(0.96) # Precision and recall ~87% 0.96 threshold.
264
+ )
265
+ return fdap_cocoa.rename("Cocoa_2023_FDaP")
266
+
267
+
224
268
  # Rubber FDaP
225
- def fdap_rubber_prep():
269
+ def g_fdap_rubber_prep():
226
270
  fdap_rubber2020_model_raw = ee.ImageCollection(
227
- "projects/forestdatapartnership/assets/rubber/model_2024a"
271
+ "projects/forestdatapartnership/assets/rubber/model_2025a"
228
272
  )
229
273
  fdap_rubber = (
230
274
  fdap_rubber2020_model_raw.filterDate("2020-01-01", "2020-12-31")
231
275
  .mosaic()
232
- .gt(0.93) # Threshold for Rubber
276
+ .gt(0.59) # Precision and recall ~80% 0.59 threshold.
233
277
  )
234
278
  return fdap_rubber.rename("Rubber_FDaP")
235
279
 
236
- def fdap_rubber_2023_prep():
237
- fdap_rubber2020_model_raw = ee.ImageCollection("projects/forestdatapartnership/assets/rubber/model_2024a")
280
+
281
+ def g_fdap_rubber_2023_prep():
282
+ fdap_rubber2020_model_raw = ee.ImageCollection(
283
+ "projects/forestdatapartnership/assets/rubber/model_2025a"
284
+ )
238
285
  fdap_rubber = (
239
- fdap_rubber2020_model_raw
240
- .filterDate('2023-01-01', '2023-12-31')
286
+ fdap_rubber2020_model_raw.filterDate("2023-01-01", "2023-12-31")
241
287
  .mosaic()
242
288
  .gt(0.93) # Threshold for Rubber
243
-
244
289
  )
245
290
  return fdap_rubber.rename("Rubber_2023_FDaP")
246
291
 
247
- # Cocoa FDaP
248
- def fdap_cocoa_prep():
249
- fdap_cocoa2020_model_raw = ee.ImageCollection(
250
- "projects/forestdatapartnership/assets/cocoa/model_2024a"
292
+
293
+ # # Coffee FDaP
294
+ def g_fdap_coffee_2020_prep():
295
+ # Load the coffee model for 2020
296
+ collection = ee.ImageCollection(
297
+ "projects/forestdatapartnership/assets/coffee/model_2025a"
251
298
  )
252
- fdap_cocoa = (
253
- fdap_cocoa2020_model_raw.filterDate("2020-01-01", "2020-12-31")
299
+
300
+ # Filter the collection for the year 2020 and create a binary mask
301
+ coffee_2020 = (
302
+ collection.filterDate("2020-01-01", "2020-12-31")
254
303
  .mosaic()
255
- .gt(0.5) # Threshold for Cocoa
304
+ .gt(0.99) # Precision and recall ~54% 0.99 threshold.
256
305
  )
257
- return fdap_cocoa.rename("Cocoa_FDaP")
258
306
 
259
- def fdap_cocoa_2023_prep():
260
- fdap_cocoa2020_model_raw = ee.ImageCollection("projects/forestdatapartnership/assets/cocoa/model_2024a")
261
- fdap_cocoa = (
262
- fdap_cocoa2020_model_raw
263
- .filterDate('2023-01-01', '2023-12-31')
264
- .mosaic()
265
- .gt(0.5) # Threshold for Cocoa
266
-
307
+ return coffee_2020.rename("Coffee_FDaP")
308
+
309
+
310
+ def g_fdap_coffee_2023_prep():
311
+ # Load the coffee model for 2020
312
+ collection = ee.ImageCollection(
313
+ "projects/forestdatapartnership/assets/coffee/model_2025a"
267
314
  )
268
- return fdap_cocoa.rename("Cocoa_2023_FDaP")
269
315
 
270
- # Cocoa_bnetd
271
- def civ_ocs2020_prep():
272
- return (
273
- ee.Image("BNETD/land_cover/v1/2020")
274
- .select("classification")
275
- .eq(9)
276
- .rename("Cocoa_bnetd")
277
- ) # cocoa from national land cover map for Côte d'Ivoire
316
+ # Filter the collection for the year 2023 and create a binary mask
317
+ coffee_2023 = (
318
+ collection.filterDate("2023-01-01", "2023-12-31")
319
+ .mosaic()
320
+ .gt(0.99) # Precision and recall ~54% 0.99 threshold.
321
+ )
322
+ return coffee_2023.rename("Coffee_FDaP_2023")
278
323
 
279
324
 
280
325
  # Rubber_RBGE - from Royal Botanical Gardens of Edinburgh (RBGE) NB for 2021
281
- def rbge_rubber_prep():
326
+ def g_rbge_rubber_prep():
282
327
  return (
283
328
  ee.Image(
284
329
  "users/wangyxtina/MapRubberPaper/rRubber10m202122_perc1585DifESAdist5pxPF"
@@ -287,45 +332,72 @@ def rbge_rubber_prep():
287
332
  .rename("Rubber_RBGE")
288
333
  )
289
334
 
290
- ################## seasonal crops
291
335
 
292
- #soy 2020 Brazil
293
- def soy_song_2020_prep():
294
- return ee.Image('projects/glad/soy_annual_SA/2020').unmask().rename("Soy_Song_2020")
295
- ##############2023
336
+ # soy 2020 South America
337
+ def g_soy_song_2020_prep():
338
+ return ee.Image("projects/glad/soy_annual_SA/2020").unmask().rename("Soy_Song_2020")
339
+
340
+
341
+ ##############
296
342
  # ESRI 2023
343
+
297
344
  # ESRI 2023 - Tree Cover
298
- def esri_2023_TC_prep():
299
- esri_lulc10_raw = ee.ImageCollection("projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS")
300
- esri_lulc10_TC = esri_lulc10_raw.filterDate('2023-01-01', '2023-12-31').mosaic().eq(2)
301
- return esri_lulc10_TC.rename('ESRI_2023_TC')
302
-
345
+ def g_esri_2023_tc_prep():
346
+ esri_lulc10_raw = ee.ImageCollection(
347
+ "projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS"
348
+ )
349
+ esri_lulc10_TC = (
350
+ esri_lulc10_raw.filterDate("2023-01-01", "2023-12-31").mosaic().eq(2)
351
+ )
352
+ return esri_lulc10_TC.rename("ESRI_2023_TC")
353
+
354
+
303
355
  # ESRI 2023 - Crop
304
- def esri_2023_crop_prep():
305
- esri_lulc10_raw = ee.ImageCollection("projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS")
306
- esri_lulc10_crop = esri_lulc10_raw.filterDate('2023-01-01', '2023-12-31').mosaic().eq(5)
307
- return esri_lulc10_crop.rename('ESRI_2023_crop')
356
+ def g_esri_2023_crop_prep():
357
+ esri_lulc10_raw = ee.ImageCollection(
358
+ "projects/sat-io/open-datasets/landcover/ESRI_Global-LULC_10m_TS"
359
+ )
360
+ esri_lulc10_crop = (
361
+ esri_lulc10_raw.filterDate("2023-01-01", "2023-12-31").mosaic().eq(5)
362
+ )
363
+ return esri_lulc10_crop.rename("ESRI_2023_crop")
364
+
308
365
 
309
366
  # GLC_FCS30D 2022
310
367
 
311
368
  # GLC_FCS30D Tree Cover
312
369
  # forest classes + swamp + mangrove / what to do with shrubland?
313
- def GLC_FCS30D_TC_2022_prep():
314
- GLC_FCS30D = ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual").mosaic().select(22)
315
- GLC_FCS30D_TC = (GLC_FCS30D.gte(51)).And(GLC_FCS30D.lte(92)).Or(GLC_FCS30D.eq(181)).Or(GLC_FCS30D.eq(185))
316
- return GLC_FCS30D_TC.rename('GLC_FCS30D_TC_2022')
370
+ def g_glc_fcs30d_tc_2022_prep():
371
+ GLC_FCS30D = (
372
+ ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual")
373
+ .mosaic()
374
+ .select(22)
375
+ )
376
+ GLC_FCS30D_TC = (
377
+ (GLC_FCS30D.gte(51))
378
+ .And(GLC_FCS30D.lte(92))
379
+ .Or(GLC_FCS30D.eq(181))
380
+ .Or(GLC_FCS30D.eq(185))
381
+ )
382
+ return GLC_FCS30D_TC.rename("GLC_FCS30D_TC_2022")
383
+
317
384
 
318
385
  # GLC_FCS30D crop
319
- # 10 Rainfed cropland; 11 Herbaceous cover; 12 Tree or shrub cover (Orchard); 20 Irrigated cropland
320
- def GLC_FCS30D_crop_2022_prep():
321
- GLC_FCS30D = ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual").mosaic().select(22)
386
+ # 10 Rainfed cropland; 11 Herbaceous cover; 12 Tree or shrub cover (Orchard); 20 Irrigated cropland
387
+ def g_glc_fcs30d_crop_2022_prep():
388
+ GLC_FCS30D = (
389
+ ee.ImageCollection("projects/sat-io/open-datasets/GLC-FCS30D/annual")
390
+ .mosaic()
391
+ .select(22)
392
+ )
322
393
  GLC_FCS30D_crop = GLC_FCS30D.gte(10).And(GLC_FCS30D.lte(20))
323
- return GLC_FCS30D_crop.rename('GLC_FCS30D_crop_2022')
324
-
394
+ return GLC_FCS30D_crop.rename("GLC_FCS30D_crop_2022")
395
+
396
+
325
397
  #### disturbances by year
326
398
 
327
399
  # RADD_year_2019 to RADD_year_< current year >
328
- def radd_year_prep():
400
+ def g_radd_year_prep():
329
401
  from datetime import datetime
330
402
 
331
403
  radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
@@ -363,12 +435,12 @@ def radd_year_prep():
363
435
 
364
436
 
365
437
  # TMF_def_2000 to TMF_def_2023
366
- def tmf_def_per_year_prep():
438
+ def g_tmf_def_per_year_prep():
367
439
  # Load the TMF Deforestation annual product
368
- tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2023/DeforestationYear").mosaic()
440
+ tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
369
441
  img_stack = None
370
442
  # Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
371
- for i in range(0, 23 + 1):
443
+ for i in range(0, 24 + 1):
372
444
  tmf_def_year = tmf_def.eq(2000 + i).rename("TMF_def_" + str(2000 + i))
373
445
  if img_stack is None:
374
446
  img_stack = tmf_def_year
@@ -378,12 +450,12 @@ def tmf_def_per_year_prep():
378
450
 
379
451
 
380
452
  # TMF_deg_2000 to TMF_deg_2023
381
- def tmf_deg_per_year_prep():
453
+ def g_tmf_deg_per_year_prep():
382
454
  # Load the TMF Degradation annual product
383
- tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2023/DegradationYear").mosaic()
455
+ tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
384
456
  img_stack = None
385
457
  # Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
386
- for i in range(0, 23 + 1):
458
+ for i in range(0, 24 + 1):
387
459
  tmf_def_year = tmf_def.eq(2000 + i).rename("TMF_deg_" + str(2000 + i))
388
460
  if img_stack is None:
389
461
  img_stack = tmf_def_year
@@ -393,12 +465,12 @@ def tmf_deg_per_year_prep():
393
465
 
394
466
 
395
467
  # GFC_loss_year_2001 to GFC_loss_year_2023 (correct for version 11)
396
- def glad_gfc_loss_per_year_prep():
468
+ def g_glad_gfc_loss_per_year_prep():
397
469
  # Load the Global Forest Change dataset
398
- gfc = ee.Image("UMD/hansen/global_forest_change_2023_v1_11")
470
+ gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
399
471
  img_stack = None
400
472
  # Generate an image based on GFC with one band of forest tree loss per year from 2001 to 2022
401
- for i in range(1, 23 + 1):
473
+ for i in range(1, 24 + 1):
402
474
  gfc_loss_year = (
403
475
  gfc.select(["lossyear"]).eq(i).And(gfc.select(["treecover2000"]).gt(10))
404
476
  )
@@ -411,7 +483,7 @@ def glad_gfc_loss_per_year_prep():
411
483
 
412
484
 
413
485
  # MODIS_fire_2000 to MODIS_fire_< current year >
414
- def modis_fire_prep():
486
+ def g_modis_fire_prep():
415
487
  modis_fire = ee.ImageCollection("MODIS/061/MCD64A1")
416
488
  start_year = 2000
417
489
 
@@ -438,7 +510,7 @@ def modis_fire_prep():
438
510
 
439
511
 
440
512
  # ESA_fire_2000 to ESA_fire_2020
441
- def esa_fire_prep():
513
+ def g_esa_fire_prep():
442
514
  esa_fire = ee.ImageCollection("ESA/CCI/FireCCI/5_1")
443
515
  start_year = 2001
444
516
 
@@ -555,7 +627,7 @@ def esa_fire_prep():
555
627
  #### disturbances combined (split into before and after 2020)
556
628
 
557
629
  # RADD_after_2020
558
- def radd_after_2020_prep():
630
+ def g_radd_after_2020_prep():
559
631
  from datetime import datetime
560
632
 
561
633
  radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
@@ -580,7 +652,7 @@ def radd_after_2020_prep():
580
652
 
581
653
 
582
654
  # RADD_before_2020
583
- def radd_before_2020_prep():
655
+ def g_radd_before_2020_prep():
584
656
  from datetime import datetime
585
657
 
586
658
  radd = ee.ImageCollection("projects/radar-wur/raddalert/v1")
@@ -626,33 +698,33 @@ def radd_before_2020_prep():
626
698
 
627
699
 
628
700
  # TMF_deg_before_2020
629
- def tmf_deg_before_2020_prep():
630
- tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2023/DegradationYear").mosaic()
701
+ def g_tmf_deg_before_2020_prep():
702
+ tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
631
703
  return (tmf_deg.lte(2020)).And(tmf_deg.gte(2000)).rename("TMF_deg_before_2020")
632
704
 
633
705
 
634
706
  # TMF_deg_after_2020
635
- def tmf_deg_after_2020_prep():
636
- tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2023/DegradationYear").mosaic()
707
+ def g_tmf_deg_after_2020_prep():
708
+ tmf_deg = ee.ImageCollection("projects/JRC/TMF/v1_2024/DegradationYear").mosaic()
637
709
  return tmf_deg.gt(2020).rename("TMF_deg_after_2020")
638
710
 
639
711
 
640
712
  # tmf_def_before_2020
641
- def tmf_def_before_2020_prep():
642
- tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2023/DeforestationYear").mosaic()
713
+ def g_tmf_def_before_2020_prep():
714
+ tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
643
715
  return (tmf_def.lte(2020)).And(tmf_def.gte(2000)).rename("TMF_def_before_2020")
644
716
 
645
717
 
646
718
  # tmf_def_after_2020
647
- def tmf_def_after_2020_prep():
648
- tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2023/DeforestationYear").mosaic()
719
+ def g_tmf_def_after_2020_prep():
720
+ tmf_def = ee.ImageCollection("projects/JRC/TMF/v1_2024/DeforestationYear").mosaic()
649
721
  return tmf_def.gt(2020).rename("TMF_def_after_2020")
650
722
 
651
723
 
652
724
  # GFC_loss_before_2020 (loss within 10 percent cover; includes 2020; correct for version 11)
653
- def glad_gfc_loss_before_2020_prep():
725
+ def g_glad_gfc_loss_before_2020_prep():
654
726
  # Load the Global Forest Change dataset
655
- gfc = ee.Image("UMD/hansen/global_forest_change_2023_v1_11")
727
+ gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
656
728
  gfc_loss = (
657
729
  gfc.select(["lossyear"]).lte(20).And(gfc.select(["treecover2000"]).gt(10))
658
730
  )
@@ -660,15 +732,15 @@ def glad_gfc_loss_before_2020_prep():
660
732
 
661
733
 
662
734
  # GFC_loss_after_2020 (loss within 10 percent cover; correct for version 11)
663
- def glad_gfc_loss_after_2020_prep():
735
+ def g_glad_gfc_loss_after_2020_prep():
664
736
  # Load the Global Forest Change dataset
665
- gfc = ee.Image("UMD/hansen/global_forest_change_2023_v1_11")
737
+ gfc = ee.Image("UMD/hansen/global_forest_change_2024_v1_12")
666
738
  gfc_loss = gfc.select(["lossyear"]).gt(20).And(gfc.select(["treecover2000"]).gt(10))
667
739
  return gfc_loss.rename("GFC_loss_after_2020")
668
740
 
669
741
 
670
742
  # MODIS_fire_before_2020
671
- def modis_fire_before_2020_prep():
743
+ def g_modis_fire_before_2020_prep():
672
744
  modis_fire = ee.ImageCollection("MODIS/061/MCD64A1")
673
745
  start_year = 2000
674
746
  end_year = 2020
@@ -684,7 +756,7 @@ def modis_fire_before_2020_prep():
684
756
 
685
757
 
686
758
  # MODIS_fire_after_2020
687
- def modis_fire_after_2020_prep():
759
+ def g_modis_fire_after_2020_prep():
688
760
  modis_fire = ee.ImageCollection("MODIS/061/MCD64A1")
689
761
  start_year = 2021
690
762
  end_year = datetime.now().year
@@ -700,7 +772,7 @@ def modis_fire_after_2020_prep():
700
772
 
701
773
 
702
774
  # ESA_fire_before_2020
703
- def esa_fire_before_2020_prep():
775
+ def g_esa_fire_before_2020_prep():
704
776
  esa_fire = ee.ImageCollection("ESA/CCI/FireCCI/5_1")
705
777
  start_year = 2000
706
778
  end_year = 2020
@@ -714,37 +786,489 @@ def esa_fire_before_2020_prep():
714
786
  .rename("ESA_fire_before_2020")
715
787
  )
716
788
 
789
+
717
790
  #########################logging concessions
718
- #http://data.globalforestwatch.org/datasets?q=logging&sort_by=relevance
719
- def logging_concessions_prep():
720
- RCA=ee.FeatureCollection('projects/ee-whisp/assets/logging/RCA_Permis_dExploitation_et_dAmenagement')
721
- RCA_binary = ee.Image().paint(RCA,1)
722
- CMR=ee.FeatureCollection('projects/ee-whisp/assets/logging/Cameroon_Forest_Management_Units')
723
- CMR_binary = ee.Image().paint(CMR,1)
724
- Eq_G=ee.FeatureCollection('projects/ee-whisp/assets/logging/Equatorial_Guinea_logging_concessions')
725
- Eq_G_binary = ee.Image().paint(Eq_G,1)
726
- DRC=ee.FeatureCollection('projects/ee-whisp/assets/logging/DRC_Forest_concession_agreements')
727
- DRC_binary = ee.Image().paint(DRC,1)
728
- Liberia=ee.FeatureCollection('projects/ee-whisp/assets/logging/Liberia_Forest_Management_Contracts')
729
- Liberia_binary = ee.Image().paint(Liberia,1)
730
- RoC=ee.FeatureCollection('projects/ee-whisp/assets/logging/Republic_of_the_Congo_logging_concessions')
731
- Roc_binary = ee.Image().paint(RoC,1)
732
- Sarawak=ee.FeatureCollection('projects/ee-whisp/assets/logging/Sarawak_logging_concessions')
733
- Sarawak_binary = ee.Image().paint(Sarawak,1)
734
- logging_concessions_binary=ee.ImageCollection([RCA_binary, CMR_binary, Eq_G_binary,DRC_binary,Liberia_binary,Roc_binary,Sarawak_binary]).mosaic()
735
-
736
- return logging_concessions_binary.rename('GFW_logging')
737
-
738
-
739
- # ###Combining datasets
740
-
741
-
742
- def combine_datasets():
791
+ # http://data.globalforestwatch.org/datasets?q=logging&sort_by=relevance
792
+ def g_logging_concessions_before_2020_prep():
793
+ RCA = ee.FeatureCollection(
794
+ "projects/ee-whisp/assets/logging/RCA_Permis_dExploitation_et_dAmenagement"
795
+ )
796
+ RCA_binary = ee.Image().paint(RCA, 1)
797
+ CMR = ee.FeatureCollection(
798
+ "projects/ee-whisp/assets/logging/Cameroon_Forest_Management_Units"
799
+ )
800
+ CMR_binary = ee.Image().paint(CMR, 1)
801
+ Eq_G = ee.FeatureCollection(
802
+ "projects/ee-whisp/assets/logging/Equatorial_Guinea_logging_concessions"
803
+ )
804
+ Eq_G_binary = ee.Image().paint(Eq_G, 1)
805
+ DRC = ee.FeatureCollection(
806
+ "projects/ee-whisp/assets/logging/DRC_Forest_concession_agreements"
807
+ )
808
+ DRC_binary = ee.Image().paint(DRC, 1)
809
+ Liberia = ee.FeatureCollection(
810
+ "projects/ee-whisp/assets/logging/Liberia_Forest_Management_Contracts"
811
+ )
812
+ Liberia_binary = ee.Image().paint(Liberia, 1)
813
+ RoC = ee.FeatureCollection(
814
+ "projects/ee-whisp/assets/logging/Republic_of_the_Congo_logging_concessions"
815
+ )
816
+ Roc_binary = ee.Image().paint(RoC, 1)
817
+ Sarawak = ee.FeatureCollection(
818
+ "projects/ee-whisp/assets/logging/Sarawak_logging_concessions"
819
+ )
820
+ Sarawak_binary = ee.Image().paint(Sarawak, 1)
821
+ logging_concessions_binary = ee.ImageCollection(
822
+ [
823
+ RCA_binary,
824
+ CMR_binary,
825
+ Eq_G_binary,
826
+ DRC_binary,
827
+ Liberia_binary,
828
+ Roc_binary,
829
+ Sarawak_binary,
830
+ ]
831
+ ).mosaic()
832
+
833
+ return logging_concessions_binary.rename("GFW_logging_before_2020")
834
+
835
+
836
+ #########################national datasets
837
+
838
+ # nBR Brazil
839
+
840
+ # ### nBR Natural forests in 2020:
841
+
842
+ # %%
843
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Amazon biome, 2020
844
+ # Subsetting criteria: primary forests (DN=1) and secondary forests (DN=2) // secondary forests are those recovering from deforestation
845
+ # the resulting dataset shows primary and secondary forest cover in 2020 (mostly by August 2020)
846
+
847
+ ##########################primary forests###############################################
848
+ def nbr_terraclass_amz20_primary_prep():
849
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
850
+ tcamz20_f = tcamz20.eq(1)
851
+ return tcamz20_f.rename("nBR_INPE_TC_primary_forest_Amazon_2020")
852
+
853
+
854
+ # [Official NFMS dataset] Brazilian Forest Service dataset on natural forest cover from PRODES and TerraClass data, base year 2022
855
+ # Subsetting criteria: ano_desmat > 2020 and nom_class = 'Floresta'
856
+ # the resulting datasets show primary forest cover in 2020 for the Pantanal, Caatinga, Atlantic Forest and Pampa biomes.
857
+ # the resulting dataset shows primary and secondary forest cover in 2020 for the Cerrado biome (TerraClass 2020)
858
+ # For the Amazon, best to use Terraclass 2020 directly, because the BFS used TerraClass 2014.
859
+
860
+ # Pantanal
861
+ def nbr_bfs_ptn_f20_prep():
862
+ bfs_fptn20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_ptn_2020")
863
+
864
+ bfs_fptn20_binary = ee.Image().paint(bfs_fptn20, 1)
865
+ return bfs_fptn20_binary.rename("nBR_BFS_primary_forest_Pantanal_2020")
866
+
867
+
868
+ # Caatinga - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
869
+ ## couldn't convert it to asset, working on it (Error: Primary geometry of feature '306862' has 2454627 vertices, above the limit of 1000000 vertices. (Error code: 3)
870
+ def nbr_bfs_caat_f20_prep():
871
+ bfs_fcaat20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_caat_2020")
872
+ bfs_fcaat20_binary = ee.Image().paint(bfs_fcaat20, 1)
873
+ return bfs_fcaat20_binary.rename("nBR_BFS_primary_forest_Caatinga_2020")
874
+
875
+
876
+ # Atlantic Forest - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
877
+ def nbr_bfs_atlf_f20_prep():
878
+ bfs_fatlf20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_atlf_2020")
879
+ bfs_fatlf20_binary = ee.Image().paint(bfs_fatlf20, 1)
880
+ return bfs_fatlf20_binary.rename("nBR_BFS_primary_forest_AtlanticForest_2020")
881
+
882
+
883
+ # Pampa - filtered in QGIS to save some storage space
884
+ def nbr_bfs_pmp_f20_prep():
885
+ bfs_fpmp20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_pmp_2020")
886
+ bfs_fpmp20_binary = ee.Image().paint(bfs_fpmp20, 1)
887
+ return bfs_fpmp20_binary.rename("nBR_BFS_primary_forest_Pampa_2020")
888
+
889
+
890
+ ##########################secondary forests###############################################
891
+ def nbr_terraclass_amz20_secondary_prep():
892
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
893
+ tcamz20_f = tcamz20.eq(2)
894
+ return tcamz20_f.rename("nBR_INPE_TC_secondary_forest_Amazon_2020")
895
+
896
+
897
+ # Cerrado - filtered with QGIS because the original geodatabase is too large to export as a shapefile (GEE accepted format)
898
+ def nbr_bfs_cer_f20_prep():
899
+ bfs_fcer20 = ee.FeatureCollection("projects/ee-whisp/assets/NBR/bfs_pmp_2020")
900
+ bfs_fcer20_binary = ee.Image().paint(bfs_fcer20, 1)
901
+ return bfs_fcer20_binary.rename("nBR_BFS_primary&secondary_forest_Cerrado_2020")
902
+
903
+
904
+ # %%
905
+ # [non-official dataset by MapBiomas multisector initiative]
906
+ # land use/cover from 1985 up to 2023, collection 9
907
+ # Subsetting criteria: classification_2020 = Forest formation (DN=3), Savanna Formation (DN=4, forest according to BR definition), Mangrove (DN=5), Floodable Forest (DN=6), Wooded Sandbank veg (DN=49)
908
+ # the resulting dataset shows forest cover in 2020, without distinguishing between primary and secondary forests
909
+ def nbr_mapbiomasc9_f20_prep():
910
+ mapbiomasc9_20 = ee.Image(
911
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
912
+ ).select("classification_2020")
913
+ mapbiomasc9_20_forest = (
914
+ mapbiomasc9_20.eq(3)
915
+ .Or(mapbiomasc9_20.eq(4))
916
+ .Or(mapbiomasc9_20.eq(5))
917
+ .Or(mapbiomasc9_20.eq(6))
918
+ .Or(mapbiomasc9_20.eq(49))
919
+ )
920
+ return mapbiomasc9_20_forest.rename("nBR_MapBiomas_col9_forest_Brazil_2020")
921
+
922
+
923
+ # ### ########################NBR plantation forest in 2020:#######################################
924
+
925
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Amazon biome, 2020
926
+ # Subsetting criteria: silviculture (DN=9)
927
+ # the resulting dataset shows monospecific commercial plantations, mostly eucalyptus and pinus.
928
+ def nbr_terraclass_amz20_silv_prep():
929
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
930
+ tcamz20_silviculture = tcamz20.eq(9)
931
+ return tcamz20_silviculture.rename("nBR_INPE_TCsilviculture_Amazon_2020")
932
+
933
+
934
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
935
+ # Subsetting criteria: silviculture (DN=9)
936
+ # the resulting dataset shows monospecific commercial plantations, mostly eucalyptus and pinus.
937
+ def nbr_terraclass_silv_cer20_prep():
938
+ tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
939
+ tccer20_silviculture = tccer20.eq(9)
940
+ return tccer20_silviculture.rename("nBR_INPE_TCsilviculture_Cerrado_2020")
941
+
942
+
943
+ # [non-official dataset by MapBiomas multisector initiative]
944
+ # land use/cover from 1985 up to 2023, collection 9
945
+ # Subsetting criteria: 'classification_2020' = Forest plantation (DN=9)
946
+ # the resulting dataset shows forest plantation in 2020
947
+ def nbr_mapbiomasc9_silv20_prep():
948
+ mapbiomasc9_20 = ee.Image(
949
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
950
+ ).select("classification_2020")
951
+ mapbiomasc9_20_silviculture = mapbiomasc9_20.eq(9)
952
+ return mapbiomasc9_20_silviculture.rename(
953
+ "nBR_MapBiomas_col9_silviculture_Brazil_2020"
954
+ )
955
+
956
+
957
+ ################ ### NBR Disturbances before 2020:########################################
958
+
959
+ # [Official NFMS dataset] INPE PRODES data up to 2023
960
+ # Subsetting criteria: DN = [0, 2, 4, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60];
961
+
962
+ # the resulting dataset shows deforestation and conversion of OWL and OL up to 2020 (mostly August 2020), including residues (omission errors corrections)
963
+ def nbr_prodes_before_2020_prep():
964
+ prodes = ee.Image("projects/ee-whisp/assets/NBR/prodes_brasil_2023")
965
+ prodes_before_20_dn = [
966
+ 0,
967
+ 2,
968
+ 4,
969
+ 6,
970
+ 7,
971
+ 8,
972
+ 9,
973
+ 10,
974
+ 11,
975
+ 12,
976
+ 13,
977
+ 14,
978
+ 15,
979
+ 16,
980
+ 17,
981
+ 18,
982
+ 19,
983
+ 20,
984
+ 50,
985
+ 51,
986
+ 52,
987
+ 53,
988
+ 54,
989
+ 55,
990
+ 56,
991
+ 57,
992
+ 58,
993
+ 59,
994
+ 60,
995
+ ]
996
+ prodes_before_20_mask = prodes.remap(
997
+ prodes_before_20_dn, [1] * len(prodes_before_20_dn)
998
+ ) # .eq(1)
999
+ prodes_before_20 = prodes_before_20_mask.selfMask()
1000
+ return prodes_before_20.rename("nBR_PRODES_deforestation_Brazil_before_2020")
1001
+
1002
+
1003
+ ## Caution: 1) includes deforestation and conversion of other wooded land and grassland
1004
+
1005
+ # [Official NFMS dataset] INPE.DETER data from 2nd August 2016 up to the 04th of April 2025
1006
+ # Subsetting criteria: forest degradation classes ['CICATRIZ_DE_QUEIMADA', 'CS_DESORDENADO', 'DEGRADACAO'] and view_date until 2020-12-31
1007
+ # 'CS_GEOMETRICO' excluded to align with FREL
1008
+
1009
+
1010
+ def nbr_deter_amazon_before_2020_prep():
1011
+ deteramz = ee.FeatureCollection("projects/ee-whisp/assets/NBR/deter_amz_16apr2025")
1012
+ degradation_classes = ["CICATRIZ_DE_QUEIMADA", "CS_DESORDENADO", "DEGRADACAO"]
1013
+
1014
+ # Add a formatted date field based on VIEW_DATE
1015
+ def add_formatted_date(feature):
1016
+ return feature.set("formatted_date", ee.Date(feature.get("VIEW_DATE")))
1017
+
1018
+ deteramz = deteramz.map(add_formatted_date)
1019
+
1020
+ deter_deg = deteramz.filter(
1021
+ ee.Filter.inList("CLASSNAME", degradation_classes)
1022
+ ).filter(ee.Filter.lt("formatted_date", ee.Date("2020-12-31")))
1023
+
1024
+ deter_deg_binary = ee.Image().paint(deter_deg, 1)
1025
+ return deter_deg_binary.rename("nBR_DETER_forestdegradation_Amazon_before_2020")
1026
+
1027
+
1028
+ ################ ### NBR Disturbances after 2020:########################################
1029
+ # [Official NFMS dataset] INPE PRODES data up to 2023
1030
+ # Subsetting criteria: DN = [21, 22, 23, 61, 62, 63];
1031
+
1032
+ # the resulting dataset shows deforestation and conversion of OWL and OL up to 2020 (mostly August 2020), including residues (omission errors corrections)
1033
+
1034
+
1035
+ def nbr_prodes_after_2020_prep():
1036
+ prodes = ee.Image("projects/ee-whisp/assets/NBR/prodes_brasil_2023")
1037
+ prodes_after_20_dn = [21, 22, 23, 61, 62, 63]
1038
+ prodes_after_20_mask = prodes.remap(
1039
+ prodes_after_20_dn, [1] * len(prodes_after_20_dn)
1040
+ ) # .eq(1)
1041
+ prodes_after_20 = prodes_after_20_mask.selfMask()
1042
+ return prodes_after_20.rename("nBR_PRODES_deforestation_Brazil_after_2020")
1043
+
1044
+
1045
+ # %%
1046
+ # [Official NFMS dataset] INPE.DETER data from 2nd August 2016 up to the 04th of April 2025
1047
+ # Subsetting criteria: forest degradation classes ['CICATRIZ_DE_QUEIMADA', 'CS_DESORDENADO', 'DEGRADACAO'] and view_date from 2021-01-01 onward
1048
+ # 'CS_GEOMETRICO' excluded to align with FREL
1049
+ def nbr_deter_amazon_after_2020_prep():
1050
+ deteramz = ee.FeatureCollection("projects/ee-whisp/assets/NBR/deter_amz_16apr2025")
1051
+ degradation_classes = ["CICATRIZ_DE_QUEIMADA", "CS_DESORDENADO", "DEGRADACAO"]
1052
+
1053
+ # Add a formatted date field based on VIEW_DATE
1054
+ def add_formatted_date(feature):
1055
+ return feature.set("formatted_date", ee.Date(feature.get("VIEW_DATE")))
1056
+
1057
+ deteramz = deteramz.map(add_formatted_date)
1058
+
1059
+ deter_deg = deteramz.filter(
1060
+ ee.Filter.inList("CLASSNAME", degradation_classes)
1061
+ ).filter(ee.Filter.gt("formatted_date", ee.Date("2021-01-01")))
1062
+
1063
+ deter_deg_binary = ee.Image().paint(deter_deg, 1)
1064
+ return deter_deg_binary.rename("nBR_DETER_forestdegradation_Amazon_after_2020")
1065
+
1066
+
1067
+ # ########################## NBR commodities - permanent/perennial crops in 2020:###############################
1068
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Amazon biome, 2020
1069
+ # OR [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
1070
+ # Subsetting criteria: perennial (DN=12) and semi-perennial (DN=13) crops
1071
+ # the resulting dataset shows perennial and semi-perennial crops in 2020
1072
+ def nbr_terraclass_amz_cer20_pc_prep():
1073
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
1074
+ tcamz20_pc = tcamz20.eq(12).Or(tcamz20.eq(13))
1075
+ tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
1076
+ tccer20_pc = tccer20.eq(12).Or(tccer20.eq(13))
1077
+ tc_pc = ee.ImageCollection([tcamz20_pc, tccer20_pc]).mosaic()
1078
+ return tc_pc.rename("nBR_INPE_TCamz_cer_perennial_2020")
1079
+
1080
+
1081
+ # [non-official dataset by MapBiomas multisector initiative]
1082
+ # land use/cover from 1985 up to 2023, collection 9
1083
+ # Subsetting criteria: 'classification_2020' = coffee (DN=46) <================== COFFEE
1084
+ # the resulting dataset shows coffee area in 2020
1085
+ def nbr_mapbiomasc9_cof_prep():
1086
+ mapbiomasc9_20 = ee.Image(
1087
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1088
+ ).select("classification_2020")
1089
+ mapbiomasc9_20_coffee = mapbiomasc9_20.eq(46)
1090
+ return mapbiomasc9_20_coffee.rename("nBR_MapBiomas_col9_coffee_2020")
1091
+
1092
+
1093
+ # [non-official dataset by MapBiomas multisector initiative]
1094
+ # land use/cover from 1985 up to 2023, collection 9
1095
+ # Subsetting criteria: 'classification_2020' = palm oil (DN=35) <================= PALM OIL
1096
+ # the resulting dataset shows palm oil area in 2020
1097
+ def nbr_mapbiomasc9_po_prep():
1098
+ mapbiomasc9_20 = ee.Image(
1099
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1100
+ ).select("classification_2020")
1101
+ mapbiomasc9_20_palm = mapbiomasc9_20.eq(35)
1102
+ return mapbiomasc9_20_palm.rename("nBR_MapBiomas_col9_palmoil_2020")
1103
+
1104
+
1105
+ # [non-official dataset by MapBiomas multisector initiative]
1106
+ # land use/cover from 1985 up to 2023, collection 9
1107
+ # Subsetting criteria: 'classification_2020' = other perennial crops (DN=48)
1108
+ # the resulting dataset shows citrus and perennial crops other than coffee and palm oil in 2020
1109
+ def nbr_mapbiomasc9_pc_prep():
1110
+ mapbiomasc9_20 = ee.Image(
1111
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1112
+ ).select("classification_2020")
1113
+ mapbiomasc9_20_pc = mapbiomasc9_20.eq(35).Or(mapbiomasc9_20.eq(46))
1114
+ return mapbiomasc9_20_pc.rename("nBR_MapBiomas_col9_pc_2020")
1115
+
1116
+
1117
+ # ######################## NBR commodities - annual crops in 2020:##############################
1118
+
1119
+ # %%
1120
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Amazon biome, 2020
1121
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
1122
+ # Subsetting criteria: annual/temporary 1 cycle (DN=14) or more than 1 cycle (DN=15)
1123
+ # the resulting dataset shows temporary crop in 2020
1124
+ def nbr_terraclass_amz_cer20_ac_prep():
1125
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
1126
+ tcamz20_ac = tcamz20.eq(14).Or(tcamz20.eq(15))
1127
+ tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
1128
+ tccer20_ac = tccer20.eq(14).Or(tccer20.eq(15))
1129
+ tc_ac = ee.ImageCollection([tcamz20_ac, tccer20_ac]).mosaic()
1130
+ return tc_ac.rename("nBR_INPE_TCamz_cer_annual_2020")
1131
+
1132
+
1133
+ # [non-official dataset by MapBiomas multisector initiative]
1134
+ # land use/cover from 1985 up to 2023, collection 9
1135
+ # Subsetting criteria: 'classification_2020' = soybean (DN=39) <================== SOY
1136
+ # the resulting dataset shows soybean plantation area in 2020
1137
+ def nbr_mapbiomasc9_soy_prep():
1138
+ mapbiomasc9_20 = ee.Image(
1139
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1140
+ ).select("classification_2020")
1141
+ mapbiomasc9_20_soy = mapbiomasc9_20.eq(39)
1142
+ return mapbiomasc9_20_soy.rename("nBR_MapBiomas_col9_soy_2020")
1143
+
1144
+
1145
+ # [non-official dataset by MapBiomas multisector initiative]
1146
+ # land use/cover from 1985 up to 2023, collection 9
1147
+ # Subsetting criteria: 'classification_2020' = other temporary crops (DN=41)
1148
+ # Subsetting criteria: 'classification_2020' = sugar cane (DN=20)
1149
+ # Subsetting criteria: 'classification_2020' = rice (DN=40)
1150
+ # Subsetting criteria: 'classification_2020' = cotton (beta version, DN=62)
1151
+ # the resulting dataset shows temporary crop area other than soy, includes sugar cane, rice, and cotton
1152
+ def nbr_mapbiomasc9_ac_prep():
1153
+ mapbiomasc9_20 = ee.Image(
1154
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1155
+ ).select("classification_2020")
1156
+ mapbiomasc9_20_ac = (
1157
+ mapbiomasc9_20.eq(41)
1158
+ .Or(mapbiomasc9_20.eq(20))
1159
+ .Or(mapbiomasc9_20.eq(40))
1160
+ .Or(mapbiomasc9_20.eq(62))
1161
+ )
1162
+ return mapbiomasc9_20_ac.rename("nBR_MapBiomas_col9_annual_crops_2020")
1163
+
1164
+
1165
+ # ################################### NBR commodities - pasture/livestock in 2020:##############################
1166
+
1167
+ # %%
1168
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Amazon biome, 2020
1169
+ # Subsetting criteria: BUSH/SHRUB PASTURE (DN=10) or HERBACEOUS PASTURE (DN=11)
1170
+
1171
+ # the resulting dataset shows 2020 pasture area in the Amazon
1172
+ def nbr_terraclass_amz20_pasture_prep():
1173
+ tcamz20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_amz_2020")
1174
+ tcamz20_pasture = tcamz20.eq(10).Or(tcamz20.eq(11))
1175
+ return tcamz20_pasture.rename("nBR_INPE_TCamz_pasture_2020")
1176
+
1177
+
1178
+ # %%
1179
+ # [Official NFMS dataset] INPE/EMBRAPA TerraClass land use/cover in the Cerrado biome, 2020
1180
+ # Subsetting criteria: PASTURE (DN=11)
1181
+ # the resulting dataset shows 2020 pasture area in the Cerrado
1182
+
1183
+
1184
+ def nbr_terraclass_cer20_ac_prep():
1185
+ tccer20 = ee.Image("projects/ee-whisp/assets/NBR/terraclass_cer_2020")
1186
+ tccer20_pasture = tccer20.eq(11)
1187
+ return tccer20_pasture.rename("nBR_INPE_TCcer_pasture_2020")
1188
+
1189
+
1190
+ # %%
1191
+ # [non-official dataset by MapBiomas multisector initiative]
1192
+ # land use/cover from 1985 up to 2023, collection 9
1193
+ # Subsetting criteria: 'classification_2020' = pasture (DN=15)
1194
+ # the resulting dataset shows pasture area in 2020 in Brazil
1195
+ def nbr_mapbiomasc9_pasture_prep():
1196
+ mapbiomasc9_20 = ee.Image(
1197
+ "projects/mapbiomas-public/assets/brazil/lulc/collection9/mapbiomas_collection90_integration_v1"
1198
+ ).select("classification_2020")
1199
+ mapbiomasc9_20_pasture = mapbiomasc9_20.eq(15)
1200
+ return mapbiomasc9_20_pasture.rename("nBR_MapBiomas_col9_pasture_2020")
1201
+
1202
+
1203
+ ###################################################################
1204
+ # nCO - Colombia
1205
+
1206
+
1207
+ def nco_ideam_forest_2020_prep():
1208
+ ideam_forest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo")
1209
+ ideam_forest = ideam_forest_raw.eq(1) # get forest class
1210
+ return ideam_forest.rename("nCO_ideam_forest_2020")
1211
+
1212
+
1213
+ def nco_ideam_agroforest_2020_prep():
1214
+ ideam_agroforest_raw = ee.Image("projects/ee-whisp/assets/nCO/ideam_2020_geo_EUFO")
1215
+ ideam_agroforest = ideam_agroforest_raw.eq(4) # get forest class
1216
+ return ideam_agroforest.rename("nCO_ideam_agroforest_2020")
1217
+
1218
+
1219
+ # Cocoa_bnetd
1220
+ def nci_ocs2020_prep():
1221
+ return (
1222
+ ee.Image("BNETD/land_cover/v1/2020")
1223
+ .select("classification")
1224
+ .eq(9)
1225
+ .rename("nCI_Cocoa_bnetd")
1226
+ ) # cocoa from national land cover map for Côte d'Ivoire
1227
+
1228
+
1229
+ ###Combining datasets
1230
+
1231
+ ###Combining datasets
1232
+
1233
+ # def combine_datasets():
1234
+ # """Combines datasets into a single multiband image, with fallback if assets are missing."""
1235
+ # img_combined = ee.Image(1).rename(geometry_area_column)
1236
+
1237
+ # # Combine images directly
1238
+ # for img in [func() for func in list_functions()]:
1239
+ # try:
1240
+ # img_combined = img_combined.addBands(img)
1241
+ # except ee.EEException as e:
1242
+ # # logger.error(f"Error adding image: {e}")
1243
+ # print(f"Error adding image: {e}")
1244
+
1245
+ # try:
1246
+ # # Attempt to print band names to check for errors
1247
+ # print(img_combined.bandNames().getInfo())
1248
+ # except ee.EEException as e:
1249
+ # # logger.error(f"Error printing band names: {e}")
1250
+ # # logger.info("Running code for filtering to only valid datasets due to error in input")
1251
+ # print("using valid datasets filter due to error in input")
1252
+ # # Validate images
1253
+ # images_to_test = [func() for func in list_functions()]
1254
+ # valid_imgs = keep_valid_images(images_to_test) # Validate images
1255
+
1256
+ # # Retry combining images after validation
1257
+ # img_combined = ee.Image(1).rename(geometry_area_column)
1258
+ # for img in valid_imgs:
1259
+ # img_combined = img_combined.addBands(img)
1260
+
1261
+ # img_combined = img_combined.multiply(ee.Image.pixelArea())
1262
+
1263
+ # return img_combined
1264
+
1265
+
1266
+ def combine_datasets(national_codes=None):
743
1267
  """Combines datasets into a single multiband image, with fallback if assets are missing."""
744
1268
  img_combined = ee.Image(1).rename(geometry_area_column)
745
1269
 
746
1270
  # Combine images directly
747
- for img in [func() for func in list_functions()]:
1271
+ for img in [func() for func in list_functions(national_codes=national_codes)]:
748
1272
  try:
749
1273
  img_combined = img_combined.addBands(img)
750
1274
  except ee.EEException as e:
@@ -759,7 +1283,9 @@ def combine_datasets():
759
1283
  # logger.info("Running code for filtering to only valid datasets due to error in input")
760
1284
  print("using valid datasets filter due to error in input")
761
1285
  # Validate images
762
- images_to_test = [func() for func in list_functions()]
1286
+ images_to_test = [
1287
+ func() for func in list_functions(national_codes=national_codes)
1288
+ ]
763
1289
  valid_imgs = keep_valid_images(images_to_test) # Validate images
764
1290
 
765
1291
  # Retry combining images after validation
@@ -773,20 +1299,61 @@ def combine_datasets():
773
1299
 
774
1300
 
775
1301
  ######helper functions to check images
776
-
777
-
778
1302
  # list all functions ending with "_prep" (in the current script)
779
- def list_functions():
1303
+ # def list_functions():
1304
+ # # Use the module's globals to get all defined functions
1305
+ # current_module = inspect.getmodule(inspect.currentframe())
1306
+ # functions = [
1307
+ # func
1308
+ # for name, func in inspect.getmembers(current_module, inspect.isfunction)
1309
+ # if name.endswith("_prep")
1310
+ # ]
1311
+ # return functions
1312
+
1313
+
1314
+ def list_functions(national_codes=None):
1315
+ """
1316
+ Returns a list of functions that end with "_prep" and either:
1317
+ - Start with "g_" (global/regional products)
1318
+ - Start with any provided national code prefix (nXX_)
1319
+
1320
+ Args:
1321
+ national_codes: List of ISO2 country codes (without the 'n' prefix)
1322
+ """
780
1323
  # Use the module's globals to get all defined functions
781
1324
  current_module = inspect.getmodule(inspect.currentframe())
1325
+
1326
+ # If national_codes is None, default to an empty list
1327
+ if national_codes is None:
1328
+ national_codes = []
1329
+
1330
+ # Create prefixes list with proper formatting ('n' + code + '_')
1331
+ allowed_prefixes = ["g_"] + [f"n{code.lower()}_" for code in national_codes]
1332
+
1333
+ # Filter functions in a single pass
782
1334
  functions = [
783
1335
  func
784
1336
  for name, func in inspect.getmembers(current_module, inspect.isfunction)
785
1337
  if name.endswith("_prep")
1338
+ and any(name.startswith(prefix) for prefix in allowed_prefixes)
786
1339
  ]
1340
+
787
1341
  return functions
788
1342
 
789
1343
 
1344
+ # # IN PROGRESS - expected behaviour
1345
+ # def filter_by_prefix_list(input_list=None,prefix_list=None):
1346
+
1347
+ # if input_list is None:
1348
+ # print ("No function in list")
1349
+ # if prefix_list is None:
1350
+ # print ("No prefixes listed by which to filter")
1351
+ # if input_list is not None:
1352
+ # for prefix in prefix_list:
1353
+ # if element.startsWith(prefix):
1354
+ # list.
1355
+
1356
+
790
1357
  def keep_valid_images(images):
791
1358
  """Keeps only valid images."""
792
1359
  valid_images = []