@@ -120,6 +120,8 @@ class DataUI(param.Parameterized):
120
120
show_map_markers = param .Boolean (
121
121
default = False , doc = "Show map markers for selected category"
122
122
)
123
+ map_default_span = param .Number (default = 15000 , doc = "Default span for map zoom" )
124
+
123
125
query = param .String (
124
126
default = "" ,
125
127
doc = 'Query to filter stations. See <a href="https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.query.html">Pandas Query</a> for details. E.g. max_year <= 2023' ,
@@ -146,6 +148,10 @@ def __init__(
146
148
if isinstance (self .dfcat , gpd .GeoDataFrame ):
147
149
self .tmap = gv .tile_sources .CartoLight ()
148
150
self .build_map_of_features (self .dfmapcat , crs = self .crs )
151
+ if hasattr (self , "station_select" ):
152
+ self .station_select .source = self .map_features
153
+ else :
154
+ self .station_select = streams .Selection1D (source = self .map_features )
149
155
else :
150
156
warnings .warn (
151
157
"No geolocation data found in catalog. Not displaying map of stations."
@@ -215,10 +221,6 @@ def build_map_of_features(self, dfmap, crs):
215
221
self .map_features = self .map_features .opts (
216
222
active_tools = ["wheel_zoom" ], responsive = True
217
223
)
218
- if hasattr (self , "station_select" ):
219
- self .station_select .source = self .map_features
220
- else :
221
- self .station_select = streams .Selection1D (source = self .map_features )
222
224
return self .map_features
223
225
224
226
def update_map_features (
@@ -229,6 +231,7 @@ def update_map_features(
229
231
marker_by ,
230
232
query ,
231
233
filters ,
234
+ selection ,
232
235
):
233
236
query = query .strip ()
234
237
dfs = self ._get_map_catalog ()
@@ -244,6 +247,11 @@ def update_map_features(
244
247
]
245
248
else :
246
249
dfs = dfs .iloc [self .display_table .current_view .index ]
250
+ merged_view = self .display_table .selected_dataframe .merge (
251
+ self .display_table .current_view .reset_index (drop = True ).reset_index (),
252
+ how = "inner" ,
253
+ )
254
+ current_selection = merged_view ["index" ].to_list ()
247
255
248
256
try :
249
257
if len (query ) > 0 :
@@ -257,7 +265,6 @@ def update_map_features(
257
265
self .map_color_category = color_by
258
266
self .show_map_colors = show_color_by
259
267
self .build_map_of_features (dfs , self .crs )
260
- self .map_features .data = dfs
261
268
if isinstance (self .map_features , gv .Points ):
262
269
if show_marker_by :
263
270
self .map_features = self .map_features .opts (
@@ -267,12 +274,13 @@ def update_map_features(
267
274
)
268
275
else :
269
276
self .map_features = self .map_features .opts (marker = "circle" )
270
- return self .tmap * self .map_features .opts (default_span = 15000 )
277
+ self .map_features = self .map_features .opts (
278
+ default_span = self .map_default_span , # for max zoom this is the default span in meters
279
+ selected = current_selection ,
280
+ )
281
+ return self .map_features
271
282
272
- def show_data_catalog (self , index = slice (None )):
273
- # called when map selects stations
274
- if index == []:
275
- index = slice (None )
283
+ def select_data_catalog (self , index = []):
276
284
# select rows from self.dfcat where station_id is in dfs station_ids
277
285
if self .station_id_column and self .station_id_column in self .dfcat .columns :
278
286
dfs = (
@@ -282,24 +290,19 @@ def show_data_catalog(self, index=slice(None)):
282
290
.first ()
283
291
.reset_index ()
284
292
)
285
- dfs = self .dfcat [
293
+ selected_indices = self .dfcat [
286
294
self .dfcat [self .station_id_column ].isin (dfs [self .station_id_column ])
287
- ]
288
- else :
289
- dfs = self .dfcat .iloc [index ]
290
- dfs = dfs [self .dataui_manager .get_table_columns ()]
291
- # return a UI with controls to plot and show data
292
- return self .update_data_table (dfs )
293
-
294
- def update_data_table (self , dfs ):
295
- if not hasattr (self , "display_table" ):
296
- print ("Warning: display_table not found" )
295
+ ].index .to_list ()
297
296
else :
298
- self .display_table .value = dfs
299
- return self .display_table
297
+ dfs = self .map_features .dframe ().iloc [index ]
298
+ selected_indices = self .dfcat .reset_index ().merge (dfs )["index" ].to_list ()
299
+ self .display_table .param .set_param (
300
+ selection = selected_indices
301
+ ) # set the selection in the table without triggering the callback
300
302
301
303
def create_data_table (self , dfs ):
302
304
column_width_map = self .dataui_manager .get_table_column_width_map ()
305
+ hidden_columns = set (dfs .columns ) - set (column_width_map .keys ())
303
306
self .display_table = pn .widgets .Tabulator (
304
307
dfs ,
305
308
disabled = True ,
@@ -308,6 +311,7 @@ def create_data_table(self, dfs):
308
311
sizing_mode = "stretch_width" ,
309
312
header_filters = self .dataui_manager .get_table_filters (),
310
313
page_size = 200 ,
314
+ hidden_columns = list (hidden_columns ),
311
315
)
312
316
313
317
self .plot_button = pn .widgets .Button (
@@ -328,22 +332,15 @@ def create_data_table(self, dfs):
328
332
self .download_button ,
329
333
pn .layout .HSpacer (),
330
334
)
331
- if hasattr (self , "station_select" ):
332
- show_data_catalog_bound = pn .bind (
333
- self .show_data_catalog , index = self .station_select .param .index
334
- )
335
- else :
336
- show_data_catalog_bound = pn .bind (self .show_data_catalog )
337
335
gspec [0 , 0 :5 ] = self .table_panel
338
- gspec [1 :5 , 0 :10 ] = fullscreen .FullScreen (pn .Row (show_data_catalog_bound ))
336
+ gspec [1 :5 , 0 :10 ] = fullscreen .FullScreen (pn .Row (self . display_table ))
339
337
gspec [6 :15 , 0 :10 ] = fullscreen .FullScreen (self .plots_panel )
340
338
return gspec
341
339
342
340
def update_plots (self , event ):
343
341
try :
344
342
self .plots_panel .loading = True
345
343
dfselected = self .display_table .value .iloc [self .display_table .selection ]
346
- # self.update_map_zoom(event)
347
344
plot_panel = self .dataui_manager .create_panel (dfselected )
348
345
if isinstance (self .plots_panel .objects [0 ], pn .Tabs ):
349
346
tabs = self .plots_panel .objects [0 ]
@@ -434,7 +431,7 @@ def create_view(self):
434
431
self .param .map_marker_category ,
435
432
self .param .query ,
436
433
)
437
- self .map_function = pn . panel (
434
+ self .map_function = hv . DynamicMap (
438
435
pn .bind (
439
436
self .update_map_features ,
440
437
show_color_by = self .param .show_map_colors ,
@@ -443,15 +440,18 @@ def create_view(self):
443
440
marker_by = self .param .map_marker_category ,
444
441
query = self .param .query ,
445
442
filters = self .display_table .param .filters ,
443
+ selection = self .display_table .param .selection ,
446
444
)
447
445
)
446
+ self .station_select .source = self .map_function
447
+ self .station_select .param .watch_values (self .select_data_catalog , "index" )
448
448
map_tooltip = pn .widgets .TooltipIcon (
449
449
value = """Map of geographical features. Click on a feature to see data available in the table. <br/>
450
450
See <a href="https://docs.bokeh.org/en/latest/docs/user_guide/interaction/tools.html">Bokeh Tools</a> for toolbar operation"""
451
451
)
452
452
map_view = fullscreen .FullScreen (
453
453
pn .Column (
454
- self .map_function ,
454
+ self .tmap * self . map_function ,
455
455
map_tooltip ,
456
456
min_width = 450 ,
457
457
min_height = 550 ,
0 commit comments