From 4f4c38d065bd03083db3d2bf130841f4b8fbe696 Mon Sep 17 00:00:00 2001 From: remic Date: Tue, 17 Feb 2026 09:34:06 -0500 Subject: [PATCH] Rain events --- pepsico/app_calc.py | 16 +++++++++-- pepsico/proj_wwc/layout.py | 33 ++++++++++++++++++++-- pepsico/proj_wwc/maproom.py | 55 +++++++++++++++++++++++++------------ 3 files changed, 82 insertions(+), 22 deletions(-) diff --git a/pepsico/app_calc.py b/pepsico/app_calc.py index 36393f10..feb5714d 100644 --- a/pepsico/app_calc.py +++ b/pepsico/app_calc.py @@ -101,7 +101,8 @@ def seasonal_data(monthly_data, start_month, end_month, start_year=None, end_yea def seasonal_wwc( - labelled_season_data, variable, frost_threshold, wet_threshold + labelled_season_data, variable, frost_threshold, wet_threshold, + rain_event_amount, rain_event_window, ): # Boolean variables need the additional where to return NaNs from False/0 to Nans # and the sum parameters for entirely NaNs seasons to remain NaNs and not turn to @@ -162,6 +163,17 @@ def seasonal_wwc( .sum(skipna=True, min_count=1) ) wwc_units = "days" + if variable == "rain_events": + data_ds = ( + labelled_season_data + .groupby(labelled_season_data["seasons_starts"]) + .map( + number_extreme_events_within_days, threshold=rain_event_amount, + window=rain_event_window, + #skipna=True, min_count=1, + ) + ) + wwc_units = "" # This is all a bit tedious but I didn't figure out another way to keep # seasons_ends and renaming time dim T # Can revisit later if this code has a future @@ -656,7 +668,7 @@ def number_extreme_events_within_days( Examples -------- Number of rain events of >80mm in 2 days or less: - number_extreme_events_within_days(rain_daily_data_in_mm, "gt", 80, 2) + number_extreme_events_within_days(rain_daily_data_in_mm, 80, 2) """ count = 0 dd = daily_data.copy() diff --git a/pepsico/proj_wwc/layout.py b/pepsico/proj_wwc/layout.py index c069bcaf..01029748 100644 --- a/pepsico/proj_wwc/layout.py +++ b/pepsico/proj_wwc/layout.py @@ -38,7 +38,7 @@ def app_layout(): id="variable", options=[ # "warm_nights", - # "rain_events", + "rain_events", "mean_Tmax", "mean_Tmin", "dry_days", @@ -57,7 +57,7 @@ def app_layout(): ], labels=[ # "Warm Nights", - # "Count of Rain Events", + "Count of Rain Events", "Mean Max Temperature", "Mean Min Temperature", "Count of Dry Days", @@ -96,7 +96,27 @@ def app_layout(): width="5em", debounce=False, ), - "mm", + "mm; ", + "Rain event: ", + Number( + id="ret", + default=80, + min=0, + max=999, + width="5em", + debounce=False, + ), + "mm or more; ", + "within: ", + Number( + id="rew", + default=2, + min=1, + max=99, + width="5em", + debounce=False, + ), + "days or less", ), Block("Season", Number( @@ -206,6 +226,13 @@ def app_layout(): Obtained through parametric Normal distributions. """ ]), + html.P([ + html.B("Count of Rain Events (rain_events):"),""" + Number of rain events in the season. A rain event accumulates + a user-defined threshold in mm or more in a user-defined number + of days or less. + """ + ]), ), lou.map(GLOBAL_CONFIG["zoom"]), diff --git a/pepsico/proj_wwc/maproom.py b/pepsico/proj_wwc/maproom.py index 2597851b..384ce900 100644 --- a/pepsico/proj_wwc/maproom.py +++ b/pepsico/proj_wwc/maproom.py @@ -97,7 +97,7 @@ def select_var(variable): ]: data_var = "tasmax" if variable in [ - # "rain_events", + "rain_events", "dry_days", "wet_days", # "longest_dry_spell", @@ -115,7 +115,7 @@ def local_data( lat, lng, region, model, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): model = [model] if model != "Multi-Model-Average" else [ "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR","MRI-ESM2-0", "UKESM1-0-LL" @@ -160,7 +160,8 @@ def local_data( ac.daily_tobegroupedby_season( data_ds, start_day, start_month, end_day, end_month, ), - variable, frost_threshold, wet_threshold, + variable, frost_threshold, wet_threshold, rain_event_amount, + rain_event_window, ) return data_ds, error_msg @@ -226,12 +227,14 @@ def invalid_button(lat, lng, lat_min, lng_min, lat_max, lng_max): State("end_month", "value"), State("frost", "value"), State("wet", "value"), + State("ret", "value"), + State("rew", "value"), prevent_initial_call=True, ) def send_data_as_csv( n_clicks, marker_pos, region, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): lat = marker_pos[0] lng = marker_pos[1] @@ -241,11 +244,13 @@ def send_data_as_csv( end_month = ac.strftimeb2int(end_month) frost_threshold = float(frost_threshold) wet_threshold = float(wet_threshold) + rain_event_amount = float(rain_event_amount) + rain_event_window = int(rain_event_window) model = "Multi-Model-Average" data_ds, error_msg = local_data( lat, lng, region, model, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ) if error_msg == None : lng_units = "E" if (lng >= 0) else "W" @@ -279,12 +284,14 @@ def send_data_as_csv( State("end_year_ref", "value"), State("frost", "value"), State("wet", "value"), + State("ret", "value"), + State("rew", "value"), ) def local_plots( marker_pos, region, n_clicks, model, variable, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): lat = marker_pos[0] lng = marker_pos[1] @@ -294,10 +301,12 @@ def local_plots( end_month = ac.strftimeb2int(end_month) frost_threshold = float(frost_threshold) wet_threshold = float(wet_threshold) + rain_event_amount = float(rain_event_amount) + rain_event_window = int(rain_event_window) data_ds, error_msg = local_data( lat, lng, region, model, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ) if error_msg != None : local_graph = pingrid.error_fig(error_msg) @@ -458,7 +467,7 @@ def seasonal_change( scenario, model, variable, region, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): model = [model] if model != "Multi-Model-Average" else [ "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR","MRI-ESM2-0", "UKESM1-0-LL" @@ -475,7 +484,8 @@ def seasonal_change( ).to_dataset(), start_day, start_month, end_day, end_month, ), - variable, frost_threshold, wet_threshold, + variable, frost_threshold, wet_threshold, rain_event_amount, + rain_event_window, ).mean(dim="T", keep_attrs=True) for m in model ], "M").mean("M", keep_attrs=True) data = xr.concat([ @@ -489,7 +499,8 @@ def seasonal_change( ).to_dataset(), start_day, start_month, end_day, end_month, ), - variable, frost_threshold, wet_threshold, + variable, frost_threshold, wet_threshold, rain_event_amount, + rain_event_window, ).mean(dim="T", keep_attrs=True) for m in model ], "M").mean("M", keep_attrs=True) #Tedious way to make a subtraction only to keep attributes (units) @@ -531,12 +542,14 @@ def map_attributes(data, variable): State("end_year_ref", "value"), State("frost", "value"), State("wet", "value"), + State("ret", "value"), + State("rew", "value"), ) def draw_colorbar( region, n_clicks, scenario, model, variable, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): start_day = int(start_day) end_day = int(end_day) @@ -544,11 +557,13 @@ def draw_colorbar( end_month = ac.strftimeb2int(end_month) frost_threshold = float(frost_threshold) wet_threshold = float(wet_threshold) + rain_event_amount = float(rain_event_amount) + rain_event_window = int(rain_event_window) data = seasonal_change( scenario, model, variable, region, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ) colorbar, min, max = map_attributes(data, variable) return ( @@ -575,12 +590,14 @@ def draw_colorbar( State("end_year_ref", "value"), State("frost", "value"), State("wet", "value"), + State("ret", "value"), + State("rew", "value"), ) def make_map( region, n_clicks, scenario, model, variable, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): try: send_alarm = False @@ -588,7 +605,8 @@ def make_map( f"{TILE_PFX}/{{z}}/{{x}}/{{y}}/{region}/{scenario}/{model}/" f"{variable}/{start_day}/{end_day}/{start_month}/{end_month}/" f"{start_year}/{end_year}/{start_year_ref}/{end_year_ref}/" - f"{frost_threshold}/{wet_threshold}" + f"{frost_threshold}/{wet_threshold}/{rain_event_amount}/" + f"{rain_event_window}" ) except: url_str= "" @@ -605,7 +623,8 @@ def make_map( f"{TILE_PFX}///////" f"/////" f"////" - f"//" + f"///" + f"" ), endpoint=f"{config['core_path']}" ) @@ -613,7 +632,7 @@ def fcst_tiles(tz, tx, ty, region, scenario, model, variable, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ): start_day = int(start_day) end_day = int(end_day) @@ -621,11 +640,13 @@ def fcst_tiles(tz, tx, ty, end_month = ac.strftimeb2int(end_month) frost_threshold = float(frost_threshold) wet_threshold = float(wet_threshold) + rain_event_amount = float(rain_event_amount) + rain_event_window = int(rain_event_window) data = seasonal_change( scenario, model, variable, region, start_day, end_day, start_month, end_month, start_year, end_year, start_year_ref, end_year_ref, - frost_threshold, wet_threshold, + frost_threshold, wet_threshold, rain_event_amount, rain_event_window, ) ( data[select_var(variable)].attrs["colormap"],