Skip to content

Fix undesired UX behavior of DataFrame output in IPython Notebook #10232

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/source/whatsnew/v0.16.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 28 additions & 3 deletions pandas/core/format.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import print_function
from distutils.version import LooseVersion
# pylint: disable=W0141

import sys
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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('<div{0}>'.format(div_style))

self.write('<table border="1" class="%s">' % ' '.join(_classes),
indent)

Expand All @@ -902,6 +923,10 @@ def write_result(self, buf):
by = chr(215) if compat.PY3 else unichr(215) # ×
self.write(u('<p>%d rows %s %d columns</p>') %
(len(frame), by, len(frame.columns)))

if self.notebook:
self.write('</div>')

_put_lines(buf, self.elements)

def _write_header(self, indent):
Expand Down
12 changes: 6 additions & 6 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -538,10 +538,9 @@ def _repr_html_(self):
max_cols = get_option("display.max_columns")
show_dimensions = get_option("display.show_dimensions")

return ('<div style="max-height:1000px;'
'max-width:1500px;overflow:auto;">\n' +
self.to_html(max_rows=max_rows, max_cols=max_cols,
show_dimensions=show_dimensions) + '\n</div>')
return self.to_html(max_rows=max_rows, max_cols=max_cols,
show_dimensions=show_dimensions,
notebook=True)
else:
return None

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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()
Expand Down
21 changes: 15 additions & 6 deletions pandas/tests/test_format.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -892,7 +901,7 @@ def test_to_html_truncate(self):
fmt.set_option('display.max_columns',4)
result = df._repr_html_()
expected = '''\
<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<div{0}>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
Expand Down Expand Up @@ -980,7 +989,7 @@ def test_to_html_truncate(self):
</tbody>
</table>
<p>20 rows × 20 columns</p>
</div>'''
</div>'''.format(div_style)
if sys.version_info[0] < 3:
expected = expected.decode('utf-8')
self.assertEqual(result, expected)
Expand All @@ -993,7 +1002,7 @@ def test_to_html_truncate_multi_index(self):
fmt.set_option('display.max_columns',7)
result = df._repr_html_()
expected = '''\
<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<div{0}>
<table border="1" class="dataframe">
<thead>
<tr>
Expand Down Expand Up @@ -1096,7 +1105,7 @@ def test_to_html_truncate_multi_index(self):
</tbody>
</table>
<p>8 rows × 8 columns</p>
</div>'''
</div>'''.format(div_style)
if sys.version_info[0] < 3:
expected = expected.decode('utf-8')
self.assertEqual(result, expected)
Expand All @@ -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 = '''\
<div style="max-height:1000px;max-width:1500px;overflow:auto;">
<div{0}>
<table border="1" class="dataframe">
<thead>
<tr>
Expand Down Expand Up @@ -1206,7 +1215,7 @@ def test_to_html_truncate_multi_index_sparse_off(self):
</tbody>
</table>
<p>8 rows × 8 columns</p>
</div>'''
</div>'''.format(div_style)
if sys.version_info[0] < 3:
expected = expected.decode('utf-8')
self.assertEqual(result, expected)
Expand Down