Skip to content

Commit 96c9abc

Browse files
committed
add bookmarking to df - part 1
1 parent 7851978 commit 96c9abc

File tree

2 files changed

+134
-0
lines changed

2 files changed

+134
-0
lines changed

shiny/render/_data_frame.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,8 @@ def _reset_reactives(self) -> None:
562562
self._updated_data.unset()
563563

564564
def _init_reactives(self) -> None:
565+
from ..bookmark._restore_state import RestoreState
566+
from ..bookmark._save_state import BookmarkState
565567

566568
# Init
567569
self._value = reactive.Value(None)
@@ -588,6 +590,57 @@ async def _():
588590
# It currently is, as `@reactive.event()` is being used
589591
await self._attempt_update_cell_style()
590592

593+
def bookmark_cell_patch_id() -> str:
594+
return f"{self.output_id}--cell_patch_map"
595+
596+
def bookmark_data_id() -> str:
597+
return f"{self.output_id}--data"
598+
599+
@self._get_session().bookmark.on_bookmark
600+
def _(state: BookmarkState):
601+
cell_patch_map = self._cell_patch_map()
602+
if cell_patch_map:
603+
cell_patch_id_val = bookmark_cell_patch_id()
604+
if cell_patch_id_val in state.values:
605+
raise RuntimeError(
606+
f"Bookmark state already contains a value for {cell_patch_id_val}. Please use a different ID."
607+
)
608+
state.values[cell_patch_id_val] = cell_patch_map
609+
610+
updated_data = self._updated_data()
611+
if updated_data:
612+
# TODO-barret-render.data_frame; Handle restoring updated data
613+
# Related: Restoring Chat UI: https://github.com/posit-dev/py-shiny/issues/1952
614+
raise RuntimeError(
615+
"Bookmarking an updated data frame is not supported."
616+
)
617+
618+
@self._get_session().bookmark.on_restore
619+
def _(state: RestoreState):
620+
if state.input[f"{self.output_id}_cell_selection"]:
621+
self.update_cell_selection(
622+
state.input[f"{self.output_id}_cell_selection"]
623+
)
624+
if state.input[f"{self.output_id}_column_sort"]:
625+
self.update_sort(state.input[f"{self.output_id}_column_sort"])
626+
if state.input[f"{self.output_id}_column_filter"]:
627+
self.update_filter(state.input[f"{self.output_id}_column_filter"])
628+
if state.input[f"{self.output_id}_cell_selection"]:
629+
self.update_cell_selection(
630+
state.input[f"{self.output_id}_cell_selection"]
631+
)
632+
if state.input[f"{self.output_id}_data_view_rows"]:
633+
634+
cell_patch_map = state.values.get(bookmark_cell_patch_id(), None)
635+
if cell_patch_map:
636+
self._cell_patch_map.set(cell_patch_map)
637+
self._updated_data.set(self._nw_data_to_original_type(self._nw_data()))
638+
639+
updated_data = state.values.get(bookmark_data_id(), None)
640+
if updated_data:
641+
# TODO-barret-render.data_frame; Handle restoring updated data
642+
raise RuntimeError("Restoring an updated data frame is not supported.")
643+
591644
def _get_session(self) -> Session:
592645
if self._session is None:
593646
raise RuntimeError(
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from palmerpenguins import load_penguins
2+
from shiny import reactive
3+
from shiny.express import app_opts, input, render, session, ui
4+
5+
penguins = load_penguins()
6+
7+
app_opts(bookmark_store="url")
8+
9+
10+
ui.h2("Palmer Penguins")
11+
12+
ui.h5("Current selection: ", {"class": "pt-2"})
13+
14+
15+
@render.code
16+
def _():
17+
return penguins_df.cell_selection()["rows"]
18+
19+
20+
ui.br()
21+
22+
23+
@render.data_frame
24+
def penguins_df():
25+
return render.DataGrid(penguins, selection_mode="rows")
26+
27+
28+
@render.text
29+
def penguins_df_text():
30+
return f"Selection mode: rows - Selected: {penguins_df.cell_selection()['rows']}"
31+
32+
33+
ui.br()
34+
35+
36+
@render.data_frame
37+
def penguins_row_df():
38+
return render.DataGrid(penguins, selection_mode="row")
39+
40+
41+
@render.text
42+
def penguins_row_df_text():
43+
return f"Selection mode: row - Selected: {penguins_row_df.cell_selection()['rows']}"
44+
45+
46+
ui.br()
47+
48+
49+
@render.data_frame
50+
def penguins_filter_df():
51+
return render.DataGrid(penguins, filters=True)
52+
53+
54+
@render.text
55+
def penguins_filter_df_text():
56+
return f"Filters enabled - Selected: {penguins_filter_df.cell_selection()['rows']}"
57+
58+
59+
ui.br()
60+
61+
62+
@render.data_frame
63+
def penguins_editable_df():
64+
return render.DataGrid(penguins, editable=True)
65+
66+
67+
@render.text
68+
def penguins_editable_df_text():
69+
return f"Editable grid - Selected: {penguins_editable_df.cell_selection()['rows']}"
70+
71+
72+
ui.br()
73+
74+
ui.input_bookmark_button()
75+
76+
ui.br()
77+
78+
79+
@session.bookmark.on_bookmarked
80+
async def _(url: str):
81+
await session.bookmark.update_query_string(url)

0 commit comments

Comments
 (0)