giswqs commited on
Commit
53ef1d3
·
1 Parent(s): 2daf2f9

Update web app

Browse files
Files changed (1) hide show
  1. pages/03_landsat.py +156 -23
pages/03_landsat.py CHANGED
@@ -4,6 +4,7 @@ import geemap
4
  import ipywidgets as widgets
5
  from IPython.display import display
6
  import solara
 
7
 
8
 
9
  class Map(geemap.Map):
@@ -12,6 +13,23 @@ class Map(geemap.Map):
12
  self.add_basemap("Esri.WorldImagery")
13
  self.add_gui_widget(add_header=True)
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def add_gui_widget(self, position="topright", **kwargs):
16
 
17
  widget = widgets.VBox(layout=widgets.Layout(padding="0px 5px 0px 5px"))
@@ -22,11 +40,13 @@ class Map(geemap.Map):
22
  padding = "0px 5px 0px 5px"
23
  pre_start_date = widgets.DatePicker(
24
  description="Start",
 
25
  style=style,
26
  layout=widgets.Layout(padding=padding, width="160px"),
27
  )
28
  pre_end_date = widgets.DatePicker(
29
  description="End",
 
30
  style=style,
31
  layout=widgets.Layout(padding=padding, width="160px"),
32
  )
@@ -50,11 +70,13 @@ class Map(geemap.Map):
50
  ]
51
  post_start_date = widgets.DatePicker(
52
  description="Start",
 
53
  style=style,
54
  layout=widgets.Layout(padding=padding, width="160px"),
55
  )
56
  post_end_date = widgets.DatePicker(
57
  description="End",
 
58
  style=style,
59
  layout=widgets.Layout(padding=padding, width="160px"),
60
  )
@@ -78,17 +100,53 @@ class Map(geemap.Map):
78
  ]
79
 
80
  apply_btn = widgets.Button(description="Apply", layout=layout)
81
- split_btn = widgets.Button(description="Split", layout=layout)
82
  reset_btn = widgets.Button(description="Reset", layout=layout)
83
- close_btn = widgets.Button(description="Close", layout=layout)
84
- buttons = widgets.HBox([apply_btn, split_btn, reset_btn, close_btn])
85
  output = widgets.Output()
86
 
87
- widget.children = [pre_widget, post_widget, buttons, output]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  self.add_widget(widget, position=position, **kwargs)
89
 
90
  def apply_btn_click(b):
91
 
 
 
 
 
 
92
  if self.user_roi is None:
93
  output.clear_output()
94
  output.append_stdout("Please draw a ROI first.")
@@ -105,34 +163,109 @@ class Map(geemap.Map):
105
  output.clear_output()
106
  output.append_stdout("Computing... Please wait.")
107
  roi = ee.FeatureCollection(self.user_roi)
108
- pre_col = (
109
- ee.ImageCollection("NASA/HLS/HLSL30/v002")
110
- .filterBounds(roi)
111
- .filterDate(
112
- pre_start_date.value.strftime("%Y-%m-%d"),
113
- pre_end_date.value.strftime("%Y-%m-%d"),
 
 
 
 
 
 
 
 
 
 
114
  )
115
- .filter(ee.Filter.lt("CLOUD_COVERAGE", pre_cloud_cover.value))
116
- )
117
- post_col = (
118
- ee.ImageCollection("NASA/HLS/HLSL30/v002")
119
- .filterBounds(roi)
120
- .filterDate(
121
- post_start_date.value.strftime("%Y-%m-%d"),
122
- post_end_date.value.strftime("%Y-%m-%d"),
 
 
 
 
 
 
 
 
123
  )
124
- .filter(ee.Filter.lt("CLOUD_COVERAGE", post_cloud_cover.value))
125
- )
126
 
127
  pre_img = pre_col.median().clip(roi)
128
  post_img = post_col.median().clip(roi)
129
- vis_params = {"bands": ["B6", "B5", "B4"], "min": 0, "max": 0.4}
130
- self.add_layer(pre_img, vis_params, "Pre-event Image")
131
- self.add_layer(post_img, vis_params, "Post-event Image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  output.clear_output()
133
 
134
  apply_btn.on_click(apply_btn_click)
135
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  @solara.component
138
  def Page():
 
4
  import ipywidgets as widgets
5
  from IPython.display import display
6
  import solara
7
+ from datetime import date
8
 
9
 
10
  class Map(geemap.Map):
 
13
  self.add_basemap("Esri.WorldImagery")
14
  self.add_gui_widget(add_header=True)
15
 
16
+ def clean_up(self):
17
+
18
+ layers = [
19
+ "Pre-event Image",
20
+ "Post-event Image",
21
+ "Pre-event NDWI",
22
+ "Post-event NDWI",
23
+ "Pre-event Water",
24
+ "Post-event Water",
25
+ "Disappeared Water",
26
+ "New Water",
27
+ ]
28
+ for layer_name in layers:
29
+ layer = self.find_layer(layer_name)
30
+ if layer is not None:
31
+ self.remove(layer)
32
+
33
  def add_gui_widget(self, position="topright", **kwargs):
34
 
35
  widget = widgets.VBox(layout=widgets.Layout(padding="0px 5px 0px 5px"))
 
40
  padding = "0px 5px 0px 5px"
41
  pre_start_date = widgets.DatePicker(
42
  description="Start",
43
+ value=date(2014, 1, 1),
44
  style=style,
45
  layout=widgets.Layout(padding=padding, width="160px"),
46
  )
47
  pre_end_date = widgets.DatePicker(
48
  description="End",
49
+ value=date(2014, 12, 31),
50
  style=style,
51
  layout=widgets.Layout(padding=padding, width="160px"),
52
  )
 
70
  ]
71
  post_start_date = widgets.DatePicker(
72
  description="Start",
73
+ value=date(2024, 1, 1),
74
  style=style,
75
  layout=widgets.Layout(padding=padding, width="160px"),
76
  )
77
  post_end_date = widgets.DatePicker(
78
  description="End",
79
+ value=date(2024, 12, 31),
80
  style=style,
81
  layout=widgets.Layout(padding=padding, width="160px"),
82
  )
 
100
  ]
101
 
102
  apply_btn = widgets.Button(description="Apply", layout=layout)
 
103
  reset_btn = widgets.Button(description="Reset", layout=layout)
104
+ buttons = widgets.HBox([apply_btn, reset_btn])
 
105
  output = widgets.Output()
106
 
107
+ use_split = widgets.Checkbox(
108
+ value=False,
109
+ description="Split map",
110
+ style=style,
111
+ layout=widgets.Layout(padding=padding, width="100px"),
112
+ )
113
+
114
+ use_ndwi = widgets.Checkbox(
115
+ value=False,
116
+ description="Compute NDWI",
117
+ style=style,
118
+ layout=widgets.Layout(padding=padding, width="160px"),
119
+ )
120
+
121
+ ndwi_threhold = widgets.FloatSlider(
122
+ description="Threshold",
123
+ min=-1,
124
+ max=1,
125
+ value=0,
126
+ step=0.05,
127
+ readout=True,
128
+ style=style,
129
+ layout=widgets.Layout(padding=padding, width="230px"),
130
+ )
131
+
132
+ options = widgets.HBox(
133
+ [
134
+ use_split,
135
+ use_ndwi,
136
+ ndwi_threhold,
137
+ ]
138
+ )
139
+
140
+ widget.children = [pre_widget, post_widget, options, buttons, output]
141
  self.add_widget(widget, position=position, **kwargs)
142
 
143
  def apply_btn_click(b):
144
 
145
+ marker_layer = self.find_layer("Search location")
146
+ if marker_layer is not None:
147
+ self.remove(marker_layer)
148
+ self.clean_up()
149
+
150
  if self.user_roi is None:
151
  output.clear_output()
152
  output.append_stdout("Please draw a ROI first.")
 
163
  output.clear_output()
164
  output.append_stdout("Computing... Please wait.")
165
  roi = ee.FeatureCollection(self.user_roi)
166
+ vis_params = {"bands": ["B6", "B5", "B4"], "min": 0, "max": 0.4}
167
+ if pre_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
168
+ pre_col = geemap.landsat_timeseries(
169
+ roi,
170
+ start_year=pre_start_date.value.year,
171
+ end_year=pre_end_date.value.year,
172
+ ).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
173
+ else:
174
+ pre_col = (
175
+ ee.ImageCollection("NASA/HLS/HLSL30/v002")
176
+ .filterBounds(roi)
177
+ .filterDate(
178
+ pre_start_date.value.strftime("%Y-%m-%d"),
179
+ pre_end_date.value.strftime("%Y-%m-%d"),
180
+ )
181
+ .filter(ee.Filter.lt("CLOUD_COVERAGE", pre_cloud_cover.value))
182
  )
183
+
184
+ if post_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
185
+ post_col = geemap.landsat_timeseries(
186
+ roi,
187
+ start_year=post_start_date.value.year,
188
+ end_year=post_end_date.value.year,
189
+ ).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
190
+ else:
191
+ post_col = (
192
+ ee.ImageCollection("NASA/HLS/HLSL30/v002")
193
+ .filterBounds(roi)
194
+ .filterDate(
195
+ post_start_date.value.strftime("%Y-%m-%d"),
196
+ post_end_date.value.strftime("%Y-%m-%d"),
197
+ )
198
+ .filter(ee.Filter.lt("CLOUD_COVERAGE", post_cloud_cover.value))
199
  )
 
 
200
 
201
  pre_img = pre_col.median().clip(roi)
202
  post_img = post_col.median().clip(roi)
203
+
204
+ if use_split.value:
205
+ left_layer = geemap.ee_tile_layer(
206
+ pre_img, vis_params, "Pre-event Image"
207
+ )
208
+ right_layer = geemap.ee_tile_layer(
209
+ post_img, vis_params, "Post-event Image"
210
+ )
211
+ self.split_map(
212
+ left_layer,
213
+ right_layer,
214
+ add_close_button=True,
215
+ left_label="Pre-event",
216
+ right_label="Post-event",
217
+ )
218
+ else:
219
+ pre_img = pre_col.median().clip(roi)
220
+ post_img = post_col.median().clip(roi)
221
+ self.add_layer(pre_img, vis_params, "Pre-event Image")
222
+ self.add_layer(post_img, vis_params, "Post-event Image")
223
+
224
+ if use_ndwi.value and (not use_split.value):
225
+ pre_ndwi = pre_img.normalizedDifference(["B3", "B6"]).rename("NDWI")
226
+ post_ndwi = post_img.normalizedDifference(["B3", "B6"]).rename(
227
+ "NDWI"
228
+ )
229
+ ndwi_vis = {"min": -1, "max": 1, "palette": "ndwi"}
230
+ self.add_layer(pre_ndwi, ndwi_vis, "Pre-event NDWI", False)
231
+ self.add_layer(post_ndwi, ndwi_vis, "Post-event NDWI", False)
232
+
233
+ pre_water = pre_ndwi.gt(ndwi_threhold.value)
234
+ post_water = post_ndwi.gt(ndwi_threhold.value)
235
+ self.add_layer(
236
+ pre_water.selfMask(), {"palette": "blue"}, "Pre-event Water"
237
+ )
238
+ self.add_layer(
239
+ post_water.selfMask(), {"palette": "red"}, "Post-event Water"
240
+ )
241
+ new_water = post_water.subtract(pre_water).gt(0)
242
+ disappear_water = pre_water.subtract(post_water).gt(0)
243
+ self.add_layer(
244
+ disappear_water.selfMask(),
245
+ {"palette": "brown"},
246
+ "Disappeared Water",
247
+ )
248
+ self.add_layer(
249
+ new_water.selfMask(), {"palette": "cyan"}, "New Water"
250
+ )
251
+
252
+ with output:
253
+ output.clear_output()
254
+
255
  output.clear_output()
256
 
257
  apply_btn.on_click(apply_btn_click)
258
 
259
+ def reset_btn_click(b):
260
+ self.clean_up()
261
+ self._draw_control.clear()
262
+ draw_layer = self.find_layer("Drawn Features")
263
+ if draw_layer is not None:
264
+ self.remove(draw_layer)
265
+ output.clear_output()
266
+
267
+ reset_btn.on_click(reset_btn_click)
268
+
269
 
270
  @solara.component
271
  def Page():