Skip to content

Commit

Permalink
BUG: fix to_latex() when using MultiIndex with NaN in (#14249)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomneep committed Feb 26, 2018
1 parent 1e4c50a commit 5dbe1af
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,7 @@ I/O
- Bug in :func:`read_csv` where missing values were not being handled properly when ``keep_default_na=False`` with dictionary ``na_values`` (:issue:`19227`)
- Bug in :func:`read_sas` where a file with 0 variables gave an ``AttributeError`` incorrectly. Now it gives an ``EmptyDataError`` (:issue:`18184`)
- Bug in :func:`DataFrame.to_latex()` where pairs of braces meant to serve as invisible placeholders were escaped (:issue:`18667`)
- Bug in :func:`DataFrame.to_latex()` where a ``NaN`` in a ``MultiIndex`` would cause an ``IndexError`` or incorrect output (:issue:`14249`)
- Bug in :func:`read_json` where large numeric values were causing an ``OverflowError`` (:issue:`18842`)
- Bug in :func:`DataFrame.to_parquet` where an exception was raised if the write destination is S3 (:issue:`19134`)
- :class:`Interval` now supported in :func:`DataFrame.to_excel` for all Excel file types (:issue:`19242`)
Expand Down
14 changes: 8 additions & 6 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,8 @@ def get_col_type(dtype):
previous_lev3 = None
for i, lev in enumerate(self.frame.index.levels):
lev2 = lev.format()
blank = ' ' * len(lev2[0])
blank = (' ' * len(lev2[0]) if lev2 else
' ' * len(self.fmt.na_rep))
# display column names in last index-column
if cname and i == lastcol:
lev3 = [x if x else '{}' for x in self.frame.columns.names]
Expand All @@ -922,15 +923,16 @@ def get_col_type(dtype):
lev3.append(lev.name)
current_idx_val = None
for level_idx in self.frame.index.labels[i]:
idx_val = (lev2[level_idx] if level_idx >= 0 else
self.fmt.na_rep)
if ((previous_lev3 is None or
previous_lev3[len(lev3)].isspace()) and
lev2[level_idx] == current_idx_val):
previous_lev3[len(lev3)].isspace()) and
idx_val == current_idx_val):
# same index as above row and left index was the same
lev3.append(blank)
else:
# different value than above or left index different
lev3.append(lev2[level_idx])
current_idx_val = lev2[level_idx]
lev3.append(idx_val)
current_idx_val = idx_val
strcols.insert(i, lev3)
previous_lev3 = lev3

Expand Down
22 changes: 22 additions & 0 deletions pandas/tests/io/formats/test_to_latex.py
Original file line number Diff line number Diff line change
Expand Up @@ -621,3 +621,25 @@ def test_to_latex_multiindex_names(self, name0, name1, axes):
\end{tabular}
""" % tuple(list(col_names) + [idx_names_row])
assert observed == expected

@pytest.mark.parametrize('one_row', [True, False])
def test_to_latex_multiindex_nans(self, one_row):
# GH 14249
df = pd.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()
expected = r"""\begin{tabular}{llr}
\toprule
& & c \\
a & b & \\
\midrule
NaN & 2 & 4 \\
"""
if not one_row:
expected += r"""1.0 & 3 & 5 \\
"""
expected += r"""\bottomrule
\end{tabular}
"""
assert observed == expected

0 comments on commit 5dbe1af

Please sign in to comment.