Skip to content

Commit d7d6315

Browse files
committed
Port selection handlers to use widgets where possible. Add LLMSummary for general LLMs.
1 parent cf83b4c commit d7d6315

8 files changed

Lines changed: 1136 additions & 551 deletions

File tree

datamapplot/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
DisplaySample,
3030
WordCloud,
3131
CohereSummary,
32+
LLMSummary,
3233
TagSelection,
3334
DataTable,
3435
ExportSelection,
@@ -71,6 +72,7 @@
7172
"DisplaySample",
7273
"WordCloud",
7374
"CohereSummary",
75+
"LLMSummary",
7476
"TagSelection",
7577
"DataTable",
7678
"ExportSelection",

datamapplot/interactive_helpers.py

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2686,50 +2686,49 @@ def prepare_selection_handler(selection_handler, custom_html, custom_js, custom_
26862686
Returns
26872687
-------
26882688
tuple
2689-
(custom_html, custom_js, custom_css) with handler content merged.
2689+
(custom_html, custom_js, custom_css, handler_widgets) with handler
2690+
content merged. ``handler_widgets`` is a list of widget instances
2691+
owned by the handlers (may be empty).
26902692
"""
2691-
if selection_handler is None:
2692-
return custom_html, custom_js, custom_css
2693+
handler_widgets = []
26932694

2694-
if isinstance(selection_handler, Iterable) and not isinstance(
2695-
selection_handler, SelectionHandlerBase
2696-
):
2697-
for handler in selection_handler:
2698-
if custom_html is None:
2699-
custom_html = handler.html
2700-
else:
2701-
custom_html += handler.html
2702-
2703-
if custom_js is None:
2704-
custom_js = handler.javascript
2705-
else:
2706-
custom_js += handler.javascript
2695+
if selection_handler is None:
2696+
return custom_html, custom_js, custom_css, handler_widgets
27072697

2708-
if custom_css is None:
2709-
custom_css = handler.css
2710-
else:
2711-
custom_css += handler.css
2712-
elif isinstance(selection_handler, SelectionHandlerBase):
2698+
def _process_one(handler):
2699+
nonlocal custom_html, custom_js, custom_css
27132700
if custom_html is None:
2714-
custom_html = selection_handler.html
2701+
custom_html = handler.html
27152702
else:
2716-
custom_html += selection_handler.html
2703+
custom_html += handler.html
27172704

27182705
if custom_js is None:
2719-
custom_js = selection_handler.javascript
2706+
custom_js = handler.javascript
27202707
else:
2721-
custom_js += selection_handler.javascript
2708+
custom_js += handler.javascript
27222709

27232710
if custom_css is None:
2724-
custom_css = selection_handler.css
2711+
custom_css = handler.css
27252712
else:
2726-
custom_css += selection_handler.css
2713+
custom_css += handler.css
2714+
2715+
# Collect any widgets owned by this handler
2716+
if hasattr(handler, "widgets"):
2717+
handler_widgets.extend(handler.widgets)
2718+
2719+
if isinstance(selection_handler, Iterable) and not isinstance(
2720+
selection_handler, SelectionHandlerBase
2721+
):
2722+
for handler in selection_handler:
2723+
_process_one(handler)
2724+
elif isinstance(selection_handler, SelectionHandlerBase):
2725+
_process_one(selection_handler)
27272726
else:
27282727
raise ValueError(
27292728
"selection_handler must be an instance of SelectionHandlerBase or an iterable of SelectionHandlerBase instances"
27302729
)
27312730

2732-
return custom_html, custom_js, custom_css
2731+
return custom_html, custom_js, custom_css, handler_widgets
27332732

27342733

27352734
def prepare_dynamic_tooltip(dynamic_tooltip):

datamapplot/interactive_rendering.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,22 @@
228228
]
229229

230230

231+
def _collect_handler_widgets(selection_handler):
232+
"""Return a flat list of widgets owned by the given selection handler(s)."""
233+
widgets = []
234+
if selection_handler is None:
235+
return widgets
236+
handlers = (
237+
selection_handler
238+
if isinstance(selection_handler, (list, tuple))
239+
else [selection_handler]
240+
)
241+
for handler in handlers:
242+
if hasattr(handler, "widgets"):
243+
widgets.extend(handler.widgets)
244+
return widgets
245+
246+
231247
def _get_jinja_env():
232248
"""Get a Jinja2 Environment configured with template directories.
233249
@@ -1254,6 +1270,7 @@ def render_html(
12541270
widgets is not None
12551271
or widget_layout is not None
12561272
or default_widget_config is not None
1273+
or len(_collect_handler_widgets(selection_handler)) > 0
12571274
)
12581275

12591276
# Initialize widget containers
@@ -1323,6 +1340,12 @@ def render_html(
13231340
logo_width=logo_width,
13241341
)
13251342

1343+
# Collect widgets owned by selection handlers and add them to
1344+
# the widget list *before* grouping so that drawer enablement
1345+
# and placement are handled through the normal widget pipeline.
1346+
handler_widgets = _collect_handler_widgets(selection_handler)
1347+
all_widgets += handler_widgets
1348+
13261349
# Group widgets by location, applying layout overrides
13271350
widgets_by_location = group_widgets_by_location(all_widgets, merged_layout)
13281351

@@ -1430,8 +1453,10 @@ def render_html(
14301453
font_data = font_result["font_data"]
14311454
api_tooltip_fontname = font_result["api_tooltip_fontname"]
14321455

1433-
# Process selection handler(s)
1434-
custom_html, custom_js, custom_css = prepare_selection_handler(
1456+
# Process selection handler(s) — handler-owned widgets were already
1457+
# injected into ``all_widgets`` above so they are rendered inside the
1458+
# correct drawer / stack containers by the template.
1459+
custom_html, custom_js, custom_css, _handler_widgets = prepare_selection_handler(
14351460
selection_handler, custom_html, custom_js, custom_css
14361461
)
14371462

0 commit comments

Comments
 (0)