File size: 8,359 Bytes
e93f6b0
 
8349bfb
e93f6b0
8349bfb
 
e93f6b0
468b5dc
 
e93f6b0
 
8349bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f738da
 
8349bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f738da
 
 
 
 
 
8349bfb
 
 
 
 
9f738da
8349bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
9f738da
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8349bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9f738da
 
 
 
 
 
 
8349bfb
 
9f738da
8349bfb
 
 
 
 
 
 
 
 
9f738da
 
 
 
 
 
8349bfb
 
9f738da
 
 
 
8349bfb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e93f6b0
 
 
8349bfb
e93f6b0
 
8349bfb
d4fa6e8
e93f6b0
 
d4fa6e8
 
 
9efc051
 
d4fa6e8
e93f6b0
61c62e9
 
 
9efc051
 
8349bfb
61c62e9
8349bfb
61c62e9
 
 
 
e93f6b0
 
 
 
 
 
 
 
 
 
 
d4fa6e8
8349bfb
e93f6b0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
import ee
import geemap
import ipyleaflet
import solara
import ipywidgets as widgets
from IPython.display import display

zoom = solara.reactive(3)
center = solara.reactive([20, 0])


def zonal_stats_chart(image, vector, **kwargs):
    if isinstance(vector, ee.Geometry):
        fc = ee.FeatureCollection(vector)
    elif isinstance(vector, ee.FeatureCollection):
        fc = vector
    else:
        raise ValueError(
            "The vector argument must be an ee.Geometry or ee.FeatureCollection."
        )
    result = geemap.zonal_stats(
        image, fc, statistics_type="SUM", return_fc=True, verbose=False, **kwargs
    )
    df = geemap.ee_to_df(result).T
    df.reset_index(inplace=True)
    df.columns = ["Type", "Area"]
    chart = geemap.bar_chart(df, "Type", "Area", x_label='', y_label="Area (m2)")
    chart.update_layout(
        margin=dict(l=0, r=0, t=10, b=0),
        height=280,
    )

    return chart


def add_analysis_gui(m=None, position='topright', opened=True):
    """Create a toolbar widget.

    Args:
        m (geemap.Map, optional): The geemap.Map instance. Defaults to None.
        opened (bool, optional): Whether to open the toolbar. Defaults to True.
    """

    fc = ee.FeatureCollection('users/giswqs/public/countries')
    countries = fc.aggregate_array('NAME').getInfo()
    countries.sort()
    gswe = ee.ImageCollection("users/h2i_lab/gswe/gswe_datasets")
    image = gswe.mosaic()
    # esa = gswe.select("esa").mosaic()
    # esri = gswe.select("esri").mosaic()
    # jrc = gswe.select("jrc").mosaic()
    # osm = gswe.select("osm").mosaic()
    # hydrolakes = gswe.select("hydrolakes").mosaic()

    widget_width = "270px"
    padding = "0px 0px 0px 5px"  # upper, right, bottom, left

    toolbar_button = widgets.ToggleButton(
        value=False,
        tooltip="Toolbar",
        icon="bar-chart",
        layout=widgets.Layout(width="28px", height="28px", padding="0px 0px 0px 4px"),
    )

    close_button = widgets.ToggleButton(
        value=False,
        tooltip="Close the tool",
        icon="times",
        button_style="primary",
        layout=widgets.Layout(height="28px", width="28px", padding="0px 0px 0px 4px"),
    )

    options = ["Draw an area", "Select a country"]

    radio = widgets.RadioButtons(
        options=options,
        layout=widgets.Layout(width=widget_width, padding=padding),
        style={"description_width": "initial"},
    )

    country = widgets.Dropdown(
        options=countries,
        value=None,
        layout=widgets.Layout(width=widget_width, padding=padding),
    )

    buttons = widgets.ToggleButtons(
        value=None,
        options=["Apply", "Reset", "Close"],
        tooltips=["Apply", "Reset", "Close"],
        button_style="primary",
        layout=widgets.Layout(padding="0px 2px 4px 2px"),
    )
    buttons.style.button_width = "88px"
    label = widgets.Label("Draw an area on the map first.")

    toolbar_widget = widgets.VBox()
    toolbar_widget.children = [toolbar_button]
    toolbar_header = widgets.HBox()
    toolbar_header.children = [close_button, toolbar_button]
    toolbar_footer = widgets.VBox()
    toolbar_footer.children = [
        radio,
        buttons,
    ]

    def change_radio(change):
        if change["new"] == "Select a country":
            toolbar_footer.children = [radio, country, buttons]
        else:
            toolbar_footer.children = [radio, buttons]

    radio.observe(change_radio, "value")

    m.selected_country = None

    def change_country(change):
        if change["new"]:
            country_name = country.value
            country_fc = fc.filter(ee.Filter.eq('NAME', country_name))
            vec_style = {'color': '000000ff', 'width': 3, 'fillColor': '00000000'}
            m.addLayer(country_fc.style(**vec_style), {}, 'Selected Country')
            m.centerObject(country_fc)
            m.selected_country = country_fc
            toolbar_footer.children = [radio, country, buttons]

    country.observe(change_country, "value")

    def toolbar_btn_click(change):
        if change["new"]:
            close_button.value = False
            toolbar_widget.children = [toolbar_header, toolbar_footer]
        else:
            if not close_button.value:
                toolbar_widget.children = [toolbar_button]

    toolbar_button.observe(toolbar_btn_click, "value")

    def close_btn_click(change):
        if change["new"]:
            toolbar_button.value = False
            if m is not None:
                if m.tool_control is not None and m.tool_control in m.controls:
                    m.remove_control(m.tool_control)
                    m.tool_control = None
            toolbar_widget.close()

    close_button.observe(close_btn_click, "value")

    def button_clicked(change):
        if change["new"] == "Apply":
            output = widgets.Output(
                layout=widgets.Layout(width=widget_width, padding=padding)
            )
            if radio.value == "Select a country":
                toolbar_footer.children = [radio, country, buttons, output]
            else:
                toolbar_footer.children = [radio, buttons, output]
            with output:
                output.clear_output()

                buttons.value = None

                if radio.value == "Draw an area":
                    if m.user_roi is None:
                        display(label)
                        buttons.value = None
                    else:
                        chart = zonal_stats_chart(image, m.user_roi, scale=100)
                        display(chart)
                elif radio.value == "Select a country":
                    if m.selected_country is not None:
                        chart = zonal_stats_chart(
                            image, m.selected_country.geometry(), scale=100
                        )
                        display(chart)

        elif change["new"] == "Reset":
            country.value = None
            radio.value = "Draw an area"
            toolbar_footer.children = [radio, buttons]

        elif change["new"] == "Close":
            if m is not None:
                if m.tool_control is not None and m.tool_control in m.controls:
                    m.remove_control(m.tool_control)
                    m.tool_control = None
            toolbar_widget.close()

        buttons.value = None

    buttons.observe(button_clicked, "value")

    toolbar_button.value = opened
    if m is not None:
        toolbar_control = ipyleaflet.WidgetControl(
            widget=toolbar_widget, position=position
        )

        if toolbar_control not in m.controls:
            m.add_control(toolbar_control)
            m.tool_control = toolbar_control
    else:
        return toolbar_widget


class Map(geemap.Map):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.add_basemap('SATELLITE', show=False)
        self.add_ee_data()
        self.add_layer_manager()
        add_analysis_gui(self)
        # self.add_inspector()

    def add_ee_data(self):
        gswe = ee.ImageCollection("users/h2i_lab/gswe/gswe_datasets")
        self.addLayer(gswe.select("esa"), {'palette': ['red']}, "ESA")
        self.addLayer(gswe.select("esri"), {'palette': ['yellow']}, "ESRI")
        self.addLayer(gswe.select("jrc"), {'palette': ['blue']}, "JRC")
        self.addLayer(gswe.select("osm"), {'palette': ['green']}, "OSM")
        self.addLayer(gswe.select("hydrolakes"), {'palette': ['purple']}, "Hydrolakes")

        legend_dict = {
            'ESA': 'ff0000',
            'ESRI': 'ffff00',
            'JRC': '0000ff',
            'OSM': '00ff00',
            'Hydrolakes': '800080',
        }
        self.add_legend(legend_dict=legend_dict, position='bottomleft')
        fc = ee.FeatureCollection('users/giswqs/public/countries')
        style = {'color': '000000ff', 'width': 1, 'fillColor': '00000000'}
        self.addLayer(fc.style(**style), {}, 'Countries', False)


@solara.component
def Page():
    with solara.Column(style={"min-width": "500px"}):
        Map.element(  # type: ignore
            zoom=zoom.value,
            on_zoom=zoom.set,
            center=center.value,
            on_center=center.set,
            scroll_wheel_zoom=True,
            add_google_map=True,
            height="800px",
            data_ctrl=False,
        )