Skip to content

Feature request: add an optional values parameter to Styler.background_gradient #22727

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
dclong opened this issue Sep 16, 2018 · 5 comments · Fixed by #39930
Closed

Feature request: add an optional values parameter to Styler.background_gradient #22727

dclong opened this issue Sep 16, 2018 · 5 comments · Fixed by #39930
Labels
API Design Enhancement IO HTML read_html, to_html, Styler.apply, Styler.applymap Output-Formatting __repr__ of pandas objects, to_string Styler conditional formatting using DataFrame.style
Milestone

Comments

@dclong
Copy link

dclong commented Sep 16, 2018

Sometimes we want to apply background_gradient to some columns according to values in another column. There's no easy way to do this currently. It can be made possible by adding an optional values parameter. And when the values parameter is specified, it is used to generate background colors.

@TomAugspurger
Copy link
Contributor

Can you provide an example?

@TomAugspurger TomAugspurger added Output-Formatting __repr__ of pandas objects, to_string API Design IO HTML read_html, to_html, Styler.apply, Styler.applymap labels Sep 16, 2018
@simonjayhawkins
Copy link
Member

simonjayhawkins commented Sep 16, 2018

if I understand correctly what your trying to achieve, you could render the HTML directly yourself, using df.to_html(escape=False)

something like this?..

image

import pandas as pd
from IPython.display import HTML, display

from . import datasets


def make_clickable(val):
    return '<a target="_blank" href="https://www.amazon.co.uk/dp/{}">{}</a>'.format(val, val)


def image_html(row):
    if type(row['SmallImage_URL']) != float:
        return '<img src="{}" style="height: {}px; width: {}px;">' \
            .format(row['SmallImage_URL'], int(row['SmallImage_Height']), int(row['SmallImage_Width']))
    else:
        return ''


def add_image_to_dataframe(df):
    df = df.copy()
    columns = df.columns.tolist()
    image_metadata_columns = ['SmallImage_Height',
                              'SmallImage_Width', 'SmallImage_URL']
    df = datasets.add_item_attributes(df, image_metadata_columns)
    df['image'] = df.apply(image_html, axis=1)
    df = df.drop(columns=image_metadata_columns)
    return df[['image'] + columns]


def render(df, add_image=True):
    if not df.empty is True:
        df = df.copy().fillna("")
        if 'asin' not in df.columns:
            df = datasets.add_asin(df)
        if (add_image):
            df = add_image_to_dataframe(df)
        df['asin'] = df.asin.apply(make_clickable)
        with pd.option_context('display.max_colwidth', -1):
            html = df.to_html(index=False, escape=False)
        display(HTML(html))

@dclong
Copy link
Author

dclong commented Sep 17, 2018

For example, I want to have background gradient colors for 2 columns Ctrl and Test in a DataFrame, but the background gradient colors are decided according to the difference of the 2 columns. I achieved it as below.

def bg_grad(s, m, M, cmap='PuBu', low=0, high=0):
    rng = M - m
    norm = colors.Normalize(m - (rng * low), M + (rng * high))
    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]


lift = (df.Test - df.Ctrl) / df.Ctrl 
df.style.apply(lambda _: bg_grad(lift, 
    m=-lift.max(),
    M=lift.max(),
    cmap='RdYlGn',
))

image

@TomAugspurger
Copy link
Contributor

It's not clear to me what the API would look like. IIRC, there's nothing else in Styler where a property for a column is computed by the values in another array.

It is unfortunate that you needed to duplicate the code in Styler._background_gradient with you bg_grad function.

@jbrockmendel jbrockmendel added the Styler conditional formatting using DataFrame.style label Dec 11, 2019
@attack68
Copy link
Contributor

I think this is fairly easy to deal with with an introduction of a new argument. gmap or gradient map just overrides the data in the input series with the specifically provided gmap. That way you can style a whole dataframe along an axis using only one row (or column), and achieve the OP's intent. eg.

df.style.background_gradient(cmap='PuBu', gmap=df['col1'], axis=0)

I'll get around to this at some point..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
API Design Enhancement IO HTML read_html, to_html, Styler.apply, Styler.applymap Output-Formatting __repr__ of pandas objects, to_string Styler conditional formatting using DataFrame.style
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants