diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst index 0cea08b3d2c87..8766686b25034 100644 --- a/doc/source/whatsnew/v2.0.0.rst +++ b/doc/source/whatsnew/v2.0.0.rst @@ -624,7 +624,9 @@ The arguments signature is similar, albeit ``col_space`` has been removed since it is ignored by LaTeX engines. This render engine also requires ``jinja2`` as a dependency which needs to be installed, since rendering is based upon jinja2 templates. -The pandas options below are no longer used and will be removed in future releases. +The pandas latex options below are no longer used and have been removed. The generic +max rows and columns arguments remain but for this functionality should be replaced +by the Styler equivalents. The alternative options giving similar functionality are indicated below: - ``display.latex.escape``: replaced with ``styler.format.escape``, @@ -638,6 +640,13 @@ The alternative options giving similar functionality are indicated below: ``styler.render.max_rows``, ``styler.render.max_columns`` and ``styler.render.max_elements``. +Note that due to this change some defaults have also changed: + +- ``multirow`` now defaults to *True*. +- ``multirow_align`` defaults to *"r"* instead of *"l"*. +- ``multicol_align`` defaults to *"r"* instead of *"l"*. +- ``escape`` now defaults to *False*. + Note that the behaviour of ``_repr_latex_`` is also changed. Previously setting ``display.latex.repr`` would generate LaTeX only when using nbconvert for a JupyterNotebook, and not when the user is running the notebook. Now the diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index 2e1ddb3c0a628..dd751075647d8 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -210,13 +210,6 @@ def use_numba_cb(key) -> None: (default: False) """ -pc_latex_repr_doc = """ -: boolean - Whether to produce a latex DataFrame representation for jupyter - environments that support it. - (default: False) -""" - pc_table_schema_doc = """ : boolean Whether to publish a Table Schema representation for frontends @@ -292,41 +285,6 @@ def use_numba_cb(key) -> None: df.info() is called. Valid values True,False,'deep' """ -pc_latex_escape = """ -: bool - This specifies if the to_latex method of a Dataframe uses escapes special - characters. - Valid values: False,True -""" - -pc_latex_longtable = """ -:bool - This specifies if the to_latex method of a Dataframe uses the longtable - format. - Valid values: False,True -""" - -pc_latex_multicolumn = """ -: bool - This specifies if the to_latex method of a Dataframe uses multicolumns - to pretty-print MultiIndex columns. - Valid values: False,True -""" - -pc_latex_multicolumn_format = """ -: string - This specifies the format for multicolumn headers. - Can be surrounded with '|'. - Valid values: 'l', 'c', 'r', 'p{}' -""" - -pc_latex_multirow = """ -: bool - This specifies if the to_latex method of a Dataframe uses multirows - to pretty-print MultiIndex rows. - Valid values: False,True -""" - def table_schema_cb(key) -> None: from pandas.io.formats.printing import enable_data_resource_formatter @@ -425,16 +383,6 @@ def is_terminal() -> bool: cf.register_option( "unicode.ambiguous_as_wide", False, pc_east_asian_width_doc, validator=is_bool ) - cf.register_option("latex.repr", False, pc_latex_repr_doc, validator=is_bool) - cf.register_option("latex.escape", True, pc_latex_escape, validator=is_bool) - cf.register_option("latex.longtable", False, pc_latex_longtable, validator=is_bool) - cf.register_option( - "latex.multicolumn", True, pc_latex_multicolumn, validator=is_bool - ) - cf.register_option( - "latex.multicolumn_format", "l", pc_latex_multicolumn, validator=is_text - ) - cf.register_option("latex.multirow", False, pc_latex_multirow, validator=is_bool) cf.register_option( "html.table_schema", False, diff --git a/pandas/core/generic.py b/pandas/core/generic.py index aaf1d0e022fdf..69dc5b47f1af2 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -3228,13 +3228,23 @@ def to_latex( columns. By default, 'l' will be used for all columns except columns of numbers, which default to 'r'. longtable : bool, optional - By default, the value will be read from the pandas config - module. Use a longtable environment instead of tabular. Requires + Use a longtable environment instead of tabular. Requires adding a \usepackage{{longtable}} to your LaTeX preamble. + By default, the value will be read from the pandas config + module, and set to `True` if the option ``styler.latex.environment`` is + `"longtable"`. + + .. versionchanged:: 2.0.0 + The pandas option affecting this argument has changed. escape : bool, optional By default, the value will be read from the pandas config - module. When set to False prevents from escaping latex special + module and set to `True` if the option ``styler.format.escape`` is + `"latex"`. When set to False prevents from escaping latex special characters in column names. + + .. versionchanged:: 2.0.0 + The pandas option affecting this argument has changed, as has the + default value to `False`. encoding : str, optional A string representing the encoding to use in the output file, defaults to 'utf-8'. @@ -3242,16 +3252,30 @@ def to_latex( Character recognized as decimal separator, e.g. ',' in Europe. multicolumn : bool, default True Use \multicolumn to enhance MultiIndex columns. - The default will be read from the config module. - multicolumn_format : str, default 'l' + The default will be read from the config module, and is set + as the option ``styler.sparse.columns``. + + .. versionchanged:: 2.0.0 + The pandas option affecting this argument has changed. + multicolumn_format : str, default 'r' The alignment for multicolumns, similar to `column_format` - The default will be read from the config module. - multirow : bool, default False + The default will be read from the config module, and is set as the option + ``styler.latex.multicol_align``. + + .. versionchanged:: 2.0.0 + The pandas option affecting this argument has changed, as has the + default value to "r". + multirow : bool, default True Use \multirow to enhance MultiIndex rows. Requires adding a \usepackage{{multirow}} to your LaTeX preamble. Will print centered labels (instead of top-aligned) across the contained rows, separating groups via clines. The default will be read - from the pandas config module. + from the pandas config module, and is set as the option + ``styler.sparse.index``. + + .. versionchanged:: 2.0.0 + The pandas option affecting this argument has changed, as has the + default value to `True`. caption : str or tuple, optional Tuple (full_caption, short_caption), which results in ``\caption[short_caption]{{full_caption}}``; @@ -3319,15 +3343,15 @@ def to_latex( if self.ndim == 1: self = self.to_frame() if longtable is None: - longtable = config.get_option("display.latex.longtable") + longtable = config.get_option("styler.latex.environment") == "longtable" if escape is None: - escape = config.get_option("display.latex.escape") + escape = config.get_option("styler.format.escape") == "latex" if multicolumn is None: - multicolumn = config.get_option("display.latex.multicolumn") + multicolumn = config.get_option("styler.sparse.columns") if multicolumn_format is None: - multicolumn_format = config.get_option("display.latex.multicolumn_format") + multicolumn_format = config.get_option("styler.latex.multicol_align") if multirow is None: - multirow = config.get_option("display.latex.multirow") + multirow = config.get_option("styler.sparse.index") if column_format is not None and not isinstance(column_format, str): raise ValueError("`column_format` must be str or unicode") @@ -3413,7 +3437,9 @@ def _wrap(x, alt_format_): "label": label, "position": position, "column_format": column_format, - "clines": "skip-last;data" if multirow else None, + "clines": "skip-last;data" + if (multirow and isinstance(self.index, MultiIndex)) + else None, "bold_rows": bold_rows, } diff --git a/pandas/tests/frame/test_repr_info.py b/pandas/tests/frame/test_repr_info.py index 687bad07926d0..66d8084abea68 100644 --- a/pandas/tests/frame/test_repr_info.py +++ b/pandas/tests/frame/test_repr_info.py @@ -292,7 +292,7 @@ def test_latex_repr(self): \end{tabular} """ with option_context( - "display.latex.escape", False, "styler.render.repr", "latex" + "styler.format.escape", None, "styler.render.repr", "latex" ): df = DataFrame([[r"$\alpha$", "b", "c"], [1, 2, 3]]) result = df._repr_latex_() diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py index 42adf3f7b2826..8c66963bbb438 100644 --- a/pandas/tests/io/formats/test_to_latex.py +++ b/pandas/tests/io/formats/test_to_latex.py @@ -782,24 +782,14 @@ def test_to_latex_escape_false(self, df_with_symbols): assert result == expected def test_to_latex_escape_default(self, df_with_symbols): - result = df_with_symbols.to_latex() # default: escape=True - expected = _dedent( - r""" - \begin{tabular}{lll} - \toprule - & co\$e\textasciicircum x\$ & co\textasciicircum l1 \\ - \midrule - a & a & a \\ - b & b & b \\ - \bottomrule - \end{tabular} - """ - ) - assert result == expected + # gh50871: in v2.0 escape is False by default (styler.format.escape=None) + default = df_with_symbols.to_latex() + specified_true = df_with_symbols.to_latex(escape=True) + assert default != specified_true def test_to_latex_special_escape(self): df = DataFrame([r"a\b\c", r"^a^b^c", r"~a~b~c"]) - result = df.to_latex() + result = df.to_latex(escape=True) expected = _dedent( r""" \begin{tabular}{ll} @@ -818,7 +808,7 @@ def test_to_latex_special_escape(self): def test_to_latex_escape_special_chars(self): special_characters = ["&", "%", "$", "#", "_", "{", "}", "~", "^", "\\"] df = DataFrame(data=special_characters) - result = df.to_latex() + result = df.to_latex(escape=True) expected = _dedent( r""" \begin{tabular}{ll} @@ -1039,7 +1029,7 @@ def test_to_latex_multindex_header(self): # GH 16718 df = DataFrame({"a": [0], "b": [1], "c": [2], "d": [3]}) df = df.set_index(["a", "b"]) - observed = df.to_latex(header=["r1", "r2"]) + observed = df.to_latex(header=["r1", "r2"], multirow=False) expected = _dedent( r""" \begin{tabular}{llrr} @@ -1093,7 +1083,7 @@ def test_to_latex_multiindex_column_tabular(self): def test_to_latex_multiindex_small_tabular(self): df = DataFrame({("x", "y"): ["a"]}).T - result = df.to_latex() + result = df.to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{lll} @@ -1108,7 +1098,7 @@ def test_to_latex_multiindex_small_tabular(self): assert result == expected def test_to_latex_multiindex_tabular(self, multiindex_frame): - result = multiindex_frame.to_latex() + result = multiindex_frame.to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{llrrrr} @@ -1130,12 +1120,12 @@ def test_to_latex_multicolumn_tabular(self, multiindex_frame): # GH 14184 df = multiindex_frame.T df.columns.names = ["a", "b"] - result = df.to_latex() + result = df.to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{lrrrrr} \toprule - a & \multicolumn{2}{l}{c1} & \multicolumn{2}{l}{c2} & c3 \\ + a & \multicolumn{2}{r}{c1} & \multicolumn{2}{r}{c2} & c3 \\ b & 0 & 1 & 0 & 1 & 0 \\ \midrule 0 & 0 & 4 & 0 & 4 & 0 \\ @@ -1151,7 +1141,7 @@ def test_to_latex_multicolumn_tabular(self, multiindex_frame): def test_to_latex_index_has_name_tabular(self): # GH 10660 df = DataFrame({"a": [0, 0, 1, 1], "b": list("abab"), "c": [1, 2, 3, 4]}) - result = df.set_index(["a", "b"]).to_latex() + result = df.set_index(["a", "b"]).to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{llr} @@ -1172,12 +1162,16 @@ def test_to_latex_index_has_name_tabular(self): def test_to_latex_groupby_tabular(self): # GH 10660 df = DataFrame({"a": [0, 0, 1, 1], "b": list("abab"), "c": [1, 2, 3, 4]}) - result = df.groupby("a").describe().to_latex(float_format="{:.1f}".format) + result = ( + df.groupby("a") + .describe() + .to_latex(float_format="{:.1f}".format, escape=True) + ) expected = _dedent( r""" \begin{tabular}{lrrrrrrrr} \toprule - & \multicolumn{8}{l}{c} \\ + & \multicolumn{8}{r}{c} \\ & count & mean & std & min & 25\% & 50\% & 75\% & max \\ a & & & & & & & & \\ \midrule @@ -1200,7 +1194,7 @@ def test_to_latex_multiindex_dupe_level(self): df = DataFrame( index=pd.MultiIndex.from_tuples([("A", "c"), ("B", "c")]), columns=["col"] ) - result = df.to_latex() + result = df.to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{lll} @@ -1221,7 +1215,7 @@ def test_to_latex_multicolumn_default(self, multicolumn_frame): r""" \begin{tabular}{lrrrrr} \toprule - & \multicolumn{2}{l}{c1} & \multicolumn{2}{l}{c2} & c3 \\ + & \multicolumn{2}{r}{c1} & \multicolumn{2}{r}{c2} & c3 \\ & 0 & 1 & 0 & 1 & 0 \\ \midrule 0 & 0 & 5 & 0 & 5 & 0 \\ @@ -1236,7 +1230,7 @@ def test_to_latex_multicolumn_default(self, multicolumn_frame): assert result == expected def test_to_latex_multicolumn_false(self, multicolumn_frame): - result = multicolumn_frame.to_latex(multicolumn=False) + result = multicolumn_frame.to_latex(multicolumn=False, multicolumn_format="l") expected = _dedent( r""" \begin{tabular}{lrrrrr} @@ -1323,11 +1317,11 @@ def test_to_latex_multiindex_names(self, name0, name1, axes): else "" ) col_names = [n if (bool(n) and 1 in axes) else "" for n in names] - observed = df.to_latex() + observed = df.to_latex(multirow=False) # pylint: disable-next=consider-using-f-string expected = r"""\begin{tabular}{llrrrr} \toprule - & %s & \multicolumn{2}{l}{1} & \multicolumn{2}{l}{2} \\ + & %s & \multicolumn{2}{r}{1} & \multicolumn{2}{r}{2} \\ & %s & 3 & 4 & 3 & 4 \\ %s\midrule 1 & 3 & -1 & -1 & -1 & -1 \\ @@ -1347,7 +1341,7 @@ def test_to_latex_multiindex_nans(self, one_row): df = DataFrame({"a": [None, 1], "b": [2, 3], "c": [4, 5]}) if one_row: df = df.iloc[[0]] - observed = df.set_index(["a", "b"]).to_latex() + observed = df.set_index(["a", "b"]).to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{llr} @@ -1369,7 +1363,7 @@ def test_to_latex_multiindex_nans(self, one_row): def test_to_latex_non_string_index(self): # GH 19981 df = DataFrame([[1, 2, 3]] * 2).set_index([0, 1]) - result = df.to_latex() + result = df.to_latex(multirow=False) expected = _dedent( r""" \begin{tabular}{llr} diff --git a/pandas/tests/series/test_repr.py b/pandas/tests/series/test_repr.py index 23de7106e08a4..04dcabd6b832c 100644 --- a/pandas/tests/series/test_repr.py +++ b/pandas/tests/series/test_repr.py @@ -219,7 +219,7 @@ def test_latex_repr(self): \end{tabular} """ with option_context( - "display.latex.escape", False, "styler.render.repr", "latex" + "styler.format.escape", None, "styler.render.repr", "latex" ): s = Series([r"$\alpha$", "b", "c"]) assert result == s._repr_latex_()