Skip to content

Commit 9f9f0ee

Browse files
committed
Make data frame output work correctly with Pandas index
1 parent b231425 commit 9f9f0ee

File tree

5 files changed

+80
-8
lines changed

5 files changed

+80
-8
lines changed

e2e/bugs/0676-row-selection/app.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import pandas as pd
2+
3+
from shiny import App, Inputs, Outputs, Session, render, ui
4+
5+
df = pd.DataFrame(
6+
dict(
7+
id=["one", "two", "three"],
8+
fname=["Alice", "Bob", "Charlie"],
9+
lname=["Smith", "Jones", "Brown"],
10+
)
11+
).set_index( # type: ignore
12+
"id",
13+
drop=False,
14+
)
15+
16+
app_ui = ui.page_fluid(
17+
ui.p("Select rows in the grid, make sure the selected rows appear below."),
18+
ui.output_data_frame("grid"),
19+
ui.output_table("detail"),
20+
class_="p-3",
21+
)
22+
23+
24+
def server(input: Inputs, output: Outputs, session: Session):
25+
@output
26+
@render.data_frame
27+
def grid():
28+
return render.DataGrid(
29+
df,
30+
row_selection_mode="multiple",
31+
height=350,
32+
)
33+
34+
@output
35+
@render.table
36+
def detail():
37+
if (
38+
input.grid_selected_rows() is not None
39+
and len(input.grid_selected_rows()) > 0
40+
):
41+
# "split", "records", "index", "columns", "values", "table"
42+
return df.loc[list(input.grid_selected_rows())]
43+
44+
45+
app = App(app_ui, server, debug=True)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
from __future__ import annotations
2+
3+
from conftest import ShinyAppProc
4+
from playwright.sync_api import Page, expect
5+
6+
7+
def test_row_selection(page: Page, local_app: ShinyAppProc) -> None:
8+
page.goto(local_app.url)
9+
10+
# The purpose of this test is to make sure that the data grid can work on Pandas
11+
# data frames that use an index that is not simply 0-based integers.
12+
13+
row3 = page.locator("#grid tbody tr:nth-child(3)")
14+
result_loc = page.locator("#detail tbody tr:nth-child(1) td:nth-child(1)")
15+
16+
expect(row3).to_be_visible()
17+
expect(row3.locator("td:nth-child(1)")).to_have_text("three")
18+
19+
expect(result_loc).not_to_be_attached()
20+
row3.click()
21+
expect(result_loc).to_have_text("three")

js/dataframe/index.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,15 @@ const ShinyDataGrid: FC<ShinyDataGridProps<unknown>> = (props) => {
6060
const { id, data, bgcolor } = props;
6161
const { columns, index, type_hints, data: rowData } = data;
6262
const { width, height, filters: withFilters } = data.options;
63+
// The terminology here is a bit confusing. The "key" is the `data-key` attribute on
64+
// the table>tbody>tr, which is populated by Tanstack table API's row id, which is
65+
// always [0, 1, 2, ...]. The "index" refers to the Pandas index coming from the
66+
// Python side, which may or may not be [0, 1, 2, ...]--it could be strings,
67+
// discontiguous numbers, or whatever. So the keyToIndex map lets you convert a
68+
// Tanstack row to the Pandas index.
6369
const keyToIndex: Record<string, unknown> = {};
64-
index.forEach((value) => {
65-
keyToIndex[value + ""] = value;
70+
index.forEach((value, i) => {
71+
keyToIndex[i + ""] = value;
6672
});
6773

6874
const containerRef = useRef<HTMLDivElement>(null);

0 commit comments

Comments
 (0)