File size: 20,597 Bytes
68efdc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
import ee
import geemap
import solara
import ipywidgets as widgets
import datetime

#from NBR_calculations import GcalcNBR, VcalcNBR, LcalcNBR, ScalcNBR, GcalcCCsingle
import requests

# Bit-masking
BitMask_0 = 1 << 0
BitMask_1 = 1 << 1
BitMask_2 = 1 << 2
BitMask_3 = 1 << 3
BitMask_4 = 1 << 4
BitMask_5 = 1 << 5
BitMask_6 = 1 << 6
BitMask_7 = 1 << 7
BitMask_8 = 1 << 8
BitMask_9 = 1 << 9

def GcalcCCsingle (goesImg):

  fireDQF = goesImg.select('DQF').int()
  CMI_QF3 = goesImg.select('DQF_C03').int()
  CMI_QF6 = goesImg.select('DQF_C06').int()

  #Right now, cloud mask is excluding clouds and water; active fire, bad data and fire free are unmasked. NBR mask exlcudes fire
  F_Mask = fireDQF.eq(0)
  C_Mask = (fireDQF.lt(2).Or(fireDQF.gt(2))).rename('C_Mask')
       #.And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('C_Mask')
  QF_Mask = (fireDQF.eq(1).Or(fireDQF.gt(3)))\
        .And(CMI_QF3.lt(2)).And(CMI_QF6.lt(2)).rename('QFmask')

  GOESmasked = goesImg.select(['CMI_C03','CMI_C06']).updateMask(QF_Mask)
  NBRmasked = GOESmasked.normalizedDifference(['CMI_C03', 'CMI_C06']).toFloat().rename('NBR')
  cloudMasked = goesImg.select('CMI_C03').updateMask(C_Mask).toFloat().rename('CC')
  fireMasked =  goesImg.select('CMI_C03').updateMask(F_Mask).toFloat().rename('FC')

  return goesImg.addBands([NBRmasked,cloudMasked, fireMasked,QF_Mask,C_Mask])

'''Parameter Array Name Value Bit(s) = Value
Sun Glint           QF1 Surface Reflectance None 6-7 = 00
Low Sun Mask        QF1 Surface Reflectance High 5 = 0
Day/Night           QF1 Surface Reflectance Day 4 =0
Cloud Detection     QF1 Surface Reflectance Confident Clear 2-3 = 00 or Problably Clear 2-3 = 01
Cloud Mask Quality  QF1 Surface Reflectance High or Medium 0-1 = 10 or 11
Snow/Ice            QF2 Surface Reflectance No Snow or Ice 5 = 0
Cloud Shadow        QF2 Surface Reflectance No Cloud Shadow 3 = 0
LandWater           QF2 Surface Reflectance Land, Snow, Arctic, Antarctic or Greenland, Desert 0-2  = 011, 100, 101, 110, 111
Thin Cirrus Flag    QF7 Surface Reflectance No Thin Cirrus 4 = 0
Aerosol Quantity    QF7 Surface Reflectance Climatology, Low or Medium 2-3 = 00, 01 or 10
Adjacent to Cloud   QF7 Surface Reflectance Not Adjacent to Cloud 1 = 0'''

def VcalcNBR (VIIRSimg):

    QF1 = VIIRSimg.select('QF1').int()
    QF2 = VIIRSimg.select('QF2').int()
    QF7 = VIIRSimg.select('QF7').int()

    QF_Mask = (QF1.bitwiseAnd(BitMask_3).eq(0)).And\
    ((QF2.bitwiseAnd(BitMask_2).eq(4)).Or((QF2.bitwiseAnd(BitMask_1).eq(0)))).And\
    (QF2.bitwiseAnd(BitMask_5).eq(0)).rename('QFmask');

    VIIRSm = VIIRSimg.select(['I2','M11']).updateMask(QF_Mask);
    NBR = VIIRSm.normalizedDifference(['I2','M11']).toFloat().rename('NBR')
    return VIIRSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)

''' Bit 1: Dilated Cloud
    Bit 2: Cirrus (high confidence)
    Bit 3: Cloud
    Bit 4: Cloud Shadow
    Bit 5: Snow
    Bit 6: Clear (0: Cloud or Dilated Cloud bits are set, 1: Cloud and Dilated Cloud bits are not set)
    Bit 7: Water
    Bits 8-9: Cloud Confidence (0: None, 1: Low, 2: Medium, 3: High)
    Bits 10-11: Cloud Shadow Confidence (0: None, 1: Low, 2: Medium, 3: High)
    Bits 12-13: Snow/Ice Confidence (0: None, 1: Low, 2: Medium, 3: High)
    Bits 14-15: Cirrus Confidence (0: None, 1: Low, 2: Medium, 3: High)'''

def LcalcNBR (LSimg):
  QApixel = LSimg.select('QA_PIXEL').int()
  QF_Mask =(QApixel.bitwiseAnd(BitMask_3).eq(0)).And\
           (QApixel.bitwiseAnd(BitMask_5).eq(0)).And\
           (QApixel.bitwiseAnd(BitMask_7).eq(0)).rename('QFmask');

  LSmasked = LSimg.select(['SR_B5','SR_B7']).updateMask(QF_Mask);
  NBR = LSmasked.normalizedDifference(['SR_B5','SR_B7']).toFloat().rename('NBR')
  return LSimg.addBands(NBR).addBands(QF_Mask)#.set('avgNBR', avgNBR)

''' 1    Saturated or defective
    2    Dark Area Pixels
    3    Cloud Shadows
    4    Vegetation
    5    Bare Soils
    6    Water
    7    Clouds Low Probability / Unclassified
    8    Clouds Medium Probability
    9    Clouds High Probability
    10   Cirrus
    11   Snow / Ice'''

def ScalcNBR (sentImg):
  SCL = sentImg.select('SCL');
  QF_Mask =(SCL.neq(6)).And\
    (SCL.neq(8)).And\
    (SCL.neq(9)).And\
    (SCL.neq(11))\
    .rename('QFmask');
  sentMasked = sentImg.select(['B8A','B12']).updateMask(QF_Mask); #B8 is another option- broadband NIR
  NBR = sentMasked.normalizedDifference(['B8A','B12']).toFloat().rename('NBR')
  return sentImg.addBands(NBR).addBands(QF_Mask).addBands(SCL)#.set('avgNBR', avgNBR)

#createDates = NIFC_perims_716.aggregate_array('attr_Cre_1')
#incidentIDs = NIFC_perims_716.aggregate_array('poly_Incid')
#fireList = incidentIDs.getInfo()
fireList = wildfire_names = [ "FRESNO JUNE LIGHTNING COMPLEX", "Larch Creek","Deadman","Cow Valley","0404 RV LONE ROCK",
    "PIONEER","South Fork", "Deer Springs","Basin","Lake","Horse Gulch","Falls","Silver King","Indios"]
selected_fire = solara.reactive(fireList[6])
dNBRvisParams = {'min': 0.0,'max': 0.8, 'palette': ['green', 'yellow','orange','red']}
today = datetime.datetime.today().strftime('%Y-%m-%d')

class Map(geemap.Map):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)        
        self.add_basemap('OpenStreetMap')

        self.customize_ee_data(selected_fire.value, today)
        self.add_selector()
        self.add_dwnldButton()
        self.add("layer_manager")
        self.remove("draw_control")

        
    def customize_ee_data(self, fireID, elapDays):
        NIFC_perims_716 = ee.FeatureCollection('projects/ovcrge-ssec-burn-scar-map-c116/assets/NIFC_perimeters_7-16')
        fire = NIFC_perims_716.filter(ee.Filter.eq('poly_Incid',fireID)).first()
        timestamp = fire.get('attr_Cre_1')
        geom = fire.geometry()
        
        startDate = ee.Date(timestamp)#.format('YYYY-MM-dd')
        endDate = ee.Date.parse('YYYY-MM-dd', str(today))
        
        boundingBox = ee.Geometry(geom.buffer(5000).bounds())

        elapDayNum = ee.Number(10)
        elapDay_plusOne = elapDayNum.add(ee.Number(1))

        def calc_nbr(pre_start, pre_stop, post_start, post_stop, bbox, goes):

                def MergeBands (eachImage):
                    oneImage = ee.Image.cat(eachImage.get('CMI'), eachImage.get('FDC'))
                    return oneImage
                displacementImg18 = ee.Image.load('projects/ee-losos/assets/G18-F-meter-offset_GEE')
                y_dif = displacementImg18.select([1])
                x_dif = displacementImg18.select([0]).multiply(-1)
                displacement18 = ee.Image([x_dif, y_dif])
                
                displacementImg16 = ee.Image.load('projects/ee-losos/assets/G16-F-meter-offset_GEE')
                y_dif = displacementImg16.select([1])
                x_dif = displacementImg16.select([0]).multiply(-1)
                displacement16 = ee.Image([x_dif, y_dif]);
                
                preCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
                preFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST
                postCMIcol = ee.ImageCollection(f"NOAA/GOES/{goes}/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
                postFDCcol = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(post_start, post_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST

                prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
                primary = preCMIcol,
                secondary = preFDCcol,
                condition = ee.Filter.maxDifference(
                    difference = 10, #milliseconds
                    leftField = 'system:time_start',
                    rightField = 'system:time_start',))
                preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
                preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
                pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
                pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)

                postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
                primary = postCMIcol,
                secondary = postFDCcol,
                condition = ee.Filter.maxDifference(
                    difference = 10, #milliseconds
                    leftField = 'system:time_start',
                    rightField = 'system:time_start',))
                postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
                postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
                post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
                post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)

                dNBR_goes17 = pre_meanNBR.subtract(post_meanNBR).select('NBR')

                
                #GOES-16
                preCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(pre_start, pre_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
                preFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_start, pre_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST

                prejoinedGOES = ee.Join.inner('CMI','FDC').apply(
                primary = preCMIcol,
                secondary = preFDCcol,
                condition = ee.Filter.maxDifference(
                    difference = 10, #milliseconds
                    leftField = 'system:time_start',
                    rightField = 'system:time_start',))
                preMiddayGOEScol = ee.ImageCollection(prejoinedGOES.map(lambda object: MergeBands(object)))
                preMiddayGOEScol = preMiddayGOEScol.map(GcalcCCsingle)
                pre_meanNBR = preMiddayGOEScol.select(['NBR']).mean()
                pre_meanNBR = pre_meanNBR.multiply(1.18).subtract(0.12)

                
                postCMIcol = ee.ImageCollection("NOAA/GOES/16/MCMIPF").filter(ee.Filter.date(post_start, post_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour'))#10-2pm PCT, 11am-3pm MST
                postFDCcol = ee.ImageCollection("NOAA/GOES/16/FDCF").filter(ee.Filter.date(post_start, post_stop))\
                        .filter(ee.Filter.calendarRange(17, 21, 'hour')) #10-2pm PCT, 11am-3pm MST

                postjoinedGOES = ee.Join.inner('CMI','FDC').apply(
                primary = postCMIcol,
                secondary = postFDCcol,
                condition = ee.Filter.maxDifference(
                    difference = 10, #milliseconds
                    leftField = 'system:time_start',
                    rightField = 'system:time_start',))
                postMiddayGOEScol = ee.ImageCollection(postjoinedGOES.map(lambda object: MergeBands(object)))
                postMiddayGOEScol = postMiddayGOEScol.map(GcalcCCsingle)
                post_meanNBR = postMiddayGOEScol.select(['NBR']).mean()
                post_meanNBR = post_meanNBR.multiply(1.18).subtract(0.12)

                dNBR_goes16 = pre_meanNBR.subtract(post_meanNBR).select('NBR')
                
                dNBRclip_goes17= dNBR_goes17.clip(bbox)
                dNBRclip_goes16= dNBR_goes16.clip(bbox)
                dNBRdisp_goes17 = dNBRclip_goes17.displace(displacement18, 'bicubic')
                dNBRdisp_goes16 = dNBRclip_goes16.displace(displacement16, 'bicubic')
                dNBRgoes_compos = ee.ImageCollection([dNBRdisp_goes17,dNBRdisp_goes16]).mean()
                
                #ACTIVE fire
                activeFire18 = ee.ImageCollection(f"NOAA/GOES/{goes}/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
                activeFire16 = ee.ImageCollection(f"NOAA/GOES/16/FDCF").filter(ee.Filter.date(pre_stop, post_stop))
                sumFRP18 = activeFire18.select('Power').sum().rename('sumFRP')
                sumFRP16 = activeFire16.select('Power').sum().rename('sumFRP')
                maskNoFire18 = sumFRP18.gt(200).displace(displacement18, 'bicubic')
                maskNoFire16 = sumFRP16.gt(200).displace(displacement16, 'bicubic')
                maskNoFire =  ee.ImageCollection([maskNoFire18,maskNoFire16]).sum().gt(0)
                
                '''
                activeSNPP = ee.ImageCollection("NASA/LANCE/SNPP_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
                activeNOAA20 = ee.ImageCollection("NASA/LANCE/NOAA20_VIIRS/C2").filter(ee.Filter.date(pre_stop, post_stop))
                sumFRP_SNPP = activeSNPP.select('confidence').max().rename('sumFRP')
                sumFRP_NOAA20 = activeNOAA20.select('confidence').max().rename('sumFRP')
                #maskNoFire =  ee.ImageCollection([sumFRP_SNPP,sumFRP_NOAA20]).sum().gt(0)
                maskNoFire = sumFRP_SNPP.gt(0)
                '''

                #VIIRS
                preVIIRSimg = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(pre_start, pre_stop)).mean()
                postVIIRSimgCol = ee.ImageCollection("NASA/VIIRS/002/VNP09GA").filter(ee.Filter.date(post_start, post_stop)) #TO FIX ON JUNE 18 sfork_startDate.advance(24, 'day'), sfork_startDate.advance(25,'day')
                
                #Landsat
                prelandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
                postlandsat8col = ee.ImageCollection("LANDSAT/LC08/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
                prelandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
                postlandsat9col = ee.ImageCollection("LANDSAT/LC09/C02/T1_L2").filterDate(post_start, post_stop).filterBounds(bbox)
                prelandsatcol = prelandsat8col.merge(prelandsat9col)
                postlandsatcol = postlandsat8col.merge(postlandsat9col)

                #Sentinel
                presentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(pre_start.advance(-10, 'day'), pre_stop).filterBounds(bbox)
                postsentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(post_start, post_stop).filterBounds(bbox) #TO FIX on JULY 5: sfork_startDate.advance(32, 'day'), sfork_startDate.advance(33,'day')
                #olderPostSentCol = ee.ImageCollection("COPERNICUS/S2_SR_HARMONIZED").filterDate(sfork_startDate.advance(37, 'day'), sfork_startDate.advance(38,'day')).filterBounds(bbox)
                
                #SAR
                #SARimg = ee.Image('projects/ovcrge-ssec-burn-scar-map-c116/assets/burned_20200907_20200919_test')
                #SARmask = SARimg.eq(1)

                if postVIIRSimgCol.size().getInfo() > 0:
                    postVIIRSimg = postVIIRSimgCol.mean()
                    preVIIRSimg = VcalcNBR(preVIIRSimg)
                    postVIIRSimg = VcalcNBR(postVIIRSimg)
                    dNBR_viirs = preVIIRSimg.subtract(postVIIRSimg).select('NBR')
                    dNBRclip_viirs = dNBR_viirs.clip(bbox)
                else: 
                    dNBR_composite = dNBRgoes_compos
                if postsentCol.size().getInfo() > 0:
                        presentMean = presentCol.mean()
                        postsentMean = postsentCol.mean() 
                        presentImg = ScalcNBR(presentMean)
                        postsentImg = ScalcNBR(postsentMean)
                        dnbr_sent =  presentImg.subtract(postsentImg).multiply(1.3).add(0.05).select('NBR')
                        dNBRclip_sent = dnbr_sent.clip(bbox)
                        dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_sent]).mosaic() #dNBRclip_viirs SHOULD GO IN IF UP TO DATE
                elif postlandsatcol.size().getInfo() > 0:
                        prelandsat = prelandsatcol.mean()
                        prelandsatImg = LcalcNBR(prelandsat)
                        postlandsat = postlandsatcol.mean()
                        postlandsatImg = LcalcNBR(postlandsat)
                        dNBR_landsat = prelandsatImg.subtract(postlandsatImg).multiply(3.23).add(0.01).select('NBR')
                        dNBRclip_ls = dNBR_landsat.clip(bbox)
                        dNBR_composite = ee.ImageCollection([dNBRgoes_compos,dNBRclip_ls]).mosaic() #dNBRclip_viirs  SHOULD GO IN IF UP TO DATE
                else:
                        dNBR_composite = ee.ImageCollection([dNBRgoes_compos]).mosaic() #dNBRclip_viirs  SHOULD GO IN IF UP TO DATE
                
                masked_compos = dNBR_composite.updateMask(maskNoFire) #(SARmask)
                #doubleMasked_compos = masked_compos.updateMask(maskNoFire)
                doubleMasked_compos = masked_compos.mask(masked_compos.mask()).float()
                downloadArgs = {'name': 'VIIRS_burnMap',
                                'crs': 'EPSG:4326',
                                'scale': 60,
                                'region': bbox}
                url = doubleMasked_compos.getDownloadURL(downloadArgs)
                
                print(url)
                noDataVal = -9999
                unmaskedImage = doubleMasked_compos.unmask(noDataVal, False)
                
                task = ee.batch.Export.image.toDrive(**{
                    'image': unmaskedImage,
                    'description': "Composite_burnMap6",
                    'folder': "Earth Engine Outputs",
                    'fileNamePrefix': "Composite_burnMap_noData_VIIRS_June18_espg3857_60m",
                    'region': bbox,
                    'crs': 'EPSG:3857',
                    'scale': 60,})
                task.start()
                return masked_compos
        
            
        self.clear_specific_layers()
        
        fireImg = calc_nbr(startDate.advance(-7, 'day'), startDate, endDate.advance(-3, 'day'), endDate, boundingBox, 18) 
        self.addLayer(fireImg, dNBRvisParams, fireID, True)
        self.centerObject(boundingBox, 10)
        file = fireImg

    
    def clear_specific_layers(self):
        layers_to_keep = ['OpenStreetMap']
        layers = list(self.layers)
        for layer in layers:
            if layer.name not in layers_to_keep:
                self.remove_layer(layer)  

               
    def add_selector(self):
        selector = widgets.Dropdown(options=fireList, value=fireList[6], description='Current wildfire :', style={'description_width': '125px'}, layout=widgets.Layout(width='400px')) 

        def on_selector_change(change):
            if change['name'] == 'value': 
                selected_fire.value = change['new']
                self.customize_ee_data(selected_fire.value, today)

        selector.observe(on_selector_change, names='value')
        self.add_widget(selector, position="topleft")


    def add_dwnldButton(self):
        button = widgets.Button(description='Export to Drive',icon='cloud-arrow-down')

        #def on_button_click(change, file):
        #    if change['name'] == 'value': 
        #        selected_days.value = change['new']
        #        self.download_ee_image(file, "trial_file.tif", scale=30)
        def on_button_click(b):
        # Get the currently selected fire and elapsed days
            fire = selected_fire.value
            elapDays = today
            
            # Customize the EE data and download the image
            file = self.customize_ee_data(fire, elapDays)
            #self.download_ee_image(file, f"{fire}_NBR_{elapDays}days.tif", scale=30)
        
        button.observe(on_button_click) 
        self.add_widget(button, position="topleft")

        

@solara.component
def Page():
    
    with solara.Column(align="center"):
        markdown = """
        ## Current 2024 wildfires over 10,000 acres"""
        solara.Markdown(markdown)
    
    # Isolation is required to prevent the map from overlapping navigation (when screen width < 960px)
    with solara.Column(style={"isolation": "isolate"}):
        map_widget = Map.element(
            center=[39, -120.5],
            zoom=8,
            height="600px",
            toolbar_ctrl=False
        )