From 356a94dff2aaae8c7febbec5c1f8a67e5b2a019e Mon Sep 17 00:00:00 2001 From: remic Date: Wed, 22 Apr 2026 11:39:02 -0400 Subject: [PATCH 1/5] options is deprecated --- pepsico/maproom_utilities.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pepsico/maproom_utilities.py b/pepsico/maproom_utilities.py index 10924d65..25c4d6e1 100644 --- a/pepsico/maproom_utilities.py +++ b/pepsico/maproom_utilities.py @@ -246,7 +246,7 @@ def make_adm_overlay( dlf.GeoJSON( id=border_id, data=adm_geojson, - options={ + style={ "fill": True, "color": adm_color, "weight": adm_weight, From fc4518fbcf1b2618c2fd33e7032112a405d546c3 Mon Sep 17 00:00:00 2001 From: remic Date: Wed, 22 Apr 2026 14:00:45 -0400 Subject: [PATCH 2/5] click_lat_lng is now clickData --- pepsico/maproom_utilities.py | 6 +++--- pepsico/proj_wwc/maproom.py | 5 ++++- pepsico/projections/maproom.py | 5 ++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pepsico/maproom_utilities.py b/pepsico/maproom_utilities.py index 25c4d6e1..28848756 100644 --- a/pepsico/maproom_utilities.py +++ b/pepsico/maproom_utilities.py @@ -303,7 +303,7 @@ def picked_location(data, initialization_cases, click_lat_lng, latitude, longitu spatial data of which longitude and latitude coordinates are X and Y initialization_cases: list[str] list of Input of which changes reinitialize the map - click_lat_lng: list[str] + click_lat_lng: dict dlf Input from clicking map (lat and lon) latitude: str Input from latitude pick a point control @@ -318,8 +318,8 @@ def picked_location(data, initialization_cases, click_lat_lng, latitude, longitu lng = data["X"][int(data["X"].size/2)].values else: if dash.ctx.triggered_id == "map": - lat = click_lat_lng[0] - lng = click_lat_lng[1] + lat = click_lat_lng["lat"] + lng = click_lat_lng["lng"] else: lat = latitude lng = longitude diff --git a/pepsico/proj_wwc/maproom.py b/pepsico/proj_wwc/maproom.py index 9bdab37c..5aebab51 100644 --- a/pepsico/proj_wwc/maproom.py +++ b/pepsico/proj_wwc/maproom.py @@ -63,13 +63,16 @@ def initialize(region, path): Output("lat_input", "value"), Output("lng_input", "value"), Input("submit_lat_lng","n_clicks"), - Input("map", "click_lat_lng"), + Input("map", "clickData"), Input("region", "value"), State("lat_input", "value"), State("lng_input", "value"), ) def pick_location(n_clicks, click_lat_lng, region, latitude, longitude): # Reading + click_lat_lng = ( + click_lat_lng["latlng"] if click_lat_lng is not None else None + ) scenario = "ssp126" model = "GFDL-ESM4" variable = "pr" diff --git a/pepsico/projections/maproom.py b/pepsico/projections/maproom.py index 2a9d6107..c5deb6dd 100644 --- a/pepsico/projections/maproom.py +++ b/pepsico/projections/maproom.py @@ -63,13 +63,16 @@ def initialize(region, path): Output("lat_input", "value"), Output("lng_input", "value"), Input("submit_lat_lng","n_clicks"), - Input("map", "click_lat_lng"), + Input("map", "clickData"), Input("region", "value"), State("lat_input", "value"), State("lng_input", "value"), ) def pick_location(n_clicks, click_lat_lng, region, latitude, longitude): # Reading + click_lat_lng = ( + click_lat_lng["latlng"] if click_lat_lng is not None else None + ) scenario = "ssp126" model = "GFDL-ESM4" variable = "pr" From 150e839007f51ec177f183088f043886eb4c9a1e Mon Sep 17 00:00:00 2001 From: remic Date: Thu, 23 Apr 2026 09:10:15 -0400 Subject: [PATCH 3/5] fixing memory issues --- pepsico/app_calc.py | 47 +++++---- pepsico/proj_wwc/maproom.py | 183 +++++++++++++++++++----------------- 2 files changed, 127 insertions(+), 103 deletions(-) diff --git a/pepsico/app_calc.py b/pepsico/app_calc.py index 169a54b5..f7ecb461 100644 --- a/pepsico/app_calc.py +++ b/pepsico/app_calc.py @@ -1,6 +1,7 @@ import xarray as xr import numpy as np from scipy.stats import norm +import pingrid #This is what we should need for the app @@ -22,30 +23,40 @@ def read_data( - scenario, model, variable, region, time_res="monthly", unit_convert=False + scenario, model, variable, region, time_res="monthly", unit_convert=False, + time_dim=True, years=None, ): - if region == "US-CA": - xslice = slice(-154, -45) - yslice = slice(60, 15) - elif region == "SAMER": - xslice = slice(-86, -34) - yslice = slice(16, -60) - elif region == "SASIA": - xslice = slice(59, 94) - yslice = slice(42, 7) - elif region == "Thailand": - xslice = slice(85, 115) - yslice = slice(28, 2) data = xr.open_zarr( f'/Data/data24/ISIMIP3b/InputData/climate/atmosphere/bias-adjusted/global' f'/{time_res}/{scenario}/{model}/zarr/{variable}' - )[variable].sel(X=xslice, Y=yslice) + )[variable] + if isinstance(region, tuple): + data = pingrid.sel_snap(data, region[0], region[1]) + else: + if region == "US-CA": + xslice = slice(-154, -45) + yslice = slice(60, 15) + elif region == "SAMER": + xslice = slice(-86, -34) + yslice = slice(16, -60) + elif region == "SASIA": + xslice = slice(59, 94) + yslice = slice(42, 7) + elif region == "Thailand": + xslice = slice(85, 115) + yslice = slice(28, 2) + data = data.sel(X=xslice, Y=yslice) + #Turns out that some models are centered on noon + if time_dim: + if years is not None : + data = data.sel(T=years) + if time_res == "daily" : + if data["T"][0].dt.hour == 12 : + data = data.assign_coords({"T" : data["T"] - np.timedelta64(12, "h")}) + else: + data = data.isel(T=0) if unit_convert : data = unit_conversion(data) - #Turns out that some models are centered on noon - if time_res == "daily" : - if data["T"][0].dt.hour == 12 : - data = data.assign_coords({"T" : data["T"] - np.timedelta64(12, "h")}) return data diff --git a/pepsico/proj_wwc/maproom.py b/pepsico/proj_wwc/maproom.py index 5aebab51..d859c5df 100644 --- a/pepsico/proj_wwc/maproom.py +++ b/pepsico/proj_wwc/maproom.py @@ -53,7 +53,9 @@ def initialize(region, path): scenario = "ssp126" model = "GFDL-ESM4" variable = "pr" - data = ac.read_data(scenario, model, variable, region, time_res="daily") + data = ac.read_data( + scenario, model, variable, region, time_res="daily", time_dim=False + ) zoom = {"US-CA": 4, "Thailand": 5} return mru.initialize_map(data) + (zoom[region],) @@ -76,7 +78,9 @@ def pick_location(n_clicks, click_lat_lng, region, latitude, longitude): scenario = "ssp126" model = "GFDL-ESM4" variable = "pr" - data = ac.read_data(scenario, model, variable, region, time_res="daily") + data = ac.read_data( + scenario, model, variable, region, time_res="daily", time_dim=False + ) initialization_cases = ["region"] return mru.picked_location( data, initialization_cases, click_lat_lng, latitude, longitude @@ -115,7 +119,7 @@ def select_var(variable): def local_data( - lat, lng, region, + lat, lng, model, variable, start_day, start_month, end_day, end_month, frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, @@ -124,6 +128,7 @@ def local_data( "GFDL-ESM4", "IPSL-CM6A-LR", "MPI-ESM1-2-HR","MRI-ESM2-0", "UKESM1-0-LL" ] data_var = select_var(variable) + region = (lat, lng) data_ds = xr.concat([xr.Dataset({ "histo" : ac.read_data( "historical", m, data_var, region, @@ -153,11 +158,6 @@ def local_data( #would mean something happened to that data data_ds = missing_ds error_msg="Data missing for this model or variable" - try: - data_ds = pingrid.sel_snap(data_ds, lat, lng) - except KeyError: - data_ds = missing_ds - error_msg="Grid box out of data domain" if error_msg == None : data_ds = ac.seasonal_wwc( ac.daily_tobegroupedby_season( @@ -253,7 +253,7 @@ def send_data_as_csv( dry_spell = int(dry_spell) model = "Multi-Model-Average" data_ds, error_msg = local_data( - lat, lng, region, model, variable, + lat, lng, model, variable, start_day, start_month, end_day, end_month, frost_threshold, wet_threshold, hot_threshold, warm_nights_spell, dry_spell, @@ -302,78 +302,93 @@ def local_plots( ): lat = marker_pos[0] lng = marker_pos[1] - start_day = int(start_day) - end_day = int(end_day) - start_month = ac.strftimeb2int(start_month) - end_month = ac.strftimeb2int(end_month) - frost_threshold = float(frost_threshold) - 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, dry_spell, - ) - if error_msg != None : - local_graph = pingrid.error_fig(error_msg) - else : - if (end_month < start_month) : - start_format = "%d %b %Y - " - else: - start_format = "%d %b-" - local_graph = pgo.Figure() - data_color = { - "histo": "blue", "picontrol": "green", - "ssp126": "yellow", "ssp370": "orange", "ssp585": "red", - } - lng_units = "˚E" if (lng >= 0) else "˚W" - lat_units = "˚N" if (lat >= 0) else "˚S" - for var in data_ds.data_vars: - local_graph.add_trace(plot_ts( - data_ds[var].mean("M", keep_attrs=True), var, data_color[var], - start_format, data_ds[var].attrs["units"] - )) - add_period_shape( - local_graph, - data_ds, - start_year_ref, - end_year_ref, - "blue", - "RoyalBlue", - "reference period", - ) - add_period_shape( - local_graph, - data_ds, - start_year, - end_year, - "LightPink", - "Crimson", - "projected period", + if region == "US-CA": + xslice = (-154, -45) + yslice = (60, 15) + elif region == "SAMER": + xslice = (-86, -34) + yslice = (16, -60) + elif region == "SASIA": + xslice = (59, 94) + yslice = (42, 7) + elif region == "Thailand": + xslice = (85, 115) + yslice = (28, 2) + if lat > yslice[0] or lat < yslice[1] or lng < xslice[0] or lng > xslice[1] : + local_graph = pingrid.error_fig(error_msg="Grid box out of data domain") + else: + start_day = int(start_day) + end_day = int(end_day) + start_month = ac.strftimeb2int(start_month) + end_month = ac.strftimeb2int(end_month) + frost_threshold = float(frost_threshold) + 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, model, variable, + start_day, start_month, end_day, end_month, + frost_threshold, wet_threshold, hot_threshold, + warm_nights_spell, dry_spell, ) - local_graph.update_layout( - xaxis_title="Time", - yaxis_title=( - # Compared to the monthly case, I presume that groupby dropped - # the long_name, which is fine since it's indeed transformed. Can - # consider resetting it at some point in the calculation - #f'{data_ds["histo"].attrs["long_name"]} ' - f'({data_ds["histo"].attrs["units"]})' - ), - title={ - "text": ( - f'{data_ds["histo"]["T"].dt.strftime("%d %b")[0].values}-' - f'{data_ds["histo"]["seasons_ends"].dt.strftime("%d %b")[0].values}' - f' {variable} from model {model} ' - f'at ({abs(lat)}{lat_units}, {abs(lng)}{lng_units})' + if error_msg != None : + local_graph = pingrid.error_fig(error_msg) + else: + if (end_month < start_month) : + start_format = "%d %b %Y - " + else: + start_format = "%d %b-" + local_graph = pgo.Figure() + data_color = { + "histo": "blue", "picontrol": "green", + "ssp126": "yellow", "ssp370": "orange", "ssp585": "red", + } + lng_units = "˚E" if (lng >= 0) else "˚W" + lat_units = "˚N" if (lat >= 0) else "˚S" + for var in data_ds.data_vars: + local_graph.add_trace(plot_ts( + data_ds[var].mean("M", keep_attrs=True), var, data_color[var], + start_format, data_ds[var].attrs["units"] + )) + add_period_shape( + local_graph, + data_ds, + start_year_ref, + end_year_ref, + "blue", + "RoyalBlue", + "reference period", + ) + add_period_shape( + local_graph, + data_ds, + start_year, + end_year, + "LightPink", + "Crimson", + "projected period", + ) + local_graph.update_layout( + xaxis_title="Time", + yaxis_title=( + # Compared to the monthly case, I presume that groupby dropped + # the long_name, which is fine since it's indeed transformed. Can + # consider resetting it at some point in the calculation + #f'{data_ds["histo"].attrs["long_name"]} ' + f'({data_ds["histo"].attrs["units"]})' ), - "font": dict(size=14), - }, - margin=dict(l=30, r=30, t=30, b=30), - ) + title={ + "text": ( + f'{data_ds["histo"]["T"].dt.strftime("%d %b")[0].values}-' + f'{data_ds["histo"]["seasons_ends"].dt.strftime("%d %b")[0].values}' + f' {variable} from model {model} ' + f'at ({abs(lat)}{lat_units}, {abs(lng)}{lng_units})' + ), + "font": dict(size=14), + }, + margin=dict(l=30, r=30, t=30, b=30), + ) return local_graph @@ -487,9 +502,8 @@ def seasonal_change( ac.daily_tobegroupedby_season( ac.read_data( "historical", m, data_var, region, - time_res="daily", unit_convert=True - ).sel( - T=slice(str(start_year_ref), str(end_year_ref)) + time_res="daily", unit_convert=True, + years=slice(str(start_year_ref), str(end_year_ref)), ).to_dataset(), start_day, start_month, end_day, end_month, ), @@ -502,9 +516,8 @@ def seasonal_change( ac.daily_tobegroupedby_season( ac.read_data( scenario, m, data_var, region, - time_res="daily", unit_convert=True - ).sel( - T=slice(str(start_year), str(end_year)) + time_res="daily", unit_convert=True, + years=slice(str(start_year), str(end_year)), ).to_dataset(), start_day, start_month, end_day, end_month, ), From 718c5b68a7e6e6049aa054580107f8da965fbfed Mon Sep 17 00:00:00 2001 From: remic Date: Thu, 23 Apr 2026 09:10:41 -0400 Subject: [PATCH 4/5] fixing error_fig --- pingrid/impl.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pingrid/impl.py b/pingrid/impl.py index 2eddb839..8d42f099 100644 --- a/pingrid/impl.py +++ b/pingrid/impl.py @@ -94,14 +94,12 @@ def sel_snap(spatial_array, lat, lng, dim_y="Y", dim_x="X"): def error_fig(error_msg="error"): return pgo.Figure().add_annotation( - x=2, - y=2, + xref="paper", + yref="paper", text=error_msg, font=dict(family="sans serif", size=30, color="crimson"), showarrow=False, - yshift=10, - xshift=60, - ) + ).update_xaxes(visible=False).update_yaxes(visible=False) FuncInterp2d = Callable[[Iterable[np.ndarray]], np.ndarray] From f98c66120e2c117babe3c6f4145fb3a5a6baa685 Mon Sep 17 00:00:00 2001 From: remic Date: Thu, 23 Apr 2026 10:12:36 -0400 Subject: [PATCH 5/5] center and zoom now updates via viewport --- pepsico/layout_utilities.py | 4 ++-- pepsico/maproom_utilities.py | 10 ++++++---- pepsico/proj_wwc/maproom.py | 5 ++--- pepsico/projections/maproom.py | 5 ++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pepsico/layout_utilities.py b/pepsico/layout_utilities.py index 0e0c28e2..48c4c66b 100644 --- a/pepsico/layout_utilities.py +++ b/pepsico/layout_utilities.py @@ -122,7 +122,7 @@ def map( "margin-top":"3px", "margin-bottom":"3px", }, ), type="dot"), - dcc.Loading(dlf.Map( + dcc.Loading(dlf.MapContainer( [ dlf.LayersControl( id="layers_control", position=layers_control_position @@ -151,7 +151,7 @@ def map( ), ], id="map", - center=(0,0), + center=[0, 0], zoom=default_zoom, style={"width": "100%", "height": "50vh"}, ), type="dot"), diff --git a/pepsico/maproom_utilities.py b/pepsico/maproom_utilities.py index 28848756..be6dbadb 100644 --- a/pepsico/maproom_utilities.py +++ b/pepsico/maproom_utilities.py @@ -259,7 +259,7 @@ def make_adm_overlay( ) -def initialize_map(data): +def initialize_map(data, zoom): """ Map initialization based on `data` spatial domain @@ -267,6 +267,8 @@ def initialize_map(data): ---------- data: xr.DataArray spatial data of which longitude and latitude coordinates are X and Y + zoom: int + dash-leaglet zoom value Returns ------- @@ -275,8 +277,8 @@ def initialize_map(data): control, center of the map coordinates values as a list """ center_of_the_map = [ - ((data["Y"][int(data["Y"].size/2)].values)), - ((data["X"][int(data["X"].size/2)].values)), + data["Y"][int(data["Y"].size/2)].values.item(), + data["X"][int(data["X"].size/2)].values.item(), ] lat_res = (data["Y"][0 ]- data["Y"][1]).values lat_min = str((data["Y"][-1] - lat_res/2).values) @@ -289,7 +291,7 @@ def initialize_map(data): return ( lat_min, lat_max, lat_label, lon_min, lon_max, lon_label, - center_of_the_map + {"center": center_of_the_map, "zoom": zoom, "transition": "flyTo"}, ) diff --git a/pepsico/proj_wwc/maproom.py b/pepsico/proj_wwc/maproom.py index d859c5df..59e3d5d5 100644 --- a/pepsico/proj_wwc/maproom.py +++ b/pepsico/proj_wwc/maproom.py @@ -44,8 +44,7 @@ def register(FLASK, config): Output("lng_input", "min"), Output("lng_input", "max"), Output("lng_input_tooltip", "children"), - Output("map", "center"), - Output("map", "zoom"), + Output("map", "viewport"), Input("region", "value"), Input("location", "pathname"), ) @@ -57,7 +56,7 @@ def initialize(region, path): scenario, model, variable, region, time_res="daily", time_dim=False ) zoom = {"US-CA": 4, "Thailand": 5} - return mru.initialize_map(data) + (zoom[region],) + return mru.initialize_map(data, zoom[region]) @APP.callback( diff --git a/pepsico/projections/maproom.py b/pepsico/projections/maproom.py index c5deb6dd..3d35d99b 100644 --- a/pepsico/projections/maproom.py +++ b/pepsico/projections/maproom.py @@ -44,8 +44,7 @@ def register(FLASK, config): Output("lng_input", "min"), Output("lng_input", "max"), Output("lng_input_tooltip", "children"), - Output("map", "center"), - Output("map", "zoom"), + Output("map", "viewport"), Input("region", "value"), Input("location", "pathname"), ) @@ -55,7 +54,7 @@ def initialize(region, path): variable = "pr" data = ac.read_data(scenario, model, variable, region) zoom = {"SAMER": 3, "US-CA": 4, "SASIA": 4, "Thailand": 5} - return mru.initialize_map(data) + (zoom[region],) + return mru.initialize_map(data, zoom[region]) @APP.callback(