Skip to content

Commit 7dcc864

Browse files
samghelmsjreback
authored andcommitted
ENH: added an optional css id to <table> tags created by frame.to_html() (#19594)
1 parent f30345f commit 7dcc864

File tree

5 files changed

+37
-10
lines changed

5 files changed

+37
-10
lines changed

doc/source/whatsnew/v0.23.0.txt

+1
Original file line numberDiff line numberDiff line change
@@ -717,6 +717,7 @@ I/O
717717
^^^
718718

719719
- :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`)
720+
- :meth:`DataFrame.to_html` now has an option to add an id to the leading `<table>` tag (:issue:`8496`)
720721
- Bug in :func:`read_msgpack` with a non existent file is passed in Python 2 (:issue:`15296`)
721722
- Bug in :func:`read_csv` where a ``MultiIndex`` with duplicate columns was not being mangled appropriately (:issue:`18062`)
722723
- Bug in :func:`read_csv` where missing values were not being handled properly when ``keep_default_na=False`` with dictionary ``na_values`` (:issue:`19227`)

pandas/core/frame.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -1727,7 +1727,7 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
17271727
sparsify=None, index_names=True, justify=None, bold_rows=True,
17281728
classes=None, escape=True, max_rows=None, max_cols=None,
17291729
show_dimensions=False, notebook=False, decimal='.',
1730-
border=None):
1730+
border=None, table_id=None):
17311731
"""
17321732
Render a DataFrame as an HTML table.
17331733
@@ -1755,6 +1755,12 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
17551755
`<table>` tag. Default ``pd.options.html.border``.
17561756
17571757
.. versionadded:: 0.19.0
1758+
1759+
table_id : str, optional
1760+
A css id is included in the opening `<table>` tag if specified.
1761+
1762+
.. versionadded:: 0.23.0
1763+
17581764
"""
17591765

17601766
if (justify is not None and
@@ -1772,7 +1778,7 @@ def to_html(self, buf=None, columns=None, col_space=None, header=True,
17721778
max_rows=max_rows,
17731779
max_cols=max_cols,
17741780
show_dimensions=show_dimensions,
1775-
decimal=decimal)
1781+
decimal=decimal, table_id=table_id)
17761782
# TODO: a generic formatter wld b in DataFrameFormatter
17771783
formatter.to_html(classes=classes, notebook=notebook, border=border)
17781784

pandas/io/formats/format.py

+19-6
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,11 @@
7777
index_names : bool, optional
7878
Prints the names of the indexes, default True
7979
line_width : int, optional
80-
Width to wrap a line in characters, default no wrap"""
80+
Width to wrap a line in characters, default no wrap
81+
table_id : str, optional
82+
id for the <table> element create by to_html
83+
84+
.. versionadded:: 0.23.0"""
8185

8286
_VALID_JUSTIFY_PARAMETERS = ("left", "right", "center", "justify",
8387
"justify-all", "start", "end", "inherit",
@@ -387,7 +391,8 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
387391
header=True, index=True, na_rep='NaN', formatters=None,
388392
justify=None, float_format=None, sparsify=None,
389393
index_names=True, line_width=None, max_rows=None,
390-
max_cols=None, show_dimensions=False, decimal='.', **kwds):
394+
max_cols=None, show_dimensions=False, decimal='.',
395+
table_id=None, **kwds):
391396
self.frame = frame
392397
if buf is not None:
393398
self.buf = _expand_user(_stringify_path(buf))
@@ -413,6 +418,7 @@ def __init__(self, frame, buf=None, columns=None, col_space=None,
413418
self.max_rows_displayed = min(max_rows or len(self.frame),
414419
len(self.frame))
415420
self.show_dimensions = show_dimensions
421+
self.table_id = table_id
416422

417423
if justify is None:
418424
self.justify = get_option("display.colheader_justify")
@@ -740,7 +746,8 @@ def to_html(self, classes=None, notebook=False, border=None):
740746
max_rows=self.max_rows,
741747
max_cols=self.max_cols,
742748
notebook=notebook,
743-
border=border)
749+
border=border,
750+
table_id=self.table_id)
744751
if hasattr(self.buf, 'write'):
745752
html_renderer.write_result(self.buf)
746753
elif isinstance(self.buf, compat.string_types):
@@ -1082,7 +1089,7 @@ class HTMLFormatter(TableFormatter):
10821089
indent_delta = 2
10831090

10841091
def __init__(self, formatter, classes=None, max_rows=None, max_cols=None,
1085-
notebook=False, border=None):
1092+
notebook=False, border=None, table_id=None):
10861093
self.fmt = formatter
10871094
self.classes = classes
10881095

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

11051113
def write(self, s, indent=0):
11061114
rs = pprint_thing(s)
@@ -1197,6 +1205,7 @@ def write_style(self):
11971205

11981206
def write_result(self, buf):
11991207
indent = 0
1208+
id_section = ""
12001209
frame = self.frame
12011210

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

12221231
self.write_style()
1223-
self.write('<table border="{border}" class="{cls}">'
1224-
.format(border=self.border, cls=' '.join(_classes)), indent)
1232+
1233+
if self.table_id is not None:
1234+
id_section = ' id="{table_id}"'.format(table_id=self.table_id)
1235+
self.write('<table border="{border}" class="{cls}"{id_section}>'
1236+
.format(border=self.border, cls=' '.join(_classes),
1237+
id_section=id_section), indent)
12251238

12261239
indent += self.indent_delta
12271240
indent = self._write_header(indent)

pandas/tests/io/formats/test_format.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1492,15 +1492,15 @@ def test_repr_html_float(self):
14921492
'B': np.arange(41, 41 + h)}).set_index('idx')
14931493
reg_repr = df._repr_html_()
14941494
assert '..' not in reg_repr
1495-
assert str(40 + h) in reg_repr
1495+
assert '<td>{val}</td>'.format(val=str(40 + h)) in reg_repr
14961496

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

pandas/tests/io/formats/test_to_html.py

+7
Original file line numberDiff line numberDiff line change
@@ -1864,3 +1864,10 @@ def test_to_html_with_index_names_false(self):
18641864
name='myindexname'))
18651865
result = df.to_html(index_names=False)
18661866
assert 'myindexname' not in result
1867+
1868+
def test_to_html_with_id(self):
1869+
# gh-8496
1870+
df = pd.DataFrame({"A": [1, 2]}, index=pd.Index(['a', 'b'],
1871+
name='myindexname'))
1872+
result = df.to_html(index_names=False, table_id="TEST_ID")
1873+
assert ' id="TEST_ID"' in result

0 commit comments

Comments
 (0)