Repository: pandas-dev/pandas

Issue:
BUG: to_latex outputs string with missing second index level values
I am using pandas to generate a LaTeX string using the to_latex() method on a DataFrame, which is indexed using a MultiIndex object. Running the code snippet produces an incorrect list of strings: the LaTeX table is missing two index numbers.
#### Code Snippet

``` python
import pandas as pd

outliers_lst = [(23240, 0),
                 (23240, 15),
                 (23240, 23),
                 (23240, 31),
                 (23240, 85),
                 (38661, 85),
                 (41231, 85),
                 (41231, 92),
                 (46371, 0)]

headers = (['max', 'EC 1', 'S'],
             ['max', 'EC 1', 'A'],
             ['max', 'EC 2', 'S'])

table = pd.DataFrame("",index = pd.MultiIndex.from_tuples(sorted(outliers_lst)), columns = pd.MultiIndex.from_tuples(headers))
table.to_latex(index = True, longtable = True, column_format = 'c'*5).split('\n')
```
#### Incorrect Output

```
[u'\\begin{longtable}{cccccccccccccccccccccccccc}',
 u'\\toprule',
 u'      &    &  max &   &      \\\\',
 u'      &    & EC 1 &   & EC 2 \\\\',
 u'      &    &    S & A &    S \\\\',
 u'\\midrule',
 u'\\endhead',
 u'\\midrule',
 u'\\multicolumn{3}{r}{{Continued on next page}} \\\\',
 u'\\midrule',
 u'\\endfoot',
 u'',
 u'\\bottomrule',
 u'\\endlastfoot',
 u'23240 & 0  &      &   &      \\\\',
 u'      & 15 &      &   &      \\\\',
 u'      & 23 &      &   &      \\\\',
 u'      & 31 &      &   &      \\\\',
 u'      & 85 &      &   &      \\\\',
 u'38661 &    &      &   &      \\\\',
 u'41231 &    &      &   &      \\\\',
 u'      & 92 &      &   &      \\\\',
 u'46371 & 0  &      &   &      \\\\',
 u'\\end{longtable}',
 u'']
```
#### Correct Output

```
[u'\\begin{longtable}{cccccccccccccccccccccccccc}',
 u'\\toprule',
 u'      &    &  max &   &      \\\\',
 u'      &    & EC 1 &   & EC 2 \\\\',
 u'      &    &    S & A &    S \\\\',
 u'\\midrule',
 u'\\endhead',
 u'\\midrule',
 u'\\multicolumn{3}{r}{{Continued on next page}} \\\\',
 u'\\midrule',
 u'\\endfoot',
 u'',
 u'\\bottomrule',
 u'\\endlastfoot',
 u'23240 & 0  &      &   &      \\\\',
 u'      & 15 &      &   &      \\\\',
 u'      & 23 &      &   &      \\\\',
 u'      & 31 &      &   &      \\\\',
 u'      & 85 &      &   &      \\\\',
 u'38661 & 85 &      &   &      \\\\',
 u'41231 & 85 &      &   &      \\\\',
 u'      & 92 &      &   &      \\\\',
 u'46371 & 0  &      &   &      \\\\',
 u'\\end{longtable}',
 u'']
```

Note that in the correct output LaTeX strings, the rows with indices (38661, 85) and (41231, 85) correctly include the second index (the number 85), but in the incorrect LaTeX strings the rows do not include the number 85.

Could this be because the row (23240, 85) above (38661, 85) includes 85 in its second index?

<details>
commit: None
python: 2.7.12.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 60 Stepping 3, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None

pandas: 0.18.1
nose: 1.3.7
pip: 8.1.2
setuptools: 23.0.0
Cython: 0.24
numpy: 1.11.1
scipy: 0.17.1
statsmodels: 0.6.1
xarray: None
IPython: 4.2.0
sphinx: 1.4.1
patsy: 0.4.1
dateutil: 2.5.3
pytz: 2016.4
blosc: None
bottleneck: 1.1.0
tables: 3.2.2
numexpr: 2.6.0
matplotlib: 1.5.1
openpyxl: 2.3.2
xlrd: 1.0.0
xlwt: 1.1.2
xlsxwriter: 0.9.2
lxml: 3.6.0
bs4: 4.4.1
html5lib: None
httplib2: None
apiclient: None
sqlalchemy: 1.0.13
pymysql: 0.7.6.None
psycopg2: None
jinja2: 2.8
boto: 2.40.0
pandas_datareader: None
</details>



Discussion:
@the-alleged-car That indeed looks like a bug in the multi-index handling (not printing consecutive values should only happen for the same values of the previous level). Thanks for the report!

Smaller reproducible example:

```
In [18]: df = pd.DataFrame(index=pd.MultiIndex.from_tuples([('A', 'c'), ('B', 'c')]), columns=['col'])

In [19]: print(df.to_latex())
\begin{tabular}{lll}
\toprule
  &   &  col \\
\midrule
A & c &  NaN \\
B &   &  NaN \\
\bottomrule
\end{tabular}

```

@the-alleged-car If you want to take a look how to fix it, always welcome!


Resolving patch:
diff --git a/pandas/io/formats/format.py b/pandas/io/formats/format.py
--- a/pandas/io/formats/format.py
+++ b/pandas/io/formats/format.py
@@ -46,7 +46,6 @@
 import pandas as pd
 import numpy as np
 
-import itertools
 import csv
 from functools import partial
 
@@ -903,6 +902,7 @@ def get_col_type(dtype):
             name = any(self.frame.index.names)
             cname = any(self.frame.columns.names)
             lastcol = self.frame.index.nlevels - 1
+            previous_lev3 = None
             for i, lev in enumerate(self.frame.index.levels):
                 lev2 = lev.format()
                 blank = ' ' * len(lev2[0])
@@ -913,11 +913,19 @@ def get_col_type(dtype):
                     lev3 = [blank] * clevels
                 if name:
                     lev3.append(lev.name)
-                for level_idx, group in itertools.groupby(
-                        self.frame.index.labels[i]):
-                    count = len(list(group))
-                    lev3.extend([lev2[level_idx]] + [blank] * (count - 1))
+                current_idx_val = None
+                for level_idx in self.frame.index.labels[i]:
+                    if ((previous_lev3 is None or
+                        previous_lev3[len(lev3)].isspace()) and
+                            lev2[level_idx] == 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]
                 strcols.insert(i, lev3)
+                previous_lev3 = lev3
 
         column_format = self.column_format
         if column_format is None:


Test patch:
diff --git a/pandas/tests/io/formats/test_to_latex.py b/pandas/tests/io/formats/test_to_latex.py
--- a/pandas/tests/io/formats/test_to_latex.py
+++ b/pandas/tests/io/formats/test_to_latex.py
@@ -221,6 +221,28 @@ def test_to_latex_multiindex(self):
 
         assert result == expected
 
+    def test_to_latex_multiindex_dupe_level(self):
+        # see gh-14484
+        #
+        # If an index is repeated in subsequent rows, it should be
+        # replaced with a blank in the created table. This should
+        # ONLY happen if all higher order indices (to the left) are
+        # equal too. In this test, 'c' has to be printed both times
+        # because the higher order index 'A' != 'B'.
+        df = pd.DataFrame(index=pd.MultiIndex.from_tuples(
+            [('A', 'c'), ('B', 'c')]), columns=['col'])
+        result = df.to_latex()
+        expected = r"""\begin{tabular}{lll}
+\toprule
+  &   &  col \\
+\midrule
+A & c &  NaN \\
+B & c &  NaN \\
+\bottomrule
+\end{tabular}
+"""
+        assert result == expected
+
     def test_to_latex_multicolumnrow(self):
         df = pd.DataFrame({
             ('c1', 0): {x: x for x in range(5)},