nfw-app / pages /06_compare.py
giswqs's picture
Add NAIP imagery
18dedc8
import ee
import geemap
import ipywidgets as widgets
import solara
from datetime import date
class Map(geemap.Map):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_basemap("Esri.WorldImagery")
self.add_gui_widget(add_header=True)
def clean_up(self):
layers = [
"Pre-event Image",
"Post-event Image",
"Pre-event NDWI",
"Post-event NDWI",
"Pre-event Water",
"Post-event Water",
"Disappeared Water",
"New Water",
]
for layer_name in layers:
layer = self.find_layer(layer_name)
if layer is not None:
self.remove(layer)
def add_gui_widget(self, position="topright", **kwargs):
widget = widgets.VBox(layout=widgets.Layout(padding="0px 5px 0px 5px"))
pre_widget = widgets.HBox()
post_widget = widgets.HBox()
layout = widgets.Layout(width="auto")
style = {"description_width": "initial"}
padding = "0px 5px 0px 5px"
pre_start_date = widgets.DatePicker(
description="Start",
value=date(2014, 1, 1),
style=style,
layout=widgets.Layout(padding=padding, width="160px"),
)
pre_end_date = widgets.DatePicker(
description="End",
value=date(2014, 12, 31),
style=style,
layout=widgets.Layout(padding=padding, width="160px"),
)
pre_cloud_cover = widgets.IntSlider(
description="Cloud",
min=0,
max=100,
value=25,
step=1,
readout=False,
style=style,
layout=widgets.Layout(padding=padding, width="130px"),
)
pre_cloud_label = widgets.Label(value=str(pre_cloud_cover.value))
geemap.jslink_slider_label(pre_cloud_cover, pre_cloud_label)
pre_widget.children = [
pre_start_date,
pre_end_date,
pre_cloud_cover,
pre_cloud_label,
]
post_start_date = widgets.DatePicker(
description="Start",
value=date(2024, 1, 1),
style=style,
layout=widgets.Layout(padding=padding, width="160px"),
)
post_end_date = widgets.DatePicker(
description="End",
value=date(2024, 12, 31),
style=style,
layout=widgets.Layout(padding=padding, width="160px"),
)
post_cloud_cover = widgets.IntSlider(
description="Cloud",
min=0,
max=100,
value=30,
step=1,
readout=False,
style=style,
layout=widgets.Layout(padding=padding, width="130px"),
)
post_cloud_label = widgets.Label(value=str(post_cloud_cover.value))
geemap.jslink_slider_label(post_cloud_cover, post_cloud_label)
post_widget.children = [
post_start_date,
post_end_date,
post_cloud_cover,
post_cloud_label,
]
apply_btn = widgets.Button(description="Apply", layout=layout)
reset_btn = widgets.Button(description="Reset", layout=layout)
buttons = widgets.HBox([apply_btn, reset_btn])
output = widgets.Output()
use_split = widgets.Checkbox(
value=False,
description="Split map",
style=style,
layout=widgets.Layout(padding=padding, width="100px"),
)
use_ndwi = widgets.Checkbox(
value=False,
description="Compute NDWI",
style=style,
layout=widgets.Layout(padding=padding, width="160px"),
)
ndwi_threhold = widgets.FloatSlider(
description="Threshold",
min=-1,
max=1,
value=0,
step=0.05,
readout=True,
style=style,
layout=widgets.Layout(padding=padding, width="230px"),
)
options = widgets.HBox(
[
use_split,
use_ndwi,
ndwi_threhold,
]
)
widget.children = [pre_widget, post_widget, options, buttons, output]
self.add_widget(widget, position=position, **kwargs)
def apply_btn_click(b):
marker_layer = self.find_layer("Search location")
if marker_layer is not None:
self.remove(marker_layer)
self.clean_up()
if self.user_roi is None:
output.clear_output()
output.append_stdout("Please draw a ROI first.")
elif (
pre_start_date.value is None
or pre_end_date.value is None
or post_start_date.value is None
or post_end_date.value is None
):
output.clear_output()
output.append_stdout("Please select start and end dates.")
elif self.user_roi is not None:
output.clear_output()
output.append_stdout("Computing... Please wait.")
roi = ee.FeatureCollection(self.user_roi)
vis_params = {"bands": ["B6", "B5", "B4"], "min": 0, "max": 0.4}
if pre_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
pre_col = geemap.landsat_timeseries(
roi,
start_year=pre_start_date.value.year,
end_year=pre_end_date.value.year,
).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
else:
pre_col = (
ee.ImageCollection("NASA/HLS/HLSL30/v002")
.filterBounds(roi)
.filterDate(
pre_start_date.value.strftime("%Y-%m-%d"),
pre_end_date.value.strftime("%Y-%m-%d"),
)
.filter(ee.Filter.lt("CLOUD_COVERAGE", pre_cloud_cover.value))
)
if post_start_date.value.strftime("%Y-%m-%d") < "2013-04-11":
post_col = geemap.landsat_timeseries(
roi,
start_year=post_start_date.value.year,
end_year=post_end_date.value.year,
).select(["SWIR1", "NIR", "Red", "Green"], ["B6", "B5", "B4", "B3"])
else:
post_col = (
ee.ImageCollection("NASA/HLS/HLSL30/v002")
.filterBounds(roi)
.filterDate(
post_start_date.value.strftime("%Y-%m-%d"),
post_end_date.value.strftime("%Y-%m-%d"),
)
.filter(ee.Filter.lt("CLOUD_COVERAGE", post_cloud_cover.value))
)
pre_img = pre_col.median().clip(roi)
post_img = post_col.median().clip(roi)
if use_split.value:
left_layer = geemap.ee_tile_layer(
pre_img, vis_params, "Pre-event Image"
)
right_layer = geemap.ee_tile_layer(
post_img, vis_params, "Post-event Image"
)
self.split_map(
left_layer,
right_layer,
add_close_button=True,
left_label="Pre-event",
right_label="Post-event",
)
else:
pre_img = pre_col.median().clip(roi)
post_img = post_col.median().clip(roi)
self.add_layer(pre_img, vis_params, "Pre-event Image")
self.add_layer(post_img, vis_params, "Post-event Image")
if use_ndwi.value and (not use_split.value):
pre_ndwi = pre_img.normalizedDifference(["B3", "B6"]).rename("NDWI")
post_ndwi = post_img.normalizedDifference(["B3", "B6"]).rename(
"NDWI"
)
ndwi_vis = {"min": -1, "max": 1, "palette": "ndwi"}
self.add_layer(pre_ndwi, ndwi_vis, "Pre-event NDWI", False)
self.add_layer(post_ndwi, ndwi_vis, "Post-event NDWI", False)
pre_water = pre_ndwi.gt(ndwi_threhold.value)
post_water = post_ndwi.gt(ndwi_threhold.value)
self.add_layer(
pre_water.selfMask(), {"palette": "blue"}, "Pre-event Water"
)
self.add_layer(
post_water.selfMask(), {"palette": "red"}, "Post-event Water"
)
new_water = post_water.subtract(pre_water).gt(0)
disappear_water = pre_water.subtract(post_water).gt(0)
self.add_layer(
disappear_water.selfMask(),
{"palette": "brown"},
"Disappeared Water",
)
self.add_layer(
new_water.selfMask(), {"palette": "cyan"}, "New Water"
)
with output:
output.clear_output()
output.clear_output()
apply_btn.on_click(apply_btn_click)
def reset_btn_click(b):
self.clean_up()
self._draw_control.clear()
draw_layer = self.find_layer("Drawn Features")
if draw_layer is not None:
self.remove(draw_layer)
output.clear_output()
reset_btn.on_click(reset_btn_click)
@solara.component
def Page():
with solara.Column(style={"min-width": "500px"}):
Map.element(
center=[20, -0],
zoom=2,
height="750px",
zoom_ctrl=False,
measure_ctrl=False,
)