diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt
index ad3b966575427..00290bb9a1484 100644
--- a/doc/source/whatsnew/v0.17.0.txt
+++ b/doc/source/whatsnew/v0.17.0.txt
@@ -464,6 +464,8 @@ Performance Improvements
Bug Fixes
~~~~~~~~~
+
+- Bug in ``DataFrame.to_html(index=False)`` renders unnecessary ``name`` row (:issue:`10344`)
- Bug in ``DataFrame.apply`` when function returns categorical series. (:issue:`9573`)
- Bug in ``to_datetime`` with invalid dates and formats supplied (:issue:`10154`)
- Bug in ``Index.drop_duplicates`` dropping name(s) (:issue:`10115`)
diff --git a/pandas/core/format.py b/pandas/core/format.py
index 6a05f819908af..81d47d9e1f36c 100644
--- a/pandas/core/format.py
+++ b/pandas/core/format.py
@@ -1037,7 +1037,7 @@ def _column_header():
self.write_tr(col_row, indent, self.indent_delta, header=True,
align=align)
- if self.fmt.has_index_names:
+ if self.fmt.has_index_names and self.fmt.index:
row = [
x if x is not None else '' for x in self.frame.index.names
] + [''] * min(len(self.columns), self.max_cols)
diff --git a/pandas/tests/test_format.py b/pandas/tests/test_format.py
index b733cacc01e05..5af12070f5a2d 100644
--- a/pandas/tests/test_format.py
+++ b/pandas/tests/test_format.py
@@ -632,6 +632,10 @@ def test_to_html_multiindex_index_false(self):
"""
self.assertEqual(result, expected)
+ df.index = Index(df.index.values, name='idx')
+ result = df.to_html(index=False)
+ self.assertEqual(result, expected)
+
def test_to_html_multiindex_sparsify_false_multi_sparse(self):
with option_context('display.multi_sparse', False):
index = MultiIndex.from_arrays([[0, 0, 1, 1], [0, 1, 0, 1]],
@@ -1922,15 +1926,195 @@ def test_to_html_index(self):
'C': ['one', 'two', np.NaN]},
columns=['A', 'B', 'C'],
index=index)
+ expected_with_index = ('
\n'
+ ' \n'
+ ' \n'
+ ' | \n'
+ ' A | \n'
+ ' B | \n'
+ ' C | \n'
+ '
\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' foo | \n'
+ ' 1 | \n'
+ ' 1.2 | \n'
+ ' one | \n'
+ '
\n'
+ ' \n'
+ ' bar | \n'
+ ' 2 | \n'
+ ' 3.4 | \n'
+ ' two | \n'
+ '
\n'
+ ' \n'
+ ' baz | \n'
+ ' 3 | \n'
+ ' 5.6 | \n'
+ ' NaN | \n'
+ '
\n'
+ ' \n'
+ '
')
+ self.assertEqual(df.to_html(), expected_with_index)
+
+ expected_without_index = ('\n'
+ ' \n'
+ ' \n'
+ ' A | \n'
+ ' B | \n'
+ ' C | \n'
+ '
\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' 1 | \n'
+ ' 1.2 | \n'
+ ' one | \n'
+ '
\n'
+ ' \n'
+ ' 2 | \n'
+ ' 3.4 | \n'
+ ' two | \n'
+ '
\n'
+ ' \n'
+ ' 3 | \n'
+ ' 5.6 | \n'
+ ' NaN | \n'
+ '
\n'
+ ' \n'
+ '
')
result = df.to_html(index=False)
for i in index:
self.assertNotIn(i, result)
+ self.assertEqual(result, expected_without_index)
+ df.index = Index(['foo', 'bar', 'baz'], name='idx')
+ expected_with_index = ('\n'
+ ' \n'
+ ' \n'
+ ' | \n'
+ ' A | \n'
+ ' B | \n'
+ ' C | \n'
+ '
\n'
+ ' \n'
+ ' idx | \n'
+ ' | \n'
+ ' | \n'
+ ' | \n'
+ '
\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' foo | \n'
+ ' 1 | \n'
+ ' 1.2 | \n'
+ ' one | \n'
+ '
\n'
+ ' \n'
+ ' bar | \n'
+ ' 2 | \n'
+ ' 3.4 | \n'
+ ' two | \n'
+ '
\n'
+ ' \n'
+ ' baz | \n'
+ ' 3 | \n'
+ ' 5.6 | \n'
+ ' NaN | \n'
+ '
\n'
+ ' \n'
+ '
')
+ self.assertEqual(df.to_html(), expected_with_index)
+ self.assertEqual(df.to_html(index=False), expected_without_index)
tuples = [('foo', 'car'), ('foo', 'bike'), ('bar', 'car')]
df.index = MultiIndex.from_tuples(tuples)
+
+ expected_with_index = ('\n'
+ ' \n'
+ ' \n'
+ ' | \n'
+ ' | \n'
+ ' A | \n'
+ ' B | \n'
+ ' C | \n'
+ '
\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' foo | \n'
+ ' car | \n'
+ ' 1 | \n'
+ ' 1.2 | \n'
+ ' one | \n'
+ '
\n'
+ ' \n'
+ ' bike | \n'
+ ' 2 | \n'
+ ' 3.4 | \n'
+ ' two | \n'
+ '
\n'
+ ' \n'
+ ' bar | \n'
+ ' car | \n'
+ ' 3 | \n'
+ ' 5.6 | \n'
+ ' NaN | \n'
+ '
\n'
+ ' \n'
+ '
')
+ self.assertEqual(df.to_html(), expected_with_index)
+
result = df.to_html(index=False)
for i in ['foo', 'bar', 'car', 'bike']:
self.assertNotIn(i, result)
+ # must be the same result as normal index
+ self.assertEqual(result, expected_without_index)
+
+ df.index = MultiIndex.from_tuples(tuples, names=['idx1', 'idx2'])
+ expected_with_index = ('\n'
+ ' \n'
+ ' \n'
+ ' | \n'
+ ' | \n'
+ ' A | \n'
+ ' B | \n'
+ ' C | \n'
+ '
\n'
+ ' \n'
+ ' idx1 | \n'
+ ' idx2 | \n'
+ ' | \n'
+ ' | \n'
+ ' | \n'
+ '
\n'
+ ' \n'
+ ' \n'
+ ' \n'
+ ' foo | \n'
+ ' car | \n'
+ ' 1 | \n'
+ ' 1.2 | \n'
+ ' one | \n'
+ '
\n'
+ ' \n'
+ ' bike | \n'
+ ' 2 | \n'
+ ' 3.4 | \n'
+ ' two | \n'
+ '
\n'
+ ' \n'
+ ' bar | \n'
+ ' car | \n'
+ ' 3 | \n'
+ ' 5.6 | \n'
+ ' NaN | \n'
+ '
\n'
+ ' \n'
+ '
')
+ self.assertEqual(df.to_html(), expected_with_index)
+ self.assertEqual(df.to_html(index=False), expected_without_index)
def test_repr_html(self):
self.frame._repr_html_()