Skip to content
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

ENH: added an optional css id to <table> tags created by `frame.to_… #19594

Merged
merged 1 commit into from
Feb 9, 2018
Merged
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
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.23.0.txt
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ I/O
^^^

- :func:`read_html` now rewinds seekable IO objects after parse failure, before attempting to parse with a new parser. If a parser errors and the object is non-seekable, an informative error is raised suggesting the use of a different parser (:issue:`17975`)
- :meth:`DataFrame.to_html` now has an option to add an id to the leading `<table>` tag (:issue:`8496`)
- Bug in :func:`read_msgpack` with a non existent file is passed in Python 2 (:issue:`15296`)
- Bug in :func:`read_csv` where a ``MultiIndex`` with duplicate columns was not being mangled appropriately (:issue:`18062`)
- Bug in :func:`read_csv` where missing values were not being handled properly when ``keep_default_na=False`` with dictionary ``na_values`` (:issue:`19227`)
Expand Down
10 changes: 8 additions & 2 deletions pandas/core/frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -1727,7 +1727,7 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
sparsify=None, index_names=True, justify=None, bold_rows=True,
classes=None, escape=True, max_rows=None, max_cols=None,
show_dimensions=False, notebook=False, decimal='.',
border=None):
border=None, table_id=None):
"""
Render a DataFrame as an HTML table.

Expand Down Expand Up @@ -1755,6 +1755,12 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
`<table>` tag. Default ``pd.options.html.border``.

.. versionadded:: 0.19.0

table_id : str, optional
A css id is included in the opening `<table>` tag if specified.

.. versionadded:: 0.23.0

"""

if (justify is not None and
Expand All @@ -1772,7 +1778,7 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
max_rows=max_rows,
max_cols=max_cols,
show_dimensions=show_dimensions,
decimal=decimal)
decimal=decimal, table_id=table_id)
# TODO: a generic formatter wld b in DataFrameFormatter
formatter.to_html(classes=classes, notebook=notebook, border=border)

Expand Down
25 changes: 19 additions & 6 deletions pandas/io/formats/format.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,11 @@
index_names : bool, optional
Prints the names of the indexes, default True
line_width : int, optional
Width to wrap a line in characters, default no wrap"""
Width to wrap a line in characters, default no wrap
table_id : str, optional
id for the <table> element create by to_html

.. versionadded:: 0.23.0"""

_VALID_JUSTIFY_PARAMETERS = ("left", "right", "center", "justify",
"justify-all", "start", "end", "inherit",
Expand Down Expand Up @@ -387,7 +391,8 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
header=True, index=True, na_rep='NaN', formatters=None,
justify=None, float_format=None, sparsify=None,
index_names=True, line_width=None, max_rows=None,
max_cols=None, show_dimensions=False, decimal='.', **kwds):
max_cols=None, show_dimensions=False, decimal='.',
table_id=None, **kwds):
self.frame = frame
if buf is not None:
self.buf = _expand_user(_stringify_path(buf))
Expand All @@ -413,6 +418,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
self.max_rows_displayed = min(max_rows or len(self.frame),
len(self.frame))
self.show_dimensions = show_dimensions
self.table_id = table_id

if justify is None:
self.justify = get_option("display.colheader_justify")
Expand Down Expand Up @@ -740,7 +746,8 @@ def to_html(self, classes=None, notebook=False, border=None):
max_rows=self.max_rows,
max_cols=self.max_cols,
notebook=notebook,
border=border)
border=border,
table_id=self.table_id)
if hasattr(self.buf, 'write'):
html_renderer.write_result(self.buf)
elif isinstance(self.buf, compat.string_types):
Expand Down Expand Up @@ -1082,7 +1089,7 @@ class HTMLFormatter(TableFormatter):
indent_delta = 2

def __init__(self, formatter, classes=None, max_rows=None, max_cols=None,
notebook=False, border=None):
notebook=False, border=None, table_id=None):
self.fmt = formatter
self.classes = classes

Expand All @@ -1101,6 +1108,7 @@ def __init__(self, formatter, classes=None, max_rows=None, max_cols=None,
if border is None:
border = get_option('display.html.border')
self.border = border
self.table_id = table_id

def write(self, s, indent=0):
rs = pprint_thing(s)
Expand Down Expand Up @@ -1197,6 +1205,7 @@ def write_style(self):

def write_result(self, buf):
indent = 0
id_section = ""
frame = self.frame

_classes = ['dataframe'] # Default class.
Expand All @@ -1220,8 +1229,12 @@ def write_result(self, buf):
self.write('<div{style}>'.format(style=div_style))

self.write_style()
self.write('<table border="{border}" class="{cls}">'
.format(border=self.border, cls=' '.join(_classes)), indent)

if self.table_id is not None:
id_section = ' id="{table_id}"'.format(table_id=self.table_id)
self.write('<table border="{border}" class="{cls}"{id_section}>'
.format(border=self.border, cls=' '.join(_classes),
id_section=id_section), indent)

indent += self.indent_delta
indent = self._write_header(indent)
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/io/formats/test_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -1492,15 +1492,15 @@ def test_repr_html_float(self):
'B': np.arange(41, 41 + h)}).set_index('idx')
reg_repr = df._repr_html_()
assert '..' not in reg_repr
assert str(40 + h) in reg_repr
assert '<td>{val}</td>'.format(val=str(40 + h)) in reg_repr

h = max_rows + 1
df = DataFrame({'idx': np.linspace(-10, 10, h),
'A': np.arange(1, 1 + h),
'B': np.arange(41, 41 + h)}).set_index('idx')
long_repr = df._repr_html_()
assert '..' in long_repr
assert '31' not in long_repr
assert '<td>{val}</td>'.format(val='31') not in long_repr
assert u('{h} rows ').format(h=h) in long_repr
assert u('2 columns') in long_repr

Expand Down
7 changes: 7 additions & 0 deletions pandas/tests/io/formats/test_to_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1864,3 +1864,10 @@ def test_to_html_with_index_names_false(self):
name='myindexname'))
result = df.to_html(index_names=False)
assert 'myindexname' not in result

def test_to_html_with_id(self):
# gh-8496
df = pd.DataFrame({"A": [1, 2]}, index=pd.Index(['a', 'b'],
name='myindexname'))
result = df.to_html(index_names=False, table_id="TEST_ID")
assert ' id="TEST_ID"' in result