giswqs pre-commit-ci[bot] commited on
Commit
7b68ac7
1 Parent(s): 192252f

Add more apps (#5)

Browse files

* Add more apps

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>

notebooks/01_basic.ipynb CHANGED
@@ -1,5 +1,14 @@
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": null,
 
1
  {
2
  "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
  {
13
  "cell_type": "code",
14
  "execution_count": null,
notebooks/02_inspector.ipynb CHANGED
@@ -1,5 +1,14 @@
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": null,
@@ -8,7 +17,6 @@
8
  "source": [
9
  "import ee\n",
10
  "import geemap\n",
11
- "\n",
12
  "import solara\n",
13
  "\n",
14
  "\n",
@@ -47,7 +55,7 @@
47
  "\n",
48
  "@solara.component\n",
49
  "def Page():\n",
50
- " with solara.Column(style={\"min-width\": \"500px\"}):\n",
51
  " Map.element(\n",
52
  " center=[40, -100],\n",
53
  " zoom=4,\n",
 
1
  {
2
  "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
  {
13
  "cell_type": "code",
14
  "execution_count": null,
 
17
  "source": [
18
  "import ee\n",
19
  "import geemap\n",
 
20
  "import solara\n",
21
  "\n",
22
  "\n",
 
55
  "\n",
56
  "@solara.component\n",
57
  "def Page():\n",
58
+ " with solara.Column(style={\"min-width\": \"500px\", \"isolation\": \"isolate\"}):\n",
59
  " Map.element(\n",
60
  " center=[40, -100],\n",
61
  " zoom=4,\n",
notebooks/03_plotting.ipynb CHANGED
@@ -1,5 +1,14 @@
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": null,
@@ -8,7 +17,6 @@
8
  "source": [
9
  "import ee\n",
10
  "import geemap\n",
11
- "\n",
12
  "import solara\n",
13
  "\n",
14
  "\n",
@@ -40,7 +48,7 @@
40
  "\n",
41
  "@solara.component\n",
42
  "def Page():\n",
43
- " with solara.Column(style={\"min-width\": \"500px\"}):\n",
44
  " Map.element(\n",
45
  " center=[40, -100],\n",
46
  " zoom=4,\n",
 
1
  {
2
  "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
  {
13
  "cell_type": "code",
14
  "execution_count": null,
 
17
  "source": [
18
  "import ee\n",
19
  "import geemap\n",
 
20
  "import solara\n",
21
  "\n",
22
  "\n",
 
48
  "\n",
49
  "@solara.component\n",
50
  "def Page():\n",
51
+ " with solara.Column(style={\"min-width\": \"500px\", \"isolation\": \"isolate\"}):\n",
52
  " Map.element(\n",
53
  " center=[40, -100],\n",
54
  " zoom=4,\n",
notebooks/04_split_map.ipynb CHANGED
@@ -1,5 +1,14 @@
1
  {
2
  "cells": [
 
 
 
 
 
 
 
 
 
3
  {
4
  "cell_type": "code",
5
  "execution_count": null,
@@ -8,7 +17,6 @@
8
  "source": [
9
  "import ee\n",
10
  "import geemap\n",
11
- "\n",
12
  "import solara\n",
13
  "\n",
14
  "\n",
@@ -58,7 +66,7 @@
58
  "\n",
59
  "@solara.component\n",
60
  "def Page():\n",
61
- " with solara.Column(style={\"min-width\": \"500px\"}):\n",
62
  " Map.element(\n",
63
  " center=[40, -100],\n",
64
  " zoom=4,\n",
 
1
  {
2
  "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
  {
13
  "cell_type": "code",
14
  "execution_count": null,
 
17
  "source": [
18
  "import ee\n",
19
  "import geemap\n",
 
20
  "import solara\n",
21
  "\n",
22
  "\n",
 
66
  "\n",
67
  "@solara.component\n",
68
  "def Page():\n",
69
+ " with solara.Column(style={\"min-width\": \"500px\", \"isolation\": \"isolate\"}):\n",
70
  " Map.element(\n",
71
  " center=[40, -100],\n",
72
  " zoom=4,\n",
notebooks/05_timelapse.ipynb ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import geemap\n",
19
+ "import solara\n",
20
+ "\n",
21
+ "\n",
22
+ "class Map(geemap.Map):\n",
23
+ " def __init__(self, **kwargs):\n",
24
+ " super().__init__(**kwargs)\n",
25
+ " self.add_basemap(\"Esri.WorldImagery\")\n",
26
+ " self.add_gui(\"timelapse\", basemap=None)\n",
27
+ "\n",
28
+ "\n",
29
+ "@solara.component\n",
30
+ "def Page():\n",
31
+ " with solara.Column(style={\"min-width\": \"500px\", \"isolation\": \"isolate\"}):\n",
32
+ " Map.element(\n",
33
+ " center=[20, -0],\n",
34
+ " zoom=2,\n",
35
+ " height=\"750px\",\n",
36
+ " zoom_ctrl=False,\n",
37
+ " measure_ctrl=False,\n",
38
+ " )"
39
+ ]
40
+ },
41
+ {
42
+ "cell_type": "code",
43
+ "execution_count": null,
44
+ "metadata": {},
45
+ "outputs": [],
46
+ "source": [
47
+ "Page()"
48
+ ]
49
+ }
50
+ ],
51
+ "metadata": {
52
+ "kernelspec": {
53
+ "display_name": "geo",
54
+ "language": "python",
55
+ "name": "python3"
56
+ },
57
+ "language_info": {
58
+ "codemirror_mode": {
59
+ "name": "ipython",
60
+ "version": 3
61
+ },
62
+ "file_extension": ".py",
63
+ "mimetype": "text/x-python",
64
+ "name": "python",
65
+ "nbconvert_exporter": "python",
66
+ "pygments_lexer": "ipython3",
67
+ "version": "3.11.8"
68
+ }
69
+ },
70
+ "nbformat": 4,
71
+ "nbformat_minor": 2
72
+ }
notebooks/06_timeseries.ipynb ADDED
@@ -0,0 +1,341 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import geemap\n",
19
+ "import ipywidgets as widgets\n",
20
+ "import solara\n",
21
+ "from geemap import get_current_year, jslink_slider_label\n",
22
+ "\n",
23
+ "\n",
24
+ "class Map(geemap.Map):\n",
25
+ " def __init__(self, **kwargs):\n",
26
+ " super().__init__(**kwargs)\n",
27
+ " self.add_basemap(\"Esri.WorldImagery\")\n",
28
+ " self.add_ts_gui(position=\"topright\")\n",
29
+ "\n",
30
+ " def clean_up(self):\n",
31
+ " if hasattr(self, \"slider_ctrl\") and self.slider_ctrl is not None:\n",
32
+ " self.remove(self.slider_ctrl)\n",
33
+ " delattr(self, \"slider_ctrl\")\n",
34
+ "\n",
35
+ " layer = self.find_layer(\"Time series\")\n",
36
+ " if layer is not None:\n",
37
+ " self.remove(layer)\n",
38
+ " layer = self.find_layer(\"Image X\")\n",
39
+ " if layer is not None:\n",
40
+ " self.remove(layer)\n",
41
+ "\n",
42
+ " draw_layer = self.find_layer(\"Drawn Features\")\n",
43
+ " if draw_layer is not None:\n",
44
+ " self.remove(draw_layer)\n",
45
+ "\n",
46
+ " def add_ts_gui(self, position=\"topright\", **kwargs):\n",
47
+ "\n",
48
+ " widget_width = \"350px\"\n",
49
+ " padding = \"0px 0px 0px 5px\" # upper, right, bottom, left\n",
50
+ " style = {\"description_width\": \"initial\"}\n",
51
+ " current_year = get_current_year()\n",
52
+ "\n",
53
+ " collection = widgets.Dropdown(\n",
54
+ " options=[\n",
55
+ " \"Landsat TM-ETM-OLI Surface Reflectance\",\n",
56
+ " ],\n",
57
+ " value=\"Landsat TM-ETM-OLI Surface Reflectance\",\n",
58
+ " description=\"Collection:\",\n",
59
+ " layout=widgets.Layout(width=widget_width, padding=padding),\n",
60
+ " style=style,\n",
61
+ " )\n",
62
+ " bands = widgets.Dropdown(\n",
63
+ " description=\"Bands:\",\n",
64
+ " options=[\n",
65
+ " \"Red/Green/Blue\",\n",
66
+ " \"NIR/Red/Green\",\n",
67
+ " \"SWIR2/SWIR1/NIR\",\n",
68
+ " \"NIR/SWIR1/Red\",\n",
69
+ " \"SWIR2/NIR/Red\",\n",
70
+ " \"SWIR2/SWIR1/Red\",\n",
71
+ " \"SWIR1/NIR/Blue\",\n",
72
+ " \"NIR/SWIR1/Blue\",\n",
73
+ " \"SWIR2/NIR/Green\",\n",
74
+ " \"SWIR1/NIR/Red\",\n",
75
+ " ],\n",
76
+ " value=\"SWIR1/NIR/Red\",\n",
77
+ " style=style,\n",
78
+ " layout=widgets.Layout(width=\"195px\", padding=padding),\n",
79
+ " )\n",
80
+ "\n",
81
+ " frequency = widgets.Dropdown(\n",
82
+ " description=\"Frequency:\",\n",
83
+ " options=[\"year\", \"quarter\", \"month\"],\n",
84
+ " value=\"year\",\n",
85
+ " style=style,\n",
86
+ " layout=widgets.Layout(width=\"150px\", padding=padding),\n",
87
+ " )\n",
88
+ "\n",
89
+ " start_year = widgets.IntSlider(\n",
90
+ " description=\"Start Year:\",\n",
91
+ " value=1984,\n",
92
+ " min=1984,\n",
93
+ " max=current_year,\n",
94
+ " readout=False,\n",
95
+ " style=style,\n",
96
+ " layout=widgets.Layout(width=\"138px\", padding=padding),\n",
97
+ " )\n",
98
+ "\n",
99
+ " start_year_label = widgets.Label(\"1984\")\n",
100
+ " jslink_slider_label(start_year, start_year_label)\n",
101
+ "\n",
102
+ " end_year = widgets.IntSlider(\n",
103
+ " description=\"End Year:\",\n",
104
+ " value=current_year,\n",
105
+ " min=1984,\n",
106
+ " max=current_year,\n",
107
+ " readout=False,\n",
108
+ " style=style,\n",
109
+ " layout=widgets.Layout(width=\"138px\", padding=padding),\n",
110
+ " )\n",
111
+ " end_year_label = widgets.Label(str(current_year))\n",
112
+ " jslink_slider_label(end_year, end_year_label)\n",
113
+ "\n",
114
+ " start_month = widgets.IntSlider(\n",
115
+ " description=\"Start Month:\",\n",
116
+ " value=5,\n",
117
+ " min=1,\n",
118
+ " max=12,\n",
119
+ " readout=False,\n",
120
+ " style=style,\n",
121
+ " layout=widgets.Layout(width=\"145px\", padding=padding),\n",
122
+ " )\n",
123
+ "\n",
124
+ " start_month_label = widgets.Label(\n",
125
+ " \"5\",\n",
126
+ " layout=widgets.Layout(width=\"20px\", padding=padding),\n",
127
+ " )\n",
128
+ " jslink_slider_label(start_month, start_month_label)\n",
129
+ "\n",
130
+ " end_month = widgets.IntSlider(\n",
131
+ " description=\"End Month:\",\n",
132
+ " value=10,\n",
133
+ " min=1,\n",
134
+ " max=12,\n",
135
+ " readout=False,\n",
136
+ " style=style,\n",
137
+ " layout=widgets.Layout(width=\"155px\", padding=padding),\n",
138
+ " )\n",
139
+ "\n",
140
+ " end_month_label = widgets.Label(\"10\")\n",
141
+ " jslink_slider_label(end_month, end_month_label)\n",
142
+ "\n",
143
+ " output = widgets.Output()\n",
144
+ "\n",
145
+ " button_width = \"113px\"\n",
146
+ " apply_btn = widgets.Button(\n",
147
+ " description=\"Time slider\",\n",
148
+ " button_style=\"primary\",\n",
149
+ " tooltip=\"Click to create timeseries\",\n",
150
+ " style=style,\n",
151
+ " layout=widgets.Layout(padding=\"0px\", width=button_width),\n",
152
+ " )\n",
153
+ "\n",
154
+ " split_btn = widgets.Button(\n",
155
+ " description=\"Split map\",\n",
156
+ " button_style=\"primary\",\n",
157
+ " tooltip=\"Click to create timeseries\",\n",
158
+ " style=style,\n",
159
+ " layout=widgets.Layout(padding=\"0px\", width=button_width),\n",
160
+ " )\n",
161
+ "\n",
162
+ " reset_btn = widgets.Button(\n",
163
+ " description=\"Reset\",\n",
164
+ " button_style=\"primary\",\n",
165
+ " style=style,\n",
166
+ " layout=widgets.Layout(padding=\"0px\", width=button_width),\n",
167
+ " )\n",
168
+ "\n",
169
+ " vbox = widgets.VBox(\n",
170
+ " [\n",
171
+ " collection,\n",
172
+ " widgets.HBox([bands, frequency]),\n",
173
+ " widgets.HBox([start_year, start_year_label, end_year, end_year_label]),\n",
174
+ " widgets.HBox(\n",
175
+ " [start_month, start_month_label, end_month, end_month_label]\n",
176
+ " ),\n",
177
+ " widgets.HBox([apply_btn, split_btn, reset_btn]),\n",
178
+ " output,\n",
179
+ " ]\n",
180
+ " )\n",
181
+ " self.add_widget(vbox, position=position, add_header=True)\n",
182
+ "\n",
183
+ " def apply_btn_click(change):\n",
184
+ "\n",
185
+ " if hasattr(self, \"slider_ctrl\") and self.slider_ctrl is not None:\n",
186
+ " self.remove(self.slider_ctrl)\n",
187
+ " delattr(self, \"slider_ctrl\")\n",
188
+ "\n",
189
+ " with output:\n",
190
+ " output.clear_output()\n",
191
+ " if self.user_roi is None:\n",
192
+ " output.append_stdout(\"Please draw a ROI first.\")\n",
193
+ " else:\n",
194
+ " output.append_stdout(\"Creating time series...\")\n",
195
+ " collection = geemap.landsat_timeseries(\n",
196
+ " roi=self.user_roi,\n",
197
+ " start_year=start_year.value,\n",
198
+ " end_year=end_year.value,\n",
199
+ " start_date=str(start_month.value).zfill(2) + \"-01\",\n",
200
+ " end_date=str(end_month.value).zfill(2) + \"-01\",\n",
201
+ " frequency=frequency.value,\n",
202
+ " )\n",
203
+ " vis_params = {\n",
204
+ " \"bands\": bands.value.split(\"/\"),\n",
205
+ " \"min\": 0,\n",
206
+ " \"max\": 0.4,\n",
207
+ " }\n",
208
+ "\n",
209
+ " if frequency.value == \"year\":\n",
210
+ " date_format = \"YYYY\"\n",
211
+ " elif frequency.value == \"quarter\":\n",
212
+ " date_format = \"YYYY-MM\"\n",
213
+ " elif frequency.value == \"month\":\n",
214
+ " date_format = \"YYYY-MM\"\n",
215
+ "\n",
216
+ " self.add_time_slider(\n",
217
+ " collection,\n",
218
+ " region=self.user_roi,\n",
219
+ " vis_params=vis_params,\n",
220
+ " date_format=date_format,\n",
221
+ " )\n",
222
+ " self._draw_control.clear()\n",
223
+ " draw_layer = self.find_layer(\"Drawn Features\")\n",
224
+ " if draw_layer is not None:\n",
225
+ " self.remove(draw_layer)\n",
226
+ " output.clear_output()\n",
227
+ "\n",
228
+ " apply_btn.on_click(apply_btn_click)\n",
229
+ "\n",
230
+ " def split_btn_click(change):\n",
231
+ "\n",
232
+ " if hasattr(self, \"slider_ctrl\") and self.slider_ctrl is not None:\n",
233
+ " self.remove(self.slider_ctrl)\n",
234
+ " delattr(self, \"slider_ctrl\")\n",
235
+ "\n",
236
+ " with output:\n",
237
+ " output.clear_output()\n",
238
+ " if self.user_roi is None:\n",
239
+ " output.append_stdout(\"Please draw a ROI first.\")\n",
240
+ " else:\n",
241
+ " output.append_stdout(\"Creating time series...\")\n",
242
+ " collection = geemap.landsat_timeseries(\n",
243
+ " roi=self.user_roi,\n",
244
+ " start_year=start_year.value,\n",
245
+ " end_year=end_year.value,\n",
246
+ " start_date=str(start_month.value).zfill(2) + \"-01\",\n",
247
+ " end_date=str(end_month.value).zfill(2) + \"-01\",\n",
248
+ " frequency=frequency.value,\n",
249
+ " )\n",
250
+ " vis_params = {\n",
251
+ " \"bands\": bands.value.split(\"/\"),\n",
252
+ " \"min\": 0,\n",
253
+ " \"max\": 0.4,\n",
254
+ " }\n",
255
+ "\n",
256
+ " if frequency.value == \"year\":\n",
257
+ " date_format = \"YYYY\"\n",
258
+ " dates = geemap.image_dates(collection, date_format).getInfo()\n",
259
+ " elif frequency.value == \"quarter\":\n",
260
+ " date_format = \"YYYY-MM\"\n",
261
+ " dates = geemap.image_dates(collection, date_format).getInfo()\n",
262
+ " elif frequency.value == \"month\":\n",
263
+ " date_format = \"YYYY-MM\"\n",
264
+ " dates = geemap.image_dates(collection, date_format).getInfo()\n",
265
+ "\n",
266
+ " self.ts_inspector(\n",
267
+ " collection,\n",
268
+ " left_names=dates,\n",
269
+ " left_vis=vis_params,\n",
270
+ " add_close_button=True,\n",
271
+ " )\n",
272
+ " output.clear_output()\n",
273
+ "\n",
274
+ " try:\n",
275
+ " self._draw_control.clear()\n",
276
+ " draw_layer = self.find_layer(\"Drawn Features\")\n",
277
+ " if draw_layer is not None:\n",
278
+ " self.remove(draw_layer)\n",
279
+ " except Exception as e:\n",
280
+ " print(e)\n",
281
+ "\n",
282
+ " split_btn.on_click(split_btn_click)\n",
283
+ "\n",
284
+ " def reset_btn_click(change):\n",
285
+ " output.clear_output()\n",
286
+ " self.clean_up()\n",
287
+ "\n",
288
+ " reset_btn.on_click(reset_btn_click)\n",
289
+ "\n",
290
+ "\n",
291
+ "@solara.component\n",
292
+ "def Page():\n",
293
+ " with solara.Column(style={\"min-width\": \"500px\"}):\n",
294
+ " Map.element(\n",
295
+ " center=[20, -0],\n",
296
+ " zoom=2,\n",
297
+ " height=\"750px\",\n",
298
+ " zoom_ctrl=False,\n",
299
+ " measure_ctrl=False,\n",
300
+ " )"
301
+ ]
302
+ },
303
+ {
304
+ "cell_type": "code",
305
+ "execution_count": null,
306
+ "metadata": {},
307
+ "outputs": [],
308
+ "source": [
309
+ "Page()"
310
+ ]
311
+ },
312
+ {
313
+ "cell_type": "code",
314
+ "execution_count": null,
315
+ "metadata": {},
316
+ "outputs": [],
317
+ "source": []
318
+ }
319
+ ],
320
+ "metadata": {
321
+ "kernelspec": {
322
+ "display_name": "geo",
323
+ "language": "python",
324
+ "name": "python3"
325
+ },
326
+ "language_info": {
327
+ "codemirror_mode": {
328
+ "name": "ipython",
329
+ "version": 3
330
+ },
331
+ "file_extension": ".py",
332
+ "mimetype": "text/x-python",
333
+ "name": "python",
334
+ "nbconvert_exporter": "python",
335
+ "pygments_lexer": "ipython3",
336
+ "version": "3.11.8"
337
+ }
338
+ },
339
+ "nbformat": 4,
340
+ "nbformat_minor": 2
341
+ }
notebooks/07_jrc.ipynb ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import ee\n",
19
+ "import geemap\n",
20
+ "import ipywidgets as widgets\n",
21
+ "from IPython.display import display\n",
22
+ "import solara\n",
23
+ "\n",
24
+ "\n",
25
+ "class Map(geemap.Map):\n",
26
+ " def __init__(self, **kwargs):\n",
27
+ " super().__init__(**kwargs)\n",
28
+ " self.add_basemap(\"Esri.WorldImagery\")\n",
29
+ " self.add_ee_data()\n",
30
+ " self.add_buttons(add_header=True)\n",
31
+ "\n",
32
+ " def add_ee_data(self):\n",
33
+ "\n",
34
+ " dataset = ee.Image(\"JRC/GSW1_4/GlobalSurfaceWater\")\n",
35
+ " image = dataset.select([\"occurrence\"])\n",
36
+ " vis_params = {\n",
37
+ " \"min\": 0.0,\n",
38
+ " \"max\": 100.0,\n",
39
+ " \"palette\": [\"ffffff\", \"ffbbbb\", \"0000ff\"],\n",
40
+ " }\n",
41
+ " self.addLayer(image, vis_params, \"Occurrence\")\n",
42
+ " self.add_colorbar(\n",
43
+ " vis_params, label=\"Water occurrence (%)\", layer_name=\"Occurrence\"\n",
44
+ " )\n",
45
+ "\n",
46
+ " def add_buttons(self, position=\"topright\", **kwargs):\n",
47
+ " padding = \"0px 5px 0px 5px\"\n",
48
+ " widget = widgets.VBox(layout=widgets.Layout(padding=padding))\n",
49
+ " layout = widgets.Layout(width=\"auto\")\n",
50
+ " style = {\"description_width\": \"initial\"}\n",
51
+ " hist_btn = widgets.Button(description=\"Occurrence\", layout=layout)\n",
52
+ " bar_btn = widgets.Button(description=\"Monthly history\", layout=layout)\n",
53
+ " reset_btn = widgets.Button(description=\"Reset\", layout=layout)\n",
54
+ " scale = widgets.IntSlider(\n",
55
+ " min=30, max=1000, value=90, description=\"Scale\", layout=layout, style=style\n",
56
+ " )\n",
57
+ " month_slider = widgets.IntRangeSlider(\n",
58
+ " description=\"Months\",\n",
59
+ " value=[5, 10],\n",
60
+ " min=1,\n",
61
+ " max=12,\n",
62
+ " step=1,\n",
63
+ " layout=layout,\n",
64
+ " style=style,\n",
65
+ " )\n",
66
+ " widget.children = [\n",
67
+ " widgets.HBox([hist_btn, bar_btn, reset_btn]),\n",
68
+ " month_slider,\n",
69
+ " scale,\n",
70
+ " ]\n",
71
+ " self.add_widget(widget, position=position, **kwargs)\n",
72
+ " output = widgets.Output()\n",
73
+ " self.add_widget(output, position=\"bottomleft\", add_header=False)\n",
74
+ "\n",
75
+ " def hist_btn_click(b):\n",
76
+ " region = self.user_roi\n",
77
+ " if region is not None:\n",
78
+ " output.clear_output()\n",
79
+ " output.append_stdout(\"Computing histogram...\")\n",
80
+ " image = ee.Image(\"JRC/GSW1_4/GlobalSurfaceWater\").select([\"occurrence\"])\n",
81
+ " self.default_style = {\"cursor\": \"wait\"}\n",
82
+ " hist = geemap.image_histogram(\n",
83
+ " image,\n",
84
+ " region,\n",
85
+ " scale=scale.value,\n",
86
+ " height=350,\n",
87
+ " width=550,\n",
88
+ " x_label=\"Water Occurrence (%)\",\n",
89
+ " y_label=\"Pixel Count\",\n",
90
+ " layout_args={\n",
91
+ " \"title\": dict(x=0.5),\n",
92
+ " \"margin\": dict(l=0, r=0, t=10, b=0),\n",
93
+ " },\n",
94
+ " return_df=False,\n",
95
+ " )\n",
96
+ "\n",
97
+ " with output:\n",
98
+ " output.clear_output()\n",
99
+ " display(hist)\n",
100
+ " self.default_style = {\"cursor\": \"default\"}\n",
101
+ " else:\n",
102
+ " output.clear_output()\n",
103
+ " with output:\n",
104
+ " output.append_stdout(\"Please draw a region of interest first.\")\n",
105
+ "\n",
106
+ " hist_btn.on_click(hist_btn_click)\n",
107
+ "\n",
108
+ " def bar_btn_click(b):\n",
109
+ " region = self.user_roi\n",
110
+ " if region is not None:\n",
111
+ " self.default_style = {\"cursor\": \"wait\"}\n",
112
+ " output.clear_output()\n",
113
+ " output.append_stdout(\"Computing monthly history...\")\n",
114
+ " bar = geemap.jrc_hist_monthly_history(\n",
115
+ " region=region,\n",
116
+ " scale=scale.value,\n",
117
+ " height=350,\n",
118
+ " width=550,\n",
119
+ " layout_args={\n",
120
+ " \"title\": dict(x=0.5),\n",
121
+ " \"margin\": dict(l=0, r=0, t=10, b=0),\n",
122
+ " },\n",
123
+ " frequency=\"month\",\n",
124
+ " start_month=month_slider.value[0],\n",
125
+ " end_month=month_slider.value[1],\n",
126
+ " denominator=1e4,\n",
127
+ " y_label=\"Area (ha)\",\n",
128
+ " )\n",
129
+ "\n",
130
+ " with output:\n",
131
+ " output.clear_output()\n",
132
+ " display(bar)\n",
133
+ " self.default_style = {\"cursor\": \"default\"}\n",
134
+ " else:\n",
135
+ " output.clear_output()\n",
136
+ " with output:\n",
137
+ " output.append_stdout(\"Please draw a region of interest first.\")\n",
138
+ "\n",
139
+ " bar_btn.on_click(bar_btn_click)\n",
140
+ "\n",
141
+ " def reset_btn_click(b):\n",
142
+ " self._draw_control.clear()\n",
143
+ " output.clear_output()\n",
144
+ "\n",
145
+ " reset_btn.on_click(reset_btn_click)\n",
146
+ "\n",
147
+ "\n",
148
+ "@solara.component\n",
149
+ "def Page():\n",
150
+ " with solara.Column(style={\"min-width\": \"500px\"}):\n",
151
+ " Map.element(\n",
152
+ " center=[20, -0],\n",
153
+ " zoom=2,\n",
154
+ " height=\"750px\",\n",
155
+ " zoom_ctrl=False,\n",
156
+ " measure_ctrl=False,\n",
157
+ " )"
158
+ ]
159
+ },
160
+ {
161
+ "cell_type": "code",
162
+ "execution_count": null,
163
+ "metadata": {},
164
+ "outputs": [],
165
+ "source": [
166
+ "Page()"
167
+ ]
168
+ },
169
+ {
170
+ "cell_type": "code",
171
+ "execution_count": null,
172
+ "metadata": {},
173
+ "outputs": [],
174
+ "source": []
175
+ }
176
+ ],
177
+ "metadata": {
178
+ "kernelspec": {
179
+ "display_name": "geo",
180
+ "language": "python",
181
+ "name": "python3"
182
+ },
183
+ "language_info": {
184
+ "codemirror_mode": {
185
+ "name": "ipython",
186
+ "version": 3
187
+ },
188
+ "file_extension": ".py",
189
+ "mimetype": "text/x-python",
190
+ "name": "python",
191
+ "nbconvert_exporter": "python",
192
+ "pygments_lexer": "ipython3",
193
+ "version": "3.11.8"
194
+ }
195
+ },
196
+ "nbformat": 4,
197
+ "nbformat_minor": 2
198
+ }
notebooks/08_compare.ipynb ADDED
@@ -0,0 +1,328 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "code",
5
+ "execution_count": null,
6
+ "metadata": {},
7
+ "outputs": [],
8
+ "source": [
9
+ "# %pip install -U geemap solara"
10
+ ]
11
+ },
12
+ {
13
+ "cell_type": "code",
14
+ "execution_count": null,
15
+ "metadata": {},
16
+ "outputs": [],
17
+ "source": [
18
+ "import ee\n",
19
+ "import geemap\n",
20
+ "import ipywidgets as widgets\n",
21
+ "import solara\n",
22
+ "from datetime import date\n",
23
+ "\n",
24
+ "\n",
25
+ "class Map(geemap.Map):\n",
26
+ " def __init__(self, **kwargs):\n",
27
+ " super().__init__(**kwargs)\n",
28
+ " self.add_basemap(\"Esri.WorldImagery\")\n",
29
+ " self.add_gui_widget(add_header=True)\n",
30
+ "\n",
31
+ " def clean_up(self):\n",
32
+ "\n",
33
+ " layers = [\n",
34
+ " \"Pre-event Image\",\n",
35
+ " \"Post-event Image\",\n",
36
+ " \"Pre-event NDWI\",\n",
37
+ " \"Post-event NDWI\",\n",
38
+ " \"Pre-event Water\",\n",
39
+ " \"Post-event Water\",\n",
40
+ " \"Disappeared Water\",\n",
41
+ " \"New Water\",\n",
42
+ " ]\n",
43
+ " for layer_name in layers:\n",
44
+ " layer = self.find_layer(layer_name)\n",
45
+ " if layer is not None:\n",
46
+ " self.remove(layer)\n",
47
+ "\n",
48
+ " def add_gui_widget(self, position=\"topright\", **kwargs):\n",
49
+ "\n",
50
+ " widget = widgets.VBox(layout=widgets.Layout(padding=\"0px 5px 0px 5px\"))\n",
51
+ " pre_widget = widgets.HBox()\n",
52
+ " post_widget = widgets.HBox()\n",
53
+ " layout = widgets.Layout(width=\"auto\")\n",
54
+ " style = {\"description_width\": \"initial\"}\n",
55
+ " padding = \"0px 5px 0px 5px\"\n",
56
+ " pre_start_date = widgets.DatePicker(\n",
57
+ " description=\"Start\",\n",
58
+ " value=date(2014, 1, 1),\n",
59
+ " style=style,\n",
60
+ " layout=widgets.Layout(padding=padding, width=\"160px\"),\n",
61
+ " )\n",
62
+ " pre_end_date = widgets.DatePicker(\n",
63
+ " description=\"End\",\n",
64
+ " value=date(2014, 12, 31),\n",
65
+ " style=style,\n",
66
+ " layout=widgets.Layout(padding=padding, width=\"160px\"),\n",
67
+ " )\n",
68
+ " pre_cloud_cover = widgets.IntSlider(\n",
69
+ " description=\"Cloud\",\n",
70
+ " min=0,\n",
71
+ " max=100,\n",
72
+ " value=25,\n",
73
+ " step=1,\n",
74
+ " readout=False,\n",
75
+ " style=style,\n",
76
+ " layout=widgets.Layout(padding=padding, width=\"130px\"),\n",
77
+ " )\n",
78
+ " pre_cloud_label = widgets.Label(value=str(pre_cloud_cover.value))\n",
79
+ " geemap.jslink_slider_label(pre_cloud_cover, pre_cloud_label)\n",
80
+ " pre_widget.children = [\n",
81
+ " pre_start_date,\n",
82
+ " pre_end_date,\n",
83
+ " pre_cloud_cover,\n",
84
+ " pre_cloud_label,\n",
85
+ " ]\n",
86
+ " post_start_date = widgets.DatePicker(\n",
87
+ " description=\"Start\",\n",
88
+ " value=date(2024, 1, 1),\n",
89
+ " style=style,\n",
90
+ " layout=widgets.Layout(padding=padding, width=\"160px\"),\n",
91
+ " )\n",
92
+ " post_end_date = widgets.DatePicker(\n",
93
+ " description=\"End\",\n",
94
+ " value=date(2024, 12, 31),\n",
95
+ " style=style,\n",
96
+ " layout=widgets.Layout(padding=padding, width=\"160px\"),\n",
97
+ " )\n",
98
+ " post_cloud_cover = widgets.IntSlider(\n",
99
+ " description=\"Cloud\",\n",
100
+ " min=0,\n",
101
+ " max=100,\n",
102
+ " value=30,\n",
103
+ " step=1,\n",
104
+ " readout=False,\n",
105
+ " style=style,\n",
106
+ " layout=widgets.Layout(padding=padding, width=\"130px\"),\n",
107
+ " )\n",
108
+ " post_cloud_label = widgets.Label(value=str(post_cloud_cover.value))\n",
109
+ " geemap.jslink_slider_label(post_cloud_cover, post_cloud_label)\n",
110
+ " post_widget.children = [\n",
111
+ " post_start_date,\n",
112
+ " post_end_date,\n",
113
+ " post_cloud_cover,\n",
114
+ " post_cloud_label,\n",
115
+ " ]\n",
116
+ "\n",
117
+ " apply_btn = widgets.Button(description=\"Apply\", layout=layout)\n",
118
+ " reset_btn = widgets.Button(description=\"Reset\", layout=layout)\n",
119
+ " buttons = widgets.HBox([apply_btn, reset_btn])\n",
120
+ " output = widgets.Output()\n",
121
+ "\n",
122
+ " use_split = widgets.Checkbox(\n",
123
+ " value=False,\n",
124
+ " description=\"Split map\",\n",
125
+ " style=style,\n",
126
+ " layout=widgets.Layout(padding=padding, width=\"100px\"),\n",
127
+ " )\n",
128
+ "\n",
129
+ " use_ndwi = widgets.Checkbox(\n",
130
+ " value=False,\n",
131
+ " description=\"Compute NDWI\",\n",
132
+ " style=style,\n",
133
+ " layout=widgets.Layout(padding=padding, width=\"160px\"),\n",
134
+ " )\n",
135
+ "\n",
136
+ " ndwi_threhold = widgets.FloatSlider(\n",
137
+ " description=\"Threshold\",\n",
138
+ " min=-1,\n",
139
+ " max=1,\n",
140
+ " value=0,\n",
141
+ " step=0.05,\n",
142
+ " readout=True,\n",
143
+ " style=style,\n",
144
+ " layout=widgets.Layout(padding=padding, width=\"230px\"),\n",
145
+ " )\n",
146
+ "\n",
147
+ " options = widgets.HBox(\n",
148
+ " [\n",
149
+ " use_split,\n",
150
+ " use_ndwi,\n",
151
+ " ndwi_threhold,\n",
152
+ " ]\n",
153
+ " )\n",
154
+ "\n",
155
+ " widget.children = [pre_widget, post_widget, options, buttons, output]\n",
156
+ " self.add_widget(widget, position=position, **kwargs)\n",
157
+ "\n",
158
+ " def apply_btn_click(b):\n",
159
+ "\n",
160
+ " marker_layer = self.find_layer(\"Search location\")\n",
161
+ " if marker_layer is not None:\n",
162
+ " self.remove(marker_layer)\n",
163
+ " self.clean_up()\n",
164
+ "\n",
165
+ " if self.user_roi is None:\n",
166
+ " output.clear_output()\n",
167
+ " output.append_stdout(\"Please draw a ROI first.\")\n",
168
+ " elif (\n",
169
+ " pre_start_date.value is None\n",
170
+ " or pre_end_date.value is None\n",
171
+ " or post_start_date.value is None\n",
172
+ " or post_end_date.value is None\n",
173
+ " ):\n",
174
+ " output.clear_output()\n",
175
+ " output.append_stdout(\"Please select start and end dates.\")\n",
176
+ "\n",
177
+ " elif self.user_roi is not None:\n",
178
+ " output.clear_output()\n",
179
+ " output.append_stdout(\"Computing... Please wait.\")\n",
180
+ " roi = ee.FeatureCollection(self.user_roi)\n",
181
+ " vis_params = {\"bands\": [\"B6\", \"B5\", \"B4\"], \"min\": 0, \"max\": 0.4}\n",
182
+ " if pre_start_date.value.strftime(\"%Y-%m-%d\") < \"2013-04-11\":\n",
183
+ " pre_col = geemap.landsat_timeseries(\n",
184
+ " roi,\n",
185
+ " start_year=pre_start_date.value.year,\n",
186
+ " end_year=pre_end_date.value.year,\n",
187
+ " ).select([\"SWIR1\", \"NIR\", \"Red\", \"Green\"], [\"B6\", \"B5\", \"B4\", \"B3\"])\n",
188
+ " else:\n",
189
+ " pre_col = (\n",
190
+ " ee.ImageCollection(\"NASA/HLS/HLSL30/v002\")\n",
191
+ " .filterBounds(roi)\n",
192
+ " .filterDate(\n",
193
+ " pre_start_date.value.strftime(\"%Y-%m-%d\"),\n",
194
+ " pre_end_date.value.strftime(\"%Y-%m-%d\"),\n",
195
+ " )\n",
196
+ " .filter(ee.Filter.lt(\"CLOUD_COVERAGE\", pre_cloud_cover.value))\n",
197
+ " )\n",
198
+ "\n",
199
+ " if post_start_date.value.strftime(\"%Y-%m-%d\") < \"2013-04-11\":\n",
200
+ " post_col = geemap.landsat_timeseries(\n",
201
+ " roi,\n",
202
+ " start_year=post_start_date.value.year,\n",
203
+ " end_year=post_end_date.value.year,\n",
204
+ " ).select([\"SWIR1\", \"NIR\", \"Red\", \"Green\"], [\"B6\", \"B5\", \"B4\", \"B3\"])\n",
205
+ " else:\n",
206
+ " post_col = (\n",
207
+ " ee.ImageCollection(\"NASA/HLS/HLSL30/v002\")\n",
208
+ " .filterBounds(roi)\n",
209
+ " .filterDate(\n",
210
+ " post_start_date.value.strftime(\"%Y-%m-%d\"),\n",
211
+ " post_end_date.value.strftime(\"%Y-%m-%d\"),\n",
212
+ " )\n",
213
+ " .filter(ee.Filter.lt(\"CLOUD_COVERAGE\", post_cloud_cover.value))\n",
214
+ " )\n",
215
+ "\n",
216
+ " pre_img = pre_col.median().clip(roi)\n",
217
+ " post_img = post_col.median().clip(roi)\n",
218
+ "\n",
219
+ " if use_split.value:\n",
220
+ " left_layer = geemap.ee_tile_layer(\n",
221
+ " pre_img, vis_params, \"Pre-event Image\"\n",
222
+ " )\n",
223
+ " right_layer = geemap.ee_tile_layer(\n",
224
+ " post_img, vis_params, \"Post-event Image\"\n",
225
+ " )\n",
226
+ " self.split_map(\n",
227
+ " left_layer,\n",
228
+ " right_layer,\n",
229
+ " add_close_button=True,\n",
230
+ " left_label=\"Pre-event\",\n",
231
+ " right_label=\"Post-event\",\n",
232
+ " )\n",
233
+ " else:\n",
234
+ " pre_img = pre_col.median().clip(roi)\n",
235
+ " post_img = post_col.median().clip(roi)\n",
236
+ " self.add_layer(pre_img, vis_params, \"Pre-event Image\")\n",
237
+ " self.add_layer(post_img, vis_params, \"Post-event Image\")\n",
238
+ "\n",
239
+ " if use_ndwi.value and (not use_split.value):\n",
240
+ " pre_ndwi = pre_img.normalizedDifference([\"B3\", \"B6\"]).rename(\"NDWI\")\n",
241
+ " post_ndwi = post_img.normalizedDifference([\"B3\", \"B6\"]).rename(\n",
242
+ " \"NDWI\"\n",
243
+ " )\n",
244
+ " ndwi_vis = {\"min\": -1, \"max\": 1, \"palette\": \"ndwi\"}\n",
245
+ " self.add_layer(pre_ndwi, ndwi_vis, \"Pre-event NDWI\", False)\n",
246
+ " self.add_layer(post_ndwi, ndwi_vis, \"Post-event NDWI\", False)\n",
247
+ "\n",
248
+ " pre_water = pre_ndwi.gt(ndwi_threhold.value)\n",
249
+ " post_water = post_ndwi.gt(ndwi_threhold.value)\n",
250
+ " self.add_layer(\n",
251
+ " pre_water.selfMask(), {\"palette\": \"blue\"}, \"Pre-event Water\"\n",
252
+ " )\n",
253
+ " self.add_layer(\n",
254
+ " post_water.selfMask(), {\"palette\": \"red\"}, \"Post-event Water\"\n",
255
+ " )\n",
256
+ " new_water = post_water.subtract(pre_water).gt(0)\n",
257
+ " disappear_water = pre_water.subtract(post_water).gt(0)\n",
258
+ " self.add_layer(\n",
259
+ " disappear_water.selfMask(),\n",
260
+ " {\"palette\": \"brown\"},\n",
261
+ " \"Disappeared Water\",\n",
262
+ " )\n",
263
+ " self.add_layer(\n",
264
+ " new_water.selfMask(), {\"palette\": \"cyan\"}, \"New Water\"\n",
265
+ " )\n",
266
+ "\n",
267
+ " with output:\n",
268
+ " output.clear_output()\n",
269
+ "\n",
270
+ " output.clear_output()\n",
271
+ "\n",
272
+ " apply_btn.on_click(apply_btn_click)\n",
273
+ "\n",
274
+ " def reset_btn_click(b):\n",
275
+ " self.clean_up()\n",
276
+ " self._draw_control.clear()\n",
277
+ " draw_layer = self.find_layer(\"Drawn Features\")\n",
278
+ " if draw_layer is not None:\n",
279
+ " self.remove(draw_layer)\n",
280
+ " output.clear_output()\n",
281
+ "\n",
282
+ " reset_btn.on_click(reset_btn_click)\n",
283
+ "\n",
284
+ "\n",
285
+ "@solara.component\n",
286
+ "def Page():\n",
287
+ " with solara.Column(style={\"min-width\": \"500px\"}):\n",
288
+ " Map.element(\n",
289
+ " center=[20, -0],\n",
290
+ " zoom=2,\n",
291
+ " height=\"750px\",\n",
292
+ " zoom_ctrl=False,\n",
293
+ " measure_ctrl=False,\n",
294
+ " )"
295
+ ]
296
+ },
297
+ {
298
+ "cell_type": "code",
299
+ "execution_count": null,
300
+ "metadata": {},
301
+ "outputs": [],
302
+ "source": [
303
+ "Page()"
304
+ ]
305
+ }
306
+ ],
307
+ "metadata": {
308
+ "kernelspec": {
309
+ "display_name": "geo",
310
+ "language": "python",
311
+ "name": "python3"
312
+ },
313
+ "language_info": {
314
+ "codemirror_mode": {
315
+ "name": "ipython",
316
+ "version": 3
317
+ },
318
+ "file_extension": ".py",
319
+ "mimetype": "text/x-python",
320
+ "name": "python",
321
+ "nbconvert_exporter": "python",
322
+ "pygments_lexer": "ipython3",
323
+ "version": "3.11.8"
324
+ }
325
+ },
326
+ "nbformat": 4,
327
+ "nbformat_minor": 2
328
+ }
pages/05_timelapse.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import geemap
2
+ import solara
3
+
4
+
5
+ class Map(geemap.Map):
6
+ def __init__(self, **kwargs):
7
+ super().__init__(**kwargs)
8
+ self.add_basemap("Esri.WorldImagery")
9
+ self.add_gui("timelapse", basemap=None)
10
+
11
+
12
+ @solara.component
13
+ def Page():
14
+ with solara.Column(style={"min-width": "500px", "isolation": "isolate"}):
15
+ Map.element(
16
+ center=[20, -0],
17
+ zoom=2,
18
+ height="750px",
19
+ zoom_ctrl=False,
20
+ measure_ctrl=False,
21
+ )
pages/06_timeseries.py ADDED
@@ -0,0 +1,283 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import geemap
2
+ import ipywidgets as widgets
3
+ import solara
4
+ from geemap import get_current_year, jslink_slider_label
5
+
6
+
7
+ class Map(geemap.Map):
8
+ def __init__(self, **kwargs):
9
+ super().__init__(**kwargs)
10
+ self.add_basemap("Esri.WorldImagery")
11
+ self.add_ts_gui(position="topright")
12
+
13
+ def clean_up(self):
14
+ if hasattr(self, "slider_ctrl") and self.slider_ctrl is not None:
15
+ self.remove(self.slider_ctrl)
16
+ delattr(self, "slider_ctrl")
17
+
18
+ layer = self.find_layer("Time series")
19
+ if layer is not None:
20
+ self.remove(layer)
21
+ layer = self.find_layer("Image X")
22
+ if layer is not None:
23
+ self.remove(layer)
24
+
25
+ draw_layer = self.find_layer("Drawn Features")
26
+ if draw_layer is not None:
27
+ self.remove(draw_layer)
28
+
29
+ def add_ts_gui(self, position="topright", **kwargs):
30
+
31
+ widget_width = "350px"
32
+ padding = "0px 0px 0px 5px" # upper, right, bottom, left
33
+ style = {"description_width": "initial"}
34
+ current_year = get_current_year()
35
+
36
+ collection = widgets.Dropdown(
37
+ options=[
38
+ "Landsat TM-ETM-OLI Surface Reflectance",
39
+ ],
40
+ value="Landsat TM-ETM-OLI Surface Reflectance",
41
+ description="Collection:",
42
+ layout=widgets.Layout(width=widget_width, padding=padding),
43
+ style=style,
44
+ )
45
+ bands = widgets.Dropdown(
46
+ description="Bands:",
47
+ options=[
48
+ "Red/Green/Blue",
49
+ "NIR/Red/Green",
50
+ "SWIR2/SWIR1/NIR",
51
+ "NIR/SWIR1/Red",
52
+ "SWIR2/NIR/Red",
53
+ "SWIR2/SWIR1/Red",
54
+ "SWIR1/NIR/Blue",
55
+ "NIR/SWIR1/Blue",
56
+ "SWIR2/NIR/Green",
57
+ "SWIR1/NIR/Red",
58
+ ],
59
+ value="SWIR1/NIR/Red",
60
+ style=style,
61
+ layout=widgets.Layout(width="195px", padding=padding),
62
+ )
63
+
64
+ frequency = widgets.Dropdown(
65
+ description="Frequency:",
66
+ options=["year", "quarter", "month"],
67
+ value="year",
68
+ style=style,
69
+ layout=widgets.Layout(width="150px", padding=padding),
70
+ )
71
+
72
+ start_year = widgets.IntSlider(
73
+ description="Start Year:",
74
+ value=1984,
75
+ min=1984,
76
+ max=current_year,
77
+ readout=False,
78
+ style=style,
79
+ layout=widgets.Layout(width="138px", padding=padding),
80
+ )
81
+
82
+ start_year_label = widgets.Label("1984")
83
+ jslink_slider_label(start_year, start_year_label)
84
+
85
+ end_year = widgets.IntSlider(
86
+ description="End Year:",
87
+ value=current_year,
88
+ min=1984,
89
+ max=current_year,
90
+ readout=False,
91
+ style=style,
92
+ layout=widgets.Layout(width="138px", padding=padding),
93
+ )
94
+ end_year_label = widgets.Label(str(current_year))
95
+ jslink_slider_label(end_year, end_year_label)
96
+
97
+ start_month = widgets.IntSlider(
98
+ description="Start Month:",
99
+ value=5,
100
+ min=1,
101
+ max=12,
102
+ readout=False,
103
+ style=style,
104
+ layout=widgets.Layout(width="145px", padding=padding),
105
+ )
106
+
107
+ start_month_label = widgets.Label(
108
+ "5",
109
+ layout=widgets.Layout(width="20px", padding=padding),
110
+ )
111
+ jslink_slider_label(start_month, start_month_label)
112
+
113
+ end_month = widgets.IntSlider(
114
+ description="End Month:",
115
+ value=10,
116
+ min=1,
117
+ max=12,
118
+ readout=False,
119
+ style=style,
120
+ layout=widgets.Layout(width="155px", padding=padding),
121
+ )
122
+
123
+ end_month_label = widgets.Label("10")
124
+ jslink_slider_label(end_month, end_month_label)
125
+
126
+ output = widgets.Output()
127
+
128
+ button_width = "113px"
129
+ apply_btn = widgets.Button(
130
+ description="Time slider",
131
+ button_style="primary",
132
+ tooltip="Click to create timeseries",
133
+ style=style,
134
+ layout=widgets.Layout(padding="0px", width=button_width),
135
+ )
136
+
137
+ split_btn = widgets.Button(
138
+ description="Split map",
139
+ button_style="primary",
140
+ tooltip="Click to create timeseries",
141
+ style=style,
142
+ layout=widgets.Layout(padding="0px", width=button_width),
143
+ )
144
+
145
+ reset_btn = widgets.Button(
146
+ description="Reset",
147
+ button_style="primary",
148
+ style=style,
149
+ layout=widgets.Layout(padding="0px", width=button_width),
150
+ )
151
+
152
+ vbox = widgets.VBox(
153
+ [
154
+ collection,
155
+ widgets.HBox([bands, frequency]),
156
+ widgets.HBox([start_year, start_year_label, end_year, end_year_label]),
157
+ widgets.HBox(
158
+ [start_month, start_month_label, end_month, end_month_label]
159
+ ),
160
+ widgets.HBox([apply_btn, split_btn, reset_btn]),
161
+ output,
162
+ ]
163
+ )
164
+ self.add_widget(vbox, position=position, add_header=True)
165
+
166
+ def apply_btn_click(change):
167
+
168
+ if hasattr(self, "slider_ctrl") and self.slider_ctrl is not None:
169
+ self.remove(self.slider_ctrl)
170
+ delattr(self, "slider_ctrl")
171
+
172
+ with output:
173
+ output.clear_output()
174
+ if self.user_roi is None:
175
+ output.append_stdout("Please draw a ROI first.")
176
+ else:
177
+ output.append_stdout("Creating time series...")
178
+ collection = geemap.landsat_timeseries(
179
+ roi=self.user_roi,
180
+ start_year=start_year.value,
181
+ end_year=end_year.value,
182
+ start_date=str(start_month.value).zfill(2) + "-01",
183
+ end_date=str(end_month.value).zfill(2) + "-01",
184
+ frequency=frequency.value,
185
+ )
186
+ vis_params = {
187
+ "bands": bands.value.split("/"),
188
+ "min": 0,
189
+ "max": 0.4,
190
+ }
191
+
192
+ if frequency.value == "year":
193
+ date_format = "YYYY"
194
+ elif frequency.value == "quarter":
195
+ date_format = "YYYY-MM"
196
+ elif frequency.value == "month":
197
+ date_format = "YYYY-MM"
198
+
199
+ self.add_time_slider(
200
+ collection,
201
+ region=self.user_roi,
202
+ vis_params=vis_params,
203
+ date_format=date_format,
204
+ )
205
+ self._draw_control.clear()
206
+ draw_layer = self.find_layer("Drawn Features")
207
+ if draw_layer is not None:
208
+ self.remove(draw_layer)
209
+ output.clear_output()
210
+
211
+ apply_btn.on_click(apply_btn_click)
212
+
213
+ def split_btn_click(change):
214
+
215
+ if hasattr(self, "slider_ctrl") and self.slider_ctrl is not None:
216
+ self.remove(self.slider_ctrl)
217
+ delattr(self, "slider_ctrl")
218
+
219
+ with output:
220
+ output.clear_output()
221
+ if self.user_roi is None:
222
+ output.append_stdout("Please draw a ROI first.")
223
+ else:
224
+ output.append_stdout("Creating time series...")
225
+ collection = geemap.landsat_timeseries(
226
+ roi=self.user_roi,
227
+ start_year=start_year.value,
228
+ end_year=end_year.value,
229
+ start_date=str(start_month.value).zfill(2) + "-01",
230
+ end_date=str(end_month.value).zfill(2) + "-01",
231
+ frequency=frequency.value,
232
+ )
233
+ vis_params = {
234
+ "bands": bands.value.split("/"),
235
+ "min": 0,
236
+ "max": 0.4,
237
+ }
238
+
239
+ if frequency.value == "year":
240
+ date_format = "YYYY"
241
+ dates = geemap.image_dates(collection, date_format).getInfo()
242
+ elif frequency.value == "quarter":
243
+ date_format = "YYYY-MM"
244
+ dates = geemap.image_dates(collection, date_format).getInfo()
245
+ elif frequency.value == "month":
246
+ date_format = "YYYY-MM"
247
+ dates = geemap.image_dates(collection, date_format).getInfo()
248
+
249
+ self.ts_inspector(
250
+ collection,
251
+ left_names=dates,
252
+ left_vis=vis_params,
253
+ add_close_button=True,
254
+ )
255
+ output.clear_output()
256
+
257
+ try:
258
+ self._draw_control.clear()
259
+ draw_layer = self.find_layer("Drawn Features")
260
+ if draw_layer is not None:
261
+ self.remove(draw_layer)
262
+ except Exception as e:
263
+ print(e)
264
+
265
+ split_btn.on_click(split_btn_click)
266
+
267
+ def reset_btn_click(change):
268
+ output.clear_output()
269
+ self.clean_up()
270
+
271
+ reset_btn.on_click(reset_btn_click)
272
+
273
+
274
+ @solara.component
275
+ def Page():
276
+ with solara.Column(style={"min-width": "500px"}):
277
+ Map.element(
278
+ center=[20, -0],
279
+ zoom=2,
280
+ height="750px",
281
+ zoom_ctrl=False,
282
+ measure_ctrl=False,
283
+ )
pages/07_jrc.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ee
2
+ import geemap
3
+ import ipywidgets as widgets
4
+ from IPython.display import display
5
+ import solara
6
+
7
+
8
+ class Map(geemap.Map):
9
+ def __init__(self, **kwargs):
10
+ super().__init__(**kwargs)
11
+ self.add_basemap("Esri.WorldImagery")
12
+ self.add_ee_data()
13
+ self.add_buttons(add_header=True)
14
+
15
+ def add_ee_data(self):
16
+
17
+ dataset = ee.Image("JRC/GSW1_4/GlobalSurfaceWater")
18
+ image = dataset.select(["occurrence"])
19
+ vis_params = {
20
+ "min": 0.0,
21
+ "max": 100.0,
22
+ "palette": ["ffffff", "ffbbbb", "0000ff"],
23
+ }
24
+ self.addLayer(image, vis_params, "Occurrence")
25
+ self.add_colorbar(
26
+ vis_params, label="Water occurrence (%)", layer_name="Occurrence"
27
+ )
28
+
29
+ def add_buttons(self, position="topright", **kwargs):
30
+ padding = "0px 5px 0px 5px"
31
+ widget = widgets.VBox(layout=widgets.Layout(padding=padding))
32
+ layout = widgets.Layout(width="auto")
33
+ style = {"description_width": "initial"}
34
+ hist_btn = widgets.Button(description="Occurrence", layout=layout)
35
+ bar_btn = widgets.Button(description="Monthly history", layout=layout)
36
+ reset_btn = widgets.Button(description="Reset", layout=layout)
37
+ scale = widgets.IntSlider(
38
+ min=30, max=1000, value=90, description="Scale", layout=layout, style=style
39
+ )
40
+ month_slider = widgets.IntRangeSlider(
41
+ description="Months",
42
+ value=[5, 10],
43
+ min=1,
44
+ max=12,
45
+ step=1,
46
+ layout=layout,
47
+ style=style,
48
+ )
49
+ widget.children = [
50
+ widgets.HBox([hist_btn, bar_btn, reset_btn]),
51
+ month_slider,
52
+ scale,
53
+ ]
54
+ self.add_widget(widget, position=position, **kwargs)
55
+ output = widgets.Output()
56
+ self.add_widget(output, position="bottomleft", add_header=False)
57
+
58
+ def hist_btn_click(b):
59
+ region = self.user_roi
60
+ if region is not None:
61
+ output.clear_output()
62
+ output.append_stdout("Computing histogram...")
63
+ image = ee.Image("JRC/GSW1_4/GlobalSurfaceWater").select(["occurrence"])
64
+ self.default_style = {"cursor": "wait"}
65
+ hist = geemap.image_histogram(
66
+ image,
67
+ region,
68
+ scale=scale.value,
69
+ height=350,
70
+ width=550,
71
+ x_label="Water Occurrence (%)",
72
+ y_label="Pixel Count",
73
+ layout_args={
74
+ "title": dict(x=0.5),
75
+ "margin": dict(l=0, r=0, t=10, b=0),
76
+ },
77
+ return_df=False,
78
+ )
79
+
80
+ with output:
81
+ output.clear_output()
82
+ display(hist)
83
+ self.default_style = {"cursor": "default"}
84
+ else:
85
+ output.clear_output()
86
+ with output:
87
+ output.append_stdout("Please draw a region of interest first.")
88
+
89
+ hist_btn.on_click(hist_btn_click)
90
+
91
+ def bar_btn_click(b):
92
+ region = self.user_roi
93
+ if region is not None:
94
+ self.default_style = {"cursor": "wait"}
95
+ output.clear_output()
96
+ output.append_stdout("Computing monthly history...")
97
+ bar = geemap.jrc_hist_monthly_history(
98
+ region=region,
99
+ scale=scale.value,
100
+ height=350,
101
+ width=550,
102
+ layout_args={
103
+ "title": dict(x=0.5),
104
+ "margin": dict(l=0, r=0, t=10, b=0),
105
+ },
106
+ frequency="month",
107
+ start_month=month_slider.value[0],
108
+ end_month=month_slider.value[1],
109
+ denominator=1e4,
110
+ y_label="Area (ha)",
111
+ )
112
+
113
+ with output:
114
+ output.clear_output()
115
+ display(bar)
116
+ self.default_style = {"cursor": "default"}
117
+ else:
118
+ output.clear_output()
119
+ with output:
120
+ output.append_stdout("Please draw a region of interest first.")
121
+
122
+ bar_btn.on_click(bar_btn_click)
123
+
124
+ def reset_btn_click(b):
125
+ self._draw_control.clear()
126
+ output.clear_output()
127
+
128
+ reset_btn.on_click(reset_btn_click)
129
+
130
+
131
+ @solara.component
132
+ def Page():
133
+ with solara.Column(style={"min-width": "500px"}):
134
+ Map.element(
135
+ center=[20, -0],
136
+ zoom=2,
137
+ height="750px",
138
+ zoom_ctrl=False,
139
+ measure_ctrl=False,
140
+ )
pages/08_compare.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import ee
2
+ import geemap
3
+ import ipywidgets as widgets
4
+ import solara
5
+ from datetime import date
6
+
7
+
8
+ class Map(geemap.Map):
9
+ def __init__(self, **kwargs):
10
+ super().__init__(**kwargs)
11
+ self.add_basemap("Esri.WorldImagery")
12
+ self.add_gui_widget(add_header=True)
13
+
14
+ def clean_up(self):
15
+
16
+ layers = [
17
+ "Pre-event Image",
18
+ "Post-event Image",
19
+ "Pre-event NDWI",
20
+ "Post-event NDWI",
21
+ "Pre-event Water",
22
+ "Post-event Water",
23
+ "Disappeared Water",
24
+ "New Water",
25
+ ]
26
+ for layer_name in layers:
27
+ layer = self.find_layer(layer_name)
28
+ if layer is not None:
29
+ self.remove(layer)
30
+
31
+ def add_gui_widget(self, position="topright", **kwargs):
32
+
33
+ widget = widgets.VBox(layout=widgets.Layout(padding="0px 5px 0px 5px"))
34
+ pre_widget = widgets.HBox()
35
+ post_widget = widgets.HBox()
36
+ layout = widgets.Layout(width="auto")
37
+ style = {"description_width": "initial"}
38
+ padding = "0px 5px 0px 5px"
39
+ pre_start_date = widgets.DatePicker(
40
+ description="Start",
41
+ value=date(2014, 1, 1),
42
+ style=style,
43
+ layout=widgets.Layout(padding=padding, width="160px"),
44
+ )
45
+ pre_end_date = widgets.DatePicker(
46
+ description="End",
47
+ value=date(2014, 12, 31),
48
+ style=style,
49
+ layout=widgets.Layout(padding=padding, width="160px"),
50
+ )
51
+ pre_cloud_cover = widgets.IntSlider(
52
+ description="Cloud",
53
+ min=0,
54
+ max=100,
55
+ value=25,
56
+ step=1,
57
+ readout=False,
58
+ style=style,
59
+ layout=widgets.Layout(padding=padding, width="130px"),
60
+ )
61
+ pre_cloud_label = widgets.Label(value=str(pre_cloud_cover.value))
62
+ geemap.jslink_slider_label(pre_cloud_cover, pre_cloud_label)
63
+ pre_widget.children = [
64
+ pre_start_date,
65
+ pre_end_date,
66
+ pre_cloud_cover,
67
+ pre_cloud_label,
68
+ ]
69
+ post_start_date = widgets.DatePicker(
70
+ description="Start",
71
+ value=date(2024, 1, 1),
72
+ style=style,
73
+ layout=widgets.Layout(padding=padding, width="160px"),
74
+ )
75
+ post_end_date = widgets.DatePicker(
76
+ description="End",
77
+ value=date(2024, 12, 31),
78
+ style=style,
79
+ layout=widgets.Layout(padding=padding, width="160px"),
80
+ )
81
+ post_cloud_cover = widgets.IntSlider(
82
+ description="Cloud",
83
+ min=0,
84
+ max=100,
85
+ value=30,
86
+ step=1,
87
+ readout=False,
88
+ style=style,
89
+ layout=widgets.Layout(padding=padding, width="130px"),
90
+ )
91
+ post_cloud_label = widgets.Label(value=str(post_cloud_cover.value))
92
+ geemap.jslink_slider_label(post_cloud_cover, post_cloud_label)
93
+ post_widget.children = [
94
+ post_start_date,
95
+ post_end_date,
96
+ post_cloud_cover,
97
+ post_cloud_label,
98
+ ]
99
+
100
+ apply_btn = widgets.Button(description="Apply", layout=layout)
101
+ reset_btn = widgets.Button(description="Reset", layout=layout)
102
+ buttons = widgets.HBox([apply_btn, reset_btn])
103
+ output = widgets.Output()
104
+
105
+ use_split = widgets.Checkbox(
106
+ value=False,
107
+ description="Split map",
108
+ style=style,
109
+ layout=widgets.Layout(padding=padding, width="100px"),
110
+ )
111
+
112
+ use_ndwi = widgets.Checkbox(
113
+ value=False,
114
+ description="Compute NDWI",
115
+ style=style,
116
+ layout=widgets.Layout(padding=padding, width="160px"),
117
+ )
118
+
119
+ ndwi_threhold = widgets.FloatSlider(
120
+ description="Threshold",
121
+ min=-1,
122
+ max=1,
123
+ value=0,
124
+ step=0.05,
125
+ readout=True,
126
+ style=style,
127
+ layout=widgets.Layout(padding=padding, width="230px"),
128
+ )
129
+
130
+ options = widgets.HBox(
131
+ [
132
+ use_split,
133
+ use_ndwi,
134
+ ndwi_threhold,
135
+ ]
136
+ )
137
+
138
+ widget.children = [pre_widget, post_widget, options, buttons, output]
139
+ self.add_widget(widget, position=position, **kwargs)
140
+
141
+ def apply_btn_click(b):
142
+
143
+ marker_layer = self.find_layer("Search location")
144
+ if marker_layer is not None:
145
+ self.remove(marker_layer)
146
+ self.clean_up()
147
+
148
+ if self.user_roi is None:
149
+ output.clear_output()
150
+ output.append_stdout("Please draw a ROI first.")
151
+ elif (
152
+ pre_start_date.value is None
153
+ or pre_end_date.value is None
154
+ or post_start_date.value is None
155
+ or post_end_date.value is None
156
+ ):
157
+ output.clear_output()
158
+ output.append_stdout("Please select start and end dates.")
159
+
160
+ elif self.user_roi is not None:
161
+ output.clear_output()
162
+ output.append_stdout("Computing... Please wait.")
163
+ roi = ee.FeatureCollection(self.user_roi)
164
+ vis_params = {"bands": ["B6", "B5", "B4"], "min": 0, "max": 0.4}
165
+ if pre_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
166
+ pre_col = geemap.landsat_timeseries(
167
+ roi,
168
+ start_year=pre_start_date.value.year,
169
+ end_year=pre_end_date.value.year,
170
+ ).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
171
+ else:
172
+ pre_col = (
173
+ ee.ImageCollection("NASA/HLS/HLSL30/v002")
174
+ .filterBounds(roi)
175
+ .filterDate(
176
+ pre_start_date.value.strftime("%Y-%m-%d"),
177
+ pre_end_date.value.strftime("%Y-%m-%d"),
178
+ )
179
+ .filter(ee.Filter.lt("CLOUD_COVERAGE", pre_cloud_cover.value))
180
+ )
181
+
182
+ if post_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
183
+ post_col = geemap.landsat_timeseries(
184
+ roi,
185
+ start_year=post_start_date.value.year,
186
+ end_year=post_end_date.value.year,
187
+ ).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
188
+ else:
189
+ post_col = (
190
+ ee.ImageCollection("NASA/HLS/HLSL30/v002")
191
+ .filterBounds(roi)
192
+ .filterDate(
193
+ post_start_date.value.strftime("%Y-%m-%d"),
194
+ post_end_date.value.strftime("%Y-%m-%d"),
195
+ )
196
+ .filter(ee.Filter.lt("CLOUD_COVERAGE", post_cloud_cover.value))
197
+ )
198
+
199
+ pre_img = pre_col.median().clip(roi)
200
+ post_img = post_col.median().clip(roi)
201
+
202
+ if use_split.value:
203
+ left_layer = geemap.ee_tile_layer(
204
+ pre_img, vis_params, "Pre-event Image"
205
+ )
206
+ right_layer = geemap.ee_tile_layer(
207
+ post_img, vis_params, "Post-event Image"
208
+ )
209
+ self.split_map(
210
+ left_layer,
211
+ right_layer,
212
+ add_close_button=True,
213
+ left_label="Pre-event",
214
+ right_label="Post-event",
215
+ )
216
+ else:
217
+ pre_img = pre_col.median().clip(roi)
218
+ post_img = post_col.median().clip(roi)
219
+ self.add_layer(pre_img, vis_params, "Pre-event Image")
220
+ self.add_layer(post_img, vis_params, "Post-event Image")
221
+
222
+ if use_ndwi.value and (not use_split.value):
223
+ pre_ndwi = pre_img.normalizedDifference(["B3", "B6"]).rename("NDWI")
224
+ post_ndwi = post_img.normalizedDifference(["B3", "B6"]).rename(
225
+ "NDWI"
226
+ )
227
+ ndwi_vis = {"min": -1, "max": 1, "palette": "ndwi"}
228
+ self.add_layer(pre_ndwi, ndwi_vis, "Pre-event NDWI", False)
229
+ self.add_layer(post_ndwi, ndwi_vis, "Post-event NDWI", False)
230
+
231
+ pre_water = pre_ndwi.gt(ndwi_threhold.value)
232
+ post_water = post_ndwi.gt(ndwi_threhold.value)
233
+ self.add_layer(
234
+ pre_water.selfMask(), {"palette": "blue"}, "Pre-event Water"
235
+ )
236
+ self.add_layer(
237
+ post_water.selfMask(), {"palette": "red"}, "Post-event Water"
238
+ )
239
+ new_water = post_water.subtract(pre_water).gt(0)
240
+ disappear_water = pre_water.subtract(post_water).gt(0)
241
+ self.add_layer(
242
+ disappear_water.selfMask(),
243
+ {"palette": "brown"},
244
+ "Disappeared Water",
245
+ )
246
+ self.add_layer(
247
+ new_water.selfMask(), {"palette": "cyan"}, "New Water"
248
+ )
249
+
250
+ with output:
251
+ output.clear_output()
252
+
253
+ output.clear_output()
254
+
255
+ apply_btn.on_click(apply_btn_click)
256
+
257
+ def reset_btn_click(b):
258
+ self.clean_up()
259
+ self._draw_control.clear()
260
+ draw_layer = self.find_layer("Drawn Features")
261
+ if draw_layer is not None:
262
+ self.remove(draw_layer)
263
+ output.clear_output()
264
+
265
+ reset_btn.on_click(reset_btn_click)
266
+
267
+
268
+ @solara.component
269
+ def Page():
270
+ with solara.Column(style={"min-width": "500px"}):
271
+ Map.element(
272
+ center=[20, -0],
273
+ zoom=2,
274
+ height="750px",
275
+ zoom_ctrl=False,
276
+ measure_ctrl=False,
277
+ )