diff --git a/pepsico/app_calc.py b/pepsico/app_calc.py index 17f8aecf..489f1003 100644 --- a/pepsico/app_calc.py +++ b/pepsico/app_calc.py @@ -102,7 +102,7 @@ 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, hot_threshold, - warm_nights_spell, + warm_nights_spell, dry_spell, ): # 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 @@ -202,6 +202,22 @@ def seasonal_wwc( min_count=1, ) / data_ds.sum(skipna=True, min_count=1) wwc_units = "%" + if variable == "dry_spells_mean_length": + data_ds = ( + (labelled_season_data <= wet_threshold) + .where(~np.isnan(labelled_season_data)) + .groupby(labelled_season_data["seasons_starts"]) + .map(mean_length_of_spells, "T", min_spell_length=dry_spell) + ) + wwc_units = "days" + if variable == "dry_spells_median_length": + data_ds = ( + (labelled_season_data <= wet_threshold) + .where(~np.isnan(labelled_season_data)) + .groupby(labelled_season_data["seasons_starts"]) + .map(median_length_of_spells, "T", min_spell_length=dry_spell) + ) + wwc_units = "days" # 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 diff --git a/pepsico/proj_wwc/layout.py b/pepsico/proj_wwc/layout.py index 6c92f6d8..a3b88ecc 100644 --- a/pepsico/proj_wwc/layout.py +++ b/pepsico/proj_wwc/layout.py @@ -50,14 +50,10 @@ def app_layout(): "Tmin_10", "longest_dry_spell", "longest_wet_spell", - # "wet_day_persistence", - # "dry_day_persistence", - # "longest_dry_spell", - # "longest_wet_spell", "wet_day_persistence", "dry_day_persistence", - # "dry_spells_mean_length", - # "dry_spells_median_length", + "dry_spells_mean_length", + "dry_spells_median_length", ], labels=[ "Warm Nights", @@ -75,8 +71,8 @@ def app_layout(): "Longest Wet Spell", "Wet Day Persistence", "Dry Day Persistence", - # "Mean Dry Spells Length", - # "Median Dry Spells Length", + "Mean Dry Spells Length", + "Median Dry Spells Length", ], init=1, )), @@ -120,6 +116,16 @@ def app_layout(): width="5em", debounce=False, ), + "days ;", + "Dry Spell >=", + Number( + id="dryspell", + default=5, + min=0, + max=99, + width="5em", + debounce=False, + ), "days", ), Block("Season", @@ -252,6 +258,16 @@ def app_layout(): or equal / greather than a user-defined threshold. """ ]), + html.P([ + html.B( + "Mean/Median Dry Spells Length (dry_spells_mean/median_length):" + ),""" + Mean/Median of dry spells length in the season. A dry spell is + defined as a user-defined minimum consecutive number of dry + days. A dray day is defined as days where precipitation is + lesser or equal than a user-defined thredhold. + """ + ]), ), lou.map(GLOBAL_CONFIG["zoom"]), diff --git a/pepsico/proj_wwc/maproom.py b/pepsico/proj_wwc/maproom.py index ac9758f7..b7caaa07 100644 --- a/pepsico/proj_wwc/maproom.py +++ b/pepsico/proj_wwc/maproom.py @@ -115,7 +115,7 @@ def local_data( lat, lng, region, model, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): model = [model] if model != "Multi-Model-Average" else [ "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR","MRI-ESM2-0", "UKESM1-0-LL" @@ -161,7 +161,7 @@ def local_data( data_ds, start_day, start_month, end_day, end_month, ), variable, frost_threshold, wet_threshold, hot_threshold, - warm_nights_spell, + warm_nights_spell, dry_spell, ) return data_ds, error_msg @@ -229,12 +229,13 @@ def invalid_button(lat, lng, lat_min, lng_min, lat_max, lng_max): State("wet", "value"), State("hot", "value"), State("wms", "value"), + State("dryspell", "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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): lat = marker_pos[0] lng = marker_pos[1] @@ -246,11 +247,13 @@ def send_data_as_csv( wet_threshold = float(wet_threshold) hot_threshold = float(hot_threshold) warm_nights_spell = int(warm_nights_spell) + dry_spell = int(dry_spell) 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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, + warm_nights_spell, dry_spell, ) if error_msg == None : lng_units = "E" if (lng >= 0) else "W" @@ -286,12 +289,13 @@ def send_data_as_csv( State("wet", "value"), State("hot", "value"), State("wms", "value"), + State("dryspell", "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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): lat = marker_pos[0] lng = marker_pos[1] @@ -303,10 +307,12 @@ def local_plots( wet_threshold = float(wet_threshold) hot_threshold = float(hot_threshold) warm_nights_spell = int(warm_nights_spell) + dry_spell = int(dry_spell) data_ds, error_msg = local_data( lat, lng, region, model, variable, start_day, start_month, end_day, end_month, - frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, + warm_nights_spell, dry_spell, ) if error_msg != None : local_graph = pingrid.error_fig(error_msg) @@ -467,7 +473,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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): model = [model] if model != "Multi-Model-Average" else [ "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR","MRI-ESM2-0", "UKESM1-0-LL" @@ -485,7 +491,7 @@ def seasonal_change( start_day, start_month, end_day, end_month, ), variable, frost_threshold, wet_threshold, hot_threshold, - warm_nights_spell, + warm_nights_spell, dry_spell, ).mean(dim="T", keep_attrs=True) for m in model ], "M").mean("M", keep_attrs=True) data = xr.concat([ @@ -500,7 +506,7 @@ def seasonal_change( start_day, start_month, end_day, end_month, ), variable, frost_threshold, wet_threshold, hot_threshold, - warm_nights_spell, + warm_nights_spell, dry_spell, ).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) @@ -516,7 +522,8 @@ def map_attributes(data, variable): if data.name in ["tasmin", "tasmax"]: colorscale = CMAPS["temp_anomaly"] if variable in [ - "frost_days", "dry_days", "longest_dry_spell", "dry_day_persistence" + "frost_days", "dry_days", "longest_dry_spell", "dry_day_persistence", + "dry_spells_mean_length", "dry_spells_median_length", ]: colorscale = colorscale.reversed() map_amp = np.max(np.abs(data)).values @@ -546,12 +553,13 @@ def map_attributes(data, variable): State("wet", "value"), State("hot", "value"), State("wms", "value"), + State("dryspell", "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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): start_day = int(start_day) end_day = int(end_day) @@ -561,11 +569,13 @@ def draw_colorbar( wet_threshold = float(wet_threshold) hot_threshold = float(hot_threshold) warm_nights_spell = int(warm_nights_spell) + dry_spell = int(dry_spell) 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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, + warm_nights_spell, dry_spell, ) colorbar, min, max = map_attributes(data, variable) return ( @@ -594,12 +604,13 @@ def draw_colorbar( State("wet", "value"), State("hot", "value"), State("wms", "value"), + State("dryspell", "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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): try: send_alarm = False @@ -608,7 +619,7 @@ def make_map( 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}/{hot_threshold}/" - f"{warm_nights_spell}" + f"{warm_nights_spell}/{dry_spell}" ) except: url_str= "" @@ -625,7 +636,8 @@ def make_map( f"{TILE_PFX}///////" f"/////" f"////" - f"///" + f"////" + f"" ), endpoint=f"{config['core_path']}" ) @@ -633,7 +645,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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, ): start_day = int(start_day) end_day = int(end_day) @@ -643,11 +655,13 @@ def fcst_tiles(tz, tx, ty, wet_threshold = float(wet_threshold) hot_threshold = float(hot_threshold) warm_nights_spell = int(warm_nights_spell) + dry_spell = int(dry_spell) 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, hot_threshold, warm_nights_spell, + frost_threshold, wet_threshold, hot_threshold, + warm_nights_spell, dry_spell, ) ( data[select_var(variable)].attrs["colormap"],