From 26421eb76a9110dc3787665d7d36fdfe4302c163 Mon Sep 17 00:00:00 2001 From: Daniel Julius Lasiman Date: Wed, 3 Jun 2015 15:07:02 +0700 Subject: [PATCH] Fix undesired UX behavior of DataFrame output in IPython Notebook #10231 --- doc/source/whatsnew/v0.16.2.txt | 2 ++ pandas/core/format.py | 31 ++++++++++++++++++++++++++++--- pandas/core/frame.py | 12 ++++++------ pandas/tests/test_format.py | 21 +++++++++++++++------ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/doc/source/whatsnew/v0.16.2.txt b/doc/source/whatsnew/v0.16.2.txt index b571aab0b19a5..800a5c71ebabb 100644 --- a/doc/source/whatsnew/v0.16.2.txt +++ b/doc/source/whatsnew/v0.16.2.txt @@ -25,6 +25,8 @@ New features Other enhancements ^^^^^^^^^^^^^^^^^^ +- Removed duplicate scroll bars in DataFrame HTML representation. In pandas internal, large DataFrame's output will be wrapped with vertical and horizontal scroll bars. It is unnecessary because IPython has "toggle output scrolling" feature. In IPython below v3.0 the output is still wrapped with horizontal scroll bar because the horizontal scroll bar is not included (yet) in "toogle output scrolling" feature. In IPython v3.0 or later it is included so the output's scrollability all handled by IPython. (:issue:`10231`) + .. _whatsnew_0162.api: Backwards incompatible API changes diff --git a/pandas/core/format.py b/pandas/core/format.py index 3ab41ded1deea..4e64ea02f93c8 100644 --- a/pandas/core/format.py +++ b/pandas/core/format.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import print_function +from distutils.version import LooseVersion # pylint: disable=W0141 import sys @@ -692,13 +693,20 @@ def _format_col(self, i): space=self.col_space ) - def to_html(self, classes=None): + def to_html(self, classes=None, notebook=False): """ Render a DataFrame to a html table. + + Parameters + ---------- + notebook : {True, False}, optional, default False + Whether the generated HTML is for IPython Notebook. + """ html_renderer = HTMLFormatter(self, classes=classes, max_rows=self.max_rows, - max_cols=self.max_cols) + max_cols=self.max_cols, + notebook=notebook) if hasattr(self.buf, 'write'): html_renderer.write_result(self.buf) elif isinstance(self.buf, compat.string_types): @@ -808,7 +816,8 @@ class HTMLFormatter(TableFormatter): indent_delta = 2 - def __init__(self, formatter, classes=None, max_rows=None, max_cols=None): + def __init__(self, formatter, classes=None, max_rows=None, max_cols=None, + notebook=False): self.fmt = formatter self.classes = classes @@ -823,6 +832,7 @@ def __init__(self, formatter, classes=None, max_rows=None, max_cols=None): self.show_dimensions = self.fmt.show_dimensions self.is_truncated = (self.max_rows < len(self.fmt.frame) or self.max_cols < len(self.fmt.columns)) + self.notebook = notebook def write(self, s, indent=0): rs = com.pprint_thing(s) @@ -890,6 +900,17 @@ def write_result(self, buf): 'not %s') % type(self.classes)) _classes.extend(self.classes) + if self.notebook: + div_style = '' + try: + import IPython + if IPython.__version__ < LooseVersion('3.0.0'): + div_style = ' style="max-width:1500px;overflow:auto;"' + except ImportError: + pass + + self.write(''.format(div_style)) + self.write('' % ' '.join(_classes), indent) @@ -902,6 +923,10 @@ def write_result(self, buf): by = chr(215) if compat.PY3 else unichr(215) # × self.write(u('

%d rows %s %d columns

') % (len(frame), by, len(frame.columns))) + + if self.notebook: + self.write('') + _put_lines(buf, self.elements) def _write_header(self, indent): diff --git a/pandas/core/frame.py b/pandas/core/frame.py index f36108262432d..1455da4ac19db 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -538,10 +538,9 @@ def _repr_html_(self): max_cols = get_option("display.max_columns") show_dimensions = get_option("display.show_dimensions") - return ('
\n' + - self.to_html(max_rows=max_rows, max_cols=max_cols, - show_dimensions=show_dimensions) + '\n
') + return self.to_html(max_rows=max_rows, max_cols=max_cols, + show_dimensions=show_dimensions, + notebook=True) else: return None @@ -1349,7 +1348,8 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, header=True, index=True, na_rep='NaN', formatters=None, float_format=None, sparsify=None, index_names=True, justify=None, bold_rows=True, classes=None, escape=True, - max_rows=None, max_cols=None, show_dimensions=False): + max_rows=None, max_cols=None, show_dimensions=False, + notebook=False): """ Render a DataFrame as an HTML table. @@ -1388,7 +1388,7 @@ def to_html(self, buf=None, columns=None, col_space=None, colSpace=None, max_rows=max_rows, max_cols=max_cols, show_dimensions=show_dimensions) - formatter.to_html(classes=classes) + formatter.to_html(classes=classes, notebook=notebook) if buf is None: return formatter.buf.getvalue() diff --git a/pandas/tests/test_format.py b/pandas/tests/test_format.py index a7129bca59a7f..535fde34d7684 100644 --- a/pandas/tests/test_format.py +++ b/pandas/tests/test_format.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import print_function +from distutils.version import LooseVersion import re from pandas.compat import range, zip, lrange, StringIO, PY3, lzip, u @@ -14,6 +15,14 @@ from numpy.random import randn import numpy as np +div_style = '' +try: + import IPython + if IPython.__version__ < LooseVersion('3.0.0'): + div_style = ' style="max-width:1500px;overflow:auto;"' +except ImportError: + pass + from pandas import DataFrame, Series, Index, Timestamp, MultiIndex, date_range, NaT import pandas.core.format as fmt @@ -892,7 +901,7 @@ def test_to_html_truncate(self): fmt.set_option('display.max_columns',4) result = df._repr_html_() expected = '''\ -
+
@@ -980,7 +989,7 @@ def test_to_html_truncate(self):

20 rows × 20 columns

-''' +'''.format(div_style) if sys.version_info[0] < 3: expected = expected.decode('utf-8') self.assertEqual(result, expected) @@ -993,7 +1002,7 @@ def test_to_html_truncate_multi_index(self): fmt.set_option('display.max_columns',7) result = df._repr_html_() expected = '''\ -
+ @@ -1096,7 +1105,7 @@ def test_to_html_truncate_multi_index(self):

8 rows × 8 columns

-
''' +'''.format(div_style) if sys.version_info[0] < 3: expected = expected.decode('utf-8') self.assertEqual(result, expected) @@ -1110,7 +1119,7 @@ def test_to_html_truncate_multi_index_sparse_off(self): fmt.set_option('display.multi_sparse',False) result = df._repr_html_() expected = '''\ -
+ @@ -1206,7 +1215,7 @@ def test_to_html_truncate_multi_index_sparse_off(self):

8 rows × 8 columns

-
''' +'''.format(div_style) if sys.version_info[0] < 3: expected = expected.decode('utf-8') self.assertEqual(result, expected)