diff --git a/py-polars/polars/dataframe/_html.py b/py-polars/polars/dataframe/_html.py index 99f52ff94dc3..06e729241f44 100644 --- a/py-polars/polars/dataframe/_html.py +++ b/py-polars/polars/dataframe/_html.py @@ -58,15 +58,16 @@ def __init__( self.elements: list[str] = [] self.max_cols = max_cols self.max_rows = max_rows - self.series = from_series + self.from_series = from_series self.row_idx: Iterable[int] self.col_idx: Iterable[int] if max_rows < df.height: + half, rest = divmod(max_rows, 2) self.row_idx = [ - *list(range(max_rows // 2)), + *list(range(half + rest)), -1, - *list(range(df.height - max_rows // 2, df.height)), + *list(range(df.height - half, df.height)), ] else: self.row_idx = range(df.height) @@ -132,7 +133,7 @@ def render(self) -> list[str]: ): # format frame/series shape with '_' thousand-separators s = self.df.shape - shape = f"({s[0]:_},)" if self.series else f"({s[0]:_}, {s[1]:_})" + shape = f"({s[0]:_},)" if self.from_series else f"({s[0]:_}, {s[1]:_})" self.elements.append(f"shape: {shape}") diff --git a/py-polars/polars/dataframe/frame.py b/py-polars/polars/dataframe/frame.py index c0807ffa05dc..d61a1829c356 100644 --- a/py-polars/polars/dataframe/frame.py +++ b/py-polars/polars/dataframe/frame.py @@ -1806,7 +1806,7 @@ def __deepcopy__(self, memo: None = None) -> Self: def _ipython_key_completions_(self) -> list[str]: return self.columns - def _repr_html_(self, **kwargs: Any) -> str: + def _repr_html_(self, *, _from_series: bool = False) -> str: """ Format output data in HTML for display in Jupyter Notebooks. @@ -1818,18 +1818,18 @@ def _repr_html_(self, **kwargs: Any) -> str: """ max_cols = int(os.environ.get("POLARS_FMT_MAX_COLS", default=75)) if max_cols < 0: - max_cols = self.shape[1] - max_rows = int(os.environ.get("POLARS_FMT_MAX_ROWS", default=25)) + max_cols = self.width + + max_rows = int(os.environ.get("POLARS_FMT_MAX_ROWS", default=10)) if max_rows < 0: - max_rows = self.shape[0] + max_rows = self.height - from_series = kwargs.get("from_series", False) return "".join( NotebookFormatter( self, max_cols=max_cols, max_rows=max_rows, - from_series=from_series, + from_series=_from_series, ).render() ) diff --git a/py-polars/polars/series/series.py b/py-polars/polars/series/series.py index 0ad26377f80a..50c65d252255 100644 --- a/py-polars/polars/series/series.py +++ b/py-polars/polars/series/series.py @@ -1488,7 +1488,7 @@ def __array_ufunc__( def _repr_html_(self) -> str: """Format output data in HTML for display in Jupyter Notebooks.""" - return self.to_frame()._repr_html_(from_series=True) + return self.to_frame()._repr_html_(_from_series=True) @deprecate_renamed_parameter("row", "index", version="0.19.3") def item(self, index: int | None = None) -> Any: diff --git a/py-polars/tests/unit/dataframe/test_df.py b/py-polars/tests/unit/dataframe/test_df.py index 3690fd162d25..adc1f8bdeeab 100644 --- a/py-polars/tests/unit/dataframe/test_df.py +++ b/py-polars/tests/unit/dataframe/test_df.py @@ -1058,32 +1058,6 @@ def test_literal_series() -> None: ) -def test_to_html() -> None: - # check it does not panic/error, and appears to contain - # a reasonable table with suitably escaped html entities. - df = pl.DataFrame( - { - "foo": [1, 2, 3], - "": ["a", "b", "c"], - "": ["a", "b", "c"], - } - ) - html = df._repr_html_() - for match in ( - "foo", - "<bar>", - "<baz", - "spam>", - "1", - "2", - "3", - ): - assert match in html, f"Expected to find {match!r} in html repr" - - def test_rename(df: pl.DataFrame) -> None: out = df.rename({"strings": "bars", "int": "foos"}) # check if we can select these new columns diff --git a/py-polars/tests/unit/dataframe/test_repr_html.py b/py-polars/tests/unit/dataframe/test_repr_html.py new file mode 100644 index 000000000000..8e7a62a6efc2 --- /dev/null +++ b/py-polars/tests/unit/dataframe/test_repr_html.py @@ -0,0 +1,79 @@ +import polars as pl + + +def test_repr_html() -> None: + # check it does not panic/error, and appears to contain + # a reasonable table with suitably escaped html entities. + df = pl.DataFrame( + { + "foo": [1, 2, 3], + "": ["a", "b", "c"], + "": ["a", "b", "c"], + } + ) + html = df._repr_html_() + for match in ( + "foo", + "<bar>", + "<baz", + "spam>", + "1", + "2", + "3", + ): + assert match in html, f"Expected to find {match!r} in html repr" + + +def test_html_tables() -> None: + df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) + + # default: header contains names/dtypes + header = "abci64i64i64" + assert header in df._repr_html_() + + # validate that relevant config options are respected + with pl.Config(tbl_hide_column_names=True): + header = "i64i64i64" + assert header in df._repr_html_() + + with pl.Config(tbl_hide_column_data_types=True): + header = "abc" + assert header in df._repr_html_() + + with pl.Config( + tbl_hide_column_data_types=True, + tbl_hide_column_names=True, + ): + header = "" + assert header in df._repr_html_() + + +def test_df_repr_html_max_rows_default() -> None: + df = pl.DataFrame({"a": range(50)}) + + html = df._repr_html_() + + expected_rows = 10 + assert html.count("") - 2 == expected_rows + + +def test_df_repr_html_max_rows_odd() -> None: + df = pl.DataFrame({"a": range(50)}) + + with pl.Config(tbl_rows=9): + html = df._repr_html_() + + expected_rows = 9 + assert html.count("") - 2 == expected_rows + + +def test_series_repr_html_max_rows_default() -> None: + s = pl.Series("a", range(50)) + + html = s._repr_html_() + + expected_rows = 10 + assert html.count("") - 2 == expected_rows diff --git a/py-polars/tests/unit/test_config.py b/py-polars/tests/unit/test_config.py index 17b58c7201c9..cfe98e6ede0c 100644 --- a/py-polars/tests/unit/test_config.py +++ b/py-polars/tests/unit/test_config.py @@ -87,30 +87,6 @@ def test_hide_header_elements() -> None: ) -def test_html_tables() -> None: - df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]}) - - # default: header contains names/dtypes - header = "abci64i64i64" - assert header in df._repr_html_() - - # validate that relevant config options are respected - with pl.Config(tbl_hide_column_names=True): - header = "i64i64i64" - assert header in df._repr_html_() - - with pl.Config(tbl_hide_column_data_types=True): - header = "abc" - assert header in df._repr_html_() - - with pl.Config( - tbl_hide_column_data_types=True, - tbl_hide_column_names=True, - ): - header = "" - assert header in df._repr_html_() - - def test_set_tbl_cols() -> None: df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6], "c": [7, 8, 9]})