Skip to content

Commit 8af7637

Browse files
simonjayhawkinsjreback
authored andcommitted
BUG: to_html misses truncation indicators (...) when index=False (pandas-dev#22786)
1 parent e50b5fe commit 8af7637

File tree

5 files changed

+122
-16
lines changed

5 files changed

+122
-16
lines changed

doc/source/whatsnew/v0.24.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -1361,6 +1361,7 @@ Notice how we now instead output ``np.nan`` itself instead of a stringified form
13611361
- :func:`read_sas()` will correctly parse sas7bdat files with many columns (:issue:`22628`)
13621362
- :func:`read_sas()` will correctly parse sas7bdat files with data page types having also bit 7 set (so page type is 128 + 256 = 384) (:issue:`16615`)
13631363
- Bug in :meth:`detect_client_encoding` where potential ``IOError`` goes unhandled when importing in a mod_wsgi process due to restricted access to stdout. (:issue:`21552`)
1364+
- Bug in :func:`to_html()` with ``index=False`` misses truncation indicators (...) on truncated DataFrame (:issue:`15019`, :issue:`22783`)
13641365
- Bug in :func:`DataFrame.to_string()` that broke column alignment when ``index=False`` and width of first column's values is greater than the width of first column's header (:issue:`16839`, :issue:`13032`)
13651366
- Bug in :func:`DataFrame.to_string()` that caused representations of :class:`DataFrame` to not take up the whole window (:issue:`22984`)
13661367
- Bug in :func:`DataFrame.to_csv` where a single level MultiIndex incorrectly wrote a tuple. Now just the value of the index is written (:issue:`19589`).

pandas/io/formats/html.py

+19-16
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ def _column_header():
305305
align = self.fmt.justify
306306

307307
if truncate_h:
308+
if not self.fmt.index:
309+
row_levels = 0
308310
ins_col = row_levels + self.fmt.tr_col_num
309311
col_row.insert(ins_col, '...')
310312

@@ -336,15 +338,10 @@ def _write_body(self, indent):
336338
fmt_values[i] = self.fmt._format_col(i)
337339

338340
# write values
339-
if self.fmt.index:
340-
if isinstance(self.frame.index, ABCMultiIndex):
341-
self._write_hierarchical_rows(fmt_values, indent)
342-
else:
343-
self._write_regular_rows(fmt_values, indent)
341+
if self.fmt.index and isinstance(self.frame.index, ABCMultiIndex):
342+
self._write_hierarchical_rows(fmt_values, indent)
344343
else:
345-
for i in range(min(len(self.frame), self.max_rows)):
346-
row = [fmt_values[j][i] for j in range(len(self.columns))]
347-
self.write_tr(row, indent, self.indent_delta, tags=None)
344+
self._write_regular_rows(fmt_values, indent)
348345

349346
indent -= self.indent_delta
350347
self.write('</tbody>', indent)
@@ -358,29 +355,35 @@ def _write_regular_rows(self, fmt_values, indent):
358355

359356
ncols = len(self.fmt.tr_frame.columns)
360357
nrows = len(self.fmt.tr_frame)
361-
fmt = self.fmt._get_formatter('__index__')
362-
if fmt is not None:
363-
index_values = self.fmt.tr_frame.index.map(fmt)
358+
359+
if self.fmt.index:
360+
fmt = self.fmt._get_formatter('__index__')
361+
if fmt is not None:
362+
index_values = self.fmt.tr_frame.index.map(fmt)
363+
else:
364+
index_values = self.fmt.tr_frame.index.format()
365+
row_levels = 1
364366
else:
365-
index_values = self.fmt.tr_frame.index.format()
367+
row_levels = 0
366368

367369
row = []
368370
for i in range(nrows):
369371

370372
if truncate_v and i == (self.fmt.tr_row_num):
371373
str_sep_row = ['...'] * len(row)
372374
self.write_tr(str_sep_row, indent, self.indent_delta,
373-
tags=None, nindex_levels=1)
375+
tags=None, nindex_levels=row_levels)
374376

375377
row = []
376-
row.append(index_values[i])
378+
if self.fmt.index:
379+
row.append(index_values[i])
377380
row.extend(fmt_values[j][i] for j in range(ncols))
378381

379382
if truncate_h:
380-
dot_col_ix = self.fmt.tr_col_num + 1
383+
dot_col_ix = self.fmt.tr_col_num + row_levels
381384
row.insert(dot_col_ix, '...')
382385
self.write_tr(row, indent, self.indent_delta, tags=None,
383-
nindex_levels=1)
386+
nindex_levels=row_levels)
384387

385388
def _write_hierarchical_rows(self, fmt_values, indent):
386389
template = 'rowspan="{span}" valign="top"'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<table border="1" class="dataframe">
2+
<thead>
3+
<tr style="text-align: right;">
4+
<th>0</th>
5+
<th>1</th>
6+
</tr>
7+
</thead>
8+
<tbody>
9+
<tr>
10+
<td>1.764052</td>
11+
<td>0.400157</td>
12+
</tr>
13+
<tr>
14+
<td>0.978738</td>
15+
<td>2.240893</td>
16+
</tr>
17+
<tr>
18+
<td>...</td>
19+
<td>...</td>
20+
</tr>
21+
<tr>
22+
<td>0.950088</td>
23+
<td>-0.151357</td>
24+
</tr>
25+
<tr>
26+
<td>-0.103219</td>
27+
<td>0.410599</td>
28+
</tr>
29+
</tbody>
30+
</table>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<table border="1" class="dataframe">
2+
<thead>
3+
<tr style="text-align: right;">
4+
<th>0</th>
5+
<th>1</th>
6+
<th>...</th>
7+
<th>3</th>
8+
<th>4</th>
9+
</tr>
10+
</thead>
11+
<tbody>
12+
<tr>
13+
<td>1.764052</td>
14+
<td>0.400157</td>
15+
<td>...</td>
16+
<td>2.240893</td>
17+
<td>1.867558</td>
18+
</tr>
19+
<tr>
20+
<td>-0.977278</td>
21+
<td>0.950088</td>
22+
<td>...</td>
23+
<td>-0.103219</td>
24+
<td>0.410599</td>
25+
</tr>
26+
</tbody>
27+
</table>

pandas/tests/io/formats/test_to_html.py

+45
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,28 @@
2222
pass
2323

2424

25+
def expected_html(datapath, name):
26+
"""
27+
Read HTML file from formats data directory.
28+
29+
Parameters
30+
----------
31+
datapath : pytest fixture
32+
The datapath fixture injected into a test by pytest.
33+
name : str
34+
The name of the HTML file without the suffix.
35+
36+
Returns
37+
-------
38+
str : contents of HTML file.
39+
"""
40+
filename = '.'.join([name, 'html'])
41+
filepath = datapath('io', 'formats', 'data', filename)
42+
with open(filepath) as f:
43+
html = f.read()
44+
return html.rstrip()
45+
46+
2547
class TestToHTML(object):
2648

2749
def test_to_html_with_col_space(self):
@@ -1881,6 +1903,29 @@ def test_to_html_multiindex_max_cols(self):
18811903
</table>""")
18821904
assert result == expected
18831905

1906+
@pytest.mark.parametrize('index', [False, 0])
1907+
def test_to_html_truncation_index_false_max_rows(self, datapath, index):
1908+
# GH 15019
1909+
data = [[1.764052, 0.400157],
1910+
[0.978738, 2.240893],
1911+
[1.867558, -0.977278],
1912+
[0.950088, -0.151357],
1913+
[-0.103219, 0.410599]]
1914+
df = pd.DataFrame(data)
1915+
result = df.to_html(max_rows=4, index=index)
1916+
expected = expected_html(datapath, 'gh15019_expected_output')
1917+
assert result == expected
1918+
1919+
@pytest.mark.parametrize('index', [False, 0])
1920+
def test_to_html_truncation_index_false_max_cols(self, datapath, index):
1921+
# GH 22783
1922+
data = [[1.764052, 0.400157, 0.978738, 2.240893, 1.867558],
1923+
[-0.977278, 0.950088, -0.151357, -0.103219, 0.410599]]
1924+
df = pd.DataFrame(data)
1925+
result = df.to_html(max_cols=4, index=index)
1926+
expected = expected_html(datapath, 'gh22783_expected_output')
1927+
assert result == expected
1928+
18841929
def test_to_html_notebook_has_style(self):
18851930
df = pd.DataFrame({"A": [1, 2, 3]})
18861931
result = df.to_html(notebook=True)

0 commit comments

Comments
 (0)