Spaces:
Running
Running
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 +9 -0
- notebooks/02_inspector.ipynb +10 -2
- notebooks/03_plotting.ipynb +10 -2
- notebooks/04_split_map.ipynb +10 -2
- notebooks/05_timelapse.ipynb +72 -0
- notebooks/06_timeseries.ipynb +341 -0
- notebooks/07_jrc.ipynb +198 -0
- notebooks/08_compare.ipynb +328 -0
- pages/05_timelapse.py +21 -0
- pages/06_timeseries.py +283 -0
- pages/07_jrc.py +140 -0
- pages/08_compare.py +277 -0
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 |
+
)
|