Skip to content

[Enhancement Request] Styler support for tooltips. #21266

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
jeremysalwen opened this issue May 31, 2018 · 6 comments · Fixed by #35643
Closed

[Enhancement Request] Styler support for tooltips. #21266

jeremysalwen opened this issue May 31, 2018 · 6 comments · Fixed by #35643
Labels
Enhancement IO HTML read_html, to_html, Styler.apply, Styler.applymap Styler conditional formatting using DataFrame.style
Milestone

Comments

@jeremysalwen
Copy link

Problem description

It would be nice if pandas stlying allowed you to set a tooltip for table cells, in the same way that it allows you to set the CSS style using apply, applymap, etc.

Currently it is possible to create a hacky workaround using css-only tooltips and set_table_styles, but it adds substantial complexity to achieve something that is conceptually very simple.

Output of pd.show_versions()

[paste the output of pd.show_versions() here below this line]
pd.show_versions()

INSTALLED VERSIONS

commit: None
python: 2.7.13.final.0
python-bits: 64
OS: Linux
OS-release: 4.9.0-6-amd64
machine: x86_64
processor:
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: None.None

pandas: 0.19.2
nose: None
pip: 9.0.1
setuptools: 36.0.1
Cython: 0.28.3
numpy: 1.14.3
scipy: 0.19.1
statsmodels: 0.8.0
xarray: None
IPython: 5.1.0
sphinx: None
patsy: 0.4.1+dev
dateutil: 2.6.1
pytz: 2017.2
blosc: None
bottleneck: None
tables: 3.4.2
numexpr: 2.6.2
matplotlib: 2.0.0
openpyxl: 2.3.0
xlrd: 1.1.0
xlwt: 0.7.5
xlsxwriter: None
lxml: 4.0.0
bs4: 4.6.0
html5lib: 0.999999999
httplib2: 0.9.2
apiclient: 1.6.5
sqlalchemy: 1.1.3
pymysql: 0.6.1.None
psycopg2: None
jinja2: 2.8
boto: 2.48.0
pandas_datareader: 0.2.0

@WillAyd
Copy link
Member

WillAyd commented Jun 2, 2018

Hmm what information would you expect to appear in a tooltip?

@WillAyd WillAyd added Code Style Code style, linting, code_checks IO HTML read_html, to_html, Styler.apply, Styler.applymap labels Jun 2, 2018
@jeremysalwen
Copy link
Author

jeremysalwen commented Jun 3, 2018

I was just expecting to give an arbitrary string to display (or maybe html). The basic idea is that I am styling some cells differently to highlight them, and I'd like the tooltip to give the specific reason why that cell is highlighted in precise terms. e.g. the cell is greater than a certain threshold, and the tooltip shows the precise threshold for that cell.

@TomAugspurger
Copy link
Contributor

This seems reasonable. A full example of what you want to achieve, and a proposed API (write the docstring) would be helpful here.

@WillAyd WillAyd added the Needs Info Clarification about behavior needed to assess issue label Jun 4, 2018
@jeremysalwen
Copy link
Author

I think the most obvious implementation of the api is just copy the styling functions, but for tooltips. For example:

import pandas as pd
import numpy as np

def tooltip_max(s):
    is_max = s == s.max()
    return ['This is the largest element of {}.'.format(s.count()) if v else None for v in is_max]

def tooltip_for_invalid(val, threshold=1.5):
    if val < threshold:
        return None
    return 'Invalid value exceeds the threshold of {} by {}.'.format(threshold, val - threshold)

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.style.applytooltipmap(tooltip_for_invalid)
            .applytooltip(tooltip_max)

Where the maximum elements of a column would get a tooltip, as well as any elements over the given threshold. (Probably you would want to style these elements differently as well to make it clear that there is a tooltip, but I didn't want to complicate the example).

If this is the direction you want to go, I could write up a docstring for these functions, although it would most be just copied from the css styling functions.

@TomAugspurger
Copy link
Contributor

Seems reasonable. I would favor tooltip_apply, tooltip_applymap, to group those methods together.

@TomAugspurger TomAugspurger added Enhancement and removed Needs Info Clarification about behavior needed to assess issue labels Jun 27, 2018
@TomAugspurger TomAugspurger added this to the Next Major Release milestone Jun 27, 2018
@jbrockmendel jbrockmendel removed the Code Style Code style, linting, code_checks label Oct 16, 2019
@jbrockmendel jbrockmendel added the Styler conditional formatting using DataFrame.style label Dec 11, 2019
@attack68
Copy link
Contributor

attack68 commented Aug 8, 2020

Laying out possible scope for development here:

It is possible to create a simple tooltip by adding a html tag to any cell value that requires it. For example consider the following table:

<table><tbody>
<tr><td>1</td>
      <td>2</td></tr>
<tr><td id="T__row1_col0">3 <span class="pd-tooltip">Tooltip Text</span></td>
      <td>4</td></tr>
</tbody></table>

To make this tooltip work we need to set CSS in two places. First we need the generic pd-tooltip class which we set in table_styles, to generally hide the tooltip and determine its color and position etc.:

styler.set_table_styles([{
    'selector': ' .pd-tooltip',
    'props': [
         (visibility, hidden)
         (position, absolute)
         (z-index, 1)
         (background-color, black)
         (color, white)
         (transform: translate(-20px, -20px))
     ]}])

And secondly the individual cell will need its own selector to activate the tooltip when hovered over. I.e. the cell should have:

[{'selector': ':hover .pd-tooltip', 'props': [('visibility', 'visible')]}]

This will generate a CSS style that looks like this:

#T__row1_col0:hover .pd-tooltip {visibility: visible;}

To integrate this into the existing format I would suggest tooltip_apply and tooltip_applymap that construct a DataFrame recording either '' or <string_text> based on the applied functions for a tooltip in a specific location, utilising the already present apply and applymap functions to create the automated styles above. edit currently apply and apply map do not allow pseudo selectors, so these would have to be systematically added to the table_styles with the necessary cell id selector #T__row1_col0:hover .pd-tooltip/edit

At render time the styles will have been added prior to constructing the render dict (so that they are captured) but the addition of the HTML elements need new functionality to be inserted to the render dict just before passing to the templating engine, by looping over the data row0 col0 indentifiers and comparing with the tooltip DataFrame row and column indices.

I.e. this can be done here:

def render(self, **kwargs) -> str:
    self._compute()
    d = self._translate()
    trimmed = [x for x in d["cellstyle"] if any(any(y) for y in x["props"])]
    d["cellstyle"] = trimmed
    # <--- EDIT d['body'] in this location adding the HTML <span>
    d.update(kwargs)
    return self.template.render(**d) 

The advantage of this integration is that it is also decoupled from the rest of the code and utilises the existing architecture.

Additional functions like set_default_tooltip_class provide further flexibility for the look and feel of the tooltip.

@jreback jreback modified the milestones: Contributions Welcome, 1.3 Jan 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement IO HTML read_html, to_html, Styler.apply, Styler.applymap Styler conditional formatting using DataFrame.style
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants