Skip to content

Commit 6a6227d

Browse files
bswegerTomAugspurger
authored andcommitted
ENH: Add to_latex() method to Series (pandas-dev#16180) (pandas-dev#16465)
* ENH: Add to_latex() method to Series (pandas-dev#16180) This changeset adds _repr_latex_ to the Series class and moves the to_latex() method from the DataFrame class to the NDFrame class. * Add Series to_latex test * Move _repr_latex_ to NDFrame Streamline things a bit by moving _repr_latex_ methods out of the Series and DataFrame classes * DOC: Added versionchanged
1 parent e81f3cc commit 6a6227d

File tree

6 files changed

+142
-101
lines changed

6 files changed

+142
-101
lines changed

doc/source/api.rst

+1
Original file line numberDiff line numberDiff line change
@@ -724,6 +724,7 @@ Serialization / IO / Conversion
724724
Series.to_dense
725725
Series.to_string
726726
Series.to_clipboard
727+
Series.to_latex
727728

728729
Sparse
729730
~~~~~~

doc/source/whatsnew/v0.20.2.txt

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ Enhancements
2020
~~~~~~~~~~~~
2121

2222
- Unblocked access to additional compression types supported in pytables: 'blosc:blosclz, 'blosc:lz4', 'blosc:lz4hc', 'blosc:snappy', 'blosc:zlib', 'blosc:zstd' (:issue:`14478`)
23+
- ``Series`` provides a ``to_latex`` method (:issue:`16180`)
2324

2425
.. _whatsnew_0202.performance:
2526

pandas/core/frame.py

-98
Original file line numberDiff line numberDiff line change
@@ -634,16 +634,6 @@ def _repr_html_(self):
634634
else:
635635
return None
636636

637-
def _repr_latex_(self):
638-
"""
639-
Returns a LaTeX representation for a particular Dataframe.
640-
Mainly for use with nbconvert (jupyter notebook conversion to pdf).
641-
"""
642-
if get_option('display.latex.repr'):
643-
return self.to_latex()
644-
else:
645-
return None
646-
647637
@property
648638
def style(self):
649639
"""
@@ -1663,94 +1653,6 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
16631653
if buf is None:
16641654
return formatter.buf.getvalue()
16651655

1666-
@Substitution(header='Write out column names. If a list of string is given, \
1667-
it is assumed to be aliases for the column names.')
1668-
@Appender(fmt.common_docstring + fmt.return_docstring, indents=1)
1669-
def to_latex(self, buf=None, columns=None, col_space=None, header=True,
1670-
index=True, na_rep='NaN', formatters=None, float_format=None,
1671-
sparsify=None, index_names=True, bold_rows=True,
1672-
column_format=None, longtable=None, escape=None,
1673-
encoding=None, decimal='.', multicolumn=None,
1674-
multicolumn_format=None, multirow=None):
1675-
r"""
1676-
Render a DataFrame to a tabular environment table. You can splice
1677-
this into a LaTeX document. Requires \usepackage{booktabs}.
1678-
1679-
`to_latex`-specific options:
1680-
1681-
bold_rows : boolean, default True
1682-
Make the row labels bold in the output
1683-
column_format : str, default None
1684-
The columns format as specified in `LaTeX table format
1685-
<https://en.wikibooks.org/wiki/LaTeX/Tables>`__ e.g 'rcl' for 3
1686-
columns
1687-
longtable : boolean, default will be read from the pandas config module
1688-
Default: False.
1689-
Use a longtable environment instead of tabular. Requires adding
1690-
a \usepackage{longtable} to your LaTeX preamble.
1691-
escape : boolean, default will be read from the pandas config module
1692-
Default: True.
1693-
When set to False prevents from escaping latex special
1694-
characters in column names.
1695-
encoding : str, default None
1696-
A string representing the encoding to use in the output file,
1697-
defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
1698-
decimal : string, default '.'
1699-
Character recognized as decimal separator, e.g. ',' in Europe.
1700-
1701-
.. versionadded:: 0.18.0
1702-
1703-
multicolumn : boolean, default True
1704-
Use \multicolumn to enhance MultiIndex columns.
1705-
The default will be read from the config module.
1706-
1707-
.. versionadded:: 0.20.0
1708-
1709-
multicolumn_format : str, default 'l'
1710-
The alignment for multicolumns, similar to `column_format`
1711-
The default will be read from the config module.
1712-
1713-
.. versionadded:: 0.20.0
1714-
1715-
multirow : boolean, default False
1716-
Use \multirow to enhance MultiIndex rows.
1717-
Requires adding a \usepackage{multirow} to your LaTeX preamble.
1718-
Will print centered labels (instead of top-aligned)
1719-
across the contained rows, separating groups via clines.
1720-
The default will be read from the pandas config module.
1721-
1722-
.. versionadded:: 0.20.0
1723-
1724-
"""
1725-
# Get defaults from the pandas config
1726-
if longtable is None:
1727-
longtable = get_option("display.latex.longtable")
1728-
if escape is None:
1729-
escape = get_option("display.latex.escape")
1730-
if multicolumn is None:
1731-
multicolumn = get_option("display.latex.multicolumn")
1732-
if multicolumn_format is None:
1733-
multicolumn_format = get_option("display.latex.multicolumn_format")
1734-
if multirow is None:
1735-
multirow = get_option("display.latex.multirow")
1736-
1737-
formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns,
1738-
col_space=col_space, na_rep=na_rep,
1739-
header=header, index=index,
1740-
formatters=formatters,
1741-
float_format=float_format,
1742-
bold_rows=bold_rows,
1743-
sparsify=sparsify,
1744-
index_names=index_names,
1745-
escape=escape, decimal=decimal)
1746-
formatter.to_latex(column_format=column_format, longtable=longtable,
1747-
encoding=encoding, multicolumn=multicolumn,
1748-
multicolumn_format=multicolumn_format,
1749-
multirow=multirow)
1750-
1751-
if buf is None:
1752-
return formatter.buf.getvalue()
1753-
17541656
def info(self, verbose=None, buf=None, max_cols=None, memory_usage=None,
17551657
null_counts=None):
17561658
"""

pandas/core/generic.py

+105-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
import pandas.core.common as com
4747
import pandas.core.missing as missing
4848
from pandas.io.formats.printing import pprint_thing
49-
from pandas.io.formats.format import format_percentiles
49+
from pandas.io.formats.format import format_percentiles, DataFrameFormatter
5050
from pandas.tseries.frequencies import to_offset
5151
from pandas import compat
5252
from pandas.compat.numpy import function as nv
@@ -1051,6 +1051,16 @@ def __setstate__(self, state):
10511051
# ----------------------------------------------------------------------
10521052
# IO
10531053

1054+
def _repr_latex_(self):
1055+
"""
1056+
Returns a LaTeX representation for a particular object.
1057+
Mainly for use with nbconvert (jupyter notebook conversion to pdf).
1058+
"""
1059+
if config.get_option('display.latex.repr'):
1060+
return self.to_latex()
1061+
else:
1062+
return None
1063+
10541064
# ----------------------------------------------------------------------
10551065
# I/O Methods
10561066

@@ -1503,6 +1513,100 @@ def to_xarray(self):
15031513
coords=coords,
15041514
)
15051515

1516+
_shared_docs['to_latex'] = """
1517+
Render an object to a tabular environment table. You can splice
1518+
this into a LaTeX document. Requires \\usepackage{booktabs}.
1519+
1520+
.. versionchanged:: 0.20.2
1521+
Added to Series
1522+
1523+
`to_latex`-specific options:
1524+
1525+
bold_rows : boolean, default True
1526+
Make the row labels bold in the output
1527+
column_format : str, default None
1528+
The columns format as specified in `LaTeX table format
1529+
<https://en.wikibooks.org/wiki/LaTeX/Tables>`__ e.g 'rcl' for 3
1530+
columns
1531+
longtable : boolean, default will be read from the pandas config module
1532+
Default: False.
1533+
Use a longtable environment instead of tabular. Requires adding
1534+
a \\usepackage{longtable} to your LaTeX preamble.
1535+
escape : boolean, default will be read from the pandas config module
1536+
Default: True.
1537+
When set to False prevents from escaping latex special
1538+
characters in column names.
1539+
encoding : str, default None
1540+
A string representing the encoding to use in the output file,
1541+
defaults to 'ascii' on Python 2 and 'utf-8' on Python 3.
1542+
decimal : string, default '.'
1543+
Character recognized as decimal separator, e.g. ',' in Europe.
1544+
1545+
.. versionadded:: 0.18.0
1546+
1547+
multicolumn : boolean, default True
1548+
Use \multicolumn to enhance MultiIndex columns.
1549+
The default will be read from the config module.
1550+
1551+
.. versionadded:: 0.20.0
1552+
1553+
multicolumn_format : str, default 'l'
1554+
The alignment for multicolumns, similar to `column_format`
1555+
The default will be read from the config module.
1556+
1557+
.. versionadded:: 0.20.0
1558+
1559+
multirow : boolean, default False
1560+
Use \multirow to enhance MultiIndex rows.
1561+
Requires adding a \\usepackage{multirow} to your LaTeX preamble.
1562+
Will print centered labels (instead of top-aligned)
1563+
across the contained rows, separating groups via clines.
1564+
The default will be read from the pandas config module.
1565+
1566+
.. versionadded:: 0.20.0
1567+
"""
1568+
1569+
@Substitution(header='Write out column names. If a list of string is given, \
1570+
it is assumed to be aliases for the column names.')
1571+
@Appender(_shared_docs['to_latex'] % _shared_doc_kwargs)
1572+
def to_latex(self, buf=None, columns=None, col_space=None, header=True,
1573+
index=True, na_rep='NaN', formatters=None, float_format=None,
1574+
sparsify=None, index_names=True, bold_rows=True,
1575+
column_format=None, longtable=None, escape=None,
1576+
encoding=None, decimal='.', multicolumn=None,
1577+
multicolumn_format=None, multirow=None):
1578+
# Get defaults from the pandas config
1579+
if self.ndim == 1:
1580+
self = self.to_frame()
1581+
if longtable is None:
1582+
longtable = config.get_option("display.latex.longtable")
1583+
if escape is None:
1584+
escape = config.get_option("display.latex.escape")
1585+
if multicolumn is None:
1586+
multicolumn = config.get_option("display.latex.multicolumn")
1587+
if multicolumn_format is None:
1588+
multicolumn_format = config.get_option(
1589+
"display.latex.multicolumn_format")
1590+
if multirow is None:
1591+
multirow = config.get_option("display.latex.multirow")
1592+
1593+
formatter = DataFrameFormatter(self, buf=buf, columns=columns,
1594+
col_space=col_space, na_rep=na_rep,
1595+
header=header, index=index,
1596+
formatters=formatters,
1597+
float_format=float_format,
1598+
bold_rows=bold_rows,
1599+
sparsify=sparsify,
1600+
index_names=index_names,
1601+
escape=escape, decimal=decimal)
1602+
formatter.to_latex(column_format=column_format, longtable=longtable,
1603+
encoding=encoding, multicolumn=multicolumn,
1604+
multicolumn_format=multicolumn_format,
1605+
multirow=multirow)
1606+
1607+
if buf is None:
1608+
return formatter.buf.getvalue()
1609+
15061610
# ----------------------------------------------------------------------
15071611
# Fancy Indexing
15081612

pandas/tests/io/formats/test_to_latex.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44

55
import pandas as pd
6-
from pandas import DataFrame, compat
6+
from pandas import DataFrame, compat, Series
77
from pandas.util import testing as tm
88
from pandas.compat import u
99
import codecs
@@ -491,3 +491,18 @@ def test_to_latex_decimal(self, frame):
491491
"""
492492

493493
assert withindex_result == withindex_expected
494+
495+
def test_to_latex_series(self):
496+
s = Series(['a', 'b', 'c'])
497+
withindex_result = s.to_latex()
498+
withindex_expected = r"""\begin{tabular}{ll}
499+
\toprule
500+
{} & 0 \\
501+
\midrule
502+
0 & a \\
503+
1 & b \\
504+
2 & c \\
505+
\bottomrule
506+
\end{tabular}
507+
"""
508+
assert withindex_result == withindex_expected

pandas/tests/series/test_repr.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import numpy as np
99
import pandas as pd
1010

11-
from pandas import (Index, Series, DataFrame, date_range)
11+
from pandas import (Index, Series, DataFrame, date_range, option_context)
1212
from pandas.core.index import MultiIndex
1313

1414
from pandas.compat import lrange, range, u
@@ -180,3 +180,21 @@ def test_timeseries_repr_object_dtype(self):
180180

181181
ts2 = ts.iloc[np.random.randint(0, len(ts) - 1, 400)]
182182
repr(ts2).splitlines()[-1]
183+
184+
def test_latex_repr(self):
185+
result = r"""\begin{tabular}{ll}
186+
\toprule
187+
{} & 0 \\
188+
\midrule
189+
0 & $\alpha$ \\
190+
1 & b \\
191+
2 & c \\
192+
\bottomrule
193+
\end{tabular}
194+
"""
195+
with option_context('display.latex.escape', False,
196+
'display.latex.repr', True):
197+
s = Series([r'$\alpha$', 'b', 'c'])
198+
assert result == s._repr_latex_()
199+
200+
assert s._repr_latex_() is None

0 commit comments

Comments
 (0)