diff --git a/ci/requirements-2.6.run b/ci/requirements-2.6.run index 5f8a2fde1409f..32d71beb24388 100644 --- a/ci/requirements-2.6.run +++ b/ci/requirements-2.6.run @@ -14,3 +14,4 @@ psycopg2=2.5.1 pymysql=0.6.0 sqlalchemy=0.7.8 xlsxwriter=0.4.6 +jinja2=2.8 diff --git a/ci/requirements-2.7.run b/ci/requirements-2.7.run index 10049179912da..8fc074b96e0e4 100644 --- a/ci/requirements-2.7.run +++ b/ci/requirements-2.7.run @@ -19,3 +19,4 @@ pymysql=0.6.3 html5lib=1.0b2 beautiful-soup=4.2.1 statsmodels +jinja2=2.8 diff --git a/ci/requirements-3.3.run b/ci/requirements-3.3.run index 0256802a69eba..2379ab42391db 100644 --- a/ci/requirements-3.3.run +++ b/ci/requirements-3.3.run @@ -14,3 +14,4 @@ lxml=3.2.1 scipy beautiful-soup=4.2.1 statsmodels +jinja2=2.8 diff --git a/ci/requirements-3.4.run b/ci/requirements-3.4.run index 45d082022713e..902a2984d4b3d 100644 --- a/ci/requirements-3.4.run +++ b/ci/requirements-3.4.run @@ -16,3 +16,4 @@ sqlalchemy bottleneck pymysql=0.6.3 psycopg2 +jinja2=2.8 diff --git a/ci/requirements-3.4_SLOW.run b/ci/requirements-3.4_SLOW.run index 1eca130ecd96a..f0101d34204a3 100644 --- a/ci/requirements-3.4_SLOW.run +++ b/ci/requirements-3.4_SLOW.run @@ -18,3 +18,4 @@ bottleneck pymysql psycopg2 statsmodels +jinja2=2.8 diff --git a/ci/requirements-3.5.run b/ci/requirements-3.5.run index 8de8f7d8f0630..64ed11b744ffd 100644 --- a/ci/requirements-3.5.run +++ b/ci/requirements-3.5.run @@ -12,6 +12,7 @@ pytables html5lib lxml matplotlib +jinja2 # currently causing some warnings #sqlalchemy diff --git a/doc/source/api.rst b/doc/source/api.rst index 6bee0a1ceafb8..668e297dc8f18 100644 --- a/doc/source/api.rst +++ b/doc/source/api.rst @@ -1662,6 +1662,56 @@ The following methods are available only for ``DataFrameGroupBy`` objects. DataFrameGroupBy.corrwith DataFrameGroupBy.boxplot +Style +----- +.. currentmodule:: pandas.core.style + +``Styler`` objects are returned by :attr:`pandas.DataFrame.style`. + + +Constructor +~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Styler + +Style Application +~~~~~~~~~~~~~~~~~ +.. autosummary:: + :toctree: generated/ + + Styler.apply + Styler.applymap + Styler.set_precision + Styler.set_table_styles + Styler.set_caption + Styler.set_properties + Styler.set_uuid + Styler.clear + +Builtin Styles +~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Styler.highlight_max + Styler.highlight_min + Styler.highlight_null + Styler.background_gradient + Styler.bar + +Style Export and Import +~~~~~~~~~~~~~~~~~~~~~~~ + +.. autosummary:: + :toctree: generated/ + + Styler.render + Styler.export + Styler.set + .. currentmodule:: pandas General utility functions diff --git a/doc/source/html-styling.html b/doc/source/html-styling.html new file mode 100644 index 0000000000000..e595cffc751a8 --- /dev/null +++ b/doc/source/html-styling.html @@ -0,0 +1,21492 @@ + + + +html-styling + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+

Conditional Formatting

New in version 0.17.1

+

Provisional: This is a new feature and still under development. We'll be adding features and possibly making breaking changes in future releases. We'd love to hear your feedback.

+

You can apply conditional formatting, the visual styling of a DataFrame +depending on the data within, by using the DataFrame.style property. +This is a property that returns a pandas.Styler object, which has +useful methods for formatting and displaying DataFrames.

+

The styling is accomplished using CSS. +You write "style functions" that take scalars, DataFrames or Series, and return like-indexed DataFrames or Series with CSS "attribute: value" pairs for the values. +These functions can be incrementally passed to the Styler which collects the styles before rendering.

+

Contents

+ +
+
+
+
+
+
+
+
+

Building Styles

Pass your style functions into one of the following methods:

+
    +
  • Styler.applymap: elementwise
  • +
  • Styler.apply: column-/row-/table-wise
  • +
+

Both of those methods take a function (and some other keyword arguments) and applies your function to the DataFrame in a certain way. +Styler.applymap works through the DataFrame elementwise. +Styler.apply passes each column or row into your DataFrame one-at-a-time or the entire table at once, depending on the axis keyword argument. +For columnwise use axis=0, rowwise use axis=1, and for the entire table at once use axis=None.

+

The result of the function application, a CSS attribute-value pair, is stored in an internal dictionary on your Styler object.

+

Let's see some examples.

+ +
+
+
+
+
+
In [1]:
+
+
+
import pandas as pd
+import numpy as np
+
+np.random.seed(24)
+df = pd.DataFrame({'A': np.linspace(1, 10, 10)})
+df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4), columns=list('BCDE'))],
+               axis=1)
+df.iloc[0, 2] = np.nan
+
+ +
+
+
+ +
+
+
+
+
+
+

Here's a boring example of rendering a DataFrame, without any (visible) styles:

+ +
+
+
+
+
+
In [2]:
+
+
+
df.style
+
+ +
+
+
+ +
+
+ + +
Out[2]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Note: The DataFrame.style attribute is a propetry that returns a Styler object. Styler has a _repr_html_ method defined on it so they are rendered automatically. If you want the actual HTML back for further processing or for writing to file call the .render() method which returns a string.

+

The above output looks very similar to the standard DataFrame HTML representation. But we've done some work behind the scenes to attach CSS classes to each cell. We can view these by calling the .render method.

+ +
+
+
+
+
+
In [3]:
+
+
+
df.style.highlight_null().render().split('\n')[:10]
+
+ +
+
+
+ +
+
+ + +
Out[3]:
+ + +
+
['',
+ '        <style  type="text/css" >',
+ '        ',
+ '        ',
+ '            #T_e7c1f51a_8bd5_11e5_803e_a45e60bd97fbrow0_col2 {',
+ '            ',
+ '                background-color:  red;',
+ '            ',
+ '            }',
+ '        ']
+
+ +
+ +
+
+ +
+
+
+
+
+
+

The row0_col2 is the identifier for that particular cell. We've also prepended each row/column identifier with a UUID unique to each DataFrame so that the style from one doesn't collied with the styling from another within the same notebook or page (you can set the uuid if you'd like to tie together the styling of two DataFrames).

+

When writing style functions, you take care of producing the CSS attribute / value pairs you want. Pandas matches those up with the CSS classes that identify each cell.

+ +
+
+
+
+
+
+
+
+

Let's write a simple style function that will color negative numbers red and positive numbers black.

+ +
+
+
+
+
+
In [4]:
+
+
+
def color_negative_red(val):
+    """
+    Takes a scalar and returns a string with
+    the css property `'color: red'` for negative
+    strings, black otherwise.
+    """
+    color = 'red' if val < 0 else 'black'
+    return 'color: %s' % color
+
+ +
+
+
+ +
+
+
+
+
+
+

In this case, the cell's style depends only on it's own value. +That means we should use the Styler.applymap method which works elementwise.

+ +
+
+
+
+
+
In [5]:
+
+
+
s = df.style.applymap(color_negative_red)
+s
+
+ +
+
+
+ +
+
+ + +
Out[5]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Notice the similarity with the standard df.applymap, which operates on DataFrames elementwise. We want you to be able to resuse your existing knowledge of how to interact with DataFrames.

+

Notice also that our function returned a string containing the CSS attribute and value, separated by a colon just like in a <style> tag. This will be a common theme.

+ +
+
+
+
+
+
+
+
+

Now suppose you wanted to highlight the maximum value in each column. +We can't use .applymap anymore since that operated elementwise. +Instead, we'll turn to .apply which operates columnwise (or rowwise using the axis keyword). Later on we'll see that something like highlight_max is already defined on Styler so you wouldn't need to write this yourself.

+ +
+
+
+
+
+
In [6]:
+
+
+
def highlight_max(s):
+    '''
+    highlight the maximum in a Series yellow.
+    '''
+    is_max = s == s.max()
+    return ['background-color: yellow' if v else '' for v in is_max]
+
+ +
+
+
+ +
+
+
+
In [7]:
+
+
+
df.style.apply(highlight_max)
+
+ +
+
+
+ +
+
+ + +
Out[7]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

We encourage you to use method chains to build up a style piecewise, before finally rending at the end of the chain.

+ +
+
+
+
+
+
In [8]:
+
+
+
df.style.\
+    applymap(color_negative_red).\
+    apply(highlight_max)
+
+ +
+
+
+ +
+
+ + +
Out[8]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Above we used Styler.apply to pass in each column one at a time.

+

*Debugging Tip*: If you're having trouble writing your style function, try just passing it into df.apply. Styler.apply uses that internally, so the result should be the same.

What if you wanted to highlight just the maximum value in the entire table? +Use .apply(function, axis=None) to indicate that your function wants the entire table, not one column or row at a time. Let's try that next.

+

We'll rewrite our highlight-max to handle either Series (from .apply(axis=0 or 1)) or DataFrames (from .apply(axis=None)). We'll also allow the color to be adjustable, to demonstrate that .apply, and .applymap pass along keyword arguments.

+ +
+
+
+
+
+
In [9]:
+
+
+
def highlight_max(data, color='yellow'):
+    '''
+    highlight the maximum in a Series or DataFrame
+    '''
+    attr = 'background-color: {}'.format(color)
+    if data.ndim == 1:  # Series from .apply(axis=0) or axis=1
+        is_max = data == data.max()
+        return [attr if v else '' for v in is_max]
+    else:  # from .apply(axis=None)
+        is_max = data == data.max().max()
+        return pd.DataFrame(np.where(is_max, attr, ''),
+                            index=data.index, columns=data.columns)
+
+ +
+
+
+ +
+
+
+
In [10]:
+
+
+
df.style.apply(highlight_max, color='darkorange', axis=None)
+
+ +
+
+
+ +
+
+ + +
Out[10]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Building Styles Summary

Style functions should return strings with one or more CSS attribute: value delimited by semicolons. Use

+
    +
  • Styler.applymap(func) for elementwise styles
  • +
  • Styler.apply(func, axis=0) for columnwise styles
  • +
  • Styler.apply(func, axis=1) for rowwise styles
  • +
  • Styler.apply(func, axis=None) for tablewise styles
  • +
+ +
+
+
+
+
+
+
+
+

Finer Control: Slicing

+
+
+
+
+
+
+
+
+

Both Styler.apply, and Styler.applymap accept a subset keyword. +This allows you to apply styles to specific rows or columns, without having to code that logic into your style function.

+

The value passed to subset behaves simlar to slicing a DataFrame.

+
    +
  • A scalar is treated as a column label
  • +
  • A list (or series or numpy array)
  • +
  • A tuple is treated as (row_indexer, column_indexer)
  • +
+

Consider using pd.IndexSlice to construct the tuple for the last one.

+ +
+
+
+
+
+
In [11]:
+
+
+
df.style.apply(highlight_max, subset=['B', 'C', 'D'])
+
+ +
+
+
+ +
+
+ + +
Out[11]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

For row and column slicing, any valid indexer to .loc will work.

+ +
+
+
+
+
+
In [12]:
+
+
+
df.style.applymap(color_negative_red,
+                  subset=pd.IndexSlice[2:5, ['B', 'D']])
+
+ +
+
+
+ +
+
+ + +
Out[12]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Only label-based slicing is supported right now, not positional.

+

If your style function uses a subset or axis keyword argument, consider wrapping your function in a functools.partial, partialing out that keyword.

+
my_func2 = functools.partial(my_func, subset=42)
+
+ +
+
+
+
+
+
+
+
+

Builtin Styles

+
+
+
+
+
+
+
+
+

Finally, we expect certain styling functions to be common enough that we've included a few "built-in" to the Styler, so you don't have to write them yourself.

+ +
+
+
+
+
+
In [13]:
+
+
+
df.style.highlight_null(null_color='red')
+
+ +
+
+
+ +
+
+ + +
Out[13]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

You can create "heatmaps" with the background_gradient method. These require matplotlib, and we'll use Seaborn to get a nice colormap.

+ +
+
+
+
+
+
In [14]:
+
+
+
import seaborn as sns
+
+cm = sns.light_palette("green", as_cmap=True)
+
+s = df.style.background_gradient(cmap=cm)
+s
+
+ +
+
+
+ +
+
+ + +
Out[14]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Styler.background_gradient takes the keyword arguments low and high. Roughly speaking these extend the range of your data by low and high percent so that when we convert the colors, the colormap's entire range isn't used. This is useful so that you can actually read the text still.

+ +
+
+
+
+
+
In [15]:
+
+
+
# Uses the full color range
+df.loc[:4].style.background_gradient(cmap='viridis')
+
+ +
+
+
+ +
+
+ + +
Out[15]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ +
+ +
+ +
+
+ +
+
+
+
In [16]:
+
+
+
# Compreess the color range
+(df.loc[:4]
+    .style
+    .background_gradient(cmap='viridis', low=.5, high=0)
+    .highlight_null('red'))
+
+ +
+
+
+ +
+
+ + +
Out[16]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

You can include "bar charts" in your DataFrame.

+ +
+
+
+
+
+
In [17]:
+
+
+
df.style.bar(subset=['A', 'B'], color='#d65f5f')
+
+ +
+
+
+ +
+
+ + +
Out[17]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

There's also .highlight_min and .highlight_max.

+ +
+
+
+
+
+
In [18]:
+
+
+
df.style.highlight_max(axis=0)
+
+ +
+
+
+ +
+
+ + +
Out[18]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
In [19]:
+
+
+
df.style.highlight_min(axis=0)
+
+ +
+
+
+ +
+
+ + +
Out[19]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Use Styler.set_properties when the style doesn't actually depend on the values.

+ +
+
+
+
+
+
In [20]:
+
+
+
df.style.set_properties(**{'background-color': 'black',
+                           'color': 'lawngreen',
+                           'border-color': 'white'})
+
+ +
+
+
+ +
+
+ + +
Out[20]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Sharing Styles

+
+
+
+
+
+
+
+
+

Say you have a lovely style built up for a DataFrame, and now you want to apply the same style to a second DataFrame. Export the style with df1.style.export, and import it on the second DataFrame with df1.style.set

+ +
+
+
+
+
+
In [21]:
+
+
+
df2 = -df
+style1 = df.style.applymap(color_negative_red)
+style1
+
+ +
+
+
+ +
+
+ + +
Out[21]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
In [22]:
+
+
+
style2 = df2.style
+style2.use(style1.export())
+style2
+
+ +
+
+
+ +
+
+ + +
Out[22]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + -1.0 + + + + + -1.329212 + + + + + nan + + + + + 0.31628 + + + + + 0.99081 + + +
+ + 1 + + + + + -2.0 + + + + + 1.070816 + + + + + 1.438713 + + + + + -0.564417 + + + + + -0.295722 + + +
+ + 2 + + + + + -3.0 + + + + + 1.626404 + + + + + -0.219565 + + + + + -0.678805 + + + + + -1.889273 + + +
+ + 3 + + + + + -4.0 + + + + + -0.961538 + + + + + -0.104011 + + + + + 0.481165 + + + + + -0.850229 + + +
+ + 4 + + + + + -5.0 + + + + + -1.453425 + + + + + -1.057737 + + + + + -0.165562 + + + + + -0.515018 + + +
+ + 5 + + + + + -6.0 + + + + + 1.336936 + + + + + -0.562861 + + + + + -1.392855 + + + + + 0.063328 + + +
+ + 6 + + + + + -7.0 + + + + + -0.121668 + + + + + -1.207603 + + + + + 0.00204 + + + + + -1.627796 + + +
+ + 7 + + + + + -8.0 + + + + + -0.354493 + + + + + -1.037528 + + + + + 0.385684 + + + + + -0.519818 + + +
+ + 8 + + + + + -9.0 + + + + + -1.686583 + + + + + 1.325963 + + + + + -1.428984 + + + + + 2.089354 + + +
+ + 9 + + + + + -10.0 + + + + + 0.12982 + + + + + -0.631523 + + + + + 0.586538 + + + + + -0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Other options

You've seen a few methods for data-driven styling. +Styler also provides a few other options for styles that don't depend on the data.

+
    +
  • precision
  • +
  • captions
  • +
  • table-wide styles
  • +
+

Each of these can be specified in two ways:

+
    +
  • A keyword argument to pandas.core.Styler
  • +
  • A call to one of the .set_ methods, e.g. .set_caption
  • +
+

The best method to use depends on the context. Use the Styler constructor when building many styled DataFrames that should all share the same properties. For interactive use, the.set_ methods are more convenient.

+ +
+
+
+
+
+
+
+
+

Precision

+
+
+
+
+
+
+
+
+

You can control the precision of floats using pandas' regular display.precision option.

+ +
+
+
+
+
+
In [23]:
+
+
+
with pd.option_context('display.precision', 2):
+    html = (df.style
+              .applymap(color_negative_red)
+              .apply(highlight_max))
+html
+
+ +
+
+
+ +
+
+ + +
Out[23]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.33 + + + + + nan + + + + + -0.32 + + + + + -0.99 + + +
+ + 1 + + + + + 2.0 + + + + + -1.07 + + + + + -1.44 + + + + + 0.56 + + + + + 0.3 + + +
+ + 2 + + + + + 3.0 + + + + + -1.63 + + + + + 0.22 + + + + + 0.68 + + + + + 1.89 + + +
+ + 3 + + + + + 4.0 + + + + + 0.96 + + + + + 0.1 + + + + + -0.48 + + + + + 0.85 + + +
+ + 4 + + + + + 5.0 + + + + + 1.45 + + + + + 1.06 + + + + + 0.17 + + + + + 0.52 + + +
+ + 5 + + + + + 6.0 + + + + + -1.34 + + + + + 0.56 + + + + + 1.39 + + + + + -0.06 + + +
+ + 6 + + + + + 7.0 + + + + + 0.12 + + + + + 1.21 + + + + + -0.0 + + + + + 1.63 + + +
+ + 7 + + + + + 8.0 + + + + + 0.35 + + + + + 1.04 + + + + + -0.39 + + + + + 0.52 + + +
+ + 8 + + + + + 9.0 + + + + + 1.69 + + + + + -1.33 + + + + + 1.43 + + + + + -2.09 + + +
+ + 9 + + + + + 10.0 + + + + + -0.13 + + + + + 0.63 + + + + + -0.59 + + + + + 0.29 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Or through a set_precision method.

+ +
+
+
+
+
+
In [24]:
+
+
+
df.style\
+  .applymap(color_negative_red)\
+  .apply(highlight_max)\
+  .set_precision(2)
+
+ +
+
+
+ +
+
+ + +
Out[24]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.33 + + + + + nan + + + + + -0.32 + + + + + -0.99 + + +
+ + 1 + + + + + 2.0 + + + + + -1.07 + + + + + -1.44 + + + + + 0.56 + + + + + 0.3 + + +
+ + 2 + + + + + 3.0 + + + + + -1.63 + + + + + 0.22 + + + + + 0.68 + + + + + 1.89 + + +
+ + 3 + + + + + 4.0 + + + + + 0.96 + + + + + 0.1 + + + + + -0.48 + + + + + 0.85 + + +
+ + 4 + + + + + 5.0 + + + + + 1.45 + + + + + 1.06 + + + + + 0.17 + + + + + 0.52 + + +
+ + 5 + + + + + 6.0 + + + + + -1.34 + + + + + 0.56 + + + + + 1.39 + + + + + -0.06 + + +
+ + 6 + + + + + 7.0 + + + + + 0.12 + + + + + 1.21 + + + + + -0.0 + + + + + 1.63 + + +
+ + 7 + + + + + 8.0 + + + + + 0.35 + + + + + 1.04 + + + + + -0.39 + + + + + 0.52 + + +
+ + 8 + + + + + 9.0 + + + + + 1.69 + + + + + -1.33 + + + + + 1.43 + + + + + -2.09 + + +
+ + 9 + + + + + 10.0 + + + + + -0.13 + + + + + 0.63 + + + + + -0.59 + + + + + 0.29 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Setting the precision only affects the printed number; the full-precision values are always passed to your style functions. You can always use df.round(2).style if you'd prefer to round from the start.

+ +
+
+
+
+
+
+
+
+

Captions

+
+
+
+
+
+
+
+
+

Regular table captions can be added in a few ways.

+ +
+
+
+
+
+
In [25]:
+
+
+
df.style.set_caption('Colormaps, with a caption.')\
+    .background_gradient(cmap=cm)
+
+ +
+
+
+ +
+
+ + +
Out[25]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Colormaps, with a caption.
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Table Styles

+
+
+
+
+
+
+
+
+

The next option you have are "table styles". +These are styles that apply to the table as a whole, but don't look at the data. +Certain sytlings, including pseudo-selectors like :hover can only be used this way.

+ +
+
+
+
+
+
In [26]:
+
+
+
from IPython.display import HTML
+
+def hover(hover_color="#ffff99"):
+    return dict(selector="tr:hover",
+                props=[("background-color", "%s" % hover_color)])
+
+styles = [
+    hover(),
+    dict(selector="th", props=[("font-size", "150%"),
+                               ("text-align", "center")]),
+    dict(selector="caption", props=[("caption-side", "bottom")])
+]
+html = (df.style.set_table_styles(styles)
+          .set_caption("Hover to highlight."))
+html
+
+ +
+
+
+ +
+
+ + +
Out[26]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hover to highlight.
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

table_styles should be a list of dictionaries. +Each dictionary should have the selector and props keys. +The value for selector should be a valid CSS selector. +Recall that all the styles are already attached to an id, unique to +each Styler. This selector is in addition to that id. +The value for props should be a list of tuples of ('attribute', 'value').

+

table_styles are extremely flexible, but not as fun to type out by hand. +We hope to collect some useful ones either in pandas, or preferable in a new package that builds on top the tools here.

+ +
+
+
+
+
+
+
+
+

Limitations

    +
  • DataFrame only (use Series.to_frame().style)
  • +
  • The index and columns must be unique
  • +
  • No large repr, and performance isn't great; this is intended for summary DataFrames
  • +
  • You can only style the values, not the index or columns
  • +
  • You can only apply styles, you can't insert new HTML entities
  • +
+

Some of these will be addressed in the future.

+ +
+
+
+
+
+
+
+
+

Terms

    +
  • Style function: a function that's passed into Styler.apply or Styler.applymap and returns values like 'css attribute: value'
  • +
  • Builtin style functions: style functions that are methods on Styler
  • +
  • table style: a dictionary with the two keys selector and props. selector is the CSS selector that props will apply to. props is a list of (attribute, value) tuples. A list of table styles passed into Styler.
  • +
+ +
+
+
+
+
+
+
+
+

Fun stuff

Here are a few interesting examples.

+

Styler interacts pretty well with widgets. If you're viewing this online instead of running the notebook yourself, you're missing out on interactively adjusting the color palette.

+ +
+
+
+
+
+
In [27]:
+
+
+
from IPython.html import widgets
+@widgets.interact
+def f(h_neg=(0, 359, 1), h_pos=(0, 359), s=(0., 99.9), l=(0., 99.9)):
+    return df.style.background_gradient(
+        cmap=sns.palettes.diverging_palette(h_neg=h_neg, h_pos=h_pos, s=s, l=l,
+                                            as_cmap=True)
+    )
+
+ +
+
+
+ +
+
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + A + + B + + C + + D + + E + +
+ + 0 + + + + + 1.0 + + + + + 1.329212 + + + + + nan + + + + + -0.31628 + + + + + -0.99081 + + +
+ + 1 + + + + + 2.0 + + + + + -1.070816 + + + + + -1.438713 + + + + + 0.564417 + + + + + 0.295722 + + +
+ + 2 + + + + + 3.0 + + + + + -1.626404 + + + + + 0.219565 + + + + + 0.678805 + + + + + 1.889273 + + +
+ + 3 + + + + + 4.0 + + + + + 0.961538 + + + + + 0.104011 + + + + + -0.481165 + + + + + 0.850229 + + +
+ + 4 + + + + + 5.0 + + + + + 1.453425 + + + + + 1.057737 + + + + + 0.165562 + + + + + 0.515018 + + +
+ + 5 + + + + + 6.0 + + + + + -1.336936 + + + + + 0.562861 + + + + + 1.392855 + + + + + -0.063328 + + +
+ + 6 + + + + + 7.0 + + + + + 0.121668 + + + + + 1.207603 + + + + + -0.00204 + + + + + 1.627796 + + +
+ + 7 + + + + + 8.0 + + + + + 0.354493 + + + + + 1.037528 + + + + + -0.385684 + + + + + 0.519818 + + +
+ + 8 + + + + + 9.0 + + + + + 1.686583 + + + + + -1.325963 + + + + + 1.428984 + + + + + -2.089354 + + +
+ + 9 + + + + + 10.0 + + + + + -0.12982 + + + + + 0.631523 + + + + + -0.586538 + + + + + 0.29072 + + +
+ +
+ +
+ +
+
+ +
+
+
+
In [28]:
+
+
+
def magnify():
+    return [dict(selector="th",
+                 props=[("font-size", "4pt")]),
+            dict(selector="th:hover",
+                 props=[("font-size", "12pt")]),
+        dict(selector="tr:hover td:hover",
+                 props=[('max-width', '200px'),
+                        ('font-size', '12pt')])
+]
+
+ +
+
+
+ +
+
+
+
In [29]:
+
+
+
np.random.seed(25)
+cmap = cmap=sns.diverging_palette(5, 250, as_cmap=True)
+df = pd.DataFrame(np.random.randn(20, 25)).cumsum()
+
+df.style.background_gradient(cmap, axis=1)\
+    .set_properties(**{'max-width': '80px', 'font-size': '1pt'})\
+    .set_caption("Hover to magify")\
+    .set_precision(2)\
+    .set_table_styles(magnify())
+
+ +
+
+
+ +
+
+ + +
Out[29]:
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Hover to magify
+ + 0 + + 1 + + 2 + + 3 + + 4 + + 5 + + 6 + + 7 + + 8 + + 9 + + 10 + + 11 + + 12 + + 13 + + 14 + + 15 + + 16 + + 17 + + 18 + + 19 + + 20 + + 21 + + 22 + + 23 + + 24 + +
+ + 0 + + + + + 0.23 + + + + + 1.03 + + + + + -0.84 + + + + + -0.59 + + + + + -0.96 + + + + + -0.22 + + + + + -0.62 + + + + + 1.84 + + + + + -2.05 + + + + + 0.87 + + + + + -0.92 + + + + + -0.23 + + + + + 2.15 + + + + + -1.33 + + + + + 0.08 + + + + + -1.25 + + + + + 1.2 + + + + + -1.05 + + + + + 1.06 + + + + + -0.42 + + + + + 2.29 + + + + + -2.59 + + + + + 2.82 + + + + + 0.68 + + + + + -1.58 + + +
+ + 1 + + + + + -1.75 + + + + + 1.56 + + + + + -1.13 + + + + + -1.1 + + + + + 1.03 + + + + + 0.0 + + + + + -2.46 + + + + + 3.45 + + + + + -1.66 + + + + + 1.27 + + + + + -0.52 + + + + + -0.02 + + + + + 1.52 + + + + + -1.09 + + + + + -1.86 + + + + + -1.13 + + + + + -0.68 + + + + + -0.81 + + + + + 0.35 + + + + + -0.06 + + + + + 1.79 + + + + + -2.82 + + + + + 2.26 + + + + + 0.78 + + + + + 0.44 + + +
+ + 2 + + + + + -0.65 + + + + + 3.22 + + + + + -1.76 + + + + + 0.52 + + + + + 2.2 + + + + + -0.37 + + + + + -3.0 + + + + + 3.73 + + + + + -1.87 + + + + + 2.46 + + + + + 0.21 + + + + + -0.24 + + + + + -0.1 + + + + + -0.78 + + + + + -3.02 + + + + + -0.82 + + + + + -0.21 + + + + + -0.23 + + + + + 0.86 + + + + + -0.68 + + + + + 1.45 + + + + + -4.89 + + + + + 3.03 + + + + + 1.91 + + + + + 0.61 + + +
+ + 3 + + + + + -1.62 + + + + + 3.71 + + + + + -2.31 + + + + + 0.43 + + + + + 4.17 + + + + + -0.43 + + + + + -3.86 + + + + + 4.16 + + + + + -2.15 + + + + + 1.08 + + + + + 0.12 + + + + + 0.6 + + + + + -0.89 + + + + + 0.27 + + + + + -3.67 + + + + + -2.71 + + + + + -0.31 + + + + + -1.59 + + + + + 1.35 + + + + + -1.83 + + + + + 0.91 + + + + + -5.8 + + + + + 2.81 + + + + + 2.11 + + + + + 0.28 + + +
+ + 4 + + + + + -3.35 + + + + + 4.48 + + + + + -1.86 + + + + + -1.7 + + + + + 5.19 + + + + + -1.02 + + + + + -3.81 + + + + + 4.72 + + + + + -0.72 + + + + + 1.08 + + + + + -0.18 + + + + + 0.83 + + + + + -0.22 + + + + + -1.08 + + + + + -4.27 + + + + + -2.88 + + + + + -0.97 + + + + + -1.78 + + + + + 1.53 + + + + + -1.8 + + + + + 2.21 + + + + + -6.34 + + + + + 3.34 + + + + + 2.49 + + + + + 2.09 + + +
+ + 5 + + + + + -0.84 + + + + + 4.23 + + + + + -1.65 + + + + + -2.0 + + + + + 5.34 + + + + + -0.99 + + + + + -4.13 + + + + + 3.94 + + + + + -1.06 + + + + + -0.94 + + + + + 1.24 + + + + + 0.09 + + + + + -1.78 + + + + + -0.11 + + + + + -4.45 + + + + + -0.85 + + + + + -2.06 + + + + + -1.35 + + + + + 0.8 + + + + + -1.63 + + + + + 1.54 + + + + + -6.51 + + + + + 2.8 + + + + + 2.14 + + + + + 3.77 + + +
+ + 6 + + + + + -0.74 + + + + + 5.35 + + + + + -2.11 + + + + + -1.13 + + + + + 4.2 + + + + + -1.85 + + + + + -3.2 + + + + + 3.76 + + + + + -3.22 + + + + + -1.23 + + + + + 0.34 + + + + + 0.57 + + + + + -1.82 + + + + + 0.54 + + + + + -4.43 + + + + + -1.83 + + + + + -4.03 + + + + + -2.62 + + + + + -0.2 + + + + + -4.68 + + + + + 1.93 + + + + + -8.46 + + + + + 3.34 + + + + + 2.52 + + + + + 5.81 + + +
+ + 7 + + + + + -0.44 + + + + + 4.69 + + + + + -2.3 + + + + + -0.21 + + + + + 5.93 + + + + + -2.63 + + + + + -1.83 + + + + + 5.46 + + + + + -4.5 + + + + + -3.16 + + + + + -1.73 + + + + + 0.18 + + + + + 0.11 + + + + + 0.04 + + + + + -5.99 + + + + + -0.45 + + + + + -6.2 + + + + + -3.89 + + + + + 0.71 + + + + + -3.95 + + + + + 0.67 + + + + + -7.26 + + + + + 2.97 + + + + + 3.39 + + + + + 6.66 + + +
+ + 8 + + + + + 0.92 + + + + + 5.8 + + + + + -3.33 + + + + + -0.65 + + + + + 5.99 + + + + + -3.19 + + + + + -1.83 + + + + + 5.63 + + + + + -3.53 + + + + + -1.3 + + + + + -1.61 + + + + + 0.82 + + + + + -2.45 + + + + + -0.4 + + + + + -6.06 + + + + + -0.52 + + + + + -6.6 + + + + + -3.48 + + + + + -0.04 + + + + + -4.6 + + + + + 0.51 + + + + + -5.85 + + + + + 3.23 + + + + + 2.4 + + + + + 5.08 + + +
+ + 9 + + + + + 0.38 + + + + + 5.54 + + + + + -4.49 + + + + + -0.8 + + + + + 7.05 + + + + + -2.64 + + + + + -0.44 + + + + + 5.35 + + + + + -1.96 + + + + + -0.33 + + + + + -0.8 + + + + + 0.26 + + + + + -3.37 + + + + + -0.82 + + + + + -6.05 + + + + + -2.61 + + + + + -8.45 + + + + + -4.45 + + + + + 0.41 + + + + + -4.71 + + + + + 1.89 + + + + + -6.93 + + + + + 2.14 + + + + + 3.0 + + + + + 5.16 + + +
+ + 10 + + + + + 2.06 + + + + + 5.84 + + + + + -3.9 + + + + + -0.98 + + + + + 7.78 + + + + + -2.49 + + + + + -0.59 + + + + + 5.59 + + + + + -2.22 + + + + + -0.71 + + + + + -0.46 + + + + + 1.8 + + + + + -2.79 + + + + + 0.48 + + + + + -5.97 + + + + + -3.44 + + + + + -7.77 + + + + + -5.49 + + + + + -0.7 + + + + + -4.61 + + + + + -0.52 + + + + + -7.72 + + + + + 1.54 + + + + + 5.02 + + + + + 5.81 + + +
+ + 11 + + + + + 1.86 + + + + + 4.47 + + + + + -2.17 + + + + + -1.38 + + + + + 5.9 + + + + + -0.49 + + + + + 0.02 + + + + + 5.78 + + + + + -1.04 + + + + + -0.6 + + + + + 0.49 + + + + + 1.96 + + + + + -1.47 + + + + + 1.88 + + + + + -5.92 + + + + + -4.55 + + + + + -8.15 + + + + + -3.42 + + + + + -2.24 + + + + + -4.33 + + + + + -1.17 + + + + + -7.9 + + + + + 1.36 + + + + + 5.31 + + + + + 5.83 + + +
+ + 12 + + + + + 3.19 + + + + + 4.22 + + + + + -3.06 + + + + + -2.27 + + + + + 5.93 + + + + + -2.64 + + + + + 0.33 + + + + + 6.72 + + + + + -2.84 + + + + + -0.2 + + + + + 1.89 + + + + + 2.63 + + + + + -1.53 + + + + + 0.75 + + + + + -5.27 + + + + + -4.53 + + + + + -7.57 + + + + + -2.85 + + + + + -2.17 + + + + + -4.78 + + + + + -1.13 + + + + + -8.99 + + + + + 2.11 + + + + + 6.42 + + + + + 5.6 + + +
+ + 13 + + + + + 2.31 + + + + + 4.45 + + + + + -3.87 + + + + + -2.05 + + + + + 6.76 + + + + + -3.25 + + + + + -2.17 + + + + + 7.99 + + + + + -2.56 + + + + + -0.8 + + + + + 0.71 + + + + + 2.33 + + + + + -0.16 + + + + + -0.46 + + + + + -5.1 + + + + + -3.79 + + + + + -7.58 + + + + + -4.0 + + + + + 0.33 + + + + + -3.67 + + + + + -1.05 + + + + + -8.71 + + + + + 2.47 + + + + + 5.87 + + + + + 6.71 + + +
+ + 14 + + + + + 3.78 + + + + + 4.33 + + + + + -3.88 + + + + + -1.58 + + + + + 6.22 + + + + + -3.23 + + + + + -1.46 + + + + + 5.57 + + + + + -2.93 + + + + + -0.33 + + + + + -0.97 + + + + + 1.72 + + + + + 3.61 + + + + + 0.29 + + + + + -4.21 + + + + + -4.1 + + + + + -6.68 + + + + + -4.5 + + + + + -2.19 + + + + + -2.43 + + + + + -1.64 + + + + + -9.36 + + + + + 3.36 + + + + + 6.11 + + + + + 7.53 + + +
+ + 15 + + + + + 5.64 + + + + + 5.31 + + + + + -3.98 + + + + + -2.26 + + + + + 5.91 + + + + + -3.3 + + + + + -1.03 + + + + + 5.68 + + + + + -3.06 + + + + + -0.33 + + + + + -1.16 + + + + + 2.19 + + + + + 4.2 + + + + + 1.01 + + + + + -3.22 + + + + + -4.31 + + + + + -5.74 + + + + + -4.44 + + + + + -2.3 + + + + + -1.36 + + + + + -1.2 + + + + + -11.27 + + + + + 2.59 + + + + + 6.69 + + + + + 5.91 + + +
+ + 16 + + + + + 4.08 + + + + + 4.34 + + + + + -2.44 + + + + + -3.3 + + + + + 6.04 + + + + + -2.52 + + + + + -0.47 + + + + + 5.28 + + + + + -4.84 + + + + + 1.58 + + + + + 0.23 + + + + + 0.1 + + + + + 5.79 + + + + + 1.8 + + + + + -3.13 + + + + + -3.85 + + + + + -5.53 + + + + + -2.97 + + + + + -2.13 + + + + + -1.15 + + + + + -0.56 + + + + + -13.13 + + + + + 2.07 + + + + + 6.16 + + + + + 4.94 + + +
+ + 17 + + + + + 5.64 + + + + + 4.57 + + + + + -3.53 + + + + + -3.76 + + + + + 6.58 + + + + + -2.58 + + + + + -0.75 + + + + + 6.58 + + + + + -4.78 + + + + + 3.63 + + + + + -0.29 + + + + + 0.56 + + + + + 5.76 + + + + + 2.05 + + + + + -2.27 + + + + + -2.31 + + + + + -4.95 + + + + + -3.16 + + + + + -3.06 + + + + + -2.43 + + + + + 0.84 + + + + + -12.57 + + + + + 3.56 + + + + + 7.36 + + + + + 4.7 + + +
+ + 18 + + + + + 5.99 + + + + + 5.82 + + + + + -2.85 + + + + + -4.15 + + + + + 7.12 + + + + + -3.32 + + + + + -1.21 + + + + + 7.93 + + + + + -4.85 + + + + + 1.44 + + + + + -0.63 + + + + + 0.35 + + + + + 7.47 + + + + + 0.87 + + + + + -1.52 + + + + + -2.09 + + + + + -4.23 + + + + + -2.55 + + + + + -2.46 + + + + + -2.89 + + + + + 1.9 + + + + + -9.74 + + + + + 3.43 + + + + + 7.07 + + + + + 4.39 + + +
+ + 19 + + + + + 4.03 + + + + + 6.23 + + + + + -4.1 + + + + + -4.11 + + + + + 7.19 + + + + + -4.1 + + + + + -1.52 + + + + + 6.53 + + + + + -5.21 + + + + + -0.24 + + + + + 0.01 + + + + + 1.16 + + + + + 6.43 + + + + + -1.97 + + + + + -2.64 + + + + + -1.66 + + + + + -5.2 + + + + + -3.25 + + + + + -2.87 + + + + + -1.65 + + + + + 1.64 + + + + + -10.66 + + + + + 2.83 + + + + + 7.48 + + + + + 3.94 + + +
+ +
+ +
+ +
+
+ +
+
+
+
+
+
+

Extensibility

The core of pandas is, and will remain, its "high-performance, easy-to-use data structures". +With that in mind, we hope that DataFrame.style accomplishes two goals

+
    +
  • Provide an API that is pleasing to use interactively and is "good enough" for many tasks
  • +
  • Provide the foundations for dedicated libraries to build on
  • +
+

If you build a great library on top of this, let us know and we'll link to it.

+

Subclassing

This section contains a bit of information about the implementation of Styler. +Since the feature is so new all of this is subject to change, even more so than the end-use API.

+

As users apply styles (via .apply, .applymap or one of the builtins), we don't actually calculate anything. +Instead, we append functions and arguments to a list self._todo. +When asked (typically in .render we'll walk through the list and execute each function (this is in self._compute(). +These functions update an internal defaultdict(list), self.ctx which maps DataFrame row / column positions to CSS attribute, value pairs.

+

We take the extra step through self._todo so that we can export styles and set them on other Stylers.

+

Rendering uses Jinja templates. +The .translate method takes self.ctx and builds another dictionary ready to be passed into Styler.template.render, the Jinja template.

+

Alternate templates

We've used Jinja templates to build up the HTML. +The template is stored as a class variable Styler.template.. Subclasses can override that.

+
class CustomStyle(Styler):
+    template = Template("""...""")
+
+ +
+
+
+
+
+ + diff --git a/doc/source/html-styling.ipynb b/doc/source/html-styling.ipynb new file mode 100644 index 0000000000000..28eb1cd09bacd --- /dev/null +++ b/doc/source/html-styling.ipynb @@ -0,0 +1,21062 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conditional Formatting\n", + "\n", + "*New in version 0.17.1*\n", + "\n", + "

*Provisional: This is a new feature and still under development. We'll be adding features and possibly making breaking changes in future releases. We'd love to hear your [feedback](https://github.com/pydata/pandas/issues).*

\n", + "\n", + "You can apply **conditional formatting**, the visual styling of a DataFrame\n", + "depending on the data within, by using the ``DataFrame.style`` property.\n", + "This is a property that returns a ``pandas.Styler`` object, which has\n", + "useful methods for formatting and displaying DataFrames.\n", + "\n", + "The styling is accomplished using CSS.\n", + "You write \"style functions\" that take scalars, `DataFrame`s or `Series`, and return *like-indexed* DataFrames or Series with CSS `\"attribute: value\"` pairs for the values.\n", + "These functions can be incrementally passed to the `Styler` which collects the styles before rendering.\n", + "\n", + "### Contents\n", + "\n", + "- [Building Styles](#Building-Styles)\n", + "- [Finer Control: Slicing](#Finer-Control:-Slicing)\n", + "- [Builtin Styles](#Builtin-Styles)\n", + "- [Other options](#Other-options)\n", + "- [Sharing Styles](#Sharing-Styles)\n", + "- [Limitations](#Limitations)\n", + "- [Terms](#Terms)\n", + "- [Extensibility](#Extensibility)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Building Styles\n", + "\n", + "Pass your style functions into one of the following methods:\n", + "\n", + "- `Styler.applymap`: elementwise\n", + "- `Styler.apply`: column-/row-/table-wise\n", + "\n", + "Both of those methods take a function (and some other keyword arguments) and applies your function to the DataFrame in a certain way.\n", + "`Styler.applymap` works through the DataFrame elementwise.\n", + "`Styler.apply` passes each column or row into your DataFrame one-at-a-time or the entire table at once, depending on the `axis` keyword argument.\n", + "For columnwise use `axis=0`, rowwise use `axis=1`, and for the entire table at once use `axis=None`.\n", + "\n", + "The result of the function application, a CSS attribute-value pair, is stored in an internal dictionary on your ``Styler`` object.\n", + "\n", + "Let's see some examples." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "\n", + "np.random.seed(24)\n", + "df = pd.DataFrame({'A': np.linspace(1, 10, 10)})\n", + "df = pd.concat([df, pd.DataFrame(np.random.randn(10, 4), columns=list('BCDE'))],\n", + " axis=1)\n", + "df.iloc[0, 2] = np.nan" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's a boring example of rendering a DataFrame, without any (visible) styles:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "*Note*: The `DataFrame.style` attribute is a propetry that returns a `Styler` object. `Styler` has a `_repr_html_` method defined on it so they are rendered automatically. If you want the actual HTML back for further processing or for writing to file call the `.render()` method which returns a string.\n", + "\n", + "The above output looks very similar to the standard DataFrame HTML representation. But we've done some work behind the scenes to attach CSS classes to each cell. We can view these by calling the `.render` method." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "['',\n", + " ' \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "s = df.style.applymap(color_negative_red)\n", + "s" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice the similarity with the standard `df.applymap`, which operates on DataFrames elementwise. We want you to be able to resuse your existing knowledge of how to interact with DataFrames.\n", + "\n", + "Notice also that our function returned a string containing the CSS attribute and value, separated by a colon just like in a `\n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.apply(highlight_max)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We encourage you to use method chains to build up a style piecewise, before finally rending at the end of the chain." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.\\\n", + " applymap(color_negative_red).\\\n", + " apply(highlight_max)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Above we used `Styler.apply` to pass in each column one at a time.\n", + "\n", + "

*Debugging Tip*: If you're having trouble writing your style function, try just passing it into df.apply. Styler.apply uses that internally, so the result should be the same.

\n", + "\n", + "What if you wanted to highlight just the maximum value in the entire table?\n", + "Use `.apply(function, axis=None)` to indicate that your function wants the entire table, not one column or row at a time. Let's try that next.\n", + "\n", + "We'll rewrite our `highlight-max` to handle either Series (from `.apply(axis=0 or 1)`) or DataFrames (from `.apply(axis=None)`). We'll also allow the color to be adjustable, to demonstrate that `.apply`, and `.applymap` pass along keyword arguments." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "def highlight_max(data, color='yellow'):\n", + " '''\n", + " highlight the maximum in a Series or DataFrame\n", + " '''\n", + " attr = 'background-color: {}'.format(color)\n", + " if data.ndim == 1: # Series from .apply(axis=0) or axis=1\n", + " is_max = data == data.max()\n", + " return [attr if v else '' for v in is_max]\n", + " else: # from .apply(axis=None)\n", + " is_max = data == data.max().max()\n", + " return pd.DataFrame(np.where(is_max, attr, ''),\n", + " index=data.index, columns=data.columns)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.apply(highlight_max, color='darkorange', axis=None)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Building Styles Summary\n", + "\n", + "Style functions should return strings with one or more CSS `attribute: value` delimited by semicolons. Use\n", + "\n", + "- `Styler.applymap(func)` for elementwise styles\n", + "- `Styler.apply(func, axis=0)` for columnwise styles\n", + "- `Styler.apply(func, axis=1)` for rowwise styles\n", + "- `Styler.apply(func, axis=None)` for tablewise styles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Finer Control: Slicing" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both `Styler.apply`, and `Styler.applymap` accept a `subset` keyword.\n", + "This allows you to apply styles to specific rows or columns, without having to code that logic into your `style` function.\n", + "\n", + "The value passed to `subset` behaves simlar to slicing a DataFrame.\n", + "\n", + "- A scalar is treated as a column label\n", + "- A list (or series or numpy array)\n", + "- A tuple is treated as `(row_indexer, column_indexer)`\n", + "\n", + "Consider using `pd.IndexSlice` to construct the tuple for the last one." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.apply(highlight_max, subset=['B', 'C', 'D'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For row and column slicing, any valid indexer to `.loc` will work." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.applymap(color_negative_red,\n", + " subset=pd.IndexSlice[2:5, ['B', 'D']])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Only label-based slicing is supported right now, not positional.\n", + "\n", + "If your style function uses a `subset` or `axis` keyword argument, consider wrapping your function in a `functools.partial`, partialing out that keyword.\n", + "\n", + "```python\n", + "my_func2 = functools.partial(my_func, subset=42)\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Builtin Styles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we expect certain styling functions to be common enough that we've included a few \"built-in\" to the `Styler`, so you don't have to write them yourself." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.highlight_null(null_color='red')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can create \"heatmaps\" with the `background_gradient` method. These require matplotlib, and we'll use [Seaborn](http://stanford.edu/~mwaskom/software/seaborn/) to get a nice colormap." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import seaborn as sns\n", + "\n", + "cm = sns.light_palette(\"green\", as_cmap=True)\n", + "\n", + "s = df.style.background_gradient(cmap=cm)\n", + "s" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`Styler.background_gradient` takes the keyword arguments `low` and `high`. Roughly speaking these extend the range of your data by `low` and `high` percent so that when we convert the colors, the colormap's entire range isn't used. This is useful so that you can actually read the text still." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Uses the full color range\n", + "df.loc[:4].style.background_gradient(cmap='viridis')" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Compreess the color range\n", + "(df.loc[:4]\n", + " .style\n", + " .background_gradient(cmap='viridis', low=.5, high=0)\n", + " .highlight_null('red'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can include \"bar charts\" in your DataFrame." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.bar(subset=['A', 'B'], color='#d65f5f')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "There's also `.highlight_min` and `.highlight_max`." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.highlight_max(axis=0)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.highlight_min(axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Use `Styler.set_properties` when the style doesn't actually depend on the values." + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.set_properties(**{'background-color': 'black',\n", + " 'color': 'lawngreen',\n", + " 'border-color': 'white'})" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Sharing Styles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Say you have a lovely style built up for a DataFrame, and now you want to apply the same style to a second DataFrame. Export the style with `df1.style.export`, and import it on the second DataFrame with `df1.style.set`" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df2 = -df\n", + "style1 = df.style.applymap(color_negative_red)\n", + "style1" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " -1.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " 0.31628\n", + " \n", + " \n", + " \n", + " \n", + " 0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " -2.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.070816\n", + " \n", + " \n", + " \n", + " \n", + " 1.438713\n", + " \n", + " \n", + " \n", + " \n", + " -0.564417\n", + " \n", + " \n", + " \n", + " \n", + " -0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " -3.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.626404\n", + " \n", + " \n", + " \n", + " \n", + " -0.219565\n", + " \n", + " \n", + " \n", + " \n", + " -0.678805\n", + " \n", + " \n", + " \n", + " \n", + " -1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " -4.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.961538\n", + " \n", + " \n", + " \n", + " \n", + " -0.104011\n", + " \n", + " \n", + " \n", + " \n", + " 0.481165\n", + " \n", + " \n", + " \n", + " \n", + " -0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " -5.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.453425\n", + " \n", + " \n", + " \n", + " \n", + " -1.057737\n", + " \n", + " \n", + " \n", + " \n", + " -0.165562\n", + " \n", + " \n", + " \n", + " \n", + " -0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " -6.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.336936\n", + " \n", + " \n", + " \n", + " \n", + " -0.562861\n", + " \n", + " \n", + " \n", + " \n", + " -1.392855\n", + " \n", + " \n", + " \n", + " \n", + " 0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " -7.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.121668\n", + " \n", + " \n", + " \n", + " \n", + " -1.207603\n", + " \n", + " \n", + " \n", + " \n", + " 0.00204\n", + " \n", + " \n", + " \n", + " \n", + " -1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " -8.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.354493\n", + " \n", + " \n", + " \n", + " \n", + " -1.037528\n", + " \n", + " \n", + " \n", + " \n", + " 0.385684\n", + " \n", + " \n", + " \n", + " \n", + " -0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " -9.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.686583\n", + " \n", + " \n", + " \n", + " \n", + " 1.325963\n", + " \n", + " \n", + " \n", + " \n", + " -1.428984\n", + " \n", + " \n", + " \n", + " \n", + " 2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " -10.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.12982\n", + " \n", + " \n", + " \n", + " \n", + " -0.631523\n", + " \n", + " \n", + " \n", + " \n", + " 0.586538\n", + " \n", + " \n", + " \n", + " \n", + " -0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "style2 = df2.style\n", + "style2.use(style1.export())\n", + "style2" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Other options\n", + "\n", + "You've seen a few methods for data-driven styling.\n", + "`Styler` also provides a few other options for styles that don't depend on the data.\n", + "\n", + "- precision\n", + "- captions\n", + "- table-wide styles\n", + "\n", + "Each of these can be specified in two ways:\n", + "\n", + "- A keyword argument to `pandas.core.Styler`\n", + "- A call to one of the `.set_` methods, e.g. `.set_caption`\n", + "\n", + "The best method to use depends on the context. Use the `Styler` constructor when building many styled DataFrames that should all share the same properties. For interactive use, the`.set_` methods are more convenient." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Precision" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can control the precision of floats using pandas' regular `display.precision` option." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.33\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.32\n", + " \n", + " \n", + " \n", + " \n", + " -0.99\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.07\n", + " \n", + " \n", + " \n", + " \n", + " -1.44\n", + " \n", + " \n", + " \n", + " \n", + " 0.56\n", + " \n", + " \n", + " \n", + " \n", + " 0.3\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.63\n", + " \n", + " \n", + " \n", + " \n", + " 0.22\n", + " \n", + " \n", + " \n", + " \n", + " 0.68\n", + " \n", + " \n", + " \n", + " \n", + " 1.89\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.96\n", + " \n", + " \n", + " \n", + " \n", + " 0.1\n", + " \n", + " \n", + " \n", + " \n", + " -0.48\n", + " \n", + " \n", + " \n", + " \n", + " 0.85\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.45\n", + " \n", + " \n", + " \n", + " \n", + " 1.06\n", + " \n", + " \n", + " \n", + " \n", + " 0.17\n", + " \n", + " \n", + " \n", + " \n", + " 0.52\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.34\n", + " \n", + " \n", + " \n", + " \n", + " 0.56\n", + " \n", + " \n", + " \n", + " \n", + " 1.39\n", + " \n", + " \n", + " \n", + " \n", + " -0.06\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.12\n", + " \n", + " \n", + " \n", + " \n", + " 1.21\n", + " \n", + " \n", + " \n", + " \n", + " -0.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.63\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.35\n", + " \n", + " \n", + " \n", + " \n", + " 1.04\n", + " \n", + " \n", + " \n", + " \n", + " -0.39\n", + " \n", + " \n", + " \n", + " \n", + " 0.52\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.69\n", + " \n", + " \n", + " \n", + " \n", + " -1.33\n", + " \n", + " \n", + " \n", + " \n", + " 1.43\n", + " \n", + " \n", + " \n", + " \n", + " -2.09\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.13\n", + " \n", + " \n", + " \n", + " \n", + " 0.63\n", + " \n", + " \n", + " \n", + " \n", + " -0.59\n", + " \n", + " \n", + " \n", + " \n", + " 0.29\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "with pd.option_context('display.precision', 2):\n", + " html = (df.style\n", + " .applymap(color_negative_red)\n", + " .apply(highlight_max))\n", + "html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Or through a `set_precision` method." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.33\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.32\n", + " \n", + " \n", + " \n", + " \n", + " -0.99\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.07\n", + " \n", + " \n", + " \n", + " \n", + " -1.44\n", + " \n", + " \n", + " \n", + " \n", + " 0.56\n", + " \n", + " \n", + " \n", + " \n", + " 0.3\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.63\n", + " \n", + " \n", + " \n", + " \n", + " 0.22\n", + " \n", + " \n", + " \n", + " \n", + " 0.68\n", + " \n", + " \n", + " \n", + " \n", + " 1.89\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.96\n", + " \n", + " \n", + " \n", + " \n", + " 0.1\n", + " \n", + " \n", + " \n", + " \n", + " -0.48\n", + " \n", + " \n", + " \n", + " \n", + " 0.85\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.45\n", + " \n", + " \n", + " \n", + " \n", + " 1.06\n", + " \n", + " \n", + " \n", + " \n", + " 0.17\n", + " \n", + " \n", + " \n", + " \n", + " 0.52\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.34\n", + " \n", + " \n", + " \n", + " \n", + " 0.56\n", + " \n", + " \n", + " \n", + " \n", + " 1.39\n", + " \n", + " \n", + " \n", + " \n", + " -0.06\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.12\n", + " \n", + " \n", + " \n", + " \n", + " 1.21\n", + " \n", + " \n", + " \n", + " \n", + " -0.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.63\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.35\n", + " \n", + " \n", + " \n", + " \n", + " 1.04\n", + " \n", + " \n", + " \n", + " \n", + " -0.39\n", + " \n", + " \n", + " \n", + " \n", + " 0.52\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.69\n", + " \n", + " \n", + " \n", + " \n", + " -1.33\n", + " \n", + " \n", + " \n", + " \n", + " 1.43\n", + " \n", + " \n", + " \n", + " \n", + " -2.09\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.13\n", + " \n", + " \n", + " \n", + " \n", + " 0.63\n", + " \n", + " \n", + " \n", + " \n", + " -0.59\n", + " \n", + " \n", + " \n", + " \n", + " 0.29\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 24, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style\\\n", + " .applymap(color_negative_red)\\\n", + " .apply(highlight_max)\\\n", + " .set_precision(2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Setting the precision only affects the printed number; the full-precision values are always passed to your style functions. You can always use `df.round(2).style` if you'd prefer to round from the start." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Captions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Regular table captions can be added in a few ways." + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Colormaps, with a caption.
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 25, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df.style.set_caption('Colormaps, with a caption.')\\\n", + " .background_gradient(cmap=cm)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Table Styles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next option you have are \"table styles\".\n", + "These are styles that apply to the table as a whole, but don't look at the data.\n", + "Certain sytlings, including pseudo-selectors like `:hover` can only be used this way." + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Hover to highlight.
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from IPython.display import HTML\n", + "\n", + "def hover(hover_color=\"#ffff99\"):\n", + " return dict(selector=\"tr:hover\",\n", + " props=[(\"background-color\", \"%s\" % hover_color)])\n", + "\n", + "styles = [\n", + " hover(),\n", + " dict(selector=\"th\", props=[(\"font-size\", \"150%\"),\n", + " (\"text-align\", \"center\")]),\n", + " dict(selector=\"caption\", props=[(\"caption-side\", \"bottom\")])\n", + "]\n", + "html = (df.style.set_table_styles(styles)\n", + " .set_caption(\"Hover to highlight.\"))\n", + "html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`table_styles` should be a list of dictionaries.\n", + "Each dictionary should have the `selector` and `props` keys.\n", + "The value for `selector` should be a valid CSS selector.\n", + "Recall that all the styles are already attached to an `id`, unique to\n", + "each `Styler`. This selector is in addition to that `id`.\n", + "The value for `props` should be a list of tuples of `('attribute', 'value')`.\n", + "\n", + "`table_styles` are extremely flexible, but not as fun to type out by hand.\n", + "We hope to collect some useful ones either in pandas, or preferable in a new package that [builds on top](#Extensibility) the tools here." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Limitations\n", + "\n", + "- DataFrame only `(use Series.to_frame().style)`\n", + "- The index and columns must be unique\n", + "- No large repr, and performance isn't great; this is intended for summary DataFrames\n", + "- You can only style the *values*, not the index or columns\n", + "- You can only apply styles, you can't insert new HTML entities\n", + "\n", + "Some of these will be addressed in the future.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Terms\n", + "\n", + "- Style function: a function that's passed into `Styler.apply` or `Styler.applymap` and returns values like `'css attribute: value'`\n", + "- Builtin style functions: style functions that are methods on `Styler`\n", + "- table style: a dictionary with the two keys `selector` and `props`. `selector` is the CSS selector that `props` will apply to. `props` is a list of `(attribute, value)` tuples. A list of table styles passed into `Styler`." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fun stuff\n", + "\n", + "Here are a few interesting examples.\n", + "\n", + "`Styler` interacts pretty well with widgets. If you're viewing this online instead of running the notebook yourself, you're missing out on interactively adjusting the color palette." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
\n", + " \n", + " A\n", + " \n", + " B\n", + " \n", + " C\n", + " \n", + " D\n", + " \n", + " E\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 1.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.329212\n", + " \n", + " \n", + " \n", + " \n", + " nan\n", + " \n", + " \n", + " \n", + " \n", + " -0.31628\n", + " \n", + " \n", + " \n", + " \n", + " -0.99081\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " 2.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.070816\n", + " \n", + " \n", + " \n", + " \n", + " -1.438713\n", + " \n", + " \n", + " \n", + " \n", + " 0.564417\n", + " \n", + " \n", + " \n", + " \n", + " 0.295722\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.626404\n", + " \n", + " \n", + " \n", + " \n", + " 0.219565\n", + " \n", + " \n", + " \n", + " \n", + " 0.678805\n", + " \n", + " \n", + " \n", + " \n", + " 1.889273\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " 4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.961538\n", + " \n", + " \n", + " \n", + " \n", + " 0.104011\n", + " \n", + " \n", + " \n", + " \n", + " -0.481165\n", + " \n", + " \n", + " \n", + " \n", + " 0.850229\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " 5.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.453425\n", + " \n", + " \n", + " \n", + " \n", + " 1.057737\n", + " \n", + " \n", + " \n", + " \n", + " 0.165562\n", + " \n", + " \n", + " \n", + " \n", + " 0.515018\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " 6.0\n", + " \n", + " \n", + " \n", + " \n", + " -1.336936\n", + " \n", + " \n", + " \n", + " \n", + " 0.562861\n", + " \n", + " \n", + " \n", + " \n", + " 1.392855\n", + " \n", + " \n", + " \n", + " \n", + " -0.063328\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " 7.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.121668\n", + " \n", + " \n", + " \n", + " \n", + " 1.207603\n", + " \n", + " \n", + " \n", + " \n", + " -0.00204\n", + " \n", + " \n", + " \n", + " \n", + " 1.627796\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " 8.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.354493\n", + " \n", + " \n", + " \n", + " \n", + " 1.037528\n", + " \n", + " \n", + " \n", + " \n", + " -0.385684\n", + " \n", + " \n", + " \n", + " \n", + " 0.519818\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 9.0\n", + " \n", + " \n", + " \n", + " \n", + " 1.686583\n", + " \n", + " \n", + " \n", + " \n", + " -1.325963\n", + " \n", + " \n", + " \n", + " \n", + " 1.428984\n", + " \n", + " \n", + " \n", + " \n", + " -2.089354\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 10.0\n", + " \n", + " \n", + " \n", + " \n", + " -0.12982\n", + " \n", + " \n", + " \n", + " \n", + " 0.631523\n", + " \n", + " \n", + " \n", + " \n", + " -0.586538\n", + " \n", + " \n", + " \n", + " \n", + " 0.29072\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from IPython.html import widgets\n", + "@widgets.interact\n", + "def f(h_neg=(0, 359, 1), h_pos=(0, 359), s=(0., 99.9), l=(0., 99.9)):\n", + " return df.style.background_gradient(\n", + " cmap=sns.palettes.diverging_palette(h_neg=h_neg, h_pos=h_pos, s=s, l=l,\n", + " as_cmap=True)\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "def magnify():\n", + " return [dict(selector=\"th\",\n", + " props=[(\"font-size\", \"4pt\")]),\n", + " dict(selector=\"th:hover\",\n", + " props=[(\"font-size\", \"12pt\")]),\n", + " dict(selector=\"tr:hover td:hover\",\n", + " props=[('max-width', '200px'),\n", + " ('font-size', '12pt')])\n", + "]" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
Hover to magify
\n", + " \n", + " 0\n", + " \n", + " 1\n", + " \n", + " 2\n", + " \n", + " 3\n", + " \n", + " 4\n", + " \n", + " 5\n", + " \n", + " 6\n", + " \n", + " 7\n", + " \n", + " 8\n", + " \n", + " 9\n", + " \n", + " 10\n", + " \n", + " 11\n", + " \n", + " 12\n", + " \n", + " 13\n", + " \n", + " 14\n", + " \n", + " 15\n", + " \n", + " 16\n", + " \n", + " 17\n", + " \n", + " 18\n", + " \n", + " 19\n", + " \n", + " 20\n", + " \n", + " 21\n", + " \n", + " 22\n", + " \n", + " 23\n", + " \n", + " 24\n", + " \n", + "
\n", + " \n", + " 0\n", + " \n", + " \n", + " \n", + " \n", + " 0.23\n", + " \n", + " \n", + " \n", + " \n", + " 1.03\n", + " \n", + " \n", + " \n", + " \n", + " -0.84\n", + " \n", + " \n", + " \n", + " \n", + " -0.59\n", + " \n", + " \n", + " \n", + " \n", + " -0.96\n", + " \n", + " \n", + " \n", + " \n", + " -0.22\n", + " \n", + " \n", + " \n", + " \n", + " -0.62\n", + " \n", + " \n", + " \n", + " \n", + " 1.84\n", + " \n", + " \n", + " \n", + " \n", + " -2.05\n", + " \n", + " \n", + " \n", + " \n", + " 0.87\n", + " \n", + " \n", + " \n", + " \n", + " -0.92\n", + " \n", + " \n", + " \n", + " \n", + " -0.23\n", + " \n", + " \n", + " \n", + " \n", + " 2.15\n", + " \n", + " \n", + " \n", + " \n", + " -1.33\n", + " \n", + " \n", + " \n", + " \n", + " 0.08\n", + " \n", + " \n", + " \n", + " \n", + " -1.25\n", + " \n", + " \n", + " \n", + " \n", + " 1.2\n", + " \n", + " \n", + " \n", + " \n", + " -1.05\n", + " \n", + " \n", + " \n", + " \n", + " 1.06\n", + " \n", + " \n", + " \n", + " \n", + " -0.42\n", + " \n", + " \n", + " \n", + " \n", + " 2.29\n", + " \n", + " \n", + " \n", + " \n", + " -2.59\n", + " \n", + " \n", + " \n", + " \n", + " 2.82\n", + " \n", + " \n", + " \n", + " \n", + " 0.68\n", + " \n", + " \n", + " \n", + " \n", + " -1.58\n", + " \n", + " \n", + "
\n", + " \n", + " 1\n", + " \n", + " \n", + " \n", + " \n", + " -1.75\n", + " \n", + " \n", + " \n", + " \n", + " 1.56\n", + " \n", + " \n", + " \n", + " \n", + " -1.13\n", + " \n", + " \n", + " \n", + " \n", + " -1.1\n", + " \n", + " \n", + " \n", + " \n", + " 1.03\n", + " \n", + " \n", + " \n", + " \n", + " 0.0\n", + " \n", + " \n", + " \n", + " \n", + " -2.46\n", + " \n", + " \n", + " \n", + " \n", + " 3.45\n", + " \n", + " \n", + " \n", + " \n", + " -1.66\n", + " \n", + " \n", + " \n", + " \n", + " 1.27\n", + " \n", + " \n", + " \n", + " \n", + " -0.52\n", + " \n", + " \n", + " \n", + " \n", + " -0.02\n", + " \n", + " \n", + " \n", + " \n", + " 1.52\n", + " \n", + " \n", + " \n", + " \n", + " -1.09\n", + " \n", + " \n", + " \n", + " \n", + " -1.86\n", + " \n", + " \n", + " \n", + " \n", + " -1.13\n", + " \n", + " \n", + " \n", + " \n", + " -0.68\n", + " \n", + " \n", + " \n", + " \n", + " -0.81\n", + " \n", + " \n", + " \n", + " \n", + " 0.35\n", + " \n", + " \n", + " \n", + " \n", + " -0.06\n", + " \n", + " \n", + " \n", + " \n", + " 1.79\n", + " \n", + " \n", + " \n", + " \n", + " -2.82\n", + " \n", + " \n", + " \n", + " \n", + " 2.26\n", + " \n", + " \n", + " \n", + " \n", + " 0.78\n", + " \n", + " \n", + " \n", + " \n", + " 0.44\n", + " \n", + " \n", + "
\n", + " \n", + " 2\n", + " \n", + " \n", + " \n", + " \n", + " -0.65\n", + " \n", + " \n", + " \n", + " \n", + " 3.22\n", + " \n", + " \n", + " \n", + " \n", + " -1.76\n", + " \n", + " \n", + " \n", + " \n", + " 0.52\n", + " \n", + " \n", + " \n", + " \n", + " 2.2\n", + " \n", + " \n", + " \n", + " \n", + " -0.37\n", + " \n", + " \n", + " \n", + " \n", + " -3.0\n", + " \n", + " \n", + " \n", + " \n", + " 3.73\n", + " \n", + " \n", + " \n", + " \n", + " -1.87\n", + " \n", + " \n", + " \n", + " \n", + " 2.46\n", + " \n", + " \n", + " \n", + " \n", + " 0.21\n", + " \n", + " \n", + " \n", + " \n", + " -0.24\n", + " \n", + " \n", + " \n", + " \n", + " -0.1\n", + " \n", + " \n", + " \n", + " \n", + " -0.78\n", + " \n", + " \n", + " \n", + " \n", + " -3.02\n", + " \n", + " \n", + " \n", + " \n", + " -0.82\n", + " \n", + " \n", + " \n", + " \n", + " -0.21\n", + " \n", + " \n", + " \n", + " \n", + " -0.23\n", + " \n", + " \n", + " \n", + " \n", + " 0.86\n", + " \n", + " \n", + " \n", + " \n", + " -0.68\n", + " \n", + " \n", + " \n", + " \n", + " 1.45\n", + " \n", + " \n", + " \n", + " \n", + " -4.89\n", + " \n", + " \n", + " \n", + " \n", + " 3.03\n", + " \n", + " \n", + " \n", + " \n", + " 1.91\n", + " \n", + " \n", + " \n", + " \n", + " 0.61\n", + " \n", + " \n", + "
\n", + " \n", + " 3\n", + " \n", + " \n", + " \n", + " \n", + " -1.62\n", + " \n", + " \n", + " \n", + " \n", + " 3.71\n", + " \n", + " \n", + " \n", + " \n", + " -2.31\n", + " \n", + " \n", + " \n", + " \n", + " 0.43\n", + " \n", + " \n", + " \n", + " \n", + " 4.17\n", + " \n", + " \n", + " \n", + " \n", + " -0.43\n", + " \n", + " \n", + " \n", + " \n", + " -3.86\n", + " \n", + " \n", + " \n", + " \n", + " 4.16\n", + " \n", + " \n", + " \n", + " \n", + " -2.15\n", + " \n", + " \n", + " \n", + " \n", + " 1.08\n", + " \n", + " \n", + " \n", + " \n", + " 0.12\n", + " \n", + " \n", + " \n", + " \n", + " 0.6\n", + " \n", + " \n", + " \n", + " \n", + " -0.89\n", + " \n", + " \n", + " \n", + " \n", + " 0.27\n", + " \n", + " \n", + " \n", + " \n", + " -3.67\n", + " \n", + " \n", + " \n", + " \n", + " -2.71\n", + " \n", + " \n", + " \n", + " \n", + " -0.31\n", + " \n", + " \n", + " \n", + " \n", + " -1.59\n", + " \n", + " \n", + " \n", + " \n", + " 1.35\n", + " \n", + " \n", + " \n", + " \n", + " -1.83\n", + " \n", + " \n", + " \n", + " \n", + " 0.91\n", + " \n", + " \n", + " \n", + " \n", + " -5.8\n", + " \n", + " \n", + " \n", + " \n", + " 2.81\n", + " \n", + " \n", + " \n", + " \n", + " 2.11\n", + " \n", + " \n", + " \n", + " \n", + " 0.28\n", + " \n", + " \n", + "
\n", + " \n", + " 4\n", + " \n", + " \n", + " \n", + " \n", + " -3.35\n", + " \n", + " \n", + " \n", + " \n", + " 4.48\n", + " \n", + " \n", + " \n", + " \n", + " -1.86\n", + " \n", + " \n", + " \n", + " \n", + " -1.7\n", + " \n", + " \n", + " \n", + " \n", + " 5.19\n", + " \n", + " \n", + " \n", + " \n", + " -1.02\n", + " \n", + " \n", + " \n", + " \n", + " -3.81\n", + " \n", + " \n", + " \n", + " \n", + " 4.72\n", + " \n", + " \n", + " \n", + " \n", + " -0.72\n", + " \n", + " \n", + " \n", + " \n", + " 1.08\n", + " \n", + " \n", + " \n", + " \n", + " -0.18\n", + " \n", + " \n", + " \n", + " \n", + " 0.83\n", + " \n", + " \n", + " \n", + " \n", + " -0.22\n", + " \n", + " \n", + " \n", + " \n", + " -1.08\n", + " \n", + " \n", + " \n", + " \n", + " -4.27\n", + " \n", + " \n", + " \n", + " \n", + " -2.88\n", + " \n", + " \n", + " \n", + " \n", + " -0.97\n", + " \n", + " \n", + " \n", + " \n", + " -1.78\n", + " \n", + " \n", + " \n", + " \n", + " 1.53\n", + " \n", + " \n", + " \n", + " \n", + " -1.8\n", + " \n", + " \n", + " \n", + " \n", + " 2.21\n", + " \n", + " \n", + " \n", + " \n", + " -6.34\n", + " \n", + " \n", + " \n", + " \n", + " 3.34\n", + " \n", + " \n", + " \n", + " \n", + " 2.49\n", + " \n", + " \n", + " \n", + " \n", + " 2.09\n", + " \n", + " \n", + "
\n", + " \n", + " 5\n", + " \n", + " \n", + " \n", + " \n", + " -0.84\n", + " \n", + " \n", + " \n", + " \n", + " 4.23\n", + " \n", + " \n", + " \n", + " \n", + " -1.65\n", + " \n", + " \n", + " \n", + " \n", + " -2.0\n", + " \n", + " \n", + " \n", + " \n", + " 5.34\n", + " \n", + " \n", + " \n", + " \n", + " -0.99\n", + " \n", + " \n", + " \n", + " \n", + " -4.13\n", + " \n", + " \n", + " \n", + " \n", + " 3.94\n", + " \n", + " \n", + " \n", + " \n", + " -1.06\n", + " \n", + " \n", + " \n", + " \n", + " -0.94\n", + " \n", + " \n", + " \n", + " \n", + " 1.24\n", + " \n", + " \n", + " \n", + " \n", + " 0.09\n", + " \n", + " \n", + " \n", + " \n", + " -1.78\n", + " \n", + " \n", + " \n", + " \n", + " -0.11\n", + " \n", + " \n", + " \n", + " \n", + " -4.45\n", + " \n", + " \n", + " \n", + " \n", + " -0.85\n", + " \n", + " \n", + " \n", + " \n", + " -2.06\n", + " \n", + " \n", + " \n", + " \n", + " -1.35\n", + " \n", + " \n", + " \n", + " \n", + " 0.8\n", + " \n", + " \n", + " \n", + " \n", + " -1.63\n", + " \n", + " \n", + " \n", + " \n", + " 1.54\n", + " \n", + " \n", + " \n", + " \n", + " -6.51\n", + " \n", + " \n", + " \n", + " \n", + " 2.8\n", + " \n", + " \n", + " \n", + " \n", + " 2.14\n", + " \n", + " \n", + " \n", + " \n", + " 3.77\n", + " \n", + " \n", + "
\n", + " \n", + " 6\n", + " \n", + " \n", + " \n", + " \n", + " -0.74\n", + " \n", + " \n", + " \n", + " \n", + " 5.35\n", + " \n", + " \n", + " \n", + " \n", + " -2.11\n", + " \n", + " \n", + " \n", + " \n", + " -1.13\n", + " \n", + " \n", + " \n", + " \n", + " 4.2\n", + " \n", + " \n", + " \n", + " \n", + " -1.85\n", + " \n", + " \n", + " \n", + " \n", + " -3.2\n", + " \n", + " \n", + " \n", + " \n", + " 3.76\n", + " \n", + " \n", + " \n", + " \n", + " -3.22\n", + " \n", + " \n", + " \n", + " \n", + " -1.23\n", + " \n", + " \n", + " \n", + " \n", + " 0.34\n", + " \n", + " \n", + " \n", + " \n", + " 0.57\n", + " \n", + " \n", + " \n", + " \n", + " -1.82\n", + " \n", + " \n", + " \n", + " \n", + " 0.54\n", + " \n", + " \n", + " \n", + " \n", + " -4.43\n", + " \n", + " \n", + " \n", + " \n", + " -1.83\n", + " \n", + " \n", + " \n", + " \n", + " -4.03\n", + " \n", + " \n", + " \n", + " \n", + " -2.62\n", + " \n", + " \n", + " \n", + " \n", + " -0.2\n", + " \n", + " \n", + " \n", + " \n", + " -4.68\n", + " \n", + " \n", + " \n", + " \n", + " 1.93\n", + " \n", + " \n", + " \n", + " \n", + " -8.46\n", + " \n", + " \n", + " \n", + " \n", + " 3.34\n", + " \n", + " \n", + " \n", + " \n", + " 2.52\n", + " \n", + " \n", + " \n", + " \n", + " 5.81\n", + " \n", + " \n", + "
\n", + " \n", + " 7\n", + " \n", + " \n", + " \n", + " \n", + " -0.44\n", + " \n", + " \n", + " \n", + " \n", + " 4.69\n", + " \n", + " \n", + " \n", + " \n", + " -2.3\n", + " \n", + " \n", + " \n", + " \n", + " -0.21\n", + " \n", + " \n", + " \n", + " \n", + " 5.93\n", + " \n", + " \n", + " \n", + " \n", + " -2.63\n", + " \n", + " \n", + " \n", + " \n", + " -1.83\n", + " \n", + " \n", + " \n", + " \n", + " 5.46\n", + " \n", + " \n", + " \n", + " \n", + " -4.5\n", + " \n", + " \n", + " \n", + " \n", + " -3.16\n", + " \n", + " \n", + " \n", + " \n", + " -1.73\n", + " \n", + " \n", + " \n", + " \n", + " 0.18\n", + " \n", + " \n", + " \n", + " \n", + " 0.11\n", + " \n", + " \n", + " \n", + " \n", + " 0.04\n", + " \n", + " \n", + " \n", + " \n", + " -5.99\n", + " \n", + " \n", + " \n", + " \n", + " -0.45\n", + " \n", + " \n", + " \n", + " \n", + " -6.2\n", + " \n", + " \n", + " \n", + " \n", + " -3.89\n", + " \n", + " \n", + " \n", + " \n", + " 0.71\n", + " \n", + " \n", + " \n", + " \n", + " -3.95\n", + " \n", + " \n", + " \n", + " \n", + " 0.67\n", + " \n", + " \n", + " \n", + " \n", + " -7.26\n", + " \n", + " \n", + " \n", + " \n", + " 2.97\n", + " \n", + " \n", + " \n", + " \n", + " 3.39\n", + " \n", + " \n", + " \n", + " \n", + " 6.66\n", + " \n", + " \n", + "
\n", + " \n", + " 8\n", + " \n", + " \n", + " \n", + " \n", + " 0.92\n", + " \n", + " \n", + " \n", + " \n", + " 5.8\n", + " \n", + " \n", + " \n", + " \n", + " -3.33\n", + " \n", + " \n", + " \n", + " \n", + " -0.65\n", + " \n", + " \n", + " \n", + " \n", + " 5.99\n", + " \n", + " \n", + " \n", + " \n", + " -3.19\n", + " \n", + " \n", + " \n", + " \n", + " -1.83\n", + " \n", + " \n", + " \n", + " \n", + " 5.63\n", + " \n", + " \n", + " \n", + " \n", + " -3.53\n", + " \n", + " \n", + " \n", + " \n", + " -1.3\n", + " \n", + " \n", + " \n", + " \n", + " -1.61\n", + " \n", + " \n", + " \n", + " \n", + " 0.82\n", + " \n", + " \n", + " \n", + " \n", + " -2.45\n", + " \n", + " \n", + " \n", + " \n", + " -0.4\n", + " \n", + " \n", + " \n", + " \n", + " -6.06\n", + " \n", + " \n", + " \n", + " \n", + " -0.52\n", + " \n", + " \n", + " \n", + " \n", + " -6.6\n", + " \n", + " \n", + " \n", + " \n", + " -3.48\n", + " \n", + " \n", + " \n", + " \n", + " -0.04\n", + " \n", + " \n", + " \n", + " \n", + " -4.6\n", + " \n", + " \n", + " \n", + " \n", + " 0.51\n", + " \n", + " \n", + " \n", + " \n", + " -5.85\n", + " \n", + " \n", + " \n", + " \n", + " 3.23\n", + " \n", + " \n", + " \n", + " \n", + " 2.4\n", + " \n", + " \n", + " \n", + " \n", + " 5.08\n", + " \n", + " \n", + "
\n", + " \n", + " 9\n", + " \n", + " \n", + " \n", + " \n", + " 0.38\n", + " \n", + " \n", + " \n", + " \n", + " 5.54\n", + " \n", + " \n", + " \n", + " \n", + " -4.49\n", + " \n", + " \n", + " \n", + " \n", + " -0.8\n", + " \n", + " \n", + " \n", + " \n", + " 7.05\n", + " \n", + " \n", + " \n", + " \n", + " -2.64\n", + " \n", + " \n", + " \n", + " \n", + " -0.44\n", + " \n", + " \n", + " \n", + " \n", + " 5.35\n", + " \n", + " \n", + " \n", + " \n", + " -1.96\n", + " \n", + " \n", + " \n", + " \n", + " -0.33\n", + " \n", + " \n", + " \n", + " \n", + " -0.8\n", + " \n", + " \n", + " \n", + " \n", + " 0.26\n", + " \n", + " \n", + " \n", + " \n", + " -3.37\n", + " \n", + " \n", + " \n", + " \n", + " -0.82\n", + " \n", + " \n", + " \n", + " \n", + " -6.05\n", + " \n", + " \n", + " \n", + " \n", + " -2.61\n", + " \n", + " \n", + " \n", + " \n", + " -8.45\n", + " \n", + " \n", + " \n", + " \n", + " -4.45\n", + " \n", + " \n", + " \n", + " \n", + " 0.41\n", + " \n", + " \n", + " \n", + " \n", + " -4.71\n", + " \n", + " \n", + " \n", + " \n", + " 1.89\n", + " \n", + " \n", + " \n", + " \n", + " -6.93\n", + " \n", + " \n", + " \n", + " \n", + " 2.14\n", + " \n", + " \n", + " \n", + " \n", + " 3.0\n", + " \n", + " \n", + " \n", + " \n", + " 5.16\n", + " \n", + " \n", + "
\n", + " \n", + " 10\n", + " \n", + " \n", + " \n", + " \n", + " 2.06\n", + " \n", + " \n", + " \n", + " \n", + " 5.84\n", + " \n", + " \n", + " \n", + " \n", + " -3.9\n", + " \n", + " \n", + " \n", + " \n", + " -0.98\n", + " \n", + " \n", + " \n", + " \n", + " 7.78\n", + " \n", + " \n", + " \n", + " \n", + " -2.49\n", + " \n", + " \n", + " \n", + " \n", + " -0.59\n", + " \n", + " \n", + " \n", + " \n", + " 5.59\n", + " \n", + " \n", + " \n", + " \n", + " -2.22\n", + " \n", + " \n", + " \n", + " \n", + " -0.71\n", + " \n", + " \n", + " \n", + " \n", + " -0.46\n", + " \n", + " \n", + " \n", + " \n", + " 1.8\n", + " \n", + " \n", + " \n", + " \n", + " -2.79\n", + " \n", + " \n", + " \n", + " \n", + " 0.48\n", + " \n", + " \n", + " \n", + " \n", + " -5.97\n", + " \n", + " \n", + " \n", + " \n", + " -3.44\n", + " \n", + " \n", + " \n", + " \n", + " -7.77\n", + " \n", + " \n", + " \n", + " \n", + " -5.49\n", + " \n", + " \n", + " \n", + " \n", + " -0.7\n", + " \n", + " \n", + " \n", + " \n", + " -4.61\n", + " \n", + " \n", + " \n", + " \n", + " -0.52\n", + " \n", + " \n", + " \n", + " \n", + " -7.72\n", + " \n", + " \n", + " \n", + " \n", + " 1.54\n", + " \n", + " \n", + " \n", + " \n", + " 5.02\n", + " \n", + " \n", + " \n", + " \n", + " 5.81\n", + " \n", + " \n", + "
\n", + " \n", + " 11\n", + " \n", + " \n", + " \n", + " \n", + " 1.86\n", + " \n", + " \n", + " \n", + " \n", + " 4.47\n", + " \n", + " \n", + " \n", + " \n", + " -2.17\n", + " \n", + " \n", + " \n", + " \n", + " -1.38\n", + " \n", + " \n", + " \n", + " \n", + " 5.9\n", + " \n", + " \n", + " \n", + " \n", + " -0.49\n", + " \n", + " \n", + " \n", + " \n", + " 0.02\n", + " \n", + " \n", + " \n", + " \n", + " 5.78\n", + " \n", + " \n", + " \n", + " \n", + " -1.04\n", + " \n", + " \n", + " \n", + " \n", + " -0.6\n", + " \n", + " \n", + " \n", + " \n", + " 0.49\n", + " \n", + " \n", + " \n", + " \n", + " 1.96\n", + " \n", + " \n", + " \n", + " \n", + " -1.47\n", + " \n", + " \n", + " \n", + " \n", + " 1.88\n", + " \n", + " \n", + " \n", + " \n", + " -5.92\n", + " \n", + " \n", + " \n", + " \n", + " -4.55\n", + " \n", + " \n", + " \n", + " \n", + " -8.15\n", + " \n", + " \n", + " \n", + " \n", + " -3.42\n", + " \n", + " \n", + " \n", + " \n", + " -2.24\n", + " \n", + " \n", + " \n", + " \n", + " -4.33\n", + " \n", + " \n", + " \n", + " \n", + " -1.17\n", + " \n", + " \n", + " \n", + " \n", + " -7.9\n", + " \n", + " \n", + " \n", + " \n", + " 1.36\n", + " \n", + " \n", + " \n", + " \n", + " 5.31\n", + " \n", + " \n", + " \n", + " \n", + " 5.83\n", + " \n", + " \n", + "
\n", + " \n", + " 12\n", + " \n", + " \n", + " \n", + " \n", + " 3.19\n", + " \n", + " \n", + " \n", + " \n", + " 4.22\n", + " \n", + " \n", + " \n", + " \n", + " -3.06\n", + " \n", + " \n", + " \n", + " \n", + " -2.27\n", + " \n", + " \n", + " \n", + " \n", + " 5.93\n", + " \n", + " \n", + " \n", + " \n", + " -2.64\n", + " \n", + " \n", + " \n", + " \n", + " 0.33\n", + " \n", + " \n", + " \n", + " \n", + " 6.72\n", + " \n", + " \n", + " \n", + " \n", + " -2.84\n", + " \n", + " \n", + " \n", + " \n", + " -0.2\n", + " \n", + " \n", + " \n", + " \n", + " 1.89\n", + " \n", + " \n", + " \n", + " \n", + " 2.63\n", + " \n", + " \n", + " \n", + " \n", + " -1.53\n", + " \n", + " \n", + " \n", + " \n", + " 0.75\n", + " \n", + " \n", + " \n", + " \n", + " -5.27\n", + " \n", + " \n", + " \n", + " \n", + " -4.53\n", + " \n", + " \n", + " \n", + " \n", + " -7.57\n", + " \n", + " \n", + " \n", + " \n", + " -2.85\n", + " \n", + " \n", + " \n", + " \n", + " -2.17\n", + " \n", + " \n", + " \n", + " \n", + " -4.78\n", + " \n", + " \n", + " \n", + " \n", + " -1.13\n", + " \n", + " \n", + " \n", + " \n", + " -8.99\n", + " \n", + " \n", + " \n", + " \n", + " 2.11\n", + " \n", + " \n", + " \n", + " \n", + " 6.42\n", + " \n", + " \n", + " \n", + " \n", + " 5.6\n", + " \n", + " \n", + "
\n", + " \n", + " 13\n", + " \n", + " \n", + " \n", + " \n", + " 2.31\n", + " \n", + " \n", + " \n", + " \n", + " 4.45\n", + " \n", + " \n", + " \n", + " \n", + " -3.87\n", + " \n", + " \n", + " \n", + " \n", + " -2.05\n", + " \n", + " \n", + " \n", + " \n", + " 6.76\n", + " \n", + " \n", + " \n", + " \n", + " -3.25\n", + " \n", + " \n", + " \n", + " \n", + " -2.17\n", + " \n", + " \n", + " \n", + " \n", + " 7.99\n", + " \n", + " \n", + " \n", + " \n", + " -2.56\n", + " \n", + " \n", + " \n", + " \n", + " -0.8\n", + " \n", + " \n", + " \n", + " \n", + " 0.71\n", + " \n", + " \n", + " \n", + " \n", + " 2.33\n", + " \n", + " \n", + " \n", + " \n", + " -0.16\n", + " \n", + " \n", + " \n", + " \n", + " -0.46\n", + " \n", + " \n", + " \n", + " \n", + " -5.1\n", + " \n", + " \n", + " \n", + " \n", + " -3.79\n", + " \n", + " \n", + " \n", + " \n", + " -7.58\n", + " \n", + " \n", + " \n", + " \n", + " -4.0\n", + " \n", + " \n", + " \n", + " \n", + " 0.33\n", + " \n", + " \n", + " \n", + " \n", + " -3.67\n", + " \n", + " \n", + " \n", + " \n", + " -1.05\n", + " \n", + " \n", + " \n", + " \n", + " -8.71\n", + " \n", + " \n", + " \n", + " \n", + " 2.47\n", + " \n", + " \n", + " \n", + " \n", + " 5.87\n", + " \n", + " \n", + " \n", + " \n", + " 6.71\n", + " \n", + " \n", + "
\n", + " \n", + " 14\n", + " \n", + " \n", + " \n", + " \n", + " 3.78\n", + " \n", + " \n", + " \n", + " \n", + " 4.33\n", + " \n", + " \n", + " \n", + " \n", + " -3.88\n", + " \n", + " \n", + " \n", + " \n", + " -1.58\n", + " \n", + " \n", + " \n", + " \n", + " 6.22\n", + " \n", + " \n", + " \n", + " \n", + " -3.23\n", + " \n", + " \n", + " \n", + " \n", + " -1.46\n", + " \n", + " \n", + " \n", + " \n", + " 5.57\n", + " \n", + " \n", + " \n", + " \n", + " -2.93\n", + " \n", + " \n", + " \n", + " \n", + " -0.33\n", + " \n", + " \n", + " \n", + " \n", + " -0.97\n", + " \n", + " \n", + " \n", + " \n", + " 1.72\n", + " \n", + " \n", + " \n", + " \n", + " 3.61\n", + " \n", + " \n", + " \n", + " \n", + " 0.29\n", + " \n", + " \n", + " \n", + " \n", + " -4.21\n", + " \n", + " \n", + " \n", + " \n", + " -4.1\n", + " \n", + " \n", + " \n", + " \n", + " -6.68\n", + " \n", + " \n", + " \n", + " \n", + " -4.5\n", + " \n", + " \n", + " \n", + " \n", + " -2.19\n", + " \n", + " \n", + " \n", + " \n", + " -2.43\n", + " \n", + " \n", + " \n", + " \n", + " -1.64\n", + " \n", + " \n", + " \n", + " \n", + " -9.36\n", + " \n", + " \n", + " \n", + " \n", + " 3.36\n", + " \n", + " \n", + " \n", + " \n", + " 6.11\n", + " \n", + " \n", + " \n", + " \n", + " 7.53\n", + " \n", + " \n", + "
\n", + " \n", + " 15\n", + " \n", + " \n", + " \n", + " \n", + " 5.64\n", + " \n", + " \n", + " \n", + " \n", + " 5.31\n", + " \n", + " \n", + " \n", + " \n", + " -3.98\n", + " \n", + " \n", + " \n", + " \n", + " -2.26\n", + " \n", + " \n", + " \n", + " \n", + " 5.91\n", + " \n", + " \n", + " \n", + " \n", + " -3.3\n", + " \n", + " \n", + " \n", + " \n", + " -1.03\n", + " \n", + " \n", + " \n", + " \n", + " 5.68\n", + " \n", + " \n", + " \n", + " \n", + " -3.06\n", + " \n", + " \n", + " \n", + " \n", + " -0.33\n", + " \n", + " \n", + " \n", + " \n", + " -1.16\n", + " \n", + " \n", + " \n", + " \n", + " 2.19\n", + " \n", + " \n", + " \n", + " \n", + " 4.2\n", + " \n", + " \n", + " \n", + " \n", + " 1.01\n", + " \n", + " \n", + " \n", + " \n", + " -3.22\n", + " \n", + " \n", + " \n", + " \n", + " -4.31\n", + " \n", + " \n", + " \n", + " \n", + " -5.74\n", + " \n", + " \n", + " \n", + " \n", + " -4.44\n", + " \n", + " \n", + " \n", + " \n", + " -2.3\n", + " \n", + " \n", + " \n", + " \n", + " -1.36\n", + " \n", + " \n", + " \n", + " \n", + " -1.2\n", + " \n", + " \n", + " \n", + " \n", + " -11.27\n", + " \n", + " \n", + " \n", + " \n", + " 2.59\n", + " \n", + " \n", + " \n", + " \n", + " 6.69\n", + " \n", + " \n", + " \n", + " \n", + " 5.91\n", + " \n", + " \n", + "
\n", + " \n", + " 16\n", + " \n", + " \n", + " \n", + " \n", + " 4.08\n", + " \n", + " \n", + " \n", + " \n", + " 4.34\n", + " \n", + " \n", + " \n", + " \n", + " -2.44\n", + " \n", + " \n", + " \n", + " \n", + " -3.3\n", + " \n", + " \n", + " \n", + " \n", + " 6.04\n", + " \n", + " \n", + " \n", + " \n", + " -2.52\n", + " \n", + " \n", + " \n", + " \n", + " -0.47\n", + " \n", + " \n", + " \n", + " \n", + " 5.28\n", + " \n", + " \n", + " \n", + " \n", + " -4.84\n", + " \n", + " \n", + " \n", + " \n", + " 1.58\n", + " \n", + " \n", + " \n", + " \n", + " 0.23\n", + " \n", + " \n", + " \n", + " \n", + " 0.1\n", + " \n", + " \n", + " \n", + " \n", + " 5.79\n", + " \n", + " \n", + " \n", + " \n", + " 1.8\n", + " \n", + " \n", + " \n", + " \n", + " -3.13\n", + " \n", + " \n", + " \n", + " \n", + " -3.85\n", + " \n", + " \n", + " \n", + " \n", + " -5.53\n", + " \n", + " \n", + " \n", + " \n", + " -2.97\n", + " \n", + " \n", + " \n", + " \n", + " -2.13\n", + " \n", + " \n", + " \n", + " \n", + " -1.15\n", + " \n", + " \n", + " \n", + " \n", + " -0.56\n", + " \n", + " \n", + " \n", + " \n", + " -13.13\n", + " \n", + " \n", + " \n", + " \n", + " 2.07\n", + " \n", + " \n", + " \n", + " \n", + " 6.16\n", + " \n", + " \n", + " \n", + " \n", + " 4.94\n", + " \n", + " \n", + "
\n", + " \n", + " 17\n", + " \n", + " \n", + " \n", + " \n", + " 5.64\n", + " \n", + " \n", + " \n", + " \n", + " 4.57\n", + " \n", + " \n", + " \n", + " \n", + " -3.53\n", + " \n", + " \n", + " \n", + " \n", + " -3.76\n", + " \n", + " \n", + " \n", + " \n", + " 6.58\n", + " \n", + " \n", + " \n", + " \n", + " -2.58\n", + " \n", + " \n", + " \n", + " \n", + " -0.75\n", + " \n", + " \n", + " \n", + " \n", + " 6.58\n", + " \n", + " \n", + " \n", + " \n", + " -4.78\n", + " \n", + " \n", + " \n", + " \n", + " 3.63\n", + " \n", + " \n", + " \n", + " \n", + " -0.29\n", + " \n", + " \n", + " \n", + " \n", + " 0.56\n", + " \n", + " \n", + " \n", + " \n", + " 5.76\n", + " \n", + " \n", + " \n", + " \n", + " 2.05\n", + " \n", + " \n", + " \n", + " \n", + " -2.27\n", + " \n", + " \n", + " \n", + " \n", + " -2.31\n", + " \n", + " \n", + " \n", + " \n", + " -4.95\n", + " \n", + " \n", + " \n", + " \n", + " -3.16\n", + " \n", + " \n", + " \n", + " \n", + " -3.06\n", + " \n", + " \n", + " \n", + " \n", + " -2.43\n", + " \n", + " \n", + " \n", + " \n", + " 0.84\n", + " \n", + " \n", + " \n", + " \n", + " -12.57\n", + " \n", + " \n", + " \n", + " \n", + " 3.56\n", + " \n", + " \n", + " \n", + " \n", + " 7.36\n", + " \n", + " \n", + " \n", + " \n", + " 4.7\n", + " \n", + " \n", + "
\n", + " \n", + " 18\n", + " \n", + " \n", + " \n", + " \n", + " 5.99\n", + " \n", + " \n", + " \n", + " \n", + " 5.82\n", + " \n", + " \n", + " \n", + " \n", + " -2.85\n", + " \n", + " \n", + " \n", + " \n", + " -4.15\n", + " \n", + " \n", + " \n", + " \n", + " 7.12\n", + " \n", + " \n", + " \n", + " \n", + " -3.32\n", + " \n", + " \n", + " \n", + " \n", + " -1.21\n", + " \n", + " \n", + " \n", + " \n", + " 7.93\n", + " \n", + " \n", + " \n", + " \n", + " -4.85\n", + " \n", + " \n", + " \n", + " \n", + " 1.44\n", + " \n", + " \n", + " \n", + " \n", + " -0.63\n", + " \n", + " \n", + " \n", + " \n", + " 0.35\n", + " \n", + " \n", + " \n", + " \n", + " 7.47\n", + " \n", + " \n", + " \n", + " \n", + " 0.87\n", + " \n", + " \n", + " \n", + " \n", + " -1.52\n", + " \n", + " \n", + " \n", + " \n", + " -2.09\n", + " \n", + " \n", + " \n", + " \n", + " -4.23\n", + " \n", + " \n", + " \n", + " \n", + " -2.55\n", + " \n", + " \n", + " \n", + " \n", + " -2.46\n", + " \n", + " \n", + " \n", + " \n", + " -2.89\n", + " \n", + " \n", + " \n", + " \n", + " 1.9\n", + " \n", + " \n", + " \n", + " \n", + " -9.74\n", + " \n", + " \n", + " \n", + " \n", + " 3.43\n", + " \n", + " \n", + " \n", + " \n", + " 7.07\n", + " \n", + " \n", + " \n", + " \n", + " 4.39\n", + " \n", + " \n", + "
\n", + " \n", + " 19\n", + " \n", + " \n", + " \n", + " \n", + " 4.03\n", + " \n", + " \n", + " \n", + " \n", + " 6.23\n", + " \n", + " \n", + " \n", + " \n", + " -4.1\n", + " \n", + " \n", + " \n", + " \n", + " -4.11\n", + " \n", + " \n", + " \n", + " \n", + " 7.19\n", + " \n", + " \n", + " \n", + " \n", + " -4.1\n", + " \n", + " \n", + " \n", + " \n", + " -1.52\n", + " \n", + " \n", + " \n", + " \n", + " 6.53\n", + " \n", + " \n", + " \n", + " \n", + " -5.21\n", + " \n", + " \n", + " \n", + " \n", + " -0.24\n", + " \n", + " \n", + " \n", + " \n", + " 0.01\n", + " \n", + " \n", + " \n", + " \n", + " 1.16\n", + " \n", + " \n", + " \n", + " \n", + " 6.43\n", + " \n", + " \n", + " \n", + " \n", + " -1.97\n", + " \n", + " \n", + " \n", + " \n", + " -2.64\n", + " \n", + " \n", + " \n", + " \n", + " -1.66\n", + " \n", + " \n", + " \n", + " \n", + " -5.2\n", + " \n", + " \n", + " \n", + " \n", + " -3.25\n", + " \n", + " \n", + " \n", + " \n", + " -2.87\n", + " \n", + " \n", + " \n", + " \n", + " -1.65\n", + " \n", + " \n", + " \n", + " \n", + " 1.64\n", + " \n", + " \n", + " \n", + " \n", + " -10.66\n", + " \n", + " \n", + " \n", + " \n", + " 2.83\n", + " \n", + " \n", + " \n", + " \n", + " 7.48\n", + " \n", + " \n", + " \n", + " \n", + " 3.94\n", + " \n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.random.seed(25)\n", + "cmap = cmap=sns.diverging_palette(5, 250, as_cmap=True)\n", + "df = pd.DataFrame(np.random.randn(20, 25)).cumsum()\n", + "\n", + "df.style.background_gradient(cmap, axis=1)\\\n", + " .set_properties(**{'max-width': '80px', 'font-size': '1pt'})\\\n", + " .set_caption(\"Hover to magify\")\\\n", + " .set_precision(2)\\\n", + " .set_table_styles(magnify())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Extensibility\n", + "\n", + "The core of pandas is, and will remain, its \"high-performance, easy-to-use data structures\".\n", + "With that in mind, we hope that `DataFrame.style` accomplishes two goals\n", + "\n", + "- Provide an API that is pleasing to use interactively and is \"good enough\" for many tasks\n", + "- Provide the foundations for dedicated libraries to build on\n", + "\n", + "If you build a great library on top of this, let us know and we'll [link](http://pandas.pydata.org/pandas-docs/stable/ecosystem.html) to it.\n", + "\n", + "## Subclassing\n", + "\n", + "This section contains a bit of information about the implementation of `Styler`.\n", + "Since the feature is so new all of this is subject to change, even more so than the end-use API.\n", + "\n", + "As users apply styles (via `.apply`, `.applymap` or one of the builtins), we don't actually calculate anything.\n", + "Instead, we append functions and arguments to a list `self._todo`.\n", + "When asked (typically in `.render` we'll walk through the list and execute each function (this is in `self._compute()`.\n", + "These functions update an internal `defaultdict(list)`, `self.ctx` which maps DataFrame row / column positions to CSS attribute, value pairs.\n", + "\n", + "We take the extra step through `self._todo` so that we can export styles and set them on other `Styler`s.\n", + "\n", + "Rendering uses [Jinja](http://jinja.pocoo.org/) templates.\n", + "The `.translate` method takes `self.ctx` and builds another dictionary ready to be passed into `Styler.template.render`, the Jinja template.\n", + "\n", + "\n", + "## Alternate templates\n", + "\n", + "We've used [Jinja](http://jinja.pocoo.org/) templates to build up the HTML.\n", + "The template is stored as a class variable ``Styler.template.``. Subclasses can override that.\n", + "\n", + "```python\n", + "class CustomStyle(Styler):\n", + " template = Template(\"\"\"...\"\"\")\n", + "```" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.4.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/doc/source/index.rst.template b/doc/source/index.rst.template index 621bd33ba5a41..6011c22e9cc2e 100644 --- a/doc/source/index.rst.template +++ b/doc/source/index.rst.template @@ -136,6 +136,7 @@ See the package overview for more detail about what's in the library. timedeltas categorical visualization + style io remote_data enhancingperf diff --git a/doc/source/install.rst b/doc/source/install.rst index 54e7b2d4df350..9accc188d567f 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -254,6 +254,7 @@ Optional Dependencies * Needed for Excel I/O * `XlsxWriter `__ * Alternative Excel writer +* `Jinja2 `__: Template engine for conditional HTML formatting. * `boto `__: necessary for Amazon S3 access. * `blosc `__: for msgpack compression using ``blosc`` diff --git a/doc/source/style.rst b/doc/source/style.rst new file mode 100644 index 0000000000000..c373a75c98345 --- /dev/null +++ b/doc/source/style.rst @@ -0,0 +1,6 @@ +.. _style: + +.. currentmodule:: pandas + +.. raw:: html + :file: html-styling.html diff --git a/doc/source/whatsnew/v0.17.1.txt b/doc/source/whatsnew/v0.17.1.txt index 151131a52a4bb..7178be1ffefd2 100755 --- a/doc/source/whatsnew/v0.17.1.txt +++ b/doc/source/whatsnew/v0.17.1.txt @@ -15,6 +15,21 @@ Highlights include: :local: :backlinks: none +New features +~~~~~~~~~~~~ + +.. _whatsnew_0171.style + +Conditional HTML Formatting +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +We've added *experimental* support for conditional HTML formatting, +the visual styling of a DataFrame based on the data. +The styling is accomplished with HTML and CSS. +Acesses the styler class with :attr:`pandas.DataFrame.style`, attribute, +an instance of :class:`~pandas.core.style.Styler` with your data attached. +See the :ref:`example notebook + + + {% if caption %} + + {% endif %} + + + {% for r in head %} + + {% for c in r %} + <{{c.type}} class="{{c.class}}">{{c.value}} + {% endfor %} + + {% endfor %} + + + {% for r in body %} + + {% for c in r %} + <{{c.type}} id="T_{{uuid}}{{c.id}}" class="{{c.class}}"> + {% if c.value is number %} + {{c.value|round(precision)}} + {% else %} + {{c.value}} + {% endif %} + {% endfor %} + + {% endfor %} + +
{{caption}}
+ """) + + def __init__(self, data, precision=None, table_styles=None, uuid=None, + caption=None): + self.ctx = defaultdict(list) + self._todo = [] + + if not isinstance(data, (pd.Series, pd.DataFrame)): + raise TypeError + if data.ndim == 1: + data = data.to_frame() + if not data.index.is_unique or not data.columns.is_unique: + raise ValueError("style is not supported for non-unique indicies.") + + self.data = data + self.index = data.index + self.columns = data.columns + + self.uuid = uuid + self.table_styles = table_styles + self.caption = caption + if precision is None: + precision = pd.options.display.precision + self.precision = precision + + def _repr_html_(self): + ''' + Hooks into Jupyter notebook rich display system. + ''' + return self.render() + + def _translate(self): + """ + Convert the DataFrame in `self.data` and the attrs from `_build_styles` + into a dictionary of {head, body, uuid, cellstyle} + """ + table_styles = self.table_styles or [] + caption = self.caption + ctx = self.ctx + precision = self.precision + uuid = self.uuid or str(uuid1()).replace("-", "_") + ROW_HEADING_CLASS = "row_heading" + COL_HEADING_CLASS = "col_heading" + DATA_CLASS = "data" + BLANK_CLASS = "blank" + BLANK_VALUE = "" + + cell_context = dict() + + n_rlvls = self.data.index.nlevels + n_clvls = self.data.columns.nlevels + rlabels = self.data.index.tolist() + clabels = self.data.columns.tolist() + + idx_values = self.data.index.format(sparsify=False, adjoin=False, + names=False) + idx_values = lzip(*idx_values) + + if n_rlvls == 1: + rlabels = [[x] for x in rlabels] + if n_clvls == 1: + clabels = [[x] for x in clabels] + clabels = list(zip(*clabels)) + + cellstyle = [] + head = [] + + for r in range(n_clvls): + row_es = [{"type": "th", "value": BLANK_VALUE, + "class": " ".join([BLANK_CLASS])}] * n_rlvls + for c in range(len(clabels[0])): + cs = [COL_HEADING_CLASS, "level%s" % r, "col%s" % c] + cs.extend(cell_context.get( + "col_headings", {}).get(r, {}).get(c, [])) + row_es.append({"type": "th", "value": clabels[r][c], + "class": " ".join(cs)}) + head.append(row_es) + + body = [] + for r, idx in enumerate(self.data.index): + cs = [ROW_HEADING_CLASS, "level%s" % c, "row%s" % r] + cs.extend(cell_context.get( + "row_headings", {}).get(r, {}).get(c, [])) + row_es = [{"type": "th", + "value": rlabels[r][c], + "class": " ".join(cs)} + for c in range(len(rlabels[r]))] + + for c, col in enumerate(self.data.columns): + cs = [DATA_CLASS, "row%s" % r, "col%s" % c] + cs.extend(cell_context.get("data", {}).get(r, {}).get(c, [])) + row_es.append({"type": "td", "value": self.data.iloc[r][c], + "class": " ".join(cs), "id": "_".join(cs[1:])}) + props = [] + for x in ctx[r, c]: + # have to handle empty styles like [''] + if x.count(":"): + props.append(x.split(":")) + else: + props.append(['', '']) + cellstyle.append( + {'props': props, + 'selector': "row%s_col%s" % (r, c)} + ) + body.append(row_es) + + return dict(head=head, cellstyle=cellstyle, body=body, uuid=uuid, + precision=precision, table_styles=table_styles, + caption=caption) + + def render(self): + """ + Render the built up styles to HTML + + .. versionadded:: 0.17.1 + + Returns + ------- + rendered: str + the rendered HTML + + Notes + ----- + ``Styler`` objects have defined the ``_repr_html_`` method + which automatically calls ``self.render()`` when it's the + last item in a Notebook cell. When calling ``Styler.render()`` + directly, wrap the resul in ``IPython.display.HTML`` to view + the rendered HTML in the notebook. + """ + self._compute() + d = self._translate() + # filter out empty styles, every cell will have a class + # but the list of props may just be [['', '']]. + # so we have the neested anys below + trimmed = [x for x in d['cellstyle'] if + any(any(y) for y in x['props'])] + d['cellstyle'] = trimmed + return self.template.render(**d) + + def _update_ctx(self, attrs): + """ + update the state of the Styler. Collects a mapping + of {index_label: [': ']} + + attrs: Series or DataFrame + should contain strings of ': ;: ' + Whitespace shouldn't matter and the final trailing ';' shouldn't + matter. + """ + for row_label, v in attrs.iterrows(): + for col_label, col in v.iteritems(): + i = self.index.get_indexer([row_label])[0] + j = self.columns.get_indexer([col_label])[0] + for pair in col.rstrip(";").split(";"): + self.ctx[(i, j)].append(pair) + + def _copy(self, deepcopy=False): + styler = Styler(self.data, precision=self.precision, + caption=self.caption, uuid=self.uuid, + table_styles=self.table_styles) + if deepcopy: + styler.ctx = copy.deepcopy(self.ctx) + styler._todo = copy.deepcopy(self._todo) + else: + styler.ctx = self.ctx + styler._todo = self._todo + return styler + + def __copy__(self): + """ + Deep copy by default. + """ + return self._copy(deepcopy=False) + + def __deepcopy__(self, memo): + return self._copy(deepcopy=True) + + def clear(self): + self.ctx.clear() + self._todo = [] + + def _compute(self): + ''' + Execute the style functions built up in `self._todo`. + + Relies on the conventions that all style functions go through + .apply or .applymap. The append styles to apply as tuples of + + (application method, *args, **kwargs) + ''' + r = self + for func, args, kwargs in self._todo: + r = func(self)(*args, **kwargs) + return r + + def _apply(self, func, axis=0, subset=None, **kwargs): + subset = slice(None) if subset is None else subset + subset = _non_reducing_slice(subset) + if axis is not None: + result = self.data.loc[subset].apply(func, axis=axis, **kwargs) + else: + # like tee + result = func(self.data.loc[subset], **kwargs) + self._update_ctx(result) + return self + + def apply(self, func, axis=0, subset=None, **kwargs): + """ + Apply a function column-wise, row-wise, or table-wase, + updating the HTML representation with the result. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + func: function + axis: int, str or None + apply to each column (``axis=0`` or ``'index'``) + or to each row (``axis=1`` or ``'columns'``) or + to the entire DataFrame at once with ``axis=None``. + subset: IndexSlice + a valid indexer to limit ``data`` to *before* applying the + function. Consider using a pandas.IndexSlice + kwargs: dict + pass along to ``func`` + + Returns + ------- + self + + Notes + ----- + This is similar to DataFrame.apply, except that axis=None applies + the function to the entire DataFrame at once, rather tha column + or rowwise. + """ + self._todo.append((lambda instance: getattr(instance, '_apply'), + (func, axis, subset), + kwargs)) + return self + + def _applymap(self, func, subset=None, **kwargs): + func = partial(func, **kwargs) # applymap doesn't take kwargs? + if subset is None: + subset = pd.IndexSlice[:] + subset = _non_reducing_slice(subset) + result = self.data.loc[subset].applymap(func) + self._update_ctx(result) + return self + + def applymap(self, func, subset=None, **kwargs): + """ + Apply a function elementwise, updating the HTML + representation with the result. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + func : function + subset : IndexSlice + a valid indexer to limit ``data`` to *before* applying the + function. Consider using a pandas.IndexSlice + kwargs : dict + pass along to ``func`` + + Returns + ------- + self + + """ + self._todo.append((lambda instance: getattr(instance, '_applymap'), + (func, subset), + kwargs)) + return self + + def set_precision(self, precision): + """ + Set the precision used to render. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + precision: int + + Returns + ------- + self + """ + self.precision = precision + return self + + def export(self): + """ + Export the styles to applied to the current Styler. + Can be applied to a second style with `.use`. + + .. versionadded:: 0.17.1 + + Returns + ------- + styles: list + + See Also + -------- + Styler.use + """ + return self._todo + + def use(self, styles): + """ + Set the styles on the current Styler, possibly using styles + from `Styler.export` + + .. versionadded:: 0.17.1 + + Parameters + ---------- + styles: list + list of style functions + + Returns + ------- + self + + See Also + -------- + Styler.export + """ + self._todo.extend(styles) + return self + + def set_uuid(self, uuid): + """ + Set the uuid for a Styler. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + uuid: str + + Returns + ------- + self + """ + self.uuid = uuid + return self + + def set_caption(self, caption): + """ + Se the caption on a Styler + + .. versionadded:: 0.17.1 + + Parameters + ---------- + caption: str + + Returns + ------- + self + """ + self.caption = caption + return self + + def set_table_styles(self, table_styles): + """ + Set the table styles on a Styler + + .. versionadded:: 0.17.1 + + Parameters + ---------- + table_styles: list + + Returns + ------- + self + """ + self.table_styles = table_styles + return self + + # ----------------------------------------------------------------------- + # A collection of "builtin" styles + # ----------------------------------------------------------------------- + + @staticmethod + def _highlight_null(v, null_color): + return 'background-color: %s' % null_color if pd.isnull(v) else '' + + def highlight_null(self, null_color='red'): + """ + Shade the background ``null_color`` for missing values. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + null_color: str + + Returns + ------- + self + """ + self.applymap(self._highlight_null, null_color=null_color) + return self + + def background_gradient(self, cmap='PuBu', low=0, high=0, + axis=0, subset=None): + """ + Color the background in a gradient according to + the data in each column (optionally row). + Requires matplotlib. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + cmap: str or colormap + matplotlib colormap + low, high: float + compress the range by these values. + axis: int or str + 1 or 'columns' for colunwise, 0 or 'index' for rowwise + subset: IndexSlice + a valid slice for ``data`` to limit the style application to + + Returns + ------- + self + + Notes + ----- + Tune ``low`` and ``high`` to keep the text legible by + not using the entire range of the color map. These extend + the range of the data by ``low * (x.max() - x.min())`` + and ``high * (x.max() - x.min())`` before normalizing. + """ + subset = _maybe_numeric_slice(self.data, subset) + subset = _non_reducing_slice(subset) + self.apply(self._background_gradient, cmap=cmap, subset=subset, + axis=axis, low=low, high=high) + return self + + @staticmethod + def _background_gradient(s, cmap='PuBu', low=0, high=0): + """Color background in a range according to the data.""" + with _mpl(Styler.background_gradient) as (plt, colors): + rng = s.max() - s.min() + # extend lower / upper bounds, compresses color range + norm = colors.Normalize(s.min() - (rng * low), + s.max() + (rng * high)) + # matplotlib modifies inplace? + # https://github.com/matplotlib/matplotlib/issues/5427 + normed = norm(s.values) + c = [colors.rgb2hex(x) for x in plt.cm.get_cmap(cmap)(normed)] + return ['background-color: %s' % color for color in c] + + def set_properties(self, subset=None, **kwargs): + """ + Convience method for setting one or more non-data dependent + properties or each cell. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + subset: IndexSlice + a valid slice for ``data`` to limit the style application to + kwargs: dict + property: value pairs to be set for each cell + + Returns + ------- + self : Styler + + Examples + -------- + >>> df = pd.DataFrame(np.random.randn(10, 4)) + >>> df.style.set_properties(color="white", align="right") + """ + values = ';'.join('{p}: {v}'.format(p=p, v=v) for p, v in + kwargs.items()) + f = lambda x: values + return self.applymap(f, subset=subset) + + @staticmethod + def _bar(s, color, width): + normed = width * (s - s.min()) / (s.max() - s.min()) + attrs = 'width: 10em; height: 80%;'\ + 'background: linear-gradient(90deg,'\ + '{c} {w}%, transparent 0%)' + return [attrs.format(c=color, w=x) for x in normed] + + def bar(self, subset=None, axis=0, color='#d65f5f', width=100): + """ + Color the background ``color`` proptional to the values in each column. + Excludes non-numeric data by default. + + .. versionadded:: 0.17.1 + + Parameters + ---------- + subset: IndexSlice, default None + a valid slice for ``data`` to limit the style application to + axis: int + color: str + width: float + A number between 0 or 100. The largest value will cover ``width`` + percent of the cell's width + + Returns + ------- + self + """ + subset = _maybe_numeric_slice(self.data, subset) + subset = _non_reducing_slice(subset) + self.apply(self._bar, subset=subset, axis=axis, color=color, + width=width) + return self + + def highlight_max(self, subset=None, color='yellow', axis=0): + """ + Highlight the maximum by shading the background + + .. versionadded:: 0.17.1 + + Parameters + ---------- + subset: IndexSlice, default None + a valid slice for ``data`` to limit the style application to + color: str, default 'yellow' + axis: int, str, or None; default None + 0 or 'index' for columnwise, 1 or 'columns' for rowwise + or ``None`` for tablewise (the default) + + Returns + ------- + self + """ + return self._highlight_handler(subset=subset, color=color, axis=axis, + max_=True) + + def highlight_min(self, subset=None, color='yellow', axis=0): + """ + Highlight the minimum by shading the background + + .. versionadded:: 0.17.1 + + Parameters + ---------- + subset: IndexSlice, default None + a valid slice for ``data`` to limit the style application to + color: str, default 'yellow' + axis: int, str, or None; default None + 0 or 'index' for columnwise, 1 or 'columns' for rowwise + or ``None`` for tablewise (the default) + + Returns + ------- + self + """ + return self._highlight_handler(subset=subset, color=color, axis=axis, + max_=False) + + def _highlight_handler(self, subset=None, color='yellow', axis=None, + max_=True): + subset = _non_reducing_slice(_maybe_numeric_slice(self.data, subset)) + self.apply(self._highlight_extrema, color=color, axis=axis, + subset=subset, max_=max_) + return self + + @staticmethod + def _highlight_extrema(data, color='yellow', max_=True): + ''' + highlight the min or max in a Series or DataFrame + ''' + attr = 'background-color: {0}'.format(color) + if data.ndim == 1: # Series from .apply + if max_: + extrema = data == data.max() + else: + extrema = data == data.min() + return [attr if v else '' for v in extrema] + else: # DataFrame from .tee + if max_: + extrema = data == data.max().max() + else: + extrema = data == data.min().min() + return pd.DataFrame(np.where(extrema, attr, ''), + index=data.index, columns=data.columns) + + + diff --git a/pandas/tests/test_indexing.py b/pandas/tests/test_indexing.py index 36e825924995a..0eb6a6a70f8b7 100644 --- a/pandas/tests/test_indexing.py +++ b/pandas/tests/test_indexing.py @@ -15,6 +15,7 @@ import pandas as pd import pandas.core.common as com from pandas import option_context +from pandas.core.indexing import _non_reducing_slice, _maybe_numeric_slice from pandas.core.api import (DataFrame, Index, Series, Panel, isnull, MultiIndex, Float64Index, Timestamp, Timedelta) from pandas.util.testing import (assert_almost_equal, assert_series_equal, @@ -4728,6 +4729,49 @@ def test_large_mi_dataframe_indexing(self): result = MultiIndex.from_arrays([range(10**6), range(10**6)]) assert(not (10**6, 0) in result) + def test_non_reducing_slice(self): + df = pd.DataFrame([[0, 1], [2, 3]]) + + slices = [ + # 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]) + ] + for slice_ in slices: + tslice_ = _non_reducing_slice(slice_) + self.assertTrue(isinstance(df.loc[tslice_], DataFrame)) + + def test_list_slice(self): + # like dataframe getitem + slices = [['A'], pd.Series(['A']), np.array(['A'])] + df = pd.DataFrame({'A': [1, 2], 'B': [3, 4]}, index=['A', 'B']) + expected = pd.IndexSlice[:, ['A']] + for subset in slices: + result = _non_reducing_slice(subset) + tm.assert_frame_equal(df.loc[result], df.loc[expected]) + + def test_maybe_numeric_slice(self): + df = pd.DataFrame({'A': [1, 2], 'B': ['c', 'd'], 'C': [True, False]}) + result = _maybe_numeric_slice(df, slice_=None) + expected = pd.IndexSlice[:, ['A']] + self.assertEqual(result, expected) + + result = _maybe_numeric_slice(df, None, include_bool=True) + expected = pd.IndexSlice[:, ['A', 'C']] + result = _maybe_numeric_slice(df, [1]) + expected = [1] + self.assertEqual(result, expected) + + class TestCategoricalIndex(tm.TestCase): def setUp(self): diff --git a/pandas/tests/test_style.py b/pandas/tests/test_style.py new file mode 100644 index 0000000000000..4c875cebe149a --- /dev/null +++ b/pandas/tests/test_style.py @@ -0,0 +1,372 @@ +import os +from nose import SkipTest + +# this is a mess. Getting failures on a python 2.7 build with +# whenever we try to import jinja, whether it's installed or not. +# so we're explicitly skipping that one *before* we try to import +# jinja. We still need to export the imports as globals, +# since importing Styler tries to import jinja2. +job_name = os.environ.get('JOB_NAME', None) +if job_name == '27_slow_nnet_LOCALE': + raise SkipTest("No jinja") +try: + from pandas.core.style import Styler +except ImportError: + raise SkipTest("No Jinja2") + +import copy + +import numpy as np +import pandas as pd +from pandas import DataFrame +from pandas.util.testing import TestCase +import pandas.util.testing as tm + + +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_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).apply(style, axis=1) + 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_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%', + 'background: linear-gradient(' + '90deg,#d65f5f 0.0%, transparent 0%)'], + (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%', + 'background: linear-gradient(' + '90deg,red 0.0%, transparent 0%)'], + (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_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_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() + + +@tm.mplskip +class TestStylerMatplotlibDep(TestCase): + + def test_background_gradient(self): + df = pd.DataFrame([[1, 2], [2, 4]], columns=['A', 'B']) + for axis in [0, 1, 'index', 'columns']: + for cmap in [None, 'YlOrRd']: + result = df.style.background_gradient(cmap=cmap)._compute().ctx + self.assertTrue(all("#" in x[0] for x in result.values())) + self.assertEqual(result[(0, 0)], result[(0, 1)]) + self.assertEqual(result[(1, 0)], result[(1, 1)]) + + result = (df.style.background_gradient(subset=pd.IndexSlice[1, 'A']) + ._compute().ctx) + self.assertEqual(result[(1, 0)], ['background-color: #fff7fb']) diff --git a/pandas/tests/test_testing.py b/pandas/tests/test_testing.py index 2b5443e6ff0d2..13c0b6a08f6e7 100644 --- a/pandas/tests/test_testing.py +++ b/pandas/tests/test_testing.py @@ -11,7 +11,8 @@ from pandas.util.testing import ( assert_almost_equal, assertRaisesRegexp, raise_with_traceback, assert_index_equal, assert_series_equal, assert_frame_equal, - assert_numpy_array_equal, assert_isinstance, RNGContext + assert_numpy_array_equal, assert_isinstance, RNGContext, + assertRaises, skip_if_no_package_deco ) from pandas.compat import is_platform_windows @@ -627,6 +628,23 @@ def test_locale(self): self.assertTrue(len(locales) >= 1) +def test_skiptest_deco(): + from nose import SkipTest + @skip_if_no_package_deco("fakepackagename") + def f(): + pass + with assertRaises(SkipTest): + f() + + @skip_if_no_package_deco("numpy") + def f(): + pass + # hack to ensure that SkipTest is *not* raised + with assertRaises(ValueError): + f() + raise ValueError + + if __name__ == '__main__': nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], exit=False) diff --git a/pandas/util/testing.py b/pandas/util/testing.py index be8b0df73593f..ba32bc1f3e377 100644 --- a/pandas/util/testing.py +++ b/pandas/util/testing.py @@ -1578,7 +1578,18 @@ def skip_if_no_package(*args, **kwargs): exc_failed_check=SkipTest, *args, **kwargs) -# +def skip_if_no_package_deco(pkg_name, version=None, app='pandas'): + from nose import SkipTest + + def deco(func): + @wraps(func) + def wrapper(*args, **kwargs): + package_check(pkg_name, version=version, app=app, + exc_failed_import=SkipTest, exc_failed_check=SkipTest) + return func(*args, **kwargs) + return wrapper + return deco + # # Additional tags decorators for nose #