Skip to content

ENH: multirow naive implementation Styler.to_latex part1 #43369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 7, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v1.4.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Styler
- :meth:`.Styler.to_html` introduces keyword arguments ``sparse_index``, ``sparse_columns``, ``bold_headers``, ``caption`` (:issue:`41946`, :issue:`43149`).
- Keyword argument ``level`` is added to :meth:`.Styler.hide_index` and :meth:`.Styler.hide_columns` for optionally controlling hidden levels in a MultiIndex (:issue:`25475`)
- Global options have been extended to configure default ``Styler`` properties including formatting and encoding and mathjax options and LaTeX (:issue:`41395`)
- Naive sparsification is now possible for LaTeX without the multirow package (:issue:`43369`)

Formerly Styler relied on ``display.html.use_mathjax``, which has now been replaced by ``styler.html.mathjax``.

Expand Down
2 changes: 1 addition & 1 deletion pandas/core/config_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ def register_converter_cb(key):
"latex.multirow_align",
"c",
styler_multirow_align,
validator=is_one_of_factory(["c", "t", "b"]),
validator=is_one_of_factory(["c", "t", "b", "naive"]),
)

cf.register_option(
Expand Down
9 changes: 6 additions & 3 deletions pandas/io/formats/style.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,10 +520,13 @@ def to_latex(
Whether to sparsify the display of a hierarchical index. Setting to False
will display each explicit level element in a hierarchical key for each
column. Defaults to ``pandas.options.styler.sparse.columns`` value.
multirow_align : {"c", "t", "b"}, optional
multirow_align : {"c", "t", "b", "naive"}, optional
If sparsifying hierarchical MultiIndexes whether to align text centrally,
at the top or bottom. If not given defaults to
``pandas.options.styler.latex.multirow_align``
at the top or bottom using the multirow package. If not given defaults to
``pandas.options.styler.latex.multirow_align``. If "naive" is given renders
without multirow.

.. versionchanged:: 1.4.0
multicol_align : {"r", "c", "l"}, optional
If sparsifying hierarchical MultiIndex columns whether to align text at
the left, centrally, or at the right. If not given defaults to
Expand Down
2 changes: 2 additions & 0 deletions pandas/io/formats/style_render.py
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@ def _parse_latex_header_span(
colspan = int(colspan[: colspan.find('"')])
return f"\\multicolumn{{{colspan}}}{{{multicol_align}}}{{{display_val}}}"
elif 'rowspan="' in attrs:
if multirow_align == "naive":
return display_val
rowspan = attrs[attrs.find('rowspan="') + 9 :]
rowspan = int(rowspan[: rowspan.find('"')])
return f"\\multirow[{multirow_align}]{{{rowspan}}}{{*}}{{{display_val}}}"
Expand Down
19 changes: 19 additions & 0 deletions pandas/tests/io/formats/style/test_to_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,25 @@ def test_multiindex_row(df):
assert expected == s.to_latex(sparse_index=False)


def test_multirow_naive(df):
ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that the letters A and B should not be repeated in both the index and columns.
What if you use these for the index?

ridx = MultiIndex.from_tuples([("X", "x"), ("X", "y"), ("Z", "z")])

I guess it will be easier to differentiate from the columns.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fully agree. silly oversight.

df.loc[2, :] = [2, -2.22, "de"]
df = df.astype({"A": int})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider simplifying the dataframe creation to this:

df = DataFrame(
    {"A": [0, 1, 2], "B": [-0.61, -1.22, -2.22], "C": ["ab", "cd", "de"]},
    index=ridx,
)

This way, it is clearer what the dataframe actually look like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

used in multiple tests so I cleaned up module with a fixture

df.index = ridx
expected = dedent(
"""\
\\begin{tabular}{llrrl}
& & A & B & C \\\\
A & a & 0 & -0.61 & ab \\\\
& b & 1 & -1.22 & cd \\\\
B & c & 2 & -2.22 & de \\\\
\\end{tabular}
"""
)
s = df.style.format(precision=2)
assert expected == s.to_latex(multirow_align="naive")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest that result variable is extracted:

result = s.to_latex(multirow_align="naive")
assert result == expected

Besides, s is not a preferred variable name, because one-letter variables make debugging more complicated.
What about making it more explicit, styler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes cleaned up module wide (somewhat)



def test_multiindex_row_and_col(df):
cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")])
ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")])
Expand Down