class TestStyler(object): def setup_method(self, method): np.random.seed(24) self.s = DataFrame({'A': np.random.permutation(range(6))}) self.df = DataFrame({'A': [0, 1], 'B': np.random.randn(2)}) self.f = lambda x: x self.g = lambda x: x def h(x, foo='bar'): return pd.Series(['color: {foo}'.format(foo=foo)], index=x.index, name=x.name) self.h = h self.styler = Styler(self.df) self.attrs = pd.DataFrame({'A': ['color: red', 'color: blue']}) self.dataframes = [ self.df, pd.DataFrame({ 'f': [1., 2.], 'o': ['a', 'b'], 'c': pd.Categorical(['a', 'b']) }) ] def test_init_non_pandas(self): with pytest.raises(TypeError): Styler([1, 2, 3]) def test_init_series(self): result = Styler(pd.Series([1, 2])) assert result.data.ndim == 2 def test_repr_html_ok(self): self.styler._repr_html_() def test_update_ctx(self): self.styler._update_ctx(self.attrs) expected = {(0, 0): ['color: red'], (1, 0): ['color: blue']} assert self.styler.ctx == expected def test_update_ctx_flatten_multi(self): attrs = DataFrame( {"A": ['color: red; foo: bar', 'color: blue; foo: baz']}) self.styler._update_ctx(attrs) expected = { (0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz'] } assert self.styler.ctx == expected def test_update_ctx_flatten_multi_traliing_semi(self): attrs = DataFrame( {"A": ['color: red; foo: bar;', 'color: blue; foo: baz;']}) self.styler._update_ctx(attrs) expected = { (0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz'] } assert self.styler.ctx == expected def test_copy(self): s2 = copy.copy(self.styler) assert self.styler is not s2 assert self.styler.ctx is s2.ctx # shallow assert self.styler._todo is s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx == s2.ctx assert self.styler._todo == s2._todo def test_deepcopy(self): s2 = copy.deepcopy(self.styler) assert self.styler is not s2 assert self.styler.ctx is not s2.ctx assert self.styler._todo is not s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx != s2.ctx assert s2._todo == [] assert self.styler._todo != s2._todo def test_clear(self): s = self.df.style.highlight_max()._compute() assert len(s.ctx) > 0 assert len(s._todo) > 0 s.clear() assert len(s.ctx) == 0 assert len(s._todo) == 0 def test_render(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red", "color: blue"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_render_empty_dfs(self): empty_df = DataFrame() es = Styler(empty_df) es.render() # An index but no columns DataFrame(columns=['a']).style.render() # A column but no index DataFrame(index=['a']).style.render() # No IndexError raised? def test_render_double(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series( ["color: red; border: 1px", "color: blue; border: 2px"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_set_properties(self): df = pd.DataFrame({"A": [0, 1]}) result = df.style.set_properties(color='white', size='10px')._compute().ctx # order is deterministic v = ["color: white", "size: 10px"] expected = {(0, 0): v, (1, 0): v} assert result.keys() == expected.keys() for v1, v2 in zip(result.values(), expected.values()): assert sorted(v1) == sorted(v2) def test_set_properties_subset(self): df = pd.DataFrame({'A': [0, 1]}) result = df.style.set_properties(subset=pd.IndexSlice[0, 'A'], color='white')._compute().ctx expected = {(0, 0): ['color: white']} assert result == expected def test_empty_index_name_doesnt_display(self): # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.style._translate() expected = [[{ 'class': 'blank level0', 'type': 'th', 'value': '', 'is_visible': True, 'display_value': '' }, { 'class': 'col_heading level0 col0', 'display_value': 'A', 'type': 'th', 'value': 'A', 'is_visible': True, }, { 'class': 'col_heading level0 col1', 'display_value': 'B', 'type': 'th', 'value': 'B', 'is_visible': True, }, { 'class': 'col_heading level0 col2', 'display_value': 'C', 'type': 'th', 'value': 'C', 'is_visible': True, }]] assert result['head'] == expected def test_index_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index('A').style._translate() expected = [[{ 'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'col_heading level0 col0', 'type': 'th', 'value': 'B', 'display_value': 'B', 'is_visible': True }, { 'class': 'col_heading level0 col1', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True }], [{ 'class': 'index_name level0', 'type': 'th', 'value': 'A' }, { 'class': 'blank', 'type': 'th', 'value': '' }, { 'class': 'blank', 'type': 'th', 'value': '' }]] assert result['head'] == expected def test_multiindex_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index(['A', 'B']).style._translate() expected = [[{ 'class': 'blank', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'col_heading level0 col0', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True }], [{ 'class': 'index_name level0', 'type': 'th', 'value': 'A' }, { 'class': 'index_name level1', 'type': 'th', 'value': 'B' }, { 'class': 'blank', 'type': 'th', 'value': '' }]] assert result['head'] == expected def test_numeric_columns(self): # https://github.com/pandas-dev/pandas/issues/12125 # smoke test for _translate df = pd.DataFrame({0: [1, 2, 3]}) df.style._translate() def test_apply_axis(self): df = pd.DataFrame({'A': [0, 0], 'B': [1, 1]}) f = lambda x: ['val: {max}'.format(max=x.max()) for v in x] result = df.style.apply(f, axis=1) assert len(result._todo) == 1 assert len(result.ctx) == 0 result._compute() expected = { (0, 0): ['val: 1'], (0, 1): ['val: 1'], (1, 0): ['val: 1'], (1, 1): ['val: 1'] } assert result.ctx == expected result = df.style.apply(f, axis=0) expected = { (0, 0): ['val: 0'], (0, 1): ['val: 1'], (1, 0): ['val: 0'], (1, 1): ['val: 1'] } result._compute() assert result.ctx == expected result = df.style.apply(f) # default result._compute() assert result.ctx == expected def test_apply_subset(self): axes = [0, 1] slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for ax in axes: for slice_ in slices: result = self.df.style.apply(self.h, axis=ax, subset=slice_, foo='baz')._compute().ctx expected = dict(((r, c), ['color: baz']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_applymap_subset(self): def f(x): return 'foo: bar' slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for slice_ in slices: result = self.df.style.applymap(f, subset=slice_)._compute().ctx expected = dict(((r, c), ['foo: bar']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_where_with_one_style(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' result = self.df.style.where(f, style1)._compute().ctx expected = dict(((r, c), [style1 if f(self.df.loc[row, col]) else '']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns)) assert result == expected def test_where_subset(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' style2 = 'baz: foo' slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for slice_ in slices: result = self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx expected = dict( ((r, c), [style1 if f(self.df.loc[row, col]) else style2]) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_where_subset_compare_with_applymap(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' style2 = 'baz: foo' def g(x): return style1 if f(x) else style2 slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for slice_ in slices: result = self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx expected = self.df.style.applymap(g, subset=slice_)._compute().ctx assert result == expected def test_empty(self): df = pd.DataFrame({'A': [1, 0]}) s = df.style s.ctx = {(0, 0): ['color: red'], (1, 0): ['']} result = s._translate()['cellstyle'] expected = [{ 'props': [['color', ' red']], 'selector': 'row0_col0' }, { 'props': [['', '']], 'selector': 'row1_col0' }] assert result == expected def test_bar_align_left(self): df = pd.DataFrame({'A': [0, 1, 2]}) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 50.0%, transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 100.0%, transparent 0%)' ] } assert result == expected result = df.style.bar(color='red', width=50)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 25.0%, transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 50.0%, transparent 0%)' ] } assert result == expected df['C'] = ['a'] * len(df) result = df.style.bar(color='red', width=50)._compute().ctx assert result == expected df['C'] = df['C'].astype('category') result = df.style.bar(color='red', width=50)._compute().ctx assert result == expected def test_bar_align_left_0points(self): df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%'], (0, 2): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (1, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (1, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ] } assert result == expected result = df.style.bar(axis=1)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (0, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (0, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (1, 0): ['width: 10em', ' height: 80%'], (1, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)' ], (1, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 0): ['width: 10em', ' height: 80%'], (2, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)' ], (2, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ] } assert result == expected def test_bar_align_mid_pos_and_neg(self): df = pd.DataFrame({'A': [-10, 0, 20, 90]}) result = df.style.bar(align='mid', color=['#d65f5f', '#5fba7d'])._compute().ctx expected = { (0, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #d65f5f 0.0%, ' '#d65f5f 10.0%, transparent 10.0%)' ], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, ' '#d65f5f 10.0%, #d65f5f 10.0%, ' 'transparent 10.0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, #5fba7d 10.0%' ', #5fba7d 30.0%, transparent 30.0%)' ], (3, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, ' '#5fba7d 10.0%, #5fba7d 100.0%, ' 'transparent 100.0%)' ] } assert result == expected def test_bar_align_mid_all_pos(self): df = pd.DataFrame({'A': [10, 20, 50, 100]}) result = df.style.bar(align='mid', color=['#d65f5f', '#5fba7d'])._compute().ctx expected = { (0, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 10.0%, transparent 10.0%)' ], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 20.0%, transparent 20.0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 50.0%, transparent 50.0%)' ], (3, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 100.0%, transparent 100.0%)' ] } assert result == expected def test_bar_align_mid_all_neg(self): df = pd.DataFrame({'A': [-100, -60, -30, -20]}) result = df.style.bar(align='mid', color=['#d65f5f', '#5fba7d'])._compute().ctx expected = { (0, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, ' '#d65f5f 0.0%, #d65f5f 100.0%, ' 'transparent 100.0%)' ], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 40.0%, ' '#d65f5f 40.0%, #d65f5f 100.0%, ' 'transparent 100.0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 70.0%, ' '#d65f5f 70.0%, #d65f5f 100.0%, ' 'transparent 100.0%)' ], (3, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 80.0%, ' '#d65f5f 80.0%, #d65f5f 100.0%, ' 'transparent 100.0%)' ] } assert result == expected def test_bar_align_zero_pos_and_neg(self): # See https://github.com/pandas-dev/pandas/pull/14757 df = pd.DataFrame({'A': [-10, 0, 20, 90]}) result = df.style.bar(align='zero', color=['#d65f5f', '#5fba7d'], width=90)._compute().ctx expected = { (0, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 45.0%, ' '#d65f5f 45.0%, #d65f5f 50%, ' 'transparent 50%)' ], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, ' '#5fba7d 50%, #5fba7d 50.0%, ' 'transparent 50.0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, #5fba7d 50%, ' '#5fba7d 60.0%, transparent 60.0%)' ], (3, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, #5fba7d 50%, ' '#5fba7d 95.0%, transparent 95.0%)' ] } assert result == expected def test_bar_bad_align_raises(self): df = pd.DataFrame({'A': [-100, -60, -30, -20]}) with pytest.raises(ValueError): df.style.bar(align='poorly', color=['#d65f5f', '#5fba7d']) def test_highlight_null(self, null_color='red'): df = pd.DataFrame({'A': [0, np.nan]}) result = df.style.highlight_null()._compute().ctx expected = {(0, 0): [''], (1, 0): ['background-color: red']} assert result == expected def test_nonunique_raises(self): df = pd.DataFrame([[1, 2]], columns=['A', 'A']) with pytest.raises(ValueError): df.style with pytest.raises(ValueError): Styler(df) def test_caption(self): styler = Styler(self.df, caption='foo') result = styler.render() assert all(['caption' in result, 'foo' in result]) styler = self.df.style result = styler.set_caption('baz') assert styler is result assert styler.caption == 'baz' def test_uuid(self): styler = Styler(self.df, uuid='abc123') result = styler.render() assert 'abc123' in result styler = self.df.style result = styler.set_uuid('aaa') 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) result = ' '.join(styler.render().split()) assert 'th { foo: bar; }' in result styler = self.df.style result = styler.set_table_styles(style) assert styler is result assert styler.table_styles == style def test_table_attributes(self): attributes = 'class="foo" data-bar' styler = Styler(self.df, table_attributes=attributes) result = styler.render() assert 'class="foo" data-bar' in result result = self.df.style.set_table_attributes(attributes).render() assert 'class="foo" data-bar' in result def test_precision(self): with pd.option_context('display.precision', 10): s = Styler(self.df) assert s.precision == 10 s = Styler(self.df, precision=2) assert s.precision == 2 s2 = s.set_precision(4) assert s is s2 assert s.precision == 4 def test_apply_none(self): def f(x): return pd.DataFrame(np.where(x == x.max(), 'color: red', ''), index=x.index, columns=x.columns) result = (pd.DataFrame([[1, 2], [3, 4]]).style.apply(f, axis=None)._compute().ctx) assert result[(1, 1)] == ['color: red'] def test_trim(self): result = self.df.style.render() # trim=True assert result.count('#') == 0 result = self.df.style.highlight_max().render() assert result.count('#') == len(self.df.columns) def test_highlight_max(self): df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B']) # max(df) = min(-df) for max_ in [True, False]: if max_: attr = 'highlight_max' else: df = -df attr = 'highlight_min' result = getattr(df.style, attr)()._compute().ctx assert result[(1, 1)] == ['background-color: yellow'] result = getattr(df.style, attr)(color='green')._compute().ctx assert result[(1, 1)] == ['background-color: green'] result = getattr(df.style, attr)(subset='A')._compute().ctx assert result[(1, 0)] == ['background-color: yellow'] result = getattr(df.style, attr)(axis=0)._compute().ctx expected = { (1, 0): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 1): [''], (0, 0): [''] } assert result == expected result = getattr(df.style, attr)(axis=1)._compute().ctx expected = { (0, 1): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 0): [''], (1, 0): [''] } assert result == expected # separate since we can't negate the strs df['C'] = ['a', 'b'] result = df.style.highlight_max()._compute().ctx expected = {(1, 1): ['background-color: yellow']} result = df.style.highlight_min()._compute().ctx expected = {(0, 0): ['background-color: yellow']} def test_export(self): f = lambda x: 'color: red' if x > 0 else 'color: blue' g = lambda x, y, z: 'color: {z}'.format(z=z) \ if x > 0 else 'color: {z}'.format(z=z) style1 = self.styler style1.applymap(f)\ .applymap(g, y='a', z='b')\ .highlight_max() result = style1.export() style2 = self.df.style style2.use(result) assert style1._todo == style2._todo style2.render() def test_display_format(self): df = pd.DataFrame(np.random.random(size=(2, 2))) ctx = df.style.format("{:0.1f}")._translate() assert all(['display_value' in c for c in row] for row in ctx['body']) assert all([len(c['display_value']) <= 3 for c in row[1:]] for row in ctx['body']) assert len(ctx['body'][0][1]['display_value'].lstrip('-')) <= 3 def test_display_format_raises(self): df = pd.DataFrame(np.random.randn(2, 2)) with pytest.raises(TypeError): df.style.format(5) with pytest.raises(TypeError): df.style.format(True) def test_display_subset(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({ "a": "{:0.1f}", "b": "{0:.2%}" }, subset=pd.IndexSlice[0, :])._translate() expected = '0.1' assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == '1.1234' assert ctx['body'][0][2]['display_value'] == '12.34%' raw_11 = '1.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice['a'])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][0][2]['display_value'] == '0.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, 'a'])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[[0, 1], ['a']])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == '1.1' assert ctx['body'][0][2]['display_value'] == '0.1234' assert ctx['body'][1][2]['display_value'] == '1.1234' def test_display_dict(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"})._translate() assert ctx['body'][0][1]['display_value'] == '0.1' assert ctx['body'][0][2]['display_value'] == '12.34%' df['c'] = ['aaa', 'bbb'] ctx = df.style.format({"a": "{:0.1f}", "c": str.upper})._translate() assert ctx['body'][0][1]['display_value'] == '0.1' assert ctx['body'][0][3]['display_value'] == 'AAA' def test_bad_apply_shape(self): df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(lambda x: 'x', subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: [''], subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', '', '']) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], subset=1) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], axis=1) def test_apply_bad_return(self): def f(x): return '' df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(TypeError): df.style._apply(f, axis=None) def test_apply_bad_labels(self): def f(x): return pd.DataFrame(index=[1, 2], columns=['a', 'b']) df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(f, axis=None) def test_get_level_lengths(self): index = pd.MultiIndex.from_product([['a', 'b'], [0, 1, 2]]) expected = { (0, 0): 3, (0, 3): 3, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, (1, 4): 1, (1, 5): 1 } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_get_level_lengths_un_sorted(self): index = pd.MultiIndex.from_arrays([[1, 1, 2, 1], ['a', 'b', 'b', 'd']]) expected = { (0, 0): 2, (0, 2): 1, (0, 3): 1, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1 } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) 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", "id": "level0_row0" } tm.assert_dict_equal(body_0, expected_0) body_1 = result['body'][0][1] 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) body_10 = result['body'][1][0] 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) head = result['head'][0] expected = [{ 'type': 'th', 'class': 'blank', 'value': '', 'is_visible': True, "display_value": '' }, { 'type': 'th', 'class': 'blank level0', 'value': '', 'is_visible': True, 'display_value': '' }, { 'type': 'th', 'class': 'col_heading level0 col0', 'value': 'A', 'is_visible': True, 'display_value': 'A' }] assert head == expected def test_mi_sparse_disabled(self): with pd.option_context('display.multi_sparse', False): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]])) result = df.style._translate() body = result['body'] for row in body: assert 'attributes' not in row[0] def test_mi_sparse_index_names(self): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1'])) result = df.style._translate() head = result['head'][1] expected = [{ 'class': 'index_name level0', 'value': 'idx_level_0', 'type': 'th' }, { 'class': 'index_name level1', 'value': 'idx_level_1', 'type': 'th' }, { 'class': 'blank', 'value': '', 'type': 'th' }] assert head == expected def test_mi_sparse_column_names(self): df = pd.DataFrame(np.arange(16).reshape(4, 4), index=pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'a'], [0, 1, 1, 2]], names=['idx_level_0', 'idx_level_1']), columns=pd.MultiIndex.from_arrays( [['C1', 'C1', 'C2', 'C2'], [1, 0, 1, 0]], names=['col_0', 'col_1'])) result = df.style._translate() head = result['head'][1] expected = [ { 'class': 'blank', 'value': '', 'display_value': '', 'type': 'th', 'is_visible': True }, { 'class': 'index_name level1', 'value': 'col_1', 'display_value': 'col_1', 'is_visible': True, 'type': 'th' }, { 'class': 'col_heading level1 col0', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1 }, { 'class': 'col_heading level1 col1', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0 }, { 'class': 'col_heading level1 col2', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1 }, { 'class': 'col_heading level1 col3', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0 }, ] assert head == expected def test_hide_single_index(self): # GH 14194 # single unnamed index ctx = self.df.style._translate() assert ctx['body'][0][0]['is_visible'] assert ctx['head'][0][0]['is_visible'] ctx2 = self.df.style.hide_index()._translate() assert not ctx2['body'][0][0]['is_visible'] assert not ctx2['head'][0][0]['is_visible'] # single named index ctx3 = self.df.set_index('A').style._translate() assert ctx3['body'][0][0]['is_visible'] assert len(ctx3['head']) == 2 # 2 header levels assert ctx3['head'][0][0]['is_visible'] ctx4 = self.df.set_index('A').style.hide_index()._translate() assert not ctx4['body'][0][0]['is_visible'] assert len(ctx4['head']) == 1 # only 1 header levels assert not ctx4['head'][0][0]['is_visible'] def test_hide_multiindex(self): # GH 14194 df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1'])) ctx1 = df.style._translate() # tests for 'a' and '0' assert ctx1['body'][0][0]['is_visible'] assert ctx1['body'][0][1]['is_visible'] # check for blank header rows assert ctx1['head'][0][0]['is_visible'] assert ctx1['head'][0][1]['is_visible'] ctx2 = df.style.hide_index()._translate() # tests for 'a' and '0' assert not ctx2['body'][0][0]['is_visible'] assert not ctx2['body'][0][1]['is_visible'] # check for blank header rows assert not ctx2['head'][0][0]['is_visible'] assert not ctx2['head'][0][1]['is_visible'] def test_hide_columns_single_level(self): # GH 14194 # test hiding single column ctx = self.df.style._translate() assert ctx['head'][0][1]['is_visible'] assert ctx['head'][0][1]['display_value'] == 'A' assert ctx['head'][0][2]['is_visible'] assert ctx['head'][0][2]['display_value'] == 'B' assert ctx['body'][0][1]['is_visible'] # col A, row 1 assert ctx['body'][1][2]['is_visible'] # col B, row 1 ctx = self.df.style.hide_columns('A')._translate() assert not ctx['head'][0][1]['is_visible'] assert not ctx['body'][0][1]['is_visible'] # col A, row 1 assert ctx['body'][1][2]['is_visible'] # col B, row 1 # test hiding mulitiple columns ctx = self.df.style.hide_columns(['A', 'B'])._translate() assert not ctx['head'][0][1]['is_visible'] assert not ctx['head'][0][2]['is_visible'] assert not ctx['body'][0][1]['is_visible'] # col A, row 1 assert not ctx['body'][1][2]['is_visible'] # col B, row 1 def test_hide_columns_mult_levels(self): # GH 14194 # setup dataframe with multiple column levels and indices i1 = pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1']) i2 = pd.MultiIndex.from_arrays([['b', 'b'], [0, 1]], names=['col_level_0', 'col_level_1']) df = pd.DataFrame([[1, 2], [3, 4]], index=i1, columns=i2) ctx = df.style._translate() # column headers assert ctx['head'][0][2]['is_visible'] assert ctx['head'][1][2]['is_visible'] assert ctx['head'][1][3]['display_value'] == 1 # indices assert ctx['body'][0][0]['is_visible'] # data assert ctx['body'][1][2]['is_visible'] assert ctx['body'][1][2]['display_value'] == 3 assert ctx['body'][1][3]['is_visible'] assert ctx['body'][1][3]['display_value'] == 4 # hide top column level, which hides both columns ctx = df.style.hide_columns('b')._translate() assert not ctx['head'][0][2]['is_visible'] # b assert not ctx['head'][1][2]['is_visible'] # 0 assert not ctx['body'][1][2]['is_visible'] # 3 assert ctx['body'][0][0]['is_visible'] # index # hide first column only ctx = df.style.hide_columns([('b', 0)])._translate() assert ctx['head'][0][2]['is_visible'] # b assert not ctx['head'][1][2]['is_visible'] # 0 assert not ctx['body'][1][2]['is_visible'] # 3 assert ctx['body'][1][3]['is_visible'] assert ctx['body'][1][3]['display_value'] == 4 # hide second column and index ctx = df.style.hide_columns([('b', 1)]).hide_index()._translate() assert not ctx['body'][0][0]['is_visible'] # index assert ctx['head'][0][2]['is_visible'] # b assert ctx['head'][1][2]['is_visible'] # 0 assert not ctx['head'][1][3]['is_visible'] # 1 assert not ctx['body'][1][3]['is_visible'] # 4 assert ctx['body'][1][2]['is_visible'] assert ctx['body'][1][2]['display_value'] == 3
class TestStyler(object): def setup_method(self, method): np.random.seed(24) self.s = DataFrame({'A': np.random.permutation(range(6))}) self.df = DataFrame({'A': [0, 1], 'B': np.random.randn(2)}) self.f = lambda x: x self.g = lambda x: x def h(x, foo='bar'): return pd.Series( ['color: {foo}'.format(foo=foo)], index=x.index, name=x.name) self.h = h self.styler = Styler(self.df) self.attrs = pd.DataFrame({'A': ['color: red', 'color: blue']}) self.dataframes = [ self.df, pd.DataFrame({'f': [1., 2.], 'o': ['a', 'b'], 'c': pd.Categorical(['a', 'b'])}) ] def test_init_non_pandas(self): with pytest.raises(TypeError): Styler([1, 2, 3]) def test_init_series(self): result = Styler(pd.Series([1, 2])) assert result.data.ndim == 2 def test_repr_html_ok(self): self.styler._repr_html_() def test_update_ctx(self): self.styler._update_ctx(self.attrs) expected = {(0, 0): ['color: red'], (1, 0): ['color: blue']} assert self.styler.ctx == expected def test_update_ctx_flatten_multi(self): attrs = DataFrame({"A": ['color: red; foo: bar', 'color: blue; foo: baz']}) self.styler._update_ctx(attrs) expected = {(0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz']} assert self.styler.ctx == expected def test_update_ctx_flatten_multi_traliing_semi(self): attrs = DataFrame({"A": ['color: red; foo: bar;', 'color: blue; foo: baz;']}) self.styler._update_ctx(attrs) expected = {(0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz']} assert self.styler.ctx == expected def test_copy(self): s2 = copy.copy(self.styler) assert self.styler is not s2 assert self.styler.ctx is s2.ctx # shallow assert self.styler._todo is s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx == s2.ctx assert self.styler._todo == s2._todo def test_deepcopy(self): s2 = copy.deepcopy(self.styler) assert self.styler is not s2 assert self.styler.ctx is not s2.ctx assert self.styler._todo is not s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx != s2.ctx assert s2._todo == [] assert self.styler._todo != s2._todo def test_clear(self): s = self.df.style.highlight_max()._compute() assert len(s.ctx) > 0 assert len(s._todo) > 0 s.clear() assert len(s.ctx) == 0 assert len(s._todo) == 0 def test_render(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red", "color: blue"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_render_empty_dfs(self): empty_df = DataFrame() es = Styler(empty_df) es.render() # An index but no columns DataFrame(columns=['a']).style.render() # A column but no index DataFrame(index=['a']).style.render() # No IndexError raised? def test_render_double(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red; border: 1px", "color: blue; border: 2px"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_set_properties(self): df = pd.DataFrame({"A": [0, 1]}) result = df.style.set_properties(color='white', size='10px')._compute().ctx # order is deterministic v = ["color: white", "size: 10px"] expected = {(0, 0): v, (1, 0): v} assert result.keys() == expected.keys() for v1, v2 in zip(result.values(), expected.values()): assert sorted(v1) == sorted(v2) def test_set_properties_subset(self): df = pd.DataFrame({'A': [0, 1]}) result = df.style.set_properties(subset=pd.IndexSlice[0, 'A'], color='white')._compute().ctx expected = {(0, 0): ['color: white']} assert result == expected def test_empty_index_name_doesnt_display(self): # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.style._translate() expected = [[{'class': 'blank level0', 'type': 'th', 'value': '', 'is_visible': True, 'display_value': ''}, {'class': 'col_heading level0 col0', 'display_value': 'A', 'type': 'th', 'value': 'A', 'is_visible': True, }, {'class': 'col_heading level0 col1', 'display_value': 'B', 'type': 'th', 'value': 'B', 'is_visible': True, }, {'class': 'col_heading level0 col2', 'display_value': 'C', 'type': 'th', 'value': 'C', 'is_visible': True, }]] assert result['head'] == expected def test_index_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index('A').style._translate() expected = [[{'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'col_heading level0 col0', 'type': 'th', 'value': 'B', 'display_value': 'B', 'is_visible': True}, {'class': 'col_heading level0 col1', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True}], [{'class': 'index_name level0', 'type': 'th', 'value': 'A'}, {'class': 'blank', 'type': 'th', 'value': ''}, {'class': 'blank', 'type': 'th', 'value': ''}]] assert result['head'] == expected def test_multiindex_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index(['A', 'B']).style._translate() expected = [[ {'class': 'blank', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'col_heading level0 col0', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True}], [{'class': 'index_name level0', 'type': 'th', 'value': 'A'}, {'class': 'index_name level1', 'type': 'th', 'value': 'B'}, {'class': 'blank', 'type': 'th', 'value': ''}]] assert result['head'] == expected def test_numeric_columns(self): # https://github.com/pandas-dev/pandas/issues/12125 # smoke test for _translate df = pd.DataFrame({0: [1, 2, 3]}) df.style._translate() def test_apply_axis(self): df = pd.DataFrame({'A': [0, 0], 'B': [1, 1]}) f = lambda x: ['val: {max}'.format(max=x.max()) for v in x] result = df.style.apply(f, axis=1) assert len(result._todo) == 1 assert len(result.ctx) == 0 result._compute() expected = {(0, 0): ['val: 1'], (0, 1): ['val: 1'], (1, 0): ['val: 1'], (1, 1): ['val: 1']} assert result.ctx == expected result = df.style.apply(f, axis=0) expected = {(0, 0): ['val: 0'], (0, 1): ['val: 1'], (1, 0): ['val: 0'], (1, 1): ['val: 1']} result._compute() assert result.ctx == expected result = df.style.apply(f) # default result._compute() assert result.ctx == expected def test_apply_subset(self): axes = [0, 1] slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for ax in axes: for slice_ in slices: result = self.df.style.apply(self.h, axis=ax, subset=slice_, foo='baz')._compute().ctx expected = dict(((r, c), ['color: baz']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_applymap_subset(self): def f(x): return 'foo: bar' slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for slice_ in slices: result = self.df.style.applymap(f, subset=slice_)._compute().ctx expected = dict(((r, c), ['foo: bar']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_where_with_one_style(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' result = self.df.style.where(f, style1)._compute().ctx expected = dict(((r, c), [style1 if f(self.df.loc[row, col]) else '']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns)) assert result == expected def test_where_subset(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' style2 = 'baz: foo' slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for slice_ in slices: result = self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx expected = dict(((r, c), [style1 if f(self.df.loc[row, col]) else style2]) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) assert result == expected def test_where_subset_compare_with_applymap(self): # GH 17474 def f(x): return x > 0.5 style1 = 'foo: bar' style2 = 'baz: foo' def g(x): return style1 if f(x) else style2 slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for slice_ in slices: result = self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx expected = self.df.style.applymap(g, subset=slice_)._compute().ctx assert result == expected def test_empty(self): df = pd.DataFrame({'A': [1, 0]}) s = df.style s.ctx = {(0, 0): ['color: red'], (1, 0): ['']} result = s._translate()['cellstyle'] expected = [{'props': [['color', ' red']], 'selector': 'row0_col0'}, {'props': [['', '']], 'selector': 'row1_col0'}] assert result == expected def test_bar_align_left(self): df = pd.DataFrame({'A': [0, 1, 2]}) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 50.0%, transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 100.0%, transparent 0%)'] } assert result == expected result = df.style.bar(color='red', width=50)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 25.0%, transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 50.0%, transparent 0%)'] } assert result == expected df['C'] = ['a'] * len(df) result = df.style.bar(color='red', width=50)._compute().ctx assert result == expected df['C'] = df['C'].astype('category') result = df.style.bar(color='red', width=50)._compute().ctx assert result == expected def test_bar_align_left_0points(self): df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) result = df.style.bar()._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%'], (0, 2): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (1, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (1, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)']} assert result == expected result = df.style.bar(axis=1)._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (0, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (1, 0): ['width: 10em', ' height: 80%'], (1, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)'], (1, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%'], (2, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)'], (2, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)']} assert result == expected def test_bar_align_mid_pos_and_neg(self): df = pd.DataFrame({'A': [-10, 0, 20, 90]}) result = df.style.bar(align='mid', color=[ '#d65f5f', '#5fba7d'])._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #d65f5f 0.0%, ' '#d65f5f 10.0%, transparent 10.0%)'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, ' '#d65f5f 10.0%, #d65f5f 10.0%, ' 'transparent 10.0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, #5fba7d 10.0%' ', #5fba7d 30.0%, transparent 30.0%)'], (3, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 10.0%, ' '#5fba7d 10.0%, #5fba7d 100.0%, ' 'transparent 100.0%)']} assert result == expected def test_bar_align_mid_all_pos(self): df = pd.DataFrame({'A': [10, 20, 50, 100]}) result = df.style.bar(align='mid', color=[ '#d65f5f', '#5fba7d'])._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 10.0%, transparent 10.0%)'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 20.0%, transparent 20.0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 50.0%, transparent 50.0%)'], (3, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, #5fba7d 0.0%, ' '#5fba7d 100.0%, transparent 100.0%)']} assert result == expected def test_bar_align_mid_all_neg(self): df = pd.DataFrame({'A': [-100, -60, -30, -20]}) result = df.style.bar(align='mid', color=[ '#d65f5f', '#5fba7d'])._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 0.0%, ' '#d65f5f 0.0%, #d65f5f 100.0%, ' 'transparent 100.0%)'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 40.0%, ' '#d65f5f 40.0%, #d65f5f 100.0%, ' 'transparent 100.0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 70.0%, ' '#d65f5f 70.0%, #d65f5f 100.0%, ' 'transparent 100.0%)'], (3, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 80.0%, ' '#d65f5f 80.0%, #d65f5f 100.0%, ' 'transparent 100.0%)']} assert result == expected def test_bar_align_zero_pos_and_neg(self): # See https://github.com/pandas-dev/pandas/pull/14757 df = pd.DataFrame({'A': [-10, 0, 20, 90]}) result = df.style.bar(align='zero', color=[ '#d65f5f', '#5fba7d'], width=90)._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 45.0%, ' '#d65f5f 45.0%, #d65f5f 50%, ' 'transparent 50%)'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, ' '#5fba7d 50%, #5fba7d 50.0%, ' 'transparent 50.0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, #5fba7d 50%, ' '#5fba7d 60.0%, transparent 60.0%)'], (3, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg, ' 'transparent 0%, transparent 50%, #5fba7d 50%, ' '#5fba7d 95.0%, transparent 95.0%)']} assert result == expected def test_bar_bad_align_raises(self): df = pd.DataFrame({'A': [-100, -60, -30, -20]}) with pytest.raises(ValueError): df.style.bar(align='poorly', color=['#d65f5f', '#5fba7d']) def test_highlight_null(self, null_color='red'): df = pd.DataFrame({'A': [0, np.nan]}) result = df.style.highlight_null()._compute().ctx expected = {(0, 0): [''], (1, 0): ['background-color: red']} assert result == expected def test_nonunique_raises(self): df = pd.DataFrame([[1, 2]], columns=['A', 'A']) with pytest.raises(ValueError): df.style with pytest.raises(ValueError): Styler(df) def test_caption(self): styler = Styler(self.df, caption='foo') result = styler.render() assert all(['caption' in result, 'foo' in result]) styler = self.df.style result = styler.set_caption('baz') assert styler is result assert styler.caption == 'baz' def test_uuid(self): styler = Styler(self.df, uuid='abc123') result = styler.render() assert 'abc123' in result styler = self.df.style result = styler.set_uuid('aaa') 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) result = ' '.join(styler.render().split()) assert 'th { foo: bar; }' in result styler = self.df.style result = styler.set_table_styles(style) assert styler is result assert styler.table_styles == style def test_table_attributes(self): attributes = 'class="foo" data-bar' styler = Styler(self.df, table_attributes=attributes) result = styler.render() assert 'class="foo" data-bar' in result result = self.df.style.set_table_attributes(attributes).render() assert 'class="foo" data-bar' in result def test_precision(self): with pd.option_context('display.precision', 10): s = Styler(self.df) assert s.precision == 10 s = Styler(self.df, precision=2) assert s.precision == 2 s2 = s.set_precision(4) assert s is s2 assert s.precision == 4 def test_apply_none(self): def f(x): return pd.DataFrame(np.where(x == x.max(), 'color: red', ''), index=x.index, columns=x.columns) result = (pd.DataFrame([[1, 2], [3, 4]]) .style.apply(f, axis=None)._compute().ctx) assert result[(1, 1)] == ['color: red'] def test_trim(self): result = self.df.style.render() # trim=True assert result.count('#') == 0 result = self.df.style.highlight_max().render() assert result.count('#') == len(self.df.columns) def test_highlight_max(self): df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B']) # max(df) = min(-df) for max_ in [True, False]: if max_: attr = 'highlight_max' else: df = -df attr = 'highlight_min' result = getattr(df.style, attr)()._compute().ctx assert result[(1, 1)] == ['background-color: yellow'] result = getattr(df.style, attr)(color='green')._compute().ctx assert result[(1, 1)] == ['background-color: green'] result = getattr(df.style, attr)(subset='A')._compute().ctx assert result[(1, 0)] == ['background-color: yellow'] result = getattr(df.style, attr)(axis=0)._compute().ctx expected = {(1, 0): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 1): [''], (0, 0): ['']} assert result == expected result = getattr(df.style, attr)(axis=1)._compute().ctx expected = {(0, 1): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 0): [''], (1, 0): ['']} assert result == expected # separate since we cant negate the strs df['C'] = ['a', 'b'] result = df.style.highlight_max()._compute().ctx expected = {(1, 1): ['background-color: yellow']} result = df.style.highlight_min()._compute().ctx expected = {(0, 0): ['background-color: yellow']} def test_export(self): f = lambda x: 'color: red' if x > 0 else 'color: blue' g = lambda x, y, z: 'color: {z}'.format(z=z) \ if x > 0 else 'color: {z}'.format(z=z) style1 = self.styler style1.applymap(f)\ .applymap(g, y='a', z='b')\ .highlight_max() result = style1.export() style2 = self.df.style style2.use(result) assert style1._todo == style2._todo style2.render() def test_display_format(self): df = pd.DataFrame(np.random.random(size=(2, 2))) ctx = df.style.format("{:0.1f}")._translate() assert all(['display_value' in c for c in row] for row in ctx['body']) assert all([len(c['display_value']) <= 3 for c in row[1:]] for row in ctx['body']) assert len(ctx['body'][0][1]['display_value'].lstrip('-')) <= 3 def test_display_format_raises(self): df = pd.DataFrame(np.random.randn(2, 2)) with pytest.raises(TypeError): df.style.format(5) with pytest.raises(TypeError): df.style.format(True) def test_display_subset(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"}, subset=pd.IndexSlice[0, :])._translate() expected = '0.1' assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == '1.1234' assert ctx['body'][0][2]['display_value'] == '12.34%' raw_11 = '1.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice['a'])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][0][2]['display_value'] == '0.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, 'a'])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == raw_11 ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[[0, 1], ['a']])._translate() assert ctx['body'][0][1]['display_value'] == expected assert ctx['body'][1][1]['display_value'] == '1.1' assert ctx['body'][0][2]['display_value'] == '0.1234' assert ctx['body'][1][2]['display_value'] == '1.1234' def test_display_dict(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"})._translate() assert ctx['body'][0][1]['display_value'] == '0.1' assert ctx['body'][0][2]['display_value'] == '12.34%' df['c'] = ['aaa', 'bbb'] ctx = df.style.format({"a": "{:0.1f}", "c": str.upper})._translate() assert ctx['body'][0][1]['display_value'] == '0.1' assert ctx['body'][0][3]['display_value'] == 'AAA' def test_bad_apply_shape(self): df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(lambda x: 'x', subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: [''], subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', '', '']) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], subset=1) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], axis=1) def test_apply_bad_return(self): def f(x): return '' df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(TypeError): df.style._apply(f, axis=None) def test_apply_bad_labels(self): def f(x): return pd.DataFrame(index=[1, 2], columns=['a', 'b']) df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(f, axis=None) def test_get_level_lengths(self): index = pd.MultiIndex.from_product([['a', 'b'], [0, 1, 2]]) expected = {(0, 0): 3, (0, 3): 3, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, (1, 4): 1, (1, 5): 1} result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_get_level_lengths_un_sorted(self): index = pd.MultiIndex.from_arrays([ [1, 1, 2, 1], ['a', 'b', 'b', 'd'] ]) expected = {(0, 0): 2, (0, 2): 1, (0, 3): 1, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1} result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) 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", "id": "level0_row0" } tm.assert_dict_equal(body_0, expected_0) body_1 = result['body'][0][1] 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) body_10 = result['body'][1][0] 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) head = result['head'][0] expected = [ {'type': 'th', 'class': 'blank', 'value': '', 'is_visible': True, "display_value": ''}, {'type': 'th', 'class': 'blank level0', 'value': '', 'is_visible': True, 'display_value': ''}, {'type': 'th', 'class': 'col_heading level0 col0', 'value': 'A', 'is_visible': True, 'display_value': 'A'}] assert head == expected def test_mi_sparse_disabled(self): with pd.option_context('display.multi_sparse', False): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]])) result = df.style._translate() body = result['body'] for row in body: assert 'attributes' not in row[0] def test_mi_sparse_index_names(self): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1']) ) result = df.style._translate() head = result['head'][1] expected = [{ 'class': 'index_name level0', 'value': 'idx_level_0', 'type': 'th'}, {'class': 'index_name level1', 'value': 'idx_level_1', 'type': 'th'}, {'class': 'blank', 'value': '', 'type': 'th'}] assert head == expected def test_mi_sparse_column_names(self): df = pd.DataFrame( np.arange(16).reshape(4, 4), index=pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'a'], [0, 1, 1, 2]], names=['idx_level_0', 'idx_level_1']), columns=pd.MultiIndex.from_arrays( [['C1', 'C1', 'C2', 'C2'], [1, 0, 1, 0]], names=['col_0', 'col_1'] ) ) result = df.style._translate() head = result['head'][1] expected = [ {'class': 'blank', 'value': '', 'display_value': '', 'type': 'th', 'is_visible': True}, {'class': 'index_name level1', 'value': 'col_1', 'display_value': 'col_1', 'is_visible': True, 'type': 'th'}, {'class': 'col_heading level1 col0', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1}, {'class': 'col_heading level1 col1', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0}, {'class': 'col_heading level1 col2', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1}, {'class': 'col_heading level1 col3', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0}, ] assert head == expected def test_hide_single_index(self): # GH 14194 # single unnamed index ctx = self.df.style._translate() assert ctx['body'][0][0]['is_visible'] assert ctx['head'][0][0]['is_visible'] ctx2 = self.df.style.hide_index()._translate() assert not ctx2['body'][0][0]['is_visible'] assert not ctx2['head'][0][0]['is_visible'] # single named index ctx3 = self.df.set_index('A').style._translate() assert ctx3['body'][0][0]['is_visible'] assert len(ctx3['head']) == 2 # 2 header levels assert ctx3['head'][0][0]['is_visible'] ctx4 = self.df.set_index('A').style.hide_index()._translate() assert not ctx4['body'][0][0]['is_visible'] assert len(ctx4['head']) == 1 # only 1 header levels assert not ctx4['head'][0][0]['is_visible'] def test_hide_multiindex(self): # GH 14194 df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1']) ) ctx1 = df.style._translate() # tests for 'a' and '0' assert ctx1['body'][0][0]['is_visible'] assert ctx1['body'][0][1]['is_visible'] # check for blank header rows assert ctx1['head'][0][0]['is_visible'] assert ctx1['head'][0][1]['is_visible'] ctx2 = df.style.hide_index()._translate() # tests for 'a' and '0' assert not ctx2['body'][0][0]['is_visible'] assert not ctx2['body'][0][1]['is_visible'] # check for blank header rows assert not ctx2['head'][0][0]['is_visible'] assert not ctx2['head'][0][1]['is_visible'] def test_hide_columns_single_level(self): # GH 14194 # test hiding single column ctx = self.df.style._translate() assert ctx['head'][0][1]['is_visible'] assert ctx['head'][0][1]['display_value'] == 'A' assert ctx['head'][0][2]['is_visible'] assert ctx['head'][0][2]['display_value'] == 'B' assert ctx['body'][0][1]['is_visible'] # col A, row 1 assert ctx['body'][1][2]['is_visible'] # col B, row 1 ctx = self.df.style.hide_columns('A')._translate() assert not ctx['head'][0][1]['is_visible'] assert not ctx['body'][0][1]['is_visible'] # col A, row 1 assert ctx['body'][1][2]['is_visible'] # col B, row 1 # test hiding mulitiple columns ctx = self.df.style.hide_columns(['A', 'B'])._translate() assert not ctx['head'][0][1]['is_visible'] assert not ctx['head'][0][2]['is_visible'] assert not ctx['body'][0][1]['is_visible'] # col A, row 1 assert not ctx['body'][1][2]['is_visible'] # col B, row 1 def test_hide_columns_mult_levels(self): # GH 14194 # setup dataframe with multiple column levels and indices i1 = pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1']) i2 = pd.MultiIndex.from_arrays([['b', 'b'], [0, 1]], names=['col_level_0', 'col_level_1']) df = pd.DataFrame([[1, 2], [3, 4]], index=i1, columns=i2) ctx = df.style._translate() # column headers assert ctx['head'][0][2]['is_visible'] assert ctx['head'][1][2]['is_visible'] assert ctx['head'][1][3]['display_value'] == 1 # indices assert ctx['body'][0][0]['is_visible'] # data assert ctx['body'][1][2]['is_visible'] assert ctx['body'][1][2]['display_value'] == 3 assert ctx['body'][1][3]['is_visible'] assert ctx['body'][1][3]['display_value'] == 4 # hide top column level, which hides both columns ctx = df.style.hide_columns('b')._translate() assert not ctx['head'][0][2]['is_visible'] # b assert not ctx['head'][1][2]['is_visible'] # 0 assert not ctx['body'][1][2]['is_visible'] # 3 assert ctx['body'][0][0]['is_visible'] # index # hide first column only ctx = df.style.hide_columns([('b', 0)])._translate() assert ctx['head'][0][2]['is_visible'] # b assert not ctx['head'][1][2]['is_visible'] # 0 assert not ctx['body'][1][2]['is_visible'] # 3 assert ctx['body'][1][3]['is_visible'] assert ctx['body'][1][3]['display_value'] == 4 # hide second column and index ctx = df.style.hide_columns([('b', 1)]).hide_index()._translate() assert not ctx['body'][0][0]['is_visible'] # index assert ctx['head'][0][2]['is_visible'] # b assert ctx['head'][1][2]['is_visible'] # 0 assert not ctx['head'][1][3]['is_visible'] # 1 assert not ctx['body'][1][3]['is_visible'] # 4 assert ctx['body'][1][2]['is_visible'] assert ctx['body'][1][2]['display_value'] == 3
class TestStyler(TestCase): def setUp(self): np.random.seed(24) self.s = DataFrame({'A': np.random.permutation(range(6))}) self.df = DataFrame({'A': [0, 1], 'B': np.random.randn(2)}) self.f = lambda x: x self.g = lambda x: x def h(x, foo='bar'): return pd.Series(['color: %s' % foo], index=x.index, name=x.name) self.h = h self.styler = Styler(self.df) self.attrs = pd.DataFrame({'A': ['color: red', 'color: blue']}) self.dataframes = [ self.df, pd.DataFrame({'f': [1., 2.], 'o': ['a', 'b'], 'c': pd.Categorical(['a', 'b'])}) ] def test_init_non_pandas(self): with tm.assertRaises(TypeError): Styler([1, 2, 3]) def test_init_series(self): result = Styler(pd.Series([1, 2])) self.assertEqual(result.data.ndim, 2) def test_repr_html_ok(self): self.styler._repr_html_() def test_update_ctx(self): self.styler._update_ctx(self.attrs) expected = {(0, 0): ['color: red'], (1, 0): ['color: blue']} self.assertEqual(self.styler.ctx, expected) def test_update_ctx_flatten_multi(self): attrs = DataFrame({"A": ['color: red; foo: bar', 'color: blue; foo: baz']}) self.styler._update_ctx(attrs) expected = {(0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz']} self.assertEqual(self.styler.ctx, expected) def test_update_ctx_flatten_multi_traliing_semi(self): attrs = DataFrame({"A": ['color: red; foo: bar;', 'color: blue; foo: baz;']}) self.styler._update_ctx(attrs) expected = {(0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz']} self.assertEqual(self.styler.ctx, expected) def test_copy(self): s2 = copy.copy(self.styler) self.assertTrue(self.styler is not s2) self.assertTrue(self.styler.ctx is s2.ctx) # shallow self.assertTrue(self.styler._todo is s2._todo) self.styler._update_ctx(self.attrs) self.styler.highlight_max() self.assertEqual(self.styler.ctx, s2.ctx) self.assertEqual(self.styler._todo, s2._todo) def test_deepcopy(self): s2 = copy.deepcopy(self.styler) self.assertTrue(self.styler is not s2) self.assertTrue(self.styler.ctx is not s2.ctx) self.assertTrue(self.styler._todo is not s2._todo) self.styler._update_ctx(self.attrs) self.styler.highlight_max() self.assertNotEqual(self.styler.ctx, s2.ctx) self.assertEqual(s2._todo, []) self.assertNotEqual(self.styler._todo, s2._todo) def test_clear(self): s = self.df.style.highlight_max()._compute() self.assertTrue(len(s.ctx) > 0) self.assertTrue(len(s._todo) > 0) s.clear() self.assertTrue(len(s.ctx) == 0) self.assertTrue(len(s._todo) == 0) def test_render(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red", "color: blue"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_render_double(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red; border: 1px", "color: blue; border: 2px"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_set_properties(self): df = pd.DataFrame({"A": [0, 1]}) result = df.style.set_properties(color='white', size='10px')._compute().ctx # order is deterministic v = ["color: white", "size: 10px"] expected = {(0, 0): v, (1, 0): v} self.assertEqual(result.keys(), expected.keys()) for v1, v2 in zip(result.values(), expected.values()): self.assertEqual(sorted(v1), sorted(v2)) def test_set_properties_subset(self): df = pd.DataFrame({'A': [0, 1]}) result = df.style.set_properties(subset=pd.IndexSlice[0, 'A'], color='white')._compute().ctx expected = {(0, 0): ['color: white']} self.assertEqual(result, expected) def test_empty_index_name_doesnt_display(self): # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.style._translate() expected = [[{'class': 'blank level0', 'type': 'th', 'value': '', 'is_visible': True, 'display_value': ''}, {'class': 'col_heading level0 col0', 'display_value': 'A', 'type': 'th', 'value': 'A', 'is_visible': True, }, {'class': 'col_heading level0 col1', 'display_value': 'B', 'type': 'th', 'value': 'B', 'is_visible': True, }, {'class': 'col_heading level0 col2', 'display_value': 'C', 'type': 'th', 'value': 'C', 'is_visible': True, }]] self.assertEqual(result['head'], expected) def test_index_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index('A').style._translate() expected = [[{'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'col_heading level0 col0', 'type': 'th', 'value': 'B', 'display_value': 'B', 'is_visible': True}, {'class': 'col_heading level0 col1', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True}], [{'class': 'index_name level0', 'type': 'th', 'value': 'A'}, {'class': 'blank', 'type': 'th', 'value': ''}, {'class': 'blank', 'type': 'th', 'value': ''}]] self.assertEqual(result['head'], expected) def test_multiindex_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index(['A', 'B']).style._translate() expected = [[ {'class': 'blank', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True}, {'class': 'col_heading level0 col0', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True}], [{'class': 'index_name level0', 'type': 'th', 'value': 'A'}, {'class': 'index_name level1', 'type': 'th', 'value': 'B'}, {'class': 'blank', 'type': 'th', 'value': ''}]] self.assertEqual(result['head'], expected) def test_numeric_columns(self): # https://github.com/pandas-dev/pandas/issues/12125 # smoke test for _translate df = pd.DataFrame({0: [1, 2, 3]}) df.style._translate() def test_apply_axis(self): df = pd.DataFrame({'A': [0, 0], 'B': [1, 1]}) f = lambda x: ['val: %s' % x.max() for v in x] result = df.style.apply(f, axis=1) self.assertEqual(len(result._todo), 1) self.assertEqual(len(result.ctx), 0) result._compute() expected = {(0, 0): ['val: 1'], (0, 1): ['val: 1'], (1, 0): ['val: 1'], (1, 1): ['val: 1']} self.assertEqual(result.ctx, expected) result = df.style.apply(f, axis=0) expected = {(0, 0): ['val: 0'], (0, 1): ['val: 1'], (1, 0): ['val: 0'], (1, 1): ['val: 1']} result._compute() self.assertEqual(result.ctx, expected) result = df.style.apply(f) # default result._compute() self.assertEqual(result.ctx, expected) def test_apply_subset(self): axes = [0, 1] slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for ax in axes: for slice_ in slices: result = self.df.style.apply(self.h, axis=ax, subset=slice_, foo='baz')._compute().ctx expected = dict(((r, c), ['color: baz']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) self.assertEqual(result, expected) def test_applymap_subset(self): def f(x): return 'foo: bar' slices = [pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']]] for slice_ in slices: result = self.df.style.applymap(f, subset=slice_)._compute().ctx expected = dict(((r, c), ['foo: bar']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) self.assertEqual(result, expected) def test_empty(self): df = pd.DataFrame({'A': [1, 0]}) s = df.style s.ctx = {(0, 0): ['color: red'], (1, 0): ['']} result = s._translate()['cellstyle'] expected = [{'props': [['color', ' red']], 'selector': 'row0_col0'}, {'props': [['', '']], 'selector': 'row1_col0'}] self.assertEqual(result, expected) def test_bar(self): df = pd.DataFrame({'A': [0, 1, 2]}) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 50.0%, transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 100.0%, transparent 0%)'] } self.assertEqual(result, expected) result = df.style.bar(color='red', width=50)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 25.0%, transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 50.0%, transparent 0%)'] } self.assertEqual(result, expected) df['C'] = ['a'] * len(df) result = df.style.bar(color='red', width=50)._compute().ctx self.assertEqual(result, expected) df['C'] = df['C'].astype('category') result = df.style.bar(color='red', width=50)._compute().ctx self.assertEqual(result, expected) def test_bar_0points(self): df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) result = df.style.bar()._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%'], (0, 2): ['width: 10em', ' height: 80%'], (1, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (1, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (1, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)']} self.assertEqual(result, expected) result = df.style.bar(axis=1)._compute().ctx expected = {(0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)'], (0, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (1, 0): ['width: 10em', ' height: 80%'], (1, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)'], (1, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)'], (2, 0): ['width: 10em', ' height: 80%'], (2, 1): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)'], (2, 2): ['width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)']} self.assertEqual(result, expected) def test_highlight_null(self, null_color='red'): df = pd.DataFrame({'A': [0, np.nan]}) result = df.style.highlight_null()._compute().ctx expected = {(0, 0): [''], (1, 0): ['background-color: red']} self.assertEqual(result, expected) def test_nonunique_raises(self): df = pd.DataFrame([[1, 2]], columns=['A', 'A']) with tm.assertRaises(ValueError): df.style with tm.assertRaises(ValueError): Styler(df) def test_caption(self): styler = Styler(self.df, caption='foo') result = styler.render() self.assertTrue(all(['caption' in result, 'foo' in result])) styler = self.df.style result = styler.set_caption('baz') self.assertTrue(styler is result) self.assertEqual(styler.caption, 'baz') def test_uuid(self): styler = Styler(self.df, uuid='abc123') result = styler.render() self.assertTrue('abc123' in result) styler = self.df.style result = styler.set_uuid('aaa') self.assertTrue(result is styler) self.assertEqual(result.uuid, 'aaa') def test_table_styles(self): style = [{'selector': 'th', 'props': [('foo', 'bar')]}] styler = Styler(self.df, table_styles=style) result = ' '.join(styler.render().split()) self.assertTrue('th { foo: bar; }' in result) styler = self.df.style result = styler.set_table_styles(style) self.assertTrue(styler is result) self.assertEqual(styler.table_styles, style) def test_table_attributes(self): attributes = 'class="foo" data-bar' styler = Styler(self.df, table_attributes=attributes) result = styler.render() self.assertTrue('class="foo" data-bar' in result) result = self.df.style.set_table_attributes(attributes).render() self.assertTrue('class="foo" data-bar' in result) def test_precision(self): with pd.option_context('display.precision', 10): s = Styler(self.df) self.assertEqual(s.precision, 10) s = Styler(self.df, precision=2) self.assertEqual(s.precision, 2) s2 = s.set_precision(4) self.assertTrue(s is s2) self.assertEqual(s.precision, 4) def test_apply_none(self): def f(x): return pd.DataFrame(np.where(x == x.max(), 'color: red', ''), index=x.index, columns=x.columns) result = (pd.DataFrame([[1, 2], [3, 4]]) .style.apply(f, axis=None)._compute().ctx) self.assertEqual(result[(1, 1)], ['color: red']) def test_trim(self): result = self.df.style.render() # trim=True self.assertEqual(result.count('#'), 0) result = self.df.style.highlight_max().render() self.assertEqual(result.count('#'), len(self.df.columns)) def test_highlight_max(self): df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B']) # max(df) = min(-df) for max_ in [True, False]: if max_: attr = 'highlight_max' else: df = -df attr = 'highlight_min' result = getattr(df.style, attr)()._compute().ctx self.assertEqual(result[(1, 1)], ['background-color: yellow']) result = getattr(df.style, attr)(color='green')._compute().ctx self.assertEqual(result[(1, 1)], ['background-color: green']) result = getattr(df.style, attr)(subset='A')._compute().ctx self.assertEqual(result[(1, 0)], ['background-color: yellow']) result = getattr(df.style, attr)(axis=0)._compute().ctx expected = {(1, 0): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 1): [''], (0, 0): ['']} self.assertEqual(result, expected) result = getattr(df.style, attr)(axis=1)._compute().ctx expected = {(0, 1): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 0): [''], (1, 0): ['']} self.assertEqual(result, expected) # separate since we cant negate the strs df['C'] = ['a', 'b'] result = df.style.highlight_max()._compute().ctx expected = {(1, 1): ['background-color: yellow']} result = df.style.highlight_min()._compute().ctx expected = {(0, 0): ['background-color: yellow']} def test_export(self): f = lambda x: 'color: red' if x > 0 else 'color: blue' g = lambda x, y, z: 'color: %s' if x > 0 else 'color: %s' % z style1 = self.styler style1.applymap(f)\ .applymap(g, y='a', z='b')\ .highlight_max() result = style1.export() style2 = self.df.style style2.use(result) self.assertEqual(style1._todo, style2._todo) style2.render() def test_display_format(self): df = pd.DataFrame(np.random.random(size=(2, 2))) ctx = df.style.format("{:0.1f}")._translate() self.assertTrue(all(['display_value' in c for c in row] for row in ctx['body'])) self.assertTrue(all([len(c['display_value']) <= 3 for c in row[1:]] for row in ctx['body'])) self.assertTrue( len(ctx['body'][0][1]['display_value'].lstrip('-')) <= 3) def test_display_format_raises(self): df = pd.DataFrame(np.random.randn(2, 2)) with tm.assertRaises(TypeError): df.style.format(5) with tm.assertRaises(TypeError): df.style.format(True) def test_display_subset(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"}, subset=pd.IndexSlice[0, :])._translate() expected = '0.1' self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], '1.1234') self.assertEqual(ctx['body'][0][2]['display_value'], '12.34%') raw_11 = '1.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice['a'])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][0][2]['display_value'], '0.1234') ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, 'a'])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[[0, 1], ['a']])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], '1.1') self.assertEqual(ctx['body'][0][2]['display_value'], '0.1234') self.assertEqual(ctx['body'][1][2]['display_value'], '1.1234') def test_display_dict(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"})._translate() self.assertEqual(ctx['body'][0][1]['display_value'], '0.1') self.assertEqual(ctx['body'][0][2]['display_value'], '12.34%') df['c'] = ['aaa', 'bbb'] ctx = df.style.format({"a": "{:0.1f}", "c": str.upper})._translate() self.assertEqual(ctx['body'][0][1]['display_value'], '0.1') self.assertEqual(ctx['body'][0][3]['display_value'], 'AAA') def test_bad_apply_shape(self): df = pd.DataFrame([[1, 2], [3, 4]]) with tm.assertRaises(ValueError): df.style._apply(lambda x: 'x', subset=pd.IndexSlice[[0, 1], :]) with tm.assertRaises(ValueError): df.style._apply(lambda x: [''], subset=pd.IndexSlice[[0, 1], :]) with tm.assertRaises(ValueError): df.style._apply(lambda x: ['', '', '', '']) with tm.assertRaises(ValueError): df.style._apply(lambda x: ['', '', ''], subset=1) with tm.assertRaises(ValueError): df.style._apply(lambda x: ['', '', ''], axis=1) def test_apply_bad_return(self): def f(x): return '' df = pd.DataFrame([[1, 2], [3, 4]]) with tm.assertRaises(TypeError): df.style._apply(f, axis=None) def test_apply_bad_labels(self): def f(x): return pd.DataFrame(index=[1, 2], columns=['a', 'b']) df = pd.DataFrame([[1, 2], [3, 4]]) with tm.assertRaises(ValueError): df.style._apply(f, axis=None) def test_get_level_lengths(self): index = pd.MultiIndex.from_product([['a', 'b'], [0, 1, 2]]) expected = {(0, 0): 3, (0, 3): 3, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, (1, 4): 1, (1, 5): 1} result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_get_level_lengths_un_sorted(self): index = pd.MultiIndex.from_arrays([ [1, 1, 2, 1], ['a', 'b', 'b', 'd'] ]) expected = {(0, 0): 2, (0, 2): 1, (0, 3): 1, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1} result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) 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", } tm.assert_dict_equal(body_0, expected_0) body_1 = result['body'][0][1] expected_1 = { "value": 0, "display_value": 0, "is_visible": True, "type": "th", "class": "row_heading level1 row0", } tm.assert_dict_equal(body_1, expected_1) body_10 = result['body'][1][0] expected_10 = { "value": 'a', "display_value": 'a', "is_visible": False, "type": "th", "class": "row_heading level0 row1", } tm.assert_dict_equal(body_10, expected_10) head = result['head'][0] expected = [ {'type': 'th', 'class': 'blank', 'value': '', 'is_visible': True, "display_value": ''}, {'type': 'th', 'class': 'blank level0', 'value': '', 'is_visible': True, 'display_value': ''}, {'type': 'th', 'class': 'col_heading level0 col0', 'value': 'A', 'is_visible': True, 'display_value': 'A'}] self.assertEqual(head, expected) def test_mi_sparse_disabled(self): with pd.option_context('display.multi_sparse', False): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]])) result = df.style._translate() body = result['body'] for row in body: assert 'attributes' not in row[0] def test_mi_sparse_index_names(self): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1']) ) result = df.style._translate() head = result['head'][1] expected = [{ 'class': 'index_name level0', 'value': 'idx_level_0', 'type': 'th'}, {'class': 'index_name level1', 'value': 'idx_level_1', 'type': 'th'}, {'class': 'blank', 'value': '', 'type': 'th'}] self.assertEqual(head, expected) def test_mi_sparse_column_names(self): df = pd.DataFrame( np.arange(16).reshape(4, 4), index=pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'a'], [0, 1, 1, 2]], names=['idx_level_0', 'idx_level_1']), columns=pd.MultiIndex.from_arrays( [['C1', 'C1', 'C2', 'C2'], [1, 0, 1, 0]], names=['col_0', 'col_1'] ) ) result = df.style._translate() head = result['head'][1] expected = [ {'class': 'blank', 'value': '', 'display_value': '', 'type': 'th', 'is_visible': True}, {'class': 'index_name level1', 'value': 'col_1', 'display_value': 'col_1', 'is_visible': True, 'type': 'th'}, {'class': 'col_heading level1 col0', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1}, {'class': 'col_heading level1 col1', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0}, {'class': 'col_heading level1 col2', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1}, {'class': 'col_heading level1 col3', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0}, ] self.assertEqual(head, expected)
class TestStyler: def setup_method(self, method): np.random.seed(24) self.s = DataFrame({"A": np.random.permutation(range(6))}) self.df = DataFrame({"A": [0, 1], "B": np.random.randn(2)}) self.f = lambda x: x self.g = lambda x: x def h(x, foo="bar"): return pd.Series(f"color: {foo}", index=x.index, name=x.name) self.h = h self.styler = Styler(self.df) self.attrs = DataFrame({"A": ["color: red", "color: blue"]}) self.dataframes = [ self.df, DataFrame({ "f": [1.0, 2.0], "o": ["a", "b"], "c": pd.Categorical(["a", "b"]) }), ] self.blank_value = " " def test_init_non_pandas(self): msg = "``data`` must be a Series or DataFrame" with pytest.raises(TypeError, match=msg): Styler([1, 2, 3]) def test_init_series(self): result = Styler(pd.Series([1, 2])) assert result.data.ndim == 2 def test_repr_html_ok(self): self.styler._repr_html_() def test_repr_html_mathjax(self): # gh-19824 assert "tex2jax_ignore" not in self.styler._repr_html_() with pd.option_context("display.html.use_mathjax", False): assert "tex2jax_ignore" in self.styler._repr_html_() def test_update_ctx(self): self.styler._update_ctx(self.attrs) expected = {(0, 0): [("color", "red")], (1, 0): [("color", "blue")]} assert self.styler.ctx == expected def test_update_ctx_flatten_multi_and_trailing_semi(self): attrs = DataFrame( {"A": ["color: red; foo: bar", "color:blue ; foo: baz;"]}) self.styler._update_ctx(attrs) expected = { (0, 0): [("color", "red"), ("foo", "bar")], (1, 0): [("color", "blue"), ("foo", "baz")], } assert self.styler.ctx == expected @pytest.mark.parametrize("do_changes", [True, False]) @pytest.mark.parametrize("do_render", [True, False]) def test_copy(self, do_changes, do_render): # Updated in GH39708 # Change some defaults (to check later if the new values are copied) if do_changes: self.styler.set_table_styles([{ "selector": "th", "props": [("foo", "bar")] }]) self.styler.set_table_attributes('class="foo" data-bar') self.styler.hidden_index = not self.styler.hidden_index self.styler.hide_columns("A") classes = DataFrame( [["favorite-val red", ""], [None, "blue my-val"]], index=self.df.index, columns=self.df.columns, ) self.styler.set_td_classes(classes) ttips = DataFrame( data=[["Favorite", ""], [np.nan, "my"]], columns=self.df.columns, index=self.df.index, ) self.styler.set_tooltips(ttips) self.styler.cell_ids = not self.styler.cell_ids if do_render: self.styler.render() s_copy = copy.copy(self.styler) s_deepcopy = copy.deepcopy(self.styler) assert self.styler is not s_copy assert self.styler is not s_deepcopy # Check for identity assert self.styler.ctx is s_copy.ctx assert self.styler._todo is s_copy._todo assert self.styler.table_styles is s_copy.table_styles assert self.styler.hidden_columns is s_copy.hidden_columns assert self.styler.cell_context is s_copy.cell_context assert self.styler.tooltips is s_copy.tooltips if do_changes: # self.styler.tooltips is not None assert self.styler.tooltips.tt_data is s_copy.tooltips.tt_data assert (self.styler.tooltips.class_properties is s_copy.tooltips.class_properties) assert self.styler.tooltips.table_styles is s_copy.tooltips.table_styles # Check for non-identity assert self.styler.ctx is not s_deepcopy.ctx assert self.styler._todo is not s_deepcopy._todo assert self.styler.hidden_columns is not s_deepcopy.hidden_columns assert self.styler.cell_context is not s_deepcopy.cell_context if do_changes: # self.styler.table_style is not None assert self.styler.table_styles is not s_deepcopy.table_styles if do_changes: # self.styler.tooltips is not None assert self.styler.tooltips is not s_deepcopy.tooltips assert self.styler.tooltips.tt_data is not s_deepcopy.tooltips.tt_data assert (self.styler.tooltips.class_properties is not s_deepcopy.tooltips.class_properties) assert (self.styler.tooltips.table_styles is not s_deepcopy.tooltips.table_styles) self.styler._update_ctx(self.attrs) self.styler.highlight_max() assert self.styler.ctx == s_copy.ctx assert self.styler.ctx != s_deepcopy.ctx assert self.styler._todo == s_copy._todo assert self.styler._todo != s_deepcopy._todo assert s_deepcopy._todo == [] equal_attributes = [ "table_styles", "table_attributes", "cell_ids", "hidden_index", "hidden_columns", "cell_context", ] for s2 in [s_copy, s_deepcopy]: for att in equal_attributes: assert self.styler.__dict__[att] == s2.__dict__[att] if do_changes: # self.styler.tooltips is not None tm.assert_frame_equal(self.styler.tooltips.tt_data, s2.tooltips.tt_data) assert (self.styler.tooltips.class_properties == s2.tooltips.class_properties) assert self.styler.tooltips.table_styles == s2.tooltips.table_styles def test_clear(self): # updated in GH 39396 tt = DataFrame({"A": [None, "tt"]}) css = DataFrame({"A": [None, "cls-a"]}) s = self.df.style.highlight_max().set_tooltips(tt).set_td_classes(css) s = s.hide_index().hide_columns("A") # _todo, tooltips and cell_context items added to.. assert len(s._todo) > 0 assert s.tooltips assert len(s.cell_context) > 0 assert s.hidden_index is True assert len(s.hidden_columns) > 0 s = s._compute() # ctx item affected when a render takes place. _todo is maintained assert len(s.ctx) > 0 assert len(s._todo) > 0 s.clear() # ctx, _todo, tooltips and cell_context items all revert to null state. assert len(s.ctx) == 0 assert len(s._todo) == 0 assert not s.tooltips assert len(s.cell_context) == 0 assert s.hidden_index is False assert len(s.hidden_columns) == 0 def test_render(self): df = DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red", "color: blue"], name=x.name) s = Styler(df, uuid="AB").apply(style) s.render() # it worked? def test_multiple_render(self): # GH 39396 s = Styler(self.df, uuid_len=0).applymap(lambda x: "color: red;", subset=["A"]) s.render() # do 2 renders to ensure css styles not duplicated assert ('<style type="text/css">\n#T__row0_col0, #T__row1_col0 {\n' " color: red;\n}\n</style>" in s.render()) def test_render_empty_dfs(self): empty_df = DataFrame() es = Styler(empty_df) es.render() # An index but no columns DataFrame(columns=["a"]).style.render() # A column but no index DataFrame(index=["a"]).style.render() # No IndexError raised? def test_render_double(self): df = DataFrame({"A": [0, 1]}) style = lambda x: pd.Series( ["color: red; border: 1px", "color: blue; border: 2px"], name=x.name) s = Styler(df, uuid="AB").apply(style) s.render() # it worked? def test_set_properties(self): df = DataFrame({"A": [0, 1]}) result = df.style.set_properties(color="white", size="10px")._compute().ctx # order is deterministic v = [("color", "white"), ("size", "10px")] expected = {(0, 0): v, (1, 0): v} assert result.keys() == expected.keys() for v1, v2 in zip(result.values(), expected.values()): assert sorted(v1) == sorted(v2) def test_set_properties_subset(self): df = DataFrame({"A": [0, 1]}) result = (df.style.set_properties(subset=pd.IndexSlice[0, "A"], color="white")._compute().ctx) expected = {(0, 0): [("color", "white")]} assert result == expected def test_empty_index_name_doesnt_display(self): # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]}) result = df.style._translate() expected = [[ { "class": "blank level0", "type": "th", "value": self.blank_value, "is_visible": True, "display_value": self.blank_value, }, { "class": "col_heading level0 col0", "display_value": "A", "type": "th", "value": "A", "is_visible": True, }, { "class": "col_heading level0 col1", "display_value": "B", "type": "th", "value": "B", "is_visible": True, }, { "class": "col_heading level0 col2", "display_value": "C", "type": "th", "value": "C", "is_visible": True, }, ]] assert result["head"] == expected def test_index_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]}) result = df.set_index("A").style._translate() expected = [ [ { "class": "blank level0", "type": "th", "value": self.blank_value, "display_value": self.blank_value, "is_visible": True, }, { "class": "col_heading level0 col0", "type": "th", "value": "B", "display_value": "B", "is_visible": True, }, { "class": "col_heading level0 col1", "type": "th", "value": "C", "display_value": "C", "is_visible": True, }, ], [ { "class": "index_name level0", "type": "th", "value": "A" }, { "class": "blank col0", "type": "th", "value": self.blank_value }, { "class": "blank col1", "type": "th", "value": self.blank_value }, ], ] assert result["head"] == expected def test_multiindex_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = DataFrame({"A": [1, 2], "B": [3, 4], "C": [5, 6]}) result = df.set_index(["A", "B"]).style._translate() expected = [ [ { "class": "blank", "type": "th", "value": self.blank_value, "display_value": self.blank_value, "is_visible": True, }, { "class": "blank level0", "type": "th", "value": self.blank_value, "display_value": self.blank_value, "is_visible": True, }, { "class": "col_heading level0 col0", "type": "th", "value": "C", "display_value": "C", "is_visible": True, }, ], [ { "class": "index_name level0", "type": "th", "value": "A" }, { "class": "index_name level1", "type": "th", "value": "B" }, { "class": "blank col0", "type": "th", "value": self.blank_value }, ], ] assert result["head"] == expected def test_numeric_columns(self): # https://github.com/pandas-dev/pandas/issues/12125 # smoke test for _translate df = DataFrame({0: [1, 2, 3]}) df.style._translate() def test_apply_axis(self): df = DataFrame({"A": [0, 0], "B": [1, 1]}) f = lambda x: [f"val: {x.max()}" for v in x] result = df.style.apply(f, axis=1) assert len(result._todo) == 1 assert len(result.ctx) == 0 result._compute() expected = { (0, 0): [("val", "1")], (0, 1): [("val", "1")], (1, 0): [("val", "1")], (1, 1): [("val", "1")], } assert result.ctx == expected result = df.style.apply(f, axis=0) expected = { (0, 0): [("val", "0")], (0, 1): [("val", "1")], (1, 0): [("val", "0")], (1, 1): [("val", "1")], } result._compute() assert result.ctx == expected result = df.style.apply(f) # default result._compute() assert result.ctx == expected @pytest.mark.parametrize( "slice_", [ pd.IndexSlice[:], pd.IndexSlice[:, ["A"]], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ["A"]], pd.IndexSlice[:2, ["A", "B"]], ], ) @pytest.mark.parametrize("axis", [0, 1]) def test_apply_subset(self, slice_, axis): result = (self.df.style.apply(self.h, axis=axis, subset=slice_, foo="baz")._compute().ctx) expected = {(r, c): [("color", "baz")] for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns} assert result == expected @pytest.mark.parametrize( "slice_", [ pd.IndexSlice[:], pd.IndexSlice[:, ["A"]], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ["A"]], pd.IndexSlice[:2, ["A", "B"]], ], ) def test_applymap_subset(self, slice_): result = (self.df.style.applymap(lambda x: "color:baz;", subset=slice_)._compute().ctx) expected = {(r, c): [("color", "baz")] for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns} assert result == expected @pytest.mark.parametrize( "slice_", [ pd.IndexSlice[:, pd.IndexSlice["x", "A"]], pd.IndexSlice[:, pd.IndexSlice[:, "A"]], pd.IndexSlice[:, pd.IndexSlice[:, ["A", "C"]]], # missing col element pd.IndexSlice[pd.IndexSlice["a", 1], :], pd.IndexSlice[pd.IndexSlice[:, 1], :], pd.IndexSlice[pd.IndexSlice[:, [1, 3]], :], # missing row element pd.IndexSlice[:, ("x", "A")], pd.IndexSlice[("a", 1), :], ], ) def test_applymap_subset_multiindex(self, slice_): # GH 19861 # edited for GH 33562 idx = pd.MultiIndex.from_product([["a", "b"], [1, 2]]) col = pd.MultiIndex.from_product([["x", "y"], ["A", "B"]]) df = DataFrame(np.random.rand(4, 4), columns=col, index=idx) df.style.applymap(lambda x: "color: red;", subset=slice_).render() def test_applymap_subset_multiindex_code(self): # https://github.com/pandas-dev/pandas/issues/25858 # Checks styler.applymap works with multindex when codes are provided codes = np.array([[0, 0, 1, 1], [0, 1, 0, 1]]) columns = pd.MultiIndex(levels=[["a", "b"], ["%", "#"]], codes=codes, names=["", ""]) df = DataFrame([[1, -1, 1, 1], [-1, 1, 1, 1]], index=["hello", "world"], columns=columns) pct_subset = pd.IndexSlice[:, pd.IndexSlice[:, "%":"%"]] def color_negative_red(val): color = "red" if val < 0 else "black" return f"color: {color}" df.loc[pct_subset] df.style.applymap(color_negative_red, subset=pct_subset) def test_where_with_one_style(self): # GH 17474 def f(x): return x > 0.5 style1 = "foo: bar" result = self.df.style.where(f, style1)._compute().ctx expected = {(r, c): [("foo", "bar")] for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if f(self.df.loc[row, col])} assert result == expected @pytest.mark.parametrize( "slice_", [ pd.IndexSlice[:], pd.IndexSlice[:, ["A"]], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ["A"]], pd.IndexSlice[:2, ["A", "B"]], ], ) def test_where_subset(self, slice_): # GH 17474 def f(x): return x > 0.5 style1 = "foo: bar" style2 = "baz: foo" result = self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx expected = {(r, c): [("foo", "bar") if f(self.df.loc[row, col]) else ("baz", "foo")] for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns} assert result == expected def test_where_subset_compare_with_applymap(self): # GH 17474 def f(x): return x > 0.5 style1 = "foo: bar" style2 = "baz: foo" def g(x): return style1 if f(x) else style2 slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ["A"]], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ["A"]], pd.IndexSlice[:2, ["A", "B"]], ] for slice_ in slices: result = (self.df.style.where(f, style1, style2, subset=slice_)._compute().ctx) expected = self.df.style.applymap(g, subset=slice_)._compute().ctx assert result == expected def test_empty(self): df = DataFrame({"A": [1, 0]}) s = df.style s.ctx = {(0, 0): [("color", "red")], (1, 0): [("", "")]} result = s._translate()["cellstyle"] expected = [ { "props": [("color", "red")], "selectors": ["row0_col0"] }, { "props": [("", "")], "selectors": ["row1_col0"] }, ] assert result == expected def test_duplicate(self): df = DataFrame({"A": [1, 0]}) s = df.style s.ctx = {(0, 0): [("color", "red")], (1, 0): [("color", "red")]} result = s._translate()["cellstyle"] expected = [{ "props": [("color", "red")], "selectors": ["row0_col0", "row1_col0"] }] assert result == expected def test_init_with_na_rep(self): # GH 21527 28358 df = DataFrame([[None, None], [1.1, 1.2]], columns=["A", "B"]) ctx = Styler(df, na_rep="NA")._translate() assert ctx["body"][0][1]["display_value"] == "NA" assert ctx["body"][0][2]["display_value"] == "NA" def test_set_na_rep(self): # GH 21527 28358 df = DataFrame([[None, None], [1.1, 1.2]], columns=["A", "B"]) with tm.assert_produces_warning(FutureWarning): ctx = df.style.set_na_rep("NA")._translate() assert ctx["body"][0][1]["display_value"] == "NA" assert ctx["body"][0][2]["display_value"] == "NA" with tm.assert_produces_warning(FutureWarning): ctx = (df.style.set_na_rep("NA").format(None, na_rep="-", subset=["B"])._translate()) assert ctx["body"][0][1]["display_value"] == "NA" assert ctx["body"][0][2]["display_value"] == "-" def test_nonunique_raises(self): df = DataFrame([[1, 2]], columns=["A", "A"]) msg = "style is not supported for non-unique indices." with pytest.raises(ValueError, match=msg): df.style with pytest.raises(ValueError, match=msg): Styler(df) def test_caption(self): styler = Styler(self.df, caption="foo") result = styler.render() assert all(["caption" in result, "foo" in result]) styler = self.df.style result = styler.set_caption("baz") assert styler is result assert styler.caption == "baz" def test_uuid(self): styler = Styler(self.df, uuid="abc123") result = styler.render() assert "abc123" in result styler = self.df.style result = styler.set_uuid("aaa") assert result is styler assert result.uuid == "aaa" def test_unique_id(self): # See https://github.com/pandas-dev/pandas/issues/16780 df = 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")] }] # default format styler = Styler(self.df, table_styles=style) result = " ".join(styler.render().split()) assert "th { foo: bar; }" in result styler = self.df.style result = styler.set_table_styles(style) assert styler is result assert styler.table_styles == style # GH 39563 style = [{"selector": "th", "props": "foo:bar;"}] # css string format styler = self.df.style.set_table_styles(style) result = " ".join(styler.render().split()) assert "th { foo: bar; }" in result def test_table_styles_multiple(self): ctx = self.df.style.set_table_styles([ { "selector": "th,td", "props": "color:red;" }, { "selector": "tr", "props": "color:green;" }, ])._translate()["table_styles"] assert ctx == [ { "selector": "th", "props": [("color", "red")] }, { "selector": "td", "props": [("color", "red")] }, { "selector": "tr", "props": [("color", "green")] }, ] def test_maybe_convert_css_to_tuples(self): expected = [("a", "b"), ("c", "d e")] assert _maybe_convert_css_to_tuples("a:b;c:d e;") == expected assert _maybe_convert_css_to_tuples("a: b ;c: d e ") == expected expected = [] assert _maybe_convert_css_to_tuples("") == expected def test_maybe_convert_css_to_tuples_err(self): msg = "Styles supplied as string must follow CSS rule formats" with pytest.raises(ValueError, match=msg): _maybe_convert_css_to_tuples("err") def test_table_attributes(self): attributes = 'class="foo" data-bar' styler = Styler(self.df, table_attributes=attributes) result = styler.render() assert 'class="foo" data-bar' in result result = self.df.style.set_table_attributes(attributes).render() assert 'class="foo" data-bar' in result def test_precision(self): s = Styler(self.df, precision=2) assert s.precision == 2 with tm.assert_produces_warning(FutureWarning): s2 = s.set_precision(4) assert s is s2 assert s.precision == 4 def test_apply_none(self): def f(x): return DataFrame( np.where(x == x.max(), "color: red", ""), index=x.index, columns=x.columns, ) result = DataFrame([[1, 2], [3, 4]]).style.apply(f, axis=None)._compute().ctx assert result[(1, 1)] == [("color", "red")] def test_trim(self): result = self.df.style.render() # trim=True assert result.count("#") == 0 result = self.df.style.highlight_max().render() assert result.count("#") == len(self.df.columns) def test_export(self): f = lambda x: "color: red" if x > 0 else "color: blue" g = lambda x, z: f"color: {z}" if x > 0 else f"color: {z}" style1 = self.styler style1.applymap(f).applymap( g, z="b").highlight_max()._compute() # = render result = style1.export() style2 = self.df.style style2.use(result) assert style1._todo == style2._todo style2.render() def test_bad_apply_shape(self): df = DataFrame([[1, 2], [3, 4]]) msg = "returned the wrong shape" with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: "x", subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: [""], subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: ["", "", "", ""]) with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: ["", "", ""], subset=1) msg = "Length mismatch: Expected axis has 3 elements" with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: ["", "", ""], axis=1) msg = "returned ndarray with wrong shape" with pytest.raises(ValueError, match=msg): df.style._apply(lambda x: np.array([[""], [""]]), axis=None) def test_apply_bad_return(self): def f(x): return "" df = DataFrame([[1, 2], [3, 4]]) msg = ( "must return a DataFrame or ndarray when passed to `Styler.apply` " "with axis=None") with pytest.raises(TypeError, match=msg): df.style._apply(f, axis=None) def test_apply_bad_labels(self): def f(x): return DataFrame(index=[1, 2], columns=["a", "b"]) df = DataFrame([[1, 2], [3, 4]]) msg = "must have identical index and columns as the input" with pytest.raises(ValueError, match=msg): df.style._apply(f, axis=None) def test_get_level_lengths(self): index = pd.MultiIndex.from_product([["a", "b"], [0, 1, 2]]) expected = { (0, 0): 3, (0, 3): 3, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, (1, 4): 1, (1, 5): 1, } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_get_level_lengths_un_sorted(self): index = pd.MultiIndex.from_arrays([[1, 1, 2, 1], ["a", "b", "b", "d"]]) expected = { (0, 0): 2, (0, 2): 1, (0, 3): 1, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_mi_sparse(self): df = 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", "id": "level0_row0", } tm.assert_dict_equal(body_0, expected_0) body_1 = result["body"][0][1] 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) body_10 = result["body"][1][0] 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) head = result["head"][0] expected = [ { "type": "th", "class": "blank", "value": self.blank_value, "is_visible": True, "display_value": self.blank_value, }, { "type": "th", "class": "blank level0", "value": self.blank_value, "is_visible": True, "display_value": self.blank_value, }, { "type": "th", "class": "col_heading level0 col0", "value": "A", "is_visible": True, "display_value": "A", }, ] assert head == expected def test_mi_sparse_disabled(self): with pd.option_context("display.multi_sparse", False): df = DataFrame({"A": [1, 2]}, index=pd.MultiIndex.from_arrays([["a", "a"], [0, 1]])) result = df.style._translate() body = result["body"] for row in body: assert "attributes" not in row[0] def test_mi_sparse_index_names(self): df = DataFrame( {"A": [1, 2]}, index=pd.MultiIndex.from_arrays( [["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"]), ) result = df.style._translate() head = result["head"][1] expected = [ { "class": "index_name level0", "value": "idx_level_0", "type": "th" }, { "class": "index_name level1", "value": "idx_level_1", "type": "th" }, { "class": "blank col0", "value": self.blank_value, "type": "th" }, ] assert head == expected def test_mi_sparse_column_names(self): df = DataFrame( np.arange(16).reshape(4, 4), index=pd.MultiIndex.from_arrays( [["a", "a", "b", "a"], [0, 1, 1, 2]], names=["idx_level_0", "idx_level_1"], ), columns=pd.MultiIndex.from_arrays( [["C1", "C1", "C2", "C2"], [1, 0, 1, 0]], names=["col_0", "col_1"]), ) result = df.style._translate() head = result["head"][1] expected = [ { "class": "blank", "value": self.blank_value, "display_value": self.blank_value, "type": "th", "is_visible": True, }, { "class": "index_name level1", "value": "col_1", "display_value": "col_1", "is_visible": True, "type": "th", }, { "class": "col_heading level1 col0", "display_value": 1, "is_visible": True, "type": "th", "value": 1, }, { "class": "col_heading level1 col1", "display_value": 0, "is_visible": True, "type": "th", "value": 0, }, { "class": "col_heading level1 col2", "display_value": 1, "is_visible": True, "type": "th", "value": 1, }, { "class": "col_heading level1 col3", "display_value": 0, "is_visible": True, "type": "th", "value": 0, }, ] assert head == expected def test_hide_single_index(self): # GH 14194 # single unnamed index ctx = self.df.style._translate() assert ctx["body"][0][0]["is_visible"] assert ctx["head"][0][0]["is_visible"] ctx2 = self.df.style.hide_index()._translate() assert not ctx2["body"][0][0]["is_visible"] assert not ctx2["head"][0][0]["is_visible"] # single named index ctx3 = self.df.set_index("A").style._translate() assert ctx3["body"][0][0]["is_visible"] assert len(ctx3["head"]) == 2 # 2 header levels assert ctx3["head"][0][0]["is_visible"] ctx4 = self.df.set_index("A").style.hide_index()._translate() assert not ctx4["body"][0][0]["is_visible"] assert len(ctx4["head"]) == 1 # only 1 header levels assert not ctx4["head"][0][0]["is_visible"] def test_hide_multiindex(self): # GH 14194 df = DataFrame( {"A": [1, 2]}, index=pd.MultiIndex.from_arrays( [["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"]), ) ctx1 = df.style._translate() # tests for 'a' and '0' assert ctx1["body"][0][0]["is_visible"] assert ctx1["body"][0][1]["is_visible"] # check for blank header rows assert ctx1["head"][0][0]["is_visible"] assert ctx1["head"][0][1]["is_visible"] ctx2 = df.style.hide_index()._translate() # tests for 'a' and '0' assert not ctx2["body"][0][0]["is_visible"] assert not ctx2["body"][0][1]["is_visible"] # check for blank header rows assert not ctx2["head"][0][0]["is_visible"] assert not ctx2["head"][0][1]["is_visible"] def test_hide_columns_single_level(self): # GH 14194 # test hiding single column ctx = self.df.style._translate() assert ctx["head"][0][1]["is_visible"] assert ctx["head"][0][1]["display_value"] == "A" assert ctx["head"][0][2]["is_visible"] assert ctx["head"][0][2]["display_value"] == "B" assert ctx["body"][0][1]["is_visible"] # col A, row 1 assert ctx["body"][1][2]["is_visible"] # col B, row 1 ctx = self.df.style.hide_columns("A")._translate() assert not ctx["head"][0][1]["is_visible"] assert not ctx["body"][0][1]["is_visible"] # col A, row 1 assert ctx["body"][1][2]["is_visible"] # col B, row 1 # test hiding mulitiple columns ctx = self.df.style.hide_columns(["A", "B"])._translate() assert not ctx["head"][0][1]["is_visible"] assert not ctx["head"][0][2]["is_visible"] assert not ctx["body"][0][1]["is_visible"] # col A, row 1 assert not ctx["body"][1][2]["is_visible"] # col B, row 1 def test_hide_columns_mult_levels(self): # GH 14194 # setup dataframe with multiple column levels and indices i1 = pd.MultiIndex.from_arrays([["a", "a"], [0, 1]], names=["idx_level_0", "idx_level_1"]) i2 = pd.MultiIndex.from_arrays([["b", "b"], [0, 1]], names=["col_level_0", "col_level_1"]) df = DataFrame([[1, 2], [3, 4]], index=i1, columns=i2) ctx = df.style._translate() # column headers assert ctx["head"][0][2]["is_visible"] assert ctx["head"][1][2]["is_visible"] assert ctx["head"][1][3]["display_value"] == 1 # indices assert ctx["body"][0][0]["is_visible"] # data assert ctx["body"][1][2]["is_visible"] assert ctx["body"][1][2]["display_value"] == 3 assert ctx["body"][1][3]["is_visible"] assert ctx["body"][1][3]["display_value"] == 4 # hide top column level, which hides both columns ctx = df.style.hide_columns("b")._translate() assert not ctx["head"][0][2]["is_visible"] # b assert not ctx["head"][1][2]["is_visible"] # 0 assert not ctx["body"][1][2]["is_visible"] # 3 assert ctx["body"][0][0]["is_visible"] # index # hide first column only ctx = df.style.hide_columns([("b", 0)])._translate() assert ctx["head"][0][2]["is_visible"] # b assert not ctx["head"][1][2]["is_visible"] # 0 assert not ctx["body"][1][2]["is_visible"] # 3 assert ctx["body"][1][3]["is_visible"] assert ctx["body"][1][3]["display_value"] == 4 # hide second column and index ctx = df.style.hide_columns([("b", 1)]).hide_index()._translate() assert not ctx["body"][0][0]["is_visible"] # index assert ctx["head"][0][2]["is_visible"] # b assert ctx["head"][1][2]["is_visible"] # 0 assert not ctx["head"][1][3]["is_visible"] # 1 assert not ctx["body"][1][3]["is_visible"] # 4 assert ctx["body"][1][2]["is_visible"] assert ctx["body"][1][2]["display_value"] == 3 def test_pipe(self): def set_caption_from_template(styler, a, b): return styler.set_caption(f"Dataframe with a = {a} and b = {b}") styler = self.df.style.pipe(set_caption_from_template, "A", b="B") assert "Dataframe with a = A and b = B" in styler.render() # Test with an argument that is a (callable, keyword_name) pair. def f(a, b, styler): return (a, b, styler) styler = self.df.style result = styler.pipe((f, "styler"), a=1, b=2) assert result == (1, 2, styler) def test_no_cell_ids(self): # GH 35588 # GH 35663 df = DataFrame(data=[[0]]) styler = Styler(df, uuid="_", cell_ids=False) styler.render() s = styler.render() # render twice to ensure ctx is not updated assert s.find('<td class="data row0 col0" >') != -1 @pytest.mark.parametrize( "classes", [ DataFrame( data=[["", "test-class"], [np.nan, None]], columns=["A", "B"], index=["a", "b"], ), DataFrame(data=[["test-class"]], columns=["B"], index=["a"]), DataFrame(data=[["test-class", "unused"]], columns=["B", "C"], index=["a"]), ], ) def test_set_data_classes(self, classes): # GH 36159 df = DataFrame(data=[[0, 1], [2, 3]], columns=["A", "B"], index=["a", "b"]) s = Styler(df, uuid_len=0, cell_ids=False).set_td_classes(classes).render() assert '<td class="data row0 col0" >0</td>' in s assert '<td class="data row0 col1 test-class" >1</td>' in s assert '<td class="data row1 col0" >2</td>' in s assert '<td class="data row1 col1" >3</td>' in s # GH 39317 s = Styler(df, uuid_len=0, cell_ids=True).set_td_classes(classes).render() assert '<td id="T__row0_col0" class="data row0 col0" >0</td>' in s assert '<td id="T__row0_col1" class="data row0 col1 test-class" >1</td>' in s assert '<td id="T__row1_col0" class="data row1 col0" >2</td>' in s assert '<td id="T__row1_col1" class="data row1 col1" >3</td>' in s def test_set_data_classes_reindex(self): # GH 39317 df = DataFrame(data=[[0, 1, 2], [3, 4, 5], [6, 7, 8]], columns=[0, 1, 2], index=[0, 1, 2]) classes = DataFrame( data=[["mi", "ma"], ["mu", "mo"]], columns=[0, 2], index=[0, 2], ) s = Styler(df, uuid_len=0).set_td_classes(classes).render() assert '<td id="T__row0_col0" class="data row0 col0 mi" >0</td>' in s assert '<td id="T__row0_col2" class="data row0 col2 ma" >2</td>' in s assert '<td id="T__row1_col1" class="data row1 col1" >4</td>' in s assert '<td id="T__row2_col0" class="data row2 col0 mu" >6</td>' in s assert '<td id="T__row2_col2" class="data row2 col2 mo" >8</td>' in s def test_chaining_table_styles(self): # GH 35607 df = DataFrame(data=[[0, 1], [1, 2]], columns=["A", "B"]) styler = df.style.set_table_styles([{ "selector": "", "props": [("background-color", "yellow")] }]).set_table_styles( [{ "selector": ".col0", "props": [("background-color", "blue")] }], overwrite=False, ) assert len(styler.table_styles) == 2 def test_column_and_row_styling(self): # GH 35607 df = DataFrame(data=[[0, 1], [1, 2]], columns=["A", "B"]) s = Styler(df, uuid_len=0) s = s.set_table_styles( {"A": [{ "selector": "", "props": [("color", "blue")] }]}) assert "#T__ .col0 {\n color: blue;\n}" in s.render() s = s.set_table_styles( {0: [{ "selector": "", "props": [("color", "blue")] }]}, axis=1) assert "#T__ .row0 {\n color: blue;\n}" in s.render() def test_colspan_w3(self): # GH 36223 df = DataFrame(data=[[1, 2]], columns=[["l0", "l0"], ["l1a", "l1b"]]) s = Styler(df, uuid="_", cell_ids=False) assert '<th class="col_heading level0 col0" colspan="2">l0</th>' in s.render( ) def test_rowspan_w3(self): # GH 38533 df = DataFrame(data=[[1, 2]], index=[["l0", "l0"], ["l1a", "l1b"]]) s = Styler(df, uuid="_", cell_ids=False) assert ('<th id="T___level0_row0" class="row_heading ' 'level0 row0" rowspan="2">l0</th>' in s.render()) @pytest.mark.parametrize("len_", [1, 5, 32, 33, 100]) def test_uuid_len(self, len_): # GH 36345 df = DataFrame(data=[["A"]]) s = Styler(df, uuid_len=len_, cell_ids=False).render() strt = s.find('id="T_') end = s[strt + 6:].find('"') if len_ > 32: assert end == 32 + 1 else: assert end == len_ + 1 @pytest.mark.parametrize("len_", [-2, "bad", None]) def test_uuid_len_raises(self, len_): # GH 36345 df = DataFrame(data=[["A"]]) msg = "``uuid_len`` must be an integer in range \\[0, 32\\]." with pytest.raises(TypeError, match=msg): Styler(df, uuid_len=len_, cell_ids=False).render() def test_w3_html_format(self): s = (Styler( DataFrame([[2.61], [2.69]], index=["a", "b"], columns=["A"]), uuid_len=0, ).set_table_styles([{ "selector": "th", "props": "att2:v2;" }]).applymap(lambda x: "att1:v1;").set_table_attributes( 'class="my-cls1" style="attr3:v3;"').set_td_classes( DataFrame(["my-cls2"], index=["a"], columns=[ "A" ])).format("{:.1f}").set_caption("A comprehensive test")) expected = """<style type="text/css"> #T__ th { att2: v2; } #T__row0_col0, #T__row1_col0 { att1: v1; } </style> <table id="T__" class="my-cls1" style="attr3:v3;"> <caption>A comprehensive test</caption> <thead> <tr> <th class="blank level0" > </th> <th class="col_heading level0 col0" >A</th> </tr> </thead> <tbody> <tr> <th id="T__level0_row0" class="row_heading level0 row0" >a</th> <td id="T__row0_col0" class="data row0 col0 my-cls2" >2.6</td> </tr> <tr> <th id="T__level0_row1" class="row_heading level0 row1" >b</th> <td id="T__row1_col0" class="data row1 col0" >2.7</td> </tr> </tbody> </table> """ assert expected == s.render() @pytest.mark.parametrize( "slc", [ pd.IndexSlice[:, :], pd.IndexSlice[:, 1], pd.IndexSlice[1, :], pd.IndexSlice[[1], [1]], pd.IndexSlice[1, [1]], pd.IndexSlice[[1], 1], pd.IndexSlice[1], pd.IndexSlice[1, 1], slice(None, None, None), [0, 1], np.array([0, 1]), pd.Series([0, 1]), ], ) def test_non_reducing_slice(self, slc): df = DataFrame([[0, 1], [2, 3]]) tslice_ = _non_reducing_slice(slc) assert isinstance(df.loc[tslice_], DataFrame) @pytest.mark.parametrize("box", [list, pd.Series, np.array]) def test_list_slice(self, box): # like dataframe getitem subset = box(["A"]) df = DataFrame({"A": [1, 2], "B": [3, 4]}, index=["A", "B"]) expected = pd.IndexSlice[:, ["A"]] result = _non_reducing_slice(subset) tm.assert_frame_equal(df.loc[result], df.loc[expected]) def test_non_reducing_slice_on_multiindex(self): # GH 19861 dic = { ("a", "d"): [1, 4], ("a", "c"): [2, 3], ("b", "c"): [3, 2], ("b", "d"): [4, 1], } df = DataFrame(dic, index=[0, 1]) idx = pd.IndexSlice slice_ = idx[:, idx["b", "d"]] tslice_ = _non_reducing_slice(slice_) result = df.loc[tslice_] expected = DataFrame({("b", "d"): [4, 1]}) tm.assert_frame_equal(result, expected) @pytest.mark.parametrize( "slice_", [ pd.IndexSlice[:, :], # check cols pd.IndexSlice[:, pd.IndexSlice[["a"]]], # inferred deeper need list pd.IndexSlice[:, pd.IndexSlice[["a"], ["c"]]], # inferred deeper need list pd.IndexSlice[:, pd.IndexSlice["a", "c", :]], pd.IndexSlice[:, pd.IndexSlice["a", :, "e"]], pd.IndexSlice[:, pd.IndexSlice[:, "c", "e"]], pd.IndexSlice[:, pd.IndexSlice["a", ["c", "d"], :]], # check list pd.IndexSlice[:, pd.IndexSlice["a", ["c", "d", "-"], :]], # allow missing pd.IndexSlice[:, pd.IndexSlice["a", ["c", "d", "-"], "e"]], # no slice # check rows pd.IndexSlice[ pd.IndexSlice[["U"]], :], # inferred deeper need list pd.IndexSlice[pd.IndexSlice[ ["U"], ["W"]], :], # inferred deeper need list pd.IndexSlice[pd.IndexSlice["U", "W", :], :], pd.IndexSlice[pd.IndexSlice["U", :, "Y"], :], pd.IndexSlice[pd.IndexSlice[:, "W", "Y"], :], pd.IndexSlice[pd.IndexSlice[:, "W", ["Y", "Z"]], :], # check list pd.IndexSlice[pd.IndexSlice[:, "W", ["Y", "Z", "-"]], :], # allow missing pd.IndexSlice[pd.IndexSlice["U", "W", ["Y", "Z", "-"]], :], # no slice # check simultaneous pd.IndexSlice[pd.IndexSlice[:, "W", "Y"], pd.IndexSlice["a", "c", :]], ], ) def test_non_reducing_multi_slice_on_multiindex(self, slice_): # GH 33562 cols = pd.MultiIndex.from_product([["a", "b"], ["c", "d"], ["e", "f"]]) idxs = pd.MultiIndex.from_product([["U", "V"], ["W", "X"], ["Y", "Z"]]) df = DataFrame(np.arange(64).reshape(8, 8), columns=cols, index=idxs) expected = df.loc[slice_] result = df.loc[_non_reducing_slice(slice_)] tm.assert_frame_equal(result, expected)
class TestStyler(TestCase): def setUp(self): np.random.seed(24) self.s = DataFrame({'A': np.random.permutation(range(6))}) self.df = DataFrame({'A': [0, 1], 'B': np.random.randn(2)}) self.f = lambda x: x self.g = lambda x: x def h(x, foo='bar'): return pd.Series(['color: %s' % foo], index=x.index, name=x.name) self.h = h self.styler = Styler(self.df) self.attrs = pd.DataFrame({'A': ['color: red', 'color: blue']}) self.dataframes = [ self.df, pd.DataFrame({ 'f': [1., 2.], 'o': ['a', 'b'], 'c': pd.Categorical(['a', 'b']) }) ] def test_init_non_pandas(self): with pytest.raises(TypeError): Styler([1, 2, 3]) def test_init_series(self): result = Styler(pd.Series([1, 2])) self.assertEqual(result.data.ndim, 2) def test_repr_html_ok(self): self.styler._repr_html_() def test_update_ctx(self): self.styler._update_ctx(self.attrs) expected = {(0, 0): ['color: red'], (1, 0): ['color: blue']} self.assertEqual(self.styler.ctx, expected) def test_update_ctx_flatten_multi(self): attrs = DataFrame( {"A": ['color: red; foo: bar', 'color: blue; foo: baz']}) self.styler._update_ctx(attrs) expected = { (0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz'] } self.assertEqual(self.styler.ctx, expected) def test_update_ctx_flatten_multi_traliing_semi(self): attrs = DataFrame( {"A": ['color: red; foo: bar;', 'color: blue; foo: baz;']}) self.styler._update_ctx(attrs) expected = { (0, 0): ['color: red', ' foo: bar'], (1, 0): ['color: blue', ' foo: baz'] } self.assertEqual(self.styler.ctx, expected) def test_copy(self): s2 = copy.copy(self.styler) assert self.styler is not s2 assert self.styler.ctx is s2.ctx # shallow assert self.styler._todo is s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() self.assertEqual(self.styler.ctx, s2.ctx) self.assertEqual(self.styler._todo, s2._todo) def test_deepcopy(self): s2 = copy.deepcopy(self.styler) assert self.styler is not s2 assert self.styler.ctx is not s2.ctx assert self.styler._todo is not s2._todo self.styler._update_ctx(self.attrs) self.styler.highlight_max() self.assertNotEqual(self.styler.ctx, s2.ctx) self.assertEqual(s2._todo, []) self.assertNotEqual(self.styler._todo, s2._todo) def test_clear(self): s = self.df.style.highlight_max()._compute() assert len(s.ctx) > 0 assert len(s._todo) > 0 s.clear() assert len(s.ctx) == 0 assert len(s._todo) == 0 def test_render(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series(["color: red", "color: blue"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_render_double(self): df = pd.DataFrame({"A": [0, 1]}) style = lambda x: pd.Series( ["color: red; border: 1px", "color: blue; border: 2px"], name=x.name) s = Styler(df, uuid='AB').apply(style) s.render() # it worked? def test_set_properties(self): df = pd.DataFrame({"A": [0, 1]}) result = df.style.set_properties(color='white', size='10px')._compute().ctx # order is deterministic v = ["color: white", "size: 10px"] expected = {(0, 0): v, (1, 0): v} self.assertEqual(result.keys(), expected.keys()) for v1, v2 in zip(result.values(), expected.values()): self.assertEqual(sorted(v1), sorted(v2)) def test_set_properties_subset(self): df = pd.DataFrame({'A': [0, 1]}) result = df.style.set_properties(subset=pd.IndexSlice[0, 'A'], color='white')._compute().ctx expected = {(0, 0): ['color: white']} self.assertEqual(result, expected) def test_empty_index_name_doesnt_display(self): # https://github.com/pandas-dev/pandas/pull/12090#issuecomment-180695902 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.style._translate() expected = [[{ 'class': 'blank level0', 'type': 'th', 'value': '', 'is_visible': True, 'display_value': '' }, { 'class': 'col_heading level0 col0', 'display_value': 'A', 'type': 'th', 'value': 'A', 'is_visible': True, }, { 'class': 'col_heading level0 col1', 'display_value': 'B', 'type': 'th', 'value': 'B', 'is_visible': True, }, { 'class': 'col_heading level0 col2', 'display_value': 'C', 'type': 'th', 'value': 'C', 'is_visible': True, }]] self.assertEqual(result['head'], expected) def test_index_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index('A').style._translate() expected = [[{ 'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'col_heading level0 col0', 'type': 'th', 'value': 'B', 'display_value': 'B', 'is_visible': True }, { 'class': 'col_heading level0 col1', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True }], [{ 'class': 'index_name level0', 'type': 'th', 'value': 'A' }, { 'class': 'blank', 'type': 'th', 'value': '' }, { 'class': 'blank', 'type': 'th', 'value': '' }]] self.assertEqual(result['head'], expected) def test_multiindex_name(self): # https://github.com/pandas-dev/pandas/issues/11655 df = pd.DataFrame({'A': [1, 2], 'B': [3, 4], 'C': [5, 6]}) result = df.set_index(['A', 'B']).style._translate() expected = [[{ 'class': 'blank', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'blank level0', 'type': 'th', 'value': '', 'display_value': '', 'is_visible': True }, { 'class': 'col_heading level0 col0', 'type': 'th', 'value': 'C', 'display_value': 'C', 'is_visible': True }], [{ 'class': 'index_name level0', 'type': 'th', 'value': 'A' }, { 'class': 'index_name level1', 'type': 'th', 'value': 'B' }, { 'class': 'blank', 'type': 'th', 'value': '' }]] self.assertEqual(result['head'], expected) def test_numeric_columns(self): # https://github.com/pandas-dev/pandas/issues/12125 # smoke test for _translate df = pd.DataFrame({0: [1, 2, 3]}) df.style._translate() def test_apply_axis(self): df = pd.DataFrame({'A': [0, 0], 'B': [1, 1]}) f = lambda x: ['val: %s' % x.max() for v in x] result = df.style.apply(f, axis=1) self.assertEqual(len(result._todo), 1) self.assertEqual(len(result.ctx), 0) result._compute() expected = { (0, 0): ['val: 1'], (0, 1): ['val: 1'], (1, 0): ['val: 1'], (1, 1): ['val: 1'] } self.assertEqual(result.ctx, expected) result = df.style.apply(f, axis=0) expected = { (0, 0): ['val: 0'], (0, 1): ['val: 1'], (1, 0): ['val: 0'], (1, 1): ['val: 1'] } result._compute() self.assertEqual(result.ctx, expected) result = df.style.apply(f) # default result._compute() self.assertEqual(result.ctx, expected) def test_apply_subset(self): axes = [0, 1] slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for ax in axes: for slice_ in slices: result = self.df.style.apply(self.h, axis=ax, subset=slice_, foo='baz')._compute().ctx expected = dict(((r, c), ['color: baz']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) self.assertEqual(result, expected) def test_applymap_subset(self): def f(x): return 'foo: bar' slices = [ pd.IndexSlice[:], pd.IndexSlice[:, ['A']], pd.IndexSlice[[1], :], pd.IndexSlice[[1], ['A']], pd.IndexSlice[:2, ['A', 'B']] ] for slice_ in slices: result = self.df.style.applymap(f, subset=slice_)._compute().ctx expected = dict(((r, c), ['foo: bar']) for r, row in enumerate(self.df.index) for c, col in enumerate(self.df.columns) if row in self.df.loc[slice_].index and col in self.df.loc[slice_].columns) self.assertEqual(result, expected) def test_empty(self): df = pd.DataFrame({'A': [1, 0]}) s = df.style s.ctx = {(0, 0): ['color: red'], (1, 0): ['']} result = s._translate()['cellstyle'] expected = [{ 'props': [['color', ' red']], 'selector': 'row0_col0' }, { 'props': [['', '']], 'selector': 'row1_col0' }] self.assertEqual(result, expected) def test_bar(self): df = pd.DataFrame({'A': [0, 1, 2]}) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 50.0%, transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,#d65f5f 100.0%, transparent 0%)' ] } self.assertEqual(result, expected) result = df.style.bar(color='red', width=50)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 25.0%, transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(' '90deg,red 50.0%, transparent 0%)' ] } self.assertEqual(result, expected) df['C'] = ['a'] * len(df) result = df.style.bar(color='red', width=50)._compute().ctx self.assertEqual(result, expected) df['C'] = df['C'].astype('category') result = df.style.bar(color='red', width=50)._compute().ctx self.assertEqual(result, expected) def test_bar_0points(self): df = pd.DataFrame([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) result = df.style.bar()._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (0, 1): ['width: 10em', ' height: 80%'], (0, 2): ['width: 10em', ' height: 80%'], (1, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (1, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (1, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (2, 0): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ] } self.assertEqual(result, expected) result = df.style.bar(axis=1)._compute().ctx expected = { (0, 0): ['width: 10em', ' height: 80%'], (0, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%,' ' transparent 0%)' ], (0, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (1, 0): ['width: 10em', ' height: 80%'], (1, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)' ], (1, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ], (2, 0): ['width: 10em', ' height: 80%'], (2, 1): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 50.0%' ', transparent 0%)' ], (2, 2): [ 'width: 10em', ' height: 80%', 'background: linear-gradient(90deg,#d65f5f 100.0%' ', transparent 0%)' ] } self.assertEqual(result, expected) def test_highlight_null(self, null_color='red'): df = pd.DataFrame({'A': [0, np.nan]}) result = df.style.highlight_null()._compute().ctx expected = {(0, 0): [''], (1, 0): ['background-color: red']} self.assertEqual(result, expected) def test_nonunique_raises(self): df = pd.DataFrame([[1, 2]], columns=['A', 'A']) with pytest.raises(ValueError): df.style with pytest.raises(ValueError): Styler(df) def test_caption(self): styler = Styler(self.df, caption='foo') result = styler.render() assert all(['caption' in result, 'foo' in result]) styler = self.df.style result = styler.set_caption('baz') assert styler is result self.assertEqual(styler.caption, 'baz') def test_uuid(self): styler = Styler(self.df, uuid='abc123') result = styler.render() assert 'abc123' in result styler = self.df.style result = styler.set_uuid('aaa') assert result is styler self.assertEqual(result.uuid, 'aaa') def test_table_styles(self): style = [{'selector': 'th', 'props': [('foo', 'bar')]}] styler = Styler(self.df, table_styles=style) result = ' '.join(styler.render().split()) assert 'th { foo: bar; }' in result styler = self.df.style result = styler.set_table_styles(style) assert styler is result self.assertEqual(styler.table_styles, style) def test_table_attributes(self): attributes = 'class="foo" data-bar' styler = Styler(self.df, table_attributes=attributes) result = styler.render() assert 'class="foo" data-bar' in result result = self.df.style.set_table_attributes(attributes).render() assert 'class="foo" data-bar' in result def test_precision(self): with pd.option_context('display.precision', 10): s = Styler(self.df) self.assertEqual(s.precision, 10) s = Styler(self.df, precision=2) self.assertEqual(s.precision, 2) s2 = s.set_precision(4) assert s is s2 self.assertEqual(s.precision, 4) def test_apply_none(self): def f(x): return pd.DataFrame(np.where(x == x.max(), 'color: red', ''), index=x.index, columns=x.columns) result = (pd.DataFrame([[1, 2], [3, 4]]).style.apply(f, axis=None)._compute().ctx) self.assertEqual(result[(1, 1)], ['color: red']) def test_trim(self): result = self.df.style.render() # trim=True self.assertEqual(result.count('#'), 0) result = self.df.style.highlight_max().render() self.assertEqual(result.count('#'), len(self.df.columns)) def test_highlight_max(self): df = pd.DataFrame([[1, 2], [3, 4]], columns=['A', 'B']) # max(df) = min(-df) for max_ in [True, False]: if max_: attr = 'highlight_max' else: df = -df attr = 'highlight_min' result = getattr(df.style, attr)()._compute().ctx self.assertEqual(result[(1, 1)], ['background-color: yellow']) result = getattr(df.style, attr)(color='green')._compute().ctx self.assertEqual(result[(1, 1)], ['background-color: green']) result = getattr(df.style, attr)(subset='A')._compute().ctx self.assertEqual(result[(1, 0)], ['background-color: yellow']) result = getattr(df.style, attr)(axis=0)._compute().ctx expected = { (1, 0): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 1): [''], (0, 0): [''] } self.assertEqual(result, expected) result = getattr(df.style, attr)(axis=1)._compute().ctx expected = { (0, 1): ['background-color: yellow'], (1, 1): ['background-color: yellow'], (0, 0): [''], (1, 0): [''] } self.assertEqual(result, expected) # separate since we cant negate the strs df['C'] = ['a', 'b'] result = df.style.highlight_max()._compute().ctx expected = {(1, 1): ['background-color: yellow']} result = df.style.highlight_min()._compute().ctx expected = {(0, 0): ['background-color: yellow']} def test_export(self): f = lambda x: 'color: red' if x > 0 else 'color: blue' g = lambda x, y, z: 'color: %s' if x > 0 else 'color: %s' % z style1 = self.styler style1.applymap(f)\ .applymap(g, y='a', z='b')\ .highlight_max() result = style1.export() style2 = self.df.style style2.use(result) self.assertEqual(style1._todo, style2._todo) style2.render() def test_display_format(self): df = pd.DataFrame(np.random.random(size=(2, 2))) ctx = df.style.format("{:0.1f}")._translate() assert all(['display_value' in c for c in row] for row in ctx['body']) assert (all([len(c['display_value']) <= 3 for c in row[1:]] for row in ctx['body'])) assert len(ctx['body'][0][1]['display_value'].lstrip('-')) <= 3 def test_display_format_raises(self): df = pd.DataFrame(np.random.randn(2, 2)) with pytest.raises(TypeError): df.style.format(5) with pytest.raises(TypeError): df.style.format(True) def test_display_subset(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({ "a": "{:0.1f}", "b": "{0:.2%}" }, subset=pd.IndexSlice[0, :])._translate() expected = '0.1' self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], '1.1234') self.assertEqual(ctx['body'][0][2]['display_value'], '12.34%') raw_11 = '1.1234' ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, :])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice['a'])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][0][2]['display_value'], '0.1234') ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[0, 'a'])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], raw_11) ctx = df.style.format("{:0.1f}", subset=pd.IndexSlice[[0, 1], ['a']])._translate() self.assertEqual(ctx['body'][0][1]['display_value'], expected) self.assertEqual(ctx['body'][1][1]['display_value'], '1.1') self.assertEqual(ctx['body'][0][2]['display_value'], '0.1234') self.assertEqual(ctx['body'][1][2]['display_value'], '1.1234') def test_display_dict(self): df = pd.DataFrame([[.1234, .1234], [1.1234, 1.1234]], columns=['a', 'b']) ctx = df.style.format({"a": "{:0.1f}", "b": "{0:.2%}"})._translate() self.assertEqual(ctx['body'][0][1]['display_value'], '0.1') self.assertEqual(ctx['body'][0][2]['display_value'], '12.34%') df['c'] = ['aaa', 'bbb'] ctx = df.style.format({"a": "{:0.1f}", "c": str.upper})._translate() self.assertEqual(ctx['body'][0][1]['display_value'], '0.1') self.assertEqual(ctx['body'][0][3]['display_value'], 'AAA') def test_bad_apply_shape(self): df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(lambda x: 'x', subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: [''], subset=pd.IndexSlice[[0, 1], :]) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', '', '']) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], subset=1) with pytest.raises(ValueError): df.style._apply(lambda x: ['', '', ''], axis=1) def test_apply_bad_return(self): def f(x): return '' df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(TypeError): df.style._apply(f, axis=None) def test_apply_bad_labels(self): def f(x): return pd.DataFrame(index=[1, 2], columns=['a', 'b']) df = pd.DataFrame([[1, 2], [3, 4]]) with pytest.raises(ValueError): df.style._apply(f, axis=None) def test_get_level_lengths(self): index = pd.MultiIndex.from_product([['a', 'b'], [0, 1, 2]]) expected = { (0, 0): 3, (0, 3): 3, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1, (1, 4): 1, (1, 5): 1 } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) def test_get_level_lengths_un_sorted(self): index = pd.MultiIndex.from_arrays([[1, 1, 2, 1], ['a', 'b', 'b', 'd']]) expected = { (0, 0): 2, (0, 2): 1, (0, 3): 1, (1, 0): 1, (1, 1): 1, (1, 2): 1, (1, 3): 1 } result = _get_level_lengths(index) tm.assert_dict_equal(result, expected) 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", } tm.assert_dict_equal(body_0, expected_0) body_1 = result['body'][0][1] expected_1 = { "value": 0, "display_value": 0, "is_visible": True, "type": "th", "class": "row_heading level1 row0", } tm.assert_dict_equal(body_1, expected_1) body_10 = result['body'][1][0] expected_10 = { "value": 'a', "display_value": 'a', "is_visible": False, "type": "th", "class": "row_heading level0 row1", } tm.assert_dict_equal(body_10, expected_10) head = result['head'][0] expected = [{ 'type': 'th', 'class': 'blank', 'value': '', 'is_visible': True, "display_value": '' }, { 'type': 'th', 'class': 'blank level0', 'value': '', 'is_visible': True, 'display_value': '' }, { 'type': 'th', 'class': 'col_heading level0 col0', 'value': 'A', 'is_visible': True, 'display_value': 'A' }] self.assertEqual(head, expected) def test_mi_sparse_disabled(self): with pd.option_context('display.multi_sparse', False): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays([['a', 'a'], [0, 1]])) result = df.style._translate() body = result['body'] for row in body: assert 'attributes' not in row[0] def test_mi_sparse_index_names(self): df = pd.DataFrame({'A': [1, 2]}, index=pd.MultiIndex.from_arrays( [['a', 'a'], [0, 1]], names=['idx_level_0', 'idx_level_1'])) result = df.style._translate() head = result['head'][1] expected = [{ 'class': 'index_name level0', 'value': 'idx_level_0', 'type': 'th' }, { 'class': 'index_name level1', 'value': 'idx_level_1', 'type': 'th' }, { 'class': 'blank', 'value': '', 'type': 'th' }] self.assertEqual(head, expected) def test_mi_sparse_column_names(self): df = pd.DataFrame(np.arange(16).reshape(4, 4), index=pd.MultiIndex.from_arrays( [['a', 'a', 'b', 'a'], [0, 1, 1, 2]], names=['idx_level_0', 'idx_level_1']), columns=pd.MultiIndex.from_arrays( [['C1', 'C1', 'C2', 'C2'], [1, 0, 1, 0]], names=['col_0', 'col_1'])) result = df.style._translate() head = result['head'][1] expected = [ { 'class': 'blank', 'value': '', 'display_value': '', 'type': 'th', 'is_visible': True }, { 'class': 'index_name level1', 'value': 'col_1', 'display_value': 'col_1', 'is_visible': True, 'type': 'th' }, { 'class': 'col_heading level1 col0', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1 }, { 'class': 'col_heading level1 col1', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0 }, { 'class': 'col_heading level1 col2', 'display_value': 1, 'is_visible': True, 'type': 'th', 'value': 1 }, { 'class': 'col_heading level1 col3', 'display_value': 0, 'is_visible': True, 'type': 'th', 'value': 0 }, ] self.assertEqual(head, expected)