Skip to content

ENH: Enable short_caption in to_latex #35668

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 39 commits into from
Oct 17, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
13d07ae
Extract helper method for caption & label macro
ivanovmg Aug 11, 2020
8912c81
Enable short_caption for df.to_latex
ivanovmg Aug 11, 2020
3f71b46
Replace unwanted pytest.warns with tm.assert...
ivanovmg Aug 11, 2020
22d2ca4
Fix missing f-string placeholder
ivanovmg Aug 11, 2020
01152c1
Apply black
ivanovmg Aug 11, 2020
6adb05c
Optionally unpack caption=(caption, short_caption)
ivanovmg Aug 18, 2020
4725d73
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Aug 18, 2020
a7b64c0
Add edge cases for caption testing
ivanovmg Aug 18, 2020
a2216a1
Pass through black
ivanovmg Aug 18, 2020
6c93de4
Remove typing and short_caption from to_latex
ivanovmg Aug 19, 2020
45de6eb
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 7, 2020
e70aafa
DOC: add parameters to LatexFormatter docstring
ivanovmg Sep 7, 2020
a0e3f53
TYP: remove type ignore for column_format
ivanovmg Sep 8, 2020
6725ca8
REF: move short caption parsing to LatexFormatter
ivanovmg Sep 8, 2020
8466421
DOC: add whatsnew for position and short caption
ivanovmg Sep 10, 2020
0cc0664
DOC: add issue number for short caption
ivanovmg Sep 10, 2020
c60a705
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 10, 2020
27891a3
CLN: update error message
ivanovmg Sep 13, 2020
e43b52f
TST: ensure that error message is tested
ivanovmg Sep 13, 2020
fbea9eb
TST: add tests for bad tuples
ivanovmg Sep 13, 2020
29b37e2
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 13, 2020
ed0132c
DOC: add/update versionadded, versionchanged tags
ivanovmg Sep 13, 2020
ed4b705
TST: add assertions in caption setter to help mypy
ivanovmg Sep 13, 2020
3453d43
DOC: add reason for caption type ignore
ivanovmg Sep 13, 2020
16884bc
DOC: add reason for strrows arg-type ignore
ivanovmg Sep 13, 2020
6fd52ca
DOC: add missing empty line before versionadded
ivanovmg Sep 13, 2020
5acfc44
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 14, 2020
ae1babe
REF: replace caption setter with initialize method
ivanovmg Sep 22, 2020
ddec116
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 22, 2020
15227b3
TST: align longtable test with the recent changes
ivanovmg Sep 22, 2020
336bfb5
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 23, 2020
b30d2d7
TST: add for list [full_caption, short_caption]
ivanovmg Sep 23, 2020
f1781f6
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 25, 2020
f4b18ff
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Sep 30, 2020
a18c85d
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Oct 7, 2020
e957c37
REF: use string concat for caption macro
ivanovmg Oct 7, 2020
09d9c85
REF: move method to module level
ivanovmg Oct 7, 2020
559ca2a
REF: drop property _short_caption_macro
ivanovmg Oct 7, 2020
0fd73e8
Merge branch 'master' into feature/latex-shortcaption
ivanovmg Oct 17, 2020
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
23 changes: 19 additions & 4 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -2887,7 +2887,8 @@ def to_latex(
multicolumn=None,
multicolumn_format=None,
multirow=None,
caption=None,
caption: Optional[Union[str, Tuple[str, str]]] = None,
short_caption=None,
Copy link
Member

Choose a reason for hiding this comment

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

This can be removed from the signature right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Did that, but the build failed due to exceeding time of 1 hour.

Copy link
Member

Choose a reason for hiding this comment

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

restarted

Copy link
Member Author

Choose a reason for hiding this comment

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

Failure of TestRegistration.test_pandas_plots_register, which does not seem to be related to the commits.

label=None,
position=None,
):
Expand Down Expand Up @@ -2965,11 +2966,12 @@ def to_latex(
centered labels (instead of top-aligned) across the contained
rows, separating groups via clines. The default will be read
from the pandas config module.
caption : str, optional
The LaTeX caption to be placed inside ``\caption{}`` in the output.
caption : str, tuple, optional
Copy link
Contributor

Choose a reason for hiding this comment

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

str or tuple, optional (change the signature as well)
Optional[Union[str, Tuple[str, str]]]

Copy link
Member Author

Choose a reason for hiding this comment

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

Done. I updated typing on caption in DataFrameFormatter.to_latex() and LatexFormatter.

Tuple (short_caption, full_caption),
which results in \caption[short_caption]{caption};
if a single string is passed, no short caption will be set.

.. versionadded:: 1.0.0
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.. versionadded:: 1.0.0
.. versionchanged:: 1.2.0

Copy link
Member Author

Choose a reason for hiding this comment

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

But I think I should keep .. versionadded for the consistency. Shouldn't I?

Copy link
Member

Choose a reason for hiding this comment

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

sure.

can have both. and add a one-liner describing the changes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added these tags for caption, position (PR #35284) and to_latex function itself.


label : str, optional
The LaTeX label to be placed inside ``\label{}`` in the output.
This is used with ``\ref{}`` in the main ``.tex`` file.
Expand Down Expand Up @@ -3014,6 +3016,18 @@ def to_latex(
if multirow is None:
multirow = config.get_option("display.latex.multirow")

if caption:
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of doing this here, can you do it in the formatter itself (in the constructor is ok)

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

if isinstance(caption, str):
short_caption = ""
else:
try:
caption, short_caption = caption
except ValueError as err:
msg = "caption must be either str or tuple of two strings"
raise ValueError(msg) from err
else:
short_caption = None

formatter = DataFrameFormatter(
self,
columns=columns,
Expand All @@ -3038,6 +3052,7 @@ def to_latex(
multicolumn_format=multicolumn_format,
multirow=multirow,
caption=caption,
short_caption=short_caption,
label=label,
position=position,
)
Expand Down
2 changes: 2 additions & 0 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -930,6 +930,7 @@ def to_latex(
multicolumn_format: Optional[str] = None,
multirow: bool = False,
caption: Optional[str] = None,
short_caption: Optional[str] = None,
Copy link
Contributor

Choose a reason for hiding this comment

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

same

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.

label: Optional[str] = None,
position: Optional[str] = None,
) -> Optional[str]:
Expand All @@ -946,6 +947,7 @@ def to_latex(
multicolumn_format=multicolumn_format,
multirow=multirow,
caption=caption,
short_caption=short_caption,
label=label,
position=position,
).get_result(buf=buf, encoding=encoding)
Expand Down
28 changes: 17 additions & 11 deletions pandas/io/formats/latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ def __init__(
multicolumn_format: Optional[str] = None,
multirow: bool = False,
caption: Optional[str] = None,
short_caption: Optional[str] = None,
label: Optional[str] = None,
position: Optional[str] = None,
):
Expand All @@ -49,6 +50,7 @@ def __init__(
self.multicolumn_format = multicolumn_format
self.multirow = multirow
self.caption = caption
self.short_caption = short_caption
self.label = label
self.escape = self.fmt.escape
self.position = position
Expand Down Expand Up @@ -283,15 +285,8 @@ def _write_tabular_begin(self, buf, column_format: str):
"""
if self._table_float:
# then write output in a nested table/tabular or longtable environment
if self.caption is None:
caption_ = ""
else:
caption_ = f"\n\\caption{{{self.caption}}}"

if self.label is None:
label_ = ""
else:
label_ = f"\n\\label{{{self.label}}}"
caption_ = self._compose_caption_macro()
label_ = self._compose_label_macro()

if self.position is None:
position_ = ""
Expand Down Expand Up @@ -339,5 +334,16 @@ def _write_tabular_end(self, buf):
buf.write("\\end{tabular}\n")
if self._table_float:
buf.write("\\end{table}\n")
else:
pass

def _compose_caption_macro(self):
if self.caption is None:
return ""
if self.short_caption:
return f"\n\\caption[{self.short_caption}]{{{self.caption}}}"
return f"\n\\caption{{{self.caption}}}"

def _compose_label_macro(self):
if self.label is None:
return ""
else:
return f"\n\\label{{{self.label}}}"
87 changes: 87 additions & 0 deletions pandas/tests/io/formats/test_to_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,7 @@ def test_to_latex_longtable(self):
def test_to_latex_caption_label(self):
# GH 25436
the_caption = "a table in a \\texttt{table/tabular} environment"
the_short_caption = "a table"
the_label = "tab:table_tabular"

df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
Expand Down Expand Up @@ -497,12 +498,73 @@ def test_to_latex_caption_label(self):
\bottomrule
\end{tabular}
\end{table}
"""
assert result_cl == expected_cl

# test when the short_caption is provided alongside caption
Copy link
Member

Choose a reason for hiding this comment

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

Can you split each comment here into a separate test?

Copy link
Member Author

Choose a reason for hiding this comment

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

Did that.

result_cl = df.to_latex(caption=(the_caption, the_short_caption))

expected_cl = r"""\begin{table}
\centering
\caption[a table]{a table in a \texttt{table/tabular} environment}
\begin{tabular}{lrl}
\toprule
{} & a & b \\
\midrule
0 & 1 & b1 \\
1 & 2 & b2 \\
\bottomrule
\end{tabular}
\end{table}
"""
assert result_cl == expected_cl

# test when the short_caption is provided alongside caption and label
result_cl = df.to_latex(
caption=(the_caption, the_short_caption), label=the_label,
)

expected_cl = r"""\begin{table}
\centering
\caption[a table]{a table in a \texttt{table/tabular} environment}
\label{tab:table_tabular}
\begin{tabular}{lrl}
\toprule
{} & a & b \\
\midrule
0 & 1 & b1 \\
1 & 2 & b2 \\
\bottomrule
\end{tabular}
\end{table}
"""
assert result_cl == expected_cl

# test that wrong number of params is raised
with pytest.raises(ValueError):
df.to_latex(caption=(the_caption, the_short_caption, "extra_string"))

# test that two chars caption is handled correctly
result_cl = df.to_latex(caption="xy")
expected_cl = r"""\begin{table}
\centering
\caption{xy}
\begin{tabular}{lrl}
\toprule
{} & a & b \\
\midrule
0 & 1 & b1 \\
1 & 2 & b2 \\
\bottomrule
\end{tabular}
\end{table}
"""
assert result_cl == expected_cl

def test_to_latex_longtable_caption_label(self):
# GH 25436
the_caption = "a table in a \\texttt{longtable} environment"
the_short_caption = "a table"
the_label = "tab:longtable"

df = DataFrame({"a": [1, 2], "b": ["b1", "b2"]})
Expand Down Expand Up @@ -566,6 +628,31 @@ def test_to_latex_longtable_caption_label(self):
\midrule
\endfoot

\bottomrule
\endlastfoot
0 & 1 & b1 \\
1 & 2 & b2 \\
\end{longtable}
"""
assert result_cl == expected_cl

# test when the caption, the short_caption and the label are provided
Copy link
Member

Choose a reason for hiding this comment

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

Same comment here - modular tests are much easier to debug in case of future issues

Copy link
Member Author

Choose a reason for hiding this comment

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

I absolutely agree. I would prefer this #36528 to be merged first, and then rebase on top of that with the separate tests.

Copy link
Member Author

@ivanovmg ivanovmg Sep 23, 2020

Choose a reason for hiding this comment

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

Split tests.

result_cl = df.to_latex(
longtable=True, caption=(the_caption, the_short_caption), label=the_label,
)

expected_cl = r"""\begin{longtable}{lrl}
\caption[a table]{a table in a \texttt{longtable} environment}
\label{tab:longtable}\\
\toprule
{} & a & b \\
\midrule
\endhead
\midrule
\multicolumn{3}{r}{{Continued on next page}} \\
\midrule
\endfoot

\bottomrule
\endlastfoot
0 & 1 & b1 \\
Expand Down