Skip to content

Commit

Permalink
ENH: added an optional css id to <table> tags created by `frame.to_…
Browse files Browse the repository at this point in the history
…html()` (#19594)
  • Loading branch information
samghelms authored and jreback committed Feb 9, 2018
1 parent f30345f commit 7dcc864
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 10 deletions.
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 @@ -717,6 +717,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

0 comments on commit 7dcc864

Please sign in to comment.