diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index 9275357e5ad18..7c98da440e1bf 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1319,6 +1319,7 @@ Notice how we now instead output ``np.nan`` itself instead of a stringified form - :func:`read_sas()` will correctly parse sas7bdat files with many columns (:issue:`22628`) - :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`) - 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`) +- Bug in :func:`to_html()` with ``index=False`` misses truncation indicators (...) on truncated DataFrame (:issue:`15019`, :issue:`22783`) - 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`) - Bug in :func:`DataFrame.to_string()` that caused representations of :class:`DataFrame` to not take up the whole window (:issue:`22984`) - 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`). diff --git a/pandas/io/formats/html.py b/pandas/io/formats/html.py index 2a2a3e57729ec..967e5fca5f711 100644 --- a/pandas/io/formats/html.py +++ b/pandas/io/formats/html.py @@ -305,6 +305,8 @@ def _column_header(): align = self.fmt.justify if truncate_h: + if not self.fmt.index: + row_levels = 0 ins_col = row_levels + self.fmt.tr_col_num col_row.insert(ins_col, '...') @@ -336,15 +338,10 @@ def _write_body(self, indent): fmt_values[i] = self.fmt._format_col(i) # write values - if self.fmt.index: - if isinstance(self.frame.index, ABCMultiIndex): - self._write_hierarchical_rows(fmt_values, indent) - else: - self._write_regular_rows(fmt_values, indent) + if self.fmt.index and isinstance(self.frame.index, ABCMultiIndex): + self._write_hierarchical_rows(fmt_values, indent) else: - for i in range(min(len(self.frame), self.max_rows)): - row = [fmt_values[j][i] for j in range(len(self.columns))] - self.write_tr(row, indent, self.indent_delta, tags=None) + self._write_regular_rows(fmt_values, indent) indent -= self.indent_delta self.write('', indent) @@ -358,11 +355,16 @@ def _write_regular_rows(self, fmt_values, indent): ncols = len(self.fmt.tr_frame.columns) nrows = len(self.fmt.tr_frame) - fmt = self.fmt._get_formatter('__index__') - if fmt is not None: - index_values = self.fmt.tr_frame.index.map(fmt) + + if self.fmt.index: + fmt = self.fmt._get_formatter('__index__') + if fmt is not None: + index_values = self.fmt.tr_frame.index.map(fmt) + else: + index_values = self.fmt.tr_frame.index.format() + row_levels = 1 else: - index_values = self.fmt.tr_frame.index.format() + row_levels = 0 row = [] for i in range(nrows): @@ -370,17 +372,18 @@ def _write_regular_rows(self, fmt_values, indent): if truncate_v and i == (self.fmt.tr_row_num): str_sep_row = ['...'] * len(row) self.write_tr(str_sep_row, indent, self.indent_delta, - tags=None, nindex_levels=1) + tags=None, nindex_levels=row_levels) row = [] - row.append(index_values[i]) + if self.fmt.index: + row.append(index_values[i]) row.extend(fmt_values[j][i] for j in range(ncols)) if truncate_h: - dot_col_ix = self.fmt.tr_col_num + 1 + dot_col_ix = self.fmt.tr_col_num + row_levels row.insert(dot_col_ix, '...') self.write_tr(row, indent, self.indent_delta, tags=None, - nindex_levels=1) + nindex_levels=row_levels) def _write_hierarchical_rows(self, fmt_values, indent): template = 'rowspan="{span}" valign="top"' diff --git a/pandas/tests/io/formats/data/gh15019_expected_output.html b/pandas/tests/io/formats/data/gh15019_expected_output.html new file mode 100644 index 0000000000000..5fb9d960f4465 --- /dev/null +++ b/pandas/tests/io/formats/data/gh15019_expected_output.html @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
01
1.7640520.400157
0.9787382.240893
......
0.950088-0.151357
-0.1032190.410599
diff --git a/pandas/tests/io/formats/data/gh22783_expected_output.html b/pandas/tests/io/formats/data/gh22783_expected_output.html new file mode 100644 index 0000000000000..107db43c48639 --- /dev/null +++ b/pandas/tests/io/formats/data/gh22783_expected_output.html @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
01...34
1.7640520.400157...2.2408931.867558
-0.9772780.950088...-0.1032190.410599
diff --git a/pandas/tests/io/formats/test_to_html.py b/pandas/tests/io/formats/test_to_html.py index 0416cf6da7912..32cf21ddf5f38 100644 --- a/pandas/tests/io/formats/test_to_html.py +++ b/pandas/tests/io/formats/test_to_html.py @@ -22,6 +22,28 @@ pass +def expected_html(datapath, name): + """ + Read HTML file from formats data directory. + + Parameters + ---------- + datapath : pytest fixture + The datapath fixture injected into a test by pytest. + name : str + The name of the HTML file without the suffix. + + Returns + ------- + str : contents of HTML file. + """ + filename = '.'.join([name, 'html']) + filepath = datapath('io', 'formats', 'data', filename) + with open(filepath) as f: + html = f.read() + return html.rstrip() + + class TestToHTML(object): def test_to_html_with_col_space(self): @@ -1881,6 +1903,29 @@ def test_to_html_multiindex_max_cols(self): """) assert result == expected + @pytest.mark.parametrize('index', [False, 0]) + def test_to_html_truncation_index_false_max_rows(self, datapath, index): + # GH 15019 + data = [[1.764052, 0.400157], + [0.978738, 2.240893], + [1.867558, -0.977278], + [0.950088, -0.151357], + [-0.103219, 0.410599]] + df = pd.DataFrame(data) + result = df.to_html(max_rows=4, index=index) + expected = expected_html(datapath, 'gh15019_expected_output') + assert result == expected + + @pytest.mark.parametrize('index', [False, 0]) + def test_to_html_truncation_index_false_max_cols(self, datapath, index): + # GH 22783 + data = [[1.764052, 0.400157, 0.978738, 2.240893, 1.867558], + [-0.977278, 0.950088, -0.151357, -0.103219, 0.410599]] + df = pd.DataFrame(data) + result = df.to_html(max_cols=4, index=index) + expected = expected_html(datapath, 'gh22783_expected_output') + assert result == expected + def test_to_html_notebook_has_style(self): df = pd.DataFrame({"A": [1, 2, 3]}) result = df.to_html(notebook=True)