Skip to content

Commit 2033377

Browse files
committed
Render non-trivial indexes of Pandas Styler object
1 parent 78944b0 commit 2033377

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-8
lines changed

docs/changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ ITables ChangeLog
1515
**Fixed**
1616
- We have added type hints to `itable.options` even for the options that don't have a default value ([#224](https://github.com/mwouts/itables/issues/224))
1717
- The optional final semicolon in `style` argument is now supported again ([#386](https://github.com/mwouts/itables/issues/386))
18+
- The index of Pandas Style object is now rendered when non-trivial ([#393](https://github.com/mwouts/itables/issues/393))
1819

1920

2021
2.4.0 (2025-05-17)

src/itables/javascript.py

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,26 @@ def to_html_datatable(
346346
)
347347

348348

349+
def _evaluate_show_index(df, showIndex) -> bool:
350+
"""
351+
We don't want to show trivial indices (RangeIndex with no name) on Pandas DataFrames.
352+
"""
353+
if showIndex != "auto":
354+
return showIndex
355+
if df is None:
356+
return False
357+
if pl is not None and isinstance(df, pl.DataFrame):
358+
return False
359+
if isinstance(df, pd.DataFrame):
360+
return df.index.name is not None or not isinstance(df.index, pd.RangeIndex)
361+
if pd_style is not None and isinstance(df, pd_style.Styler):
362+
return _evaluate_show_index(
363+
df.data, # pyright: ignore[reportAttributeAccessIssue]
364+
showIndex,
365+
)
366+
raise NotImplementedError(type(df))
367+
368+
349369
def get_itable_arguments(
350370
df, *args, app_mode: bool = False, **kwargs: Unpack[ITableOptions]
351371
) -> DTForITablesOptions:
@@ -378,14 +398,7 @@ def get_itable_arguments(
378398
if isinstance(df, (pd.Series, pl.Series)):
379399
df = df.to_frame()
380400

381-
if showIndex == "auto":
382-
if isinstance(df, pd.DataFrame):
383-
showIndex = df.index.name is not None or not isinstance(
384-
df.index, pd.RangeIndex
385-
)
386-
else:
387-
# Polars DataFrame
388-
showIndex = False
401+
showIndex = _evaluate_show_index(df, showIndex)
389402

390403
maxBytes = kwargs.pop("maxBytes", 0)
391404
maxRows = kwargs.pop("maxRows", 0)

tests/test_pandas_style.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import pytest
55

66
from itables import to_html_datatable
7+
from itables.javascript import get_itable_arguments
78

89
pytest.importorskip("jinja2")
910

@@ -36,3 +37,30 @@ def test_buttons_are_shown_on_pd_style_objects():
3637
assert "dom" not in dt_args
3738
assert "buttons" in dt_args
3839
assert "buttons" in dt_args["layout"].values()
40+
41+
42+
def test_non_trivial_index_of_styler_objects_are_included():
43+
"""
44+
When a Pandas Styler index is non trivial, it should appear
45+
in the ITable output, see issue #393
46+
"""
47+
df = pd.DataFrame({"A": [1]}, index=pd.Index([0], name="index"))
48+
dt_args = get_itable_arguments(df.style, table_id="T_id", allow_html=True)
49+
assert "table_html" in dt_args
50+
table_html = dt_args["table_html"]
51+
assert "index" in table_html, table_html
52+
53+
54+
@pytest.mark.parametrize("showIndex", [True, "auto"])
55+
def test_trivial_indexes_of_styler_objects_are_not_included(showIndex):
56+
"""
57+
When a Pandas Styler index is trivial, it should appear
58+
in the ITable output only if showIndex is True
59+
"""
60+
df = pd.DataFrame({"A": [1]})
61+
dt_args = get_itable_arguments(
62+
df.style, table_id="T_id", allow_html=True, showIndex=showIndex
63+
)
64+
assert "table_html" in dt_args
65+
table_html = dt_args["table_html"]
66+
assert ('class="blank level0"' in table_html) == (showIndex is True), table_html

0 commit comments

Comments
 (0)