diff --git a/doc/source/whatsnew/v0.20.3.txt b/doc/source/whatsnew/v0.20.3.txt index b2d382a3202a5..f9bb198abf6b7 100644 --- a/doc/source/whatsnew/v0.20.3.txt +++ b/doc/source/whatsnew/v0.20.3.txt @@ -37,6 +37,7 @@ Performance Improvements Bug Fixes ~~~~~~~~~ - Fixed issue with dataframe scatter plot for categorical data that reports incorrect column key not found when categorical data is used for plotting (:issue:`16199`) +- Fixed issue with :meth:`DataFrame.style` where element id's were not unique (:issue:`16780`) - Fixed a pytest marker failing downstream packages' tests suites (:issue:`16680`) - Fixed compat with loading a ``DataFrame`` with a ``PeriodIndex``, from a ``format='fixed'`` HDFStore, in Python 3, that was written in Python 2 (:issue:`16781`) diff --git a/pandas/io/formats/style.py b/pandas/io/formats/style.py index 3d7e0fcdc69b3..b08d3877f3b03 100644 --- a/pandas/io/formats/style.py +++ b/pandas/io/formats/style.py @@ -281,13 +281,14 @@ def format_attr(pair): for r, idx in enumerate(self.data.index): row_es = [] for c, value in enumerate(rlabels[r]): + rid = [ROW_HEADING_CLASS, "level%s" % c, "row%s" % r] es = { "type": "th", "is_visible": _is_visible(r, c, idx_lengths), "value": value, "display_value": value, - "class": " ".join([ROW_HEADING_CLASS, "level%s" % c, - "row%s" % r]), + "id": "_".join(rid[1:]), + "class": " ".join(rid) } rowspan = idx_lengths.get((c, r), 0) if rowspan > 1: diff --git a/pandas/tests/io/formats/test_style.py b/pandas/tests/io/formats/test_style.py index 9911888f758fb..59d9f938734ab 100644 --- a/pandas/tests/io/formats/test_style.py +++ b/pandas/tests/io/formats/test_style.py @@ -1,5 +1,6 @@ import copy import textwrap +import re import pytest import numpy as np @@ -505,6 +506,14 @@ def test_uuid(self): assert result is styler assert result.uuid == 'aaa' + def test_unique_id(self): + # See https://github.com/pandas-dev/pandas/issues/16780 + df = pd.DataFrame({'a': [1, 3, 5, 6], 'b': [2, 4, 12, 21]}) + result = df.style.render(uuid='test') + assert 'test' in result + ids = re.findall('id="(.*?)"', result) + assert np.unique(ids).size == len(ids) + def test_table_styles(self): style = [{'selector': 'th', 'props': [('foo', 'bar')]}] styler = Styler(self.df, table_styles=style) @@ -719,12 +728,13 @@ def test_mi_sparse(self): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]])) + result = df.style._translate() body_0 = result['body'][0][0] expected_0 = { "value": "a", "display_value": "a", "is_visible": True, "type": "th", "attributes": ["rowspan=2"], - "class": "row_heading level0 row0", + "class": "row_heading level0 row0", "id": "level0_row0" } tm.assert_dict_equal(body_0, expected_0) @@ -732,6 +742,7 @@ def test_mi_sparse(self): expected_1 = { "value": 0, "display_value": 0, "is_visible": True, "type": "th", "class": "row_heading level1 row0", + "id": "level1_row0" } tm.assert_dict_equal(body_1, expected_1) @@ -739,6 +750,7 @@ def test_mi_sparse(self): expected_10 = { "value": 'a', "display_value": 'a', "is_visible": False, "type": "th", "class": "row_heading level0 row1", + "id": "level0_row1" } tm.assert_dict_equal(body_10, expected_10)