Skip to content

Commit f9f88b2

Browse files
committed
Merge pull request #9889 from hsperr/excel_multiindex
ENH: Raise error writing excel file with a MultiIndexed DataFrame #9794
2 parents 301a773 + a97113c commit f9f88b2

File tree

3 files changed

+51
-26
lines changed

3 files changed

+51
-26
lines changed

doc/source/whatsnew/v0.16.1.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ Enhancements
5454
- Allow timedelta string conversion when leading zero is missing from time definition, ie `0:00:00` vs `00:00:00`. (:issue:`9570`)
5555
- Allow Panel.shift with ``axis='items'`` (:issue:`9890`)
5656

57+
- Trying to write an excel file now raises ``NotImplementedError`` if the ``DataFrame`` has a ``MultiIndex`` instead of writing a broken Excel file. (:issue:`9794`)
58+
5759
.. _whatsnew_0161.api:
5860

5961
API changes
@@ -138,7 +140,6 @@ Bug Fixes
138140

139141

140142
- Bug in unequal comparisons between categorical data and a scalar, which was not in the categories (e.g. ``Series(Categorical(list("abc"), ordered=True)) > "d"``. This returned ``False`` for all elements, but now raises a ``TypeError``. Equality comparisons also now return ``False`` for ``==`` and ``True`` for ``!=``. (:issue:`9848`)
141-
142143
- Bug in DataFrame ``__setitem__`` when right hand side is a dictionary (:issue:`9874`)
143144
- Bug in ``where`` when dtype is ``datetime64/timedelta64``, but dtype of other is not (:issue:`9804`)
144145
- Bug in ``MultiIndex.sortlevel()`` results in unicode level name breaks (:issue:`9875`)

pandas/core/frame.py

+3
Original file line numberDiff line numberDiff line change
@@ -1241,6 +1241,9 @@ def to_excel(self, excel_writer, sheet_name='Sheet1', na_rep='',
12411241
>>> writer.save()
12421242
"""
12431243
from pandas.io.excel import ExcelWriter
1244+
if self.columns.nlevels > 1:
1245+
raise NotImplementedError("Writing as Excel with a MultiIndex is "
1246+
"not yet implemented.")
12441247

12451248
need_save = False
12461249
if encoding == None:

pandas/io/tests/test_excel.py

+46-25
Original file line numberDiff line numberDiff line change
@@ -1132,31 +1132,29 @@ def roundtrip(df, header=True, parser_hdr=0):
11321132

11331133
nrows = 5
11341134
ncols = 3
1135-
1136-
for i in range(1, 4): # row multindex upto nlevel=3
1137-
for j in range(1, 4): # col ""
1138-
df = mkdf(nrows, ncols, r_idx_nlevels=i, c_idx_nlevels=j)
1139-
res = roundtrip(df)
1140-
# shape
1141-
self.assertEqual(res.shape, (nrows, ncols + i))
1142-
1143-
# no nans
1144-
for r in range(len(res.index)):
1145-
for c in range(len(res.columns)):
1146-
self.assertTrue(res.ix[r, c] is not np.nan)
1147-
1148-
for i in range(1, 4): # row multindex upto nlevel=3
1149-
for j in range(1, 4): # col ""
1150-
df = mkdf(nrows, ncols, r_idx_nlevels=i, c_idx_nlevels=j)
1151-
res = roundtrip(df, False)
1152-
# shape
1153-
self.assertEqual(res.shape, (
1154-
nrows - 1, ncols + i)) # first row taken as columns
1155-
1156-
# no nans
1157-
for r in range(len(res.index)):
1158-
for c in range(len(res.columns)):
1159-
self.assertTrue(res.ix[r, c] is not np.nan)
1135+
for use_headers in (True, False):
1136+
for i in range(1, 4): # row multindex upto nlevel=3
1137+
for j in range(1, 4): # col ""
1138+
df = mkdf(nrows, ncols, r_idx_nlevels=i, c_idx_nlevels=j)
1139+
1140+
#this if will be removed once multi column excel writing
1141+
#is implemented for now fixing #9794
1142+
if j>1:
1143+
with tm.assertRaises(NotImplementedError):
1144+
res = roundtrip(df, use_headers)
1145+
else:
1146+
res = roundtrip(df, use_headers)
1147+
1148+
if use_headers:
1149+
self.assertEqual(res.shape, (nrows, ncols + i))
1150+
else:
1151+
# first row taken as columns
1152+
self.assertEqual(res.shape, (nrows - 1, ncols + i))
1153+
1154+
# no nans
1155+
for r in range(len(res.index)):
1156+
for c in range(len(res.columns)):
1157+
self.assertTrue(res.ix[r, c] is not np.nan)
11601158

11611159
res = roundtrip(DataFrame([0]))
11621160
self.assertEqual(res.shape, (1, 1))
@@ -1394,6 +1392,29 @@ class XlwtTests(ExcelWriterBase, tm.TestCase):
13941392
engine_name = 'xlwt'
13951393
check_skip = staticmethod(_skip_if_no_xlwt)
13961394

1395+
def test_excel_raise_not_implemented_error_on_multiindex_columns(self):
1396+
_skip_if_no_xlwt()
1397+
#MultiIndex as columns is not yet implemented 9794
1398+
cols = pd.MultiIndex.from_tuples([('site',''),
1399+
('2014','height'),
1400+
('2014','weight')])
1401+
df = pd.DataFrame(np.random.randn(10,3), columns=cols)
1402+
with tm.assertRaises(NotImplementedError):
1403+
with ensure_clean(self.ext) as path:
1404+
df.to_excel(path, index=False)
1405+
1406+
def test_excel_multiindex_index(self):
1407+
_skip_if_no_xlwt()
1408+
#MultiIndex as index works so assert no error #9794
1409+
cols = pd.MultiIndex.from_tuples([('site',''),
1410+
('2014','height'),
1411+
('2014','weight')])
1412+
df = pd.DataFrame(np.random.randn(3,10), index=cols)
1413+
with ensure_clean(self.ext) as path:
1414+
df.to_excel(path, index=False)
1415+
1416+
1417+
13971418
def test_to_excel_styleconverter(self):
13981419
_skip_if_no_xlwt()
13991420

0 commit comments

Comments
 (0)