Spaces:
Sleeping
Sleeping
File size: 11,880 Bytes
213d2b5 8d6d0f6 213d2b5 4470c81 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8950d78 213d2b5 8950d78 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 4470c81 213d2b5 8d6d0f6 213d2b5 8d6d0f6 8909418 8d6d0f6 2a18dc5 8d6d0f6 8909418 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 4470c81 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8909418 8d6d0f6 213d2b5 4470c81 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8950d78 8d6d0f6 213d2b5 8d6d0f6 213d2b5 8d6d0f6 213d2b5 |
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 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 |
from datetime import date, timedelta
import folium
import pandas as pd
import streamlit as st
from src import hf_utils
from src.config_parameters import params
from src.gfm import get_cached_aois, get_cached_gfm_handler
from src.utils import (
add_about,
get_aoi_id_from_selector_preview,
get_existing_geojson,
set_tool_page_style,
toggle_menu_button,
)
from streamlit_folium import st_folium
today = date.today()
default_date_yesterday = today - timedelta(days=1)
# Page configuration
st.set_page_config(layout="wide", page_title=params["browser_title"])
# If app is deployed hide menu button
toggle_menu_button()
# Create sidebar
add_about()
# Page title
st.markdown("# Flood extent analysis")
# Set page style
set_tool_page_style()
# Create two rows: top and bottom panel
row1 = st.container()
row2 = st.container()
# Create two columns in the top panel: input map and paramters
col1, col2, col3, col4 = row1.columns([1, 1, 1, 2])
col2_1, col2_2 = row2.columns([3, 2])
# Retrieve GFM Handler and AOIs to fill AOI selector
gfm = get_cached_gfm_handler()
aois = get_cached_aois()
if "all_products" not in st.session_state:
st.session_state["all_products"] = None
# To force removing product checkboxes when AOI selector changes
def on_area_selector_change():
print("Area selector changed, removing product checkboxes")
st.session_state["all_products"] = None
# Contains AOI selector
with col1:
selected_area_name_id = st.selectbox(
"Select saved AOI",
options=[aoi["name_id_preview"] for aoi in aois.values()],
on_change=on_area_selector_change,
)
selected_area_id = get_aoi_id_from_selector_preview(aois, selected_area_name_id)
# Contain datepickers
with col2:
today = date.today()
two_weeks_ago = today - timedelta(days=14)
start_date = st.date_input("Start date", value=two_weeks_ago)
with col3:
end_date = st.date_input("End date", value=today)
# Contains available products button
with col4:
st.text(
"Button info",
help="""
This will show the timestamps of all available GFM products
that intersect with the AOI for the selected date range.
Getting the available products is a relatively fast operation
it will not trigger any product downloads.
""",
)
show_available_products = st.button("Show GFM products")
# If button above is triggered, get products from GFM
# Then save all products to the session state and rerun the app to display them
if show_available_products:
products = gfm.get_area_products(selected_area_id, start_date, end_date)
st.session_state["all_products"] = products
st.rerun()
# Contains the product checkboxes if they exist after pushing the "Show available products" button
with col2_2:
row_checkboxes = st.container()
row_buttons = st.container()
with row_checkboxes:
checkboxes = list()
# Products are checked against the index to check whether they are already downloaded
index_df = hf_utils.get_geojson_index_df()
if st.session_state["all_products"]:
# Get unique product time groups
unique_time_groups = set()
for product in st.session_state["all_products"]:
unique_time_groups.add(product["product_time_group"])
# Create dataframe for the table
product_data = []
for time_group in sorted(unique_time_groups):
# Check if any product in this group is already downloaded
products_in_group = [
p
for p in st.session_state["all_products"]
if p["product_time_group"] == time_group
]
dataset_link = ""
for product in products_in_group:
if product["product_id"] in index_df["product"].values:
available_status = "Available in Floodmap"
flood_geojson_path = index_df.loc[
index_df["product"] == product["product_id"],
"flood_geojson_path",
].values[0]
dataset_link = f"https://huggingface.co/datasets/rodekruis/flood-mapping/resolve/main/{flood_geojson_path}?download=true"
product_data.append(
{
"Check": False,
"Product time": time_group,
"Available": dataset_link,
}
)
product_groups_df = pd.DataFrame(product_data)
# Create the data editor with checkbox column
product_groups_st_df = st.data_editor(
product_groups_df,
column_config={
"Check": st.column_config.CheckboxColumn(
"Select",
help="Select products to process",
default=False,
),
"Product time": st.column_config.TextColumn(
"Product Time Group", disabled=True
),
"Available": st.column_config.LinkColumn("Available in dataset"),
},
hide_index=True,
disabled=["Product time", "Available"],
)
# Convert checkbox states to list for compatibility with existing code
checkboxes = product_groups_st_df["Check"].tolist()
with row_buttons:
below_checkbox_col1, below_checkbox_col2 = row_buttons.columns([1, 1])
# Contains the "Download Products" button
with below_checkbox_col1:
st.text(
"Button info",
help=""
"""
Will download the selected products from GFM to the Floodmap app
(click "Show available products" first if there are none).
Products that show that they have already been downloaded can be left checked,
they will be skipped.
""",
)
download_products = st.button("Download to Floodmap")
# If the button is clicked download all checked products that have not been downloaded yet
if download_products:
index_df = hf_utils.get_geojson_index_df()
# Get selected time groups from the table
selected_time_groups = product_groups_st_df[product_groups_st_df["Check"]][
"Product time"
].tolist()
# For each selected time group
for time_group in selected_time_groups:
# Get all products for this time group
products_in_group = [
p
for p in st.session_state["all_products"]
if p["product_time_group"] == time_group
]
# Download each product in the group that hasn't been downloaded yet
for product_to_download in products_in_group:
if product_to_download["product_id"] not in index_df["product"].values:
with st.spinner(
f"Getting GFM files for {product_to_download['product_time']}, this may take a couple of minutes"
):
gfm.download_flood_product(
selected_area_id, product_to_download
)
st.rerun()
# For all the selected products add them to the map if they are available
feature_groups = []
flood_featuregroup = None
selected_geojsons = []
if st.session_state["all_products"]:
index_df = hf_utils.get_geojson_index_df()
# Get unique time groups
unique_time_groups = sorted(
set(p["product_time_group"] for p in st.session_state["all_products"])
)
# For each checkbox (which corresponds to a time group)
for i, checkbox in enumerate(checkboxes):
if checkbox:
time_group = unique_time_groups[i]
# Get all products for this time group
products_in_group = [
p
for p in st.session_state["all_products"]
if p["product_time_group"] == time_group
]
# Create a feature group for this time group
flood_featuregroup = folium.FeatureGroup(name=time_group)
footprint_featuregroup = folium.FeatureGroup(name="Sentinel footprint")
group_has_features = False
# Add all available products from this group to the feature group
for product in products_in_group:
if product["product_id"] in index_df["product"].values:
# Get the raw geojsons for further usage in the app
flood_geojson = get_existing_geojson(product["product_id"], "flood")
selected_geojsons.append(flood_geojson)
# Convert geojsons to folium features to display on the map
flood_folium_geojson = folium.GeoJson(
flood_geojson,
style_function=lambda x: {
"fillColor": "#ff0000",
"color": "#ff0000",
"fillOpacity": 0.2,
},
)
flood_featuregroup.add_child(flood_folium_geojson)
footprint_geojson = get_existing_geojson(
product["product_id"], "footprint"
)
footprint_folium_geojson = folium.GeoJson(
footprint_geojson,
style_function=lambda x: {
"fillColor": "yellow",
"color": "yellow",
"fillOpacity": 0.2,
"weight": 0,
},
)
footprint_featuregroup.add_child(footprint_folium_geojson)
group_has_features = True
# Only add the feature group if it contains any features
if group_has_features:
feature_groups.append(flood_featuregroup)
feature_groups.append(footprint_featuregroup)
# Contains the map
with col2_1:
if selected_area_id:
# display the bounding box
bounding_box = aois[selected_area_id]["bbox"]
geojson_selected_area = folium.GeoJson(
bounding_box,
style_function=lambda x: {"fillOpacity": 0.2, "weight": 1},
)
feat_group_selected_area = folium.FeatureGroup(name="selected_area")
feat_group_selected_area.add_child(geojson_selected_area)
feature_groups.append(feat_group_selected_area)
# Create folium map
folium_map = folium.Map([39, 0], zoom_start=8)
folium_map.fit_bounds(feat_group_selected_area.get_bounds())
m = st_folium(
folium_map, width=800, height=450, feature_group_to_add=feature_groups
)
if flood_featuregroup:
flood_part_of_legend = """
<div style="display: flex; align-items: center;">
<div style="width: 20px; height: 20px; background: rgba(255, 0, 0, .2); border: 1px solid red;"></div>
<div style="margin-left: 5px;">Floods</div>
</div>
<div style="display: flex; align-items: center;">
<div style="width: 20px; height: 20px; background: rgba(255, 255, 0, .2); border: 1px solid yellow;"></div>
<div style="margin-left: 5px;">Sentinel Footprint</div>
</div>
"""
else:
flood_part_of_legend = ""
st.markdown(
f"""
<div style="display: flex; align-items: center; gap: 20px;">
<div style="display: flex; align-items: center;">
<div style="width: 20px; height: 20px; background: rgba(51, 136, 255, .2); border: 1px solid #3388ff;"></div>
<div style="margin-left: 5px;">AOI</div>
</div>
{flood_part_of_legend}
</div>
""",
unsafe_allow_html=True,
)
# Keep track of which page we're currently on for page switch events
st.session_state["prev_page"] = "flood_extent"
|