1+ import math
12from typing import Any
23
34import altair as alt
1011import xarray as xr
1112
1213from chartlets import Component , Input , State , Output
13- from chartlets .components import Box , Button , Typography , Select , VegaChart
14+ from chartlets .components import (
15+ Box ,
16+ Button ,
17+ Typography ,
18+ VegaChart ,
19+ Radio ,
20+ RadioGroup ,
21+ )
1422
1523from xcube .webapi .viewer .contrib import Panel , get_dataset
1624from xcube .server .api import Context
2129panel = Panel (__name__ , title = "Spectrum View (Demo)" , icon = "light" , position = 4 )
2230
2331
32+ class DataManager :
33+ def __init__ (self ):
34+ self .all_data = pd .DataFrame (
35+ columns = ["places" , "variable" , "reflectance" , "wavelength" ]
36+ )
37+ self .added_places_stack = []
38+
39+ def add_place_data (self , new_data : pd .DataFrame ):
40+ if self ._is_duplicate (new_data ):
41+ print ("Duplicate data detected. Not adding." )
42+ print ("self.all_data" , self .all_data ["places" ].unique ())
43+ print ("new_data" , new_data ["places" ].unique ())
44+ return
45+
46+ place_names = new_data ["places" ].unique ()
47+ self .all_data = pd .concat ([self .all_data , new_data ], ignore_index = True )
48+ self .added_places_stack .append (place_names )
49+
50+ def remove_last_added_place (self ):
51+ if self .added_places_stack :
52+ last_places = self .added_places_stack .pop ()
53+ self .all_data = self .all_data [~ self .all_data ["places" ].isin (last_places )]
54+
55+ def _is_duplicate (self , new_data : pd .DataFrame ) -> bool :
56+ merged = new_data .merge (self .all_data , how = "left" , indicator = True )
57+ return (merged ["_merge" ] == "both" ).all ()
58+
59+ def delete_all_data (self ):
60+ self .all_data = pd .DataFrame (
61+ columns = ["places" , "variable" , "reflectance" , "wavelength" ]
62+ )
63+ self .added_places_stack = []
64+
65+
66+ manager = DataManager ()
67+
68+
2469@panel .layout (
2570 State ("@app" , "selectedDatasetId" ),
2671 State ("@app" , "selectedTimeLabel" ),
@@ -50,6 +95,15 @@ def render_panel(
5095 text = f"{ dataset_id } "
5196 place_text = Typography (id = "text" , children = [text ], align = "left" )
5297
98+ active_radio = Radio (id = "active_radio" , value = "active" , label = "Active Mode" )
99+ save_radio = Radio (id = "save_radio" , value = "save" , label = "Save Mode" )
100+
101+ exploration_radio_group = RadioGroup (
102+ id = "exploration_radio_group" ,
103+ children = [active_radio , save_radio ],
104+ label = "Exploration Mode" ,
105+ )
106+
53107 # Ideas
54108 # 1. Adding radio-button for two modes:
55109 # update mode - reactive to changes to dataset/places/time/variables
@@ -74,7 +128,7 @@ def render_panel(
74128 add_button = Button (id = "add_button" , text = "Add" , style = {"maxWidth" : 100 })
75129
76130 controls = Box (
77- children = [add_button ],
131+ children = [exploration_radio_group , add_button ],
78132 style = {
79133 "display" : "flex" ,
80134 "flexDirection" : "row" ,
@@ -158,14 +212,20 @@ def get_spectra(
158212
159213 variables = list (selected_values .keys ())
160214 values = [selected_values [var ]["data" ] for var in variables ]
215+ print ("reflectance values::" , values )
216+ cleaned_values = [
217+ 0 if isinstance (x , float ) and math .isnan (x ) else x for x in values
218+ ]
219+ print ("reflectance values after::" , cleaned_values )
220+
161221 wavelengths = [
162222 dataset_place [var ].attrs .get ("wavelength" , None ) for var in variables
163223 ]
164224
165225 res = {
166226 "places" : place ,
167227 "variable" : variables ,
168- "reflectance" : values ,
228+ "reflectance" : cleaned_values ,
169229 "wavelength" : wavelengths ,
170230 }
171231
@@ -197,6 +257,7 @@ def update_text(
197257 Input ("@app" , "selectedTimeLabel" ),
198258 Input ("@app" , "selectedPlaceGeometry" ),
199259 State ("@app" , "selectedPlaceGroup" ),
260+ State ("exploration_radio_group" , "value" ),
200261 Input ("add_button" , "clicked" ),
201262 Input ("plot" , "chart" ),
202263 Output ("plot" , "chart" ),
@@ -208,11 +269,13 @@ def update_plot(
208269 time_label : str | None = None ,
209270 place_geo : dict [str , Any ] | None = None ,
210271 place_group : list [dict [str , Any ]] | None = None ,
272+ exploration_radio_group : bool | None = None ,
211273 _clicked : bool | None = None ,
212- chart = None ,
274+ previous_chart : bool | None = None ,
213275) -> tuple [alt .Chart | None , str ]:
214- print ("clicked" , _clicked )
215- print ("chart" , chart )
276+ print ("exploration_radio_group" , exploration_radio_group )
277+ if exploration_radio_group is None :
278+ return None , "Missing exploration mode choice"
216279 dataset = get_dataset (ctx , dataset_id )
217280 has_point = any (
218281 feature .get ("geometry" , {}).get ("type" ) == "Point"
@@ -228,7 +291,7 @@ def update_plot(
228291
229292 if label is None :
230293 return None , "There is no label for the selected point"
231-
294+ print ( "place_geo" , place_geo )
232295 if place_geo .get ("type" ) == "Point" :
233296 place_group = gpd .GeoDataFrame (
234297 [
@@ -253,30 +316,54 @@ def update_plot(
253316 if source is None :
254317 return None , "No reflectances found in Variables"
255318
256- chart = (
257- alt .Chart (source )
258- .mark_bar (point = True )
259- .encode (
260- x = "wavelength:Q" ,
261- y = "reflectance:Q" ,
262- color = "places:N" ,
263- tooltip = ["variable" , "wavelength" , "reflectance" ],
264- )
265- ).properties (width = "container" , height = "container" )
319+ if previous_chart is None :
320+ manager .delete_all_data ()
321+
322+ if exploration_radio_group == "active" :
323+ manager .remove_last_added_place ()
324+ manager .add_place_data (source )
325+ chart = (
326+ alt .Chart (manager .all_data )
327+ .mark_bar ()
328+ .encode (
329+ x = "wavelength:N" ,
330+ y = "reflectance:Q" ,
331+ xOffset = "places:N" ,
332+ color = "places:N" ,
333+ tooltip = ["variable" , "wavelength" , "reflectance" ],
334+ )
335+ ).properties (width = "container" , height = "container" )
336+ else :
337+ manager .add_place_data (source )
338+ print ("in save else case::" , manager .all_data ["places" ].unique ())
339+ chart = (
340+ alt .Chart (manager .all_data )
341+ .mark_bar ()
342+ .encode (
343+ x = "wavelength:N" ,
344+ y = "reflectance:Q" ,
345+ xOffset = "places:N" ,
346+ color = "places:N" ,
347+ tooltip = ["variable" , "wavelength" , "reflectance" ],
348+ )
349+ ).properties (width = "container" , height = "container" )
350+ print ("chart should be ready" , chart )
266351
267352 return chart , ""
268353
269354
270355@panel .callback (
271356 Input ("@app" , "selectedPlaceGeometry" ),
357+ Input ("exploration_radio_group" , "value" ),
272358 Output ("add_button" , "disabled" ),
273359)
274360def set_button_disablement (
275361 _ctx : Context ,
276362 place_geometry : str | None = None ,
363+ exploration_radio_group : str | None = None ,
277364) -> bool :
278365 print ("in set_button_disablement" , place_geometry )
279- return not place_geometry
366+ return not place_geometry and exploration_radio_group != "save"
280367
281368
282369def find_selected_point_label (features_data , target_point ):
0 commit comments