Skip to content

Commit f489814

Browse files
authored
ENH: styler.latex options (#43284)
1 parent 314f3da commit f489814

File tree

5 files changed

+85
-9
lines changed

5 files changed

+85
-9
lines changed

doc/source/user_guide/options.rst

+4
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,10 @@ styler.format.escape None Whether to escape "html" or
502502
styler.html.mathjax True If set to False will render specific CSS classes to
503503
table attributes that will prevent Mathjax from rendering
504504
in Jupyter Notebook.
505+
styler.latex.multicol_align r Alignment of headers in a merged column due to sparsification. Can be in {"r", "c", "l"}.
506+
styler.latex.multirow_align c Alignment of index labels in a merged row due to sparsification. Can be in {"c", "t", "b"}.
507+
styler.latex.environment None If given will replace the default ``\\begin{table}`` environment. If "longtable" is specified
508+
this will render with a specific "longtable" template with longtable features.
505509
======================================= ============ ==================================
506510

507511

doc/source/whatsnew/v1.4.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ Styler
7575
- :meth:`.Styler.to_latex` introduces keyword argument ``environment``, which also allows a specific "longtable" entry through a separate jinja2 template (:issue:`41866`).
7676
- :meth:`.Styler.to_html` introduces keyword arguments ``sparse_index``, ``sparse_columns``, ``bold_headers``, ``caption`` (:issue:`41946`, :issue:`43149`).
7777
- 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`)
78-
- Global options have been extended to configure default ``Styler`` properties including formatting and encoding and mathjax options (:issue:`41395`)
78+
- Global options have been extended to configure default ``Styler`` properties including formatting and encoding and mathjax options and LaTeX (:issue:`41395`)
7979

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

pandas/core/config_init.py

+37
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,22 @@ def register_converter_cb(key):
793793
A formatter object to be used as default within ``Styler.format``.
794794
"""
795795

796+
styler_multirow_align = """
797+
: {"c", "t", "b"}
798+
The specifier for vertical alignment of sparsified LaTeX multirows.
799+
"""
800+
801+
styler_multicol_align = """
802+
: {"r", "c", "l"}
803+
The specifier for horizontal alignment of sparsified LaTeX multicolumns.
804+
"""
805+
806+
styler_environment = """
807+
: str
808+
The environment to replace ``\\begin{table}``. If "longtable" is used results
809+
in a specific longtable environment format.
810+
"""
811+
796812
styler_encoding = """
797813
: str
798814
The encoding used for output HTML and LaTeX files.
@@ -855,3 +871,24 @@ def register_converter_cb(key):
855871
)
856872

857873
cf.register_option("html.mathjax", True, styler_mathjax, validator=is_bool)
874+
875+
cf.register_option(
876+
"latex.multirow_align",
877+
"c",
878+
styler_multirow_align,
879+
validator=is_one_of_factory(["c", "t", "b"]),
880+
)
881+
882+
cf.register_option(
883+
"latex.multicol_align",
884+
"r",
885+
styler_multicol_align,
886+
validator=is_one_of_factory(["r", "c", "l"]),
887+
)
888+
889+
cf.register_option(
890+
"latex.environment",
891+
None,
892+
styler_environment,
893+
validator=is_instance_factory([type(None), str]),
894+
)

pandas/io/formats/style.py

+13-8
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ def to_latex(
458458
caption: str | tuple | None = None,
459459
sparse_index: bool | None = None,
460460
sparse_columns: bool | None = None,
461-
multirow_align: str = "c",
462-
multicol_align: str = "r",
461+
multirow_align: str | None = None,
462+
multicol_align: str | None = None,
463463
siunitx: bool = False,
464464
environment: str | None = None,
465465
encoding: str | None = None,
@@ -512,18 +512,21 @@ def to_latex(
512512
Whether to sparsify the display of a hierarchical index. Setting to False
513513
will display each explicit level element in a hierarchical key for each
514514
column. Defaults to ``pandas.options.styler.sparse.columns`` value.
515-
multirow_align : {"c", "t", "b"}
515+
multirow_align : {"c", "t", "b"}, optional
516516
If sparsifying hierarchical MultiIndexes whether to align text centrally,
517-
at the top or bottom.
518-
multicol_align : {"r", "c", "l"}
517+
at the top or bottom. If not given defaults to
518+
``pandas.options.styler.latex.multirow_align``
519+
multicol_align : {"r", "c", "l"}, optional
519520
If sparsifying hierarchical MultiIndex columns whether to align text at
520-
the left, centrally, or at the right.
521+
the left, centrally, or at the right. If not given defaults to
522+
``pandas.options.styler.latex.multicol_align``
521523
siunitx : bool, default False
522524
Set to ``True`` to structure LaTeX compatible with the {siunitx} package.
523525
environment : str, optional
524526
If given, the environment that will replace 'table' in ``\\begin{table}``.
525527
If 'longtable' is specified then a more suitable template is
526-
rendered.
528+
rendered. If not given defaults to
529+
``pandas.options.styler.latex.environment``.
527530
528531
.. versionadded:: 1.4.0
529532
encoding : str, optional
@@ -840,7 +843,9 @@ def to_latex(
840843
sparse_index = get_option("styler.sparse.index")
841844
if sparse_columns is None:
842845
sparse_columns = get_option("styler.sparse.columns")
843-
846+
environment = environment or get_option("styler.latex.environment")
847+
multicol_align = multicol_align or get_option("styler.latex.multicol_align")
848+
multirow_align = multirow_align or get_option("styler.latex.multirow_align")
844849
latex = obj._render_latex(
845850
sparse_index=sparse_index,
846851
sparse_columns=sparse_columns,

pandas/tests/io/formats/style/test_to_latex.py

+30
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,30 @@ def test_multiindex_row_and_col(df):
276276
assert s.to_latex(sparse_index=False, sparse_columns=False) == expected
277277

278278

279+
def test_multi_options(df):
280+
cidx = MultiIndex.from_tuples([("Z", "a"), ("Z", "b"), ("Y", "c")])
281+
ridx = MultiIndex.from_tuples([("A", "a"), ("A", "b"), ("B", "c")])
282+
df.loc[2, :] = [2, -2.22, "de"]
283+
df = df.astype({"A": int})
284+
df.index, df.columns = ridx, cidx
285+
styler = df.style.format(precision=2)
286+
287+
expected = dedent(
288+
"""\
289+
{} & {} & \\multicolumn{2}{r}{Z} & {Y} \\\\
290+
{} & {} & {a} & {b} & {c} \\\\
291+
\\multirow[c]{2}{*}{A} & a & 0 & -0.61 & ab \\\\
292+
"""
293+
)
294+
assert expected in styler.to_latex()
295+
296+
with option_context("styler.latex.multicol_align", "l"):
297+
assert "{} & {} & \\multicolumn{2}{l}{Z} & {Y} \\\\" in styler.to_latex()
298+
299+
with option_context("styler.latex.multirow_align", "b"):
300+
assert "\\multirow[b]{2}{*}{A} & a & 0 & -0.61 & ab \\\\" in styler.to_latex()
301+
302+
279303
def test_multiindex_columns_hidden():
280304
df = DataFrame([[1, 2, 3, 4]])
281305
df.columns = MultiIndex.from_tuples([("A", 1), ("A", 2), ("A", 3), ("B", 1)])
@@ -376,6 +400,12 @@ def test_comprehensive(df, environment):
376400
assert s.format(precision=2).to_latex(environment=environment) == expected
377401

378402

403+
def test_environment_option(styler):
404+
with option_context("styler.latex.environment", "bar-env"):
405+
assert "\\begin{bar-env}" in styler.to_latex()
406+
assert "\\begin{foo-env}" in styler.to_latex(environment="foo-env")
407+
408+
379409
def test_parse_latex_table_styles(styler):
380410
styler.set_table_styles(
381411
[

0 commit comments

Comments
 (0)