Pandas: Conditionally styling by HTML classes

Created on 15 Sep 2016  路  4Comments  路  Source: pandas-dev/pandas

Currently the DataFrame.Styler class provides for adding of css key/value attribute pairs. But it is sometimes preferable to add a HTML class to a cell instead, and then let the styling be done by an external css file.

As an example consider the following DataFrame:

df = pd.DataFrame([[1,2],
                  [-5,1]],
                  columns=['A','B'])

As an example, we would like to attach the class "negative" to the -5 and receive the following HTML:

<html><table border="1" class="dataframe">
  <thead>
    <tr style="text-align: right;">
      <th></th>
      <th>A</th>
      <th>B</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>0</th>
      <td>1</td>
      <td>2</td>
    </tr>
    <tr>
      <th>1</th>
      <td class="negative">-5</td>
      <td>1</td>
    </tr>
  </tbody>
</table></html>

Regarding how to implement this, here are a couple of ideas:

  1. Add a flag by_class to apply() and applymap() that instructs the styler that the "function" will return a classes instead of css strings.
  2. Add new functions apply_class() and applymap_class().
  3. Create a new class StyleClass() and use isinstance(ret,StyleClass) to determine whether to modify the style directly or by adding additional classes.

IMO, I believe that it would be a better interface of styler that apply and applymap were to return classes by default and then optionally provide a css style sheet that can be resolved when turning the style into html. Such an approach would also be easier to adapt to additional backends, e.g. LaTeX. The disadvantage though is that it would break backwards compatibility, and that it would make styling for iPython (the main usecase?) more complicated.

Enhancement IO HTML Output-Formatting

Most helpful comment

This should be terribly difficult to add, if anyone is interested in implementing it.

I'd prefer the apply_class method, over adding arguments to apply / applymap.

All 4 comments

I think this would be a fantastic addition.

I think either the by_class arg/kwarg in apply() and applymap approach or the new apply_class()/applymap_class() approach make good sense and seem very intuitive.

This should be terribly difficult to add, if anyone is interested in implementing it.

I'd prefer the apply_class method, over adding arguments to apply / applymap.

I agree with the above and think it would be very useful in general.

I use styling quite extensibly to add formatting logic to user-dynamic tables, and that aspect works well, but it requires some quite extensive coding to get it working efficiently for large tables.

On thing that would be handy is a set_column_styles() method.

I currently have this workaround

table_styles = # some existing setup styles
column_styles = get_column_styles(df, props, subset)
s.set_table_styles(table_styles.update(column_styles))

def set_column_styles(df, props, subset=None):
    if subset is None:
         subset = df.columns
    styles = list()
    for col in subset:
        styles.append({'selector': '.col' + str(df.columns.get_loc(col)), 'props': props})
     return styles

I don't really have the ability yet to try and integrate this and do the github push, but it would be great if the above could be redefined as:

s.set_table_styles(table_styles)
s.set_column_styles(subset, props)

@Dov - I guess you forgot that you opened this issue long time ago :)
I suggest adding something like these:
.add_cell_class(classes, axis, subset)
.add_row_class(classes, index)
.add_column_class(classes, columns)

I will get back here when I finish adding these functions.


I still think it would be nice to have these functions but the work-around using set_table_styles kinda works.

Now I am not sure if I am going to add the functions or not...

Was this page helpful?
0 / 5 - 0 ratings