Skip to content
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

Please add tooltips to panes and widgets #1298

Open
MarcSkovMadsen opened this issue Apr 24, 2020 · 8 comments
Open

Please add tooltips to panes and widgets #1298

MarcSkovMadsen opened this issue Apr 24, 2020 · 8 comments
Assignees
Labels
bokeh Request is for change in bokeh type: enhancement Minor feature or improvement to an existing feature
Milestone

Comments

@MarcSkovMadsen
Copy link
Collaborator

From time to time I would really like to show a tooltip to the user. It could be on a button, an image or something third.

It's also requested by this post on discourse https://discourse.holoviz.org/t/is-it-possible-to-include-hover-information-over-a-pane/545

@MarcSkovMadsen MarcSkovMadsen added the TRIAGE Default label for untriaged issues label Apr 24, 2020
@maximlt
Copy link
Member

maximlt commented Apr 24, 2020

Yes, that's really a classic element of a UI that is missing.

@philippjfr philippjfr added type: enhancement Minor feature or improvement to an existing feature and removed TRIAGE Default label for untriaged issues labels May 19, 2020
@kcpevey kcpevey added this to the v0.10.0 milestone Aug 3, 2020
@philippjfr philippjfr added the bokeh Request is for change in bokeh label Aug 23, 2020
@philippjfr philippjfr modified the milestones: v0.10.0, next Aug 23, 2020
@philippjfr philippjfr modified the milestones: next, v0.12.0 Jun 29, 2021
@philippjfr philippjfr modified the milestones: next, 0.13.0 Aug 12, 2021
@philippjfr philippjfr modified the milestones: v0.13.0, Wishlist Feb 14, 2022
@philippjfr philippjfr modified the milestones: Wishlist, v1.0.0 Aug 13, 2022
@sdc50
Copy link
Contributor

sdc50 commented Feb 1, 2023

@philippjfr it looks like tooltips are supported in Bokeh 3. Do you know if Panel will also support them once it's compatible with Bokeh 3.x?

@philippjfr
Copy link
Member

Yep, it's already implemented on branch-1.0, unfortunately it is not yet implemented for all widgets.

@hoxbro hoxbro self-assigned this Mar 20, 2023
@philippjfr philippjfr modified the milestones: v1.0.0, v1.x May 8, 2023
@hoxbro
Copy link
Member

hoxbro commented May 17, 2023

The current status of description support for widgets is shown in the table below. I think a handful more can be checked off by giving StaticText a description and using it for composite sliders like the editable sliders.

Type Support description
ArrayInput ✔️
AutocompleteInput ✔️
Button ✔️
CheckBoxGroup
CheckButtonGroup
Checkbox
CodeEditor
ColorPicker ✔️
CrossSelector ✔️
DataFrame
DatePicker ✔️
DateRangeSlider
DateSlider
DatetimeInput ✔️
DatetimePicker ✔️
DatetimeRangeInput
DatetimeRangePicker ✔️
DatetimeRangeSlider
DiscretePlayer
DiscreteSlider
EditableFloatSlider
EditableIntSlider
EditableRangeSlider
FileDownload ✔️
FileInput ✔️
FileSelector
FloatInput ✔️
FloatSlider
IntInput ✔️
IntRangeSlider
IntSlider
JSONEditor
LiteralInput ✔️
MenuButton
MultiChoice ✔️
MultiSelect ✔️
NumberInput ✔️
PasswordInput ✔️
Player
RadioBoxGroup
RadioButtonGroup
RangeSlider
Select ✔️
Spinner ✔️
StaticText
Tabulator
TextAreaInput ✔️
TextEditor
TextInput ✔️
Toggle
ToggleGroup
VideoStream
Code used
import datetime as dt

import pandas as pd
import panel as pn
from panel.widgets import *
from panel.widgets import __all__ as wlist
from panel.widgets.indicators import __all__ as ilist

pn.extension("codeeditor", "jsoneditor", "tabulator", "texteditor")  # terminal

o = {"description": "Test"}
oo = dict(**o, options=list("ABC"))
do = dict(**o, start=dt.datetime(2020, 1, 1), end=dt.datetime(2020, 1, 2))
df = dict(**o, value=pd.DataFrame(range(10)))

widgets = (
    ArrayInput(name="ArrayInput", **o),
    AutocompleteInput(name="AutocompleteInput", **o),
    Button(name="Button", **o),
    Checkbox(name="Checkbox", **o),
    CheckBoxGroup(name="CheckBoxGroup", **oo),
    CheckButtonGroup(name="CheckButtonGroup", **oo),
    CodeEditor(name="CodeEditor", **o),
    ColorPicker(name="ColorPicker", **o),
    CrossSelector(name="CrossSelector", **o),
    DataFrame(name="DataFrame", **df),
    DatePicker(name="DatePicker", **o),
    DateRangeSlider(name="DateRangeSlider", **do),
    DatetimePicker(name="DatetimePicker", **do),
    DatetimeRangeSlider(name="DatetimeRangeSlider", **do),
    DateSlider(name="DateSlider", **do),
    DatetimeInput(name="DatetimeInput", **do),
    DatetimeRangeInput(name="DatetimeRangeInput", **do),
    StaticText(name="StaticText", value="Test", **o),
    DatetimeRangePicker(name="DatetimeRangePicker", **do),
    # Debugger(name="Debugger", **o),
    DiscretePlayer(name="DiscretePlayer", **o),
    DiscreteSlider(name="DiscreteSlider", **oo),
    EditableFloatSlider(name="EditableFloatSlider", **o),
    EditableIntSlider(name="EditableIntSlider", **o),
    EditableRangeSlider(name="EditableRangeSlider", **o),
    FileDownload(name="FileDownload", **o),
    FileInput(name="FileInput", **o),
    FileSelector(name="FileSelector", **o),
    FloatInput(name="FloatInput", **o),
    FloatSlider(name="FloatSlider", **o),
    IntInput(name="IntInput", **o),
    IntRangeSlider(name="IntRangeSlider", **o),
    IntSlider(name="IntSlider", **o),
    JSONEditor(name="JSONEditor", **o),
    LiteralInput(name="LiteralInput", **o),
    MenuButton(name="MenuButton", **o),
    MultiChoice(name="MultiChoice", **o),
    MultiSelect(name="MultiSelect", **o),
    NumberInput(name="NumberInput", **o),
    PasswordInput(name="PasswordInput", **o),
    Player(name="Player", **o),
    RadioBoxGroup(name="RadioBoxGroup", **oo),
    RadioButtonGroup(name="RadioButtonGroup", **oo),
    RangeSlider(name="RangeSlider", **o),
    Select(name="Select", **o),
    Spinner(name="Spinner", **o),
    Tabulator(name="Tabulator", **df),
    # Terminal(name="Terminal", **o),
    TextAreaInput(name="TextAreaInput", **o),
    TextEditor(name="TextEditor", **o),
    TextInput(name="TextInput", **o),
    Toggle(name="Toggle", **o),
    ToggleGroup(name="ToggleGroup", **oo),
    VideoStream(name="VideoStream", **o),
)

widgets = sorted(widgets, key=lambda x: x.name)

layout = []
for w in widgets:
    info = f"<b>{w.name}</b><br>Description: {'description' in w.param}"
    l = pn.Row(pn.pane.HTML(info, width=300), w)
    layout += [l, pn.layout.Divider()]

pn.Column(*layout)

# Cell 2 - Not included
print(set(wlist) - set(ilist) - set(w.name for w in widgets))

# Cell 3 - Generate table
for w in widgets:
    print(f"|{w.name}\t|{':heavy_check_mark:' if 'description' in w.param else ':x:'}|")

Not included:

  • Debugger / Terminal because it Terminal does not work with inline in Notebook.
  • Ace same as CodeEditor.
  • Others are not relevant, as far as I can see.
{'Ace',
 'CompositeWidget',
 'Debugger',
 'Grammar',
 'GrammarList',
 'SpeechToText',
 'Terminal',
 'TextToSpeech',
 'Utterance',
 'Voice',
 'Widget'}

@MarcSkovMadsen
Copy link
Collaborator Author

MarcSkovMadsen commented May 17, 2023

A tooltip on the button would make a big difference. Clicking the button often have the biggest impact, so it's nice to know beforehand what it's does.

It should probably not have the icon though.

@johann-petrak
Copy link

Is there any hope to make showing the "description" parameter as a Tooltip for DateRangeSlider, FloatSlider, CheckBoxGroup?
Is there a workaround for how to do it myself until then?

@hoxbro
Copy link
Member

hoxbro commented May 14, 2024

I have run my code again, and Button now has a description on hover pn.widgets.Button(name='Test', description='Text')
image

A way to add tooltips to widgets that do not have description is to use pn.widgets.TooltipIcon and play a bit around with margins.

image

pn.Row(
    pn.widgets.DatetimeRangeSlider(name="DatetimeRangeSlider", **do),
    pn.widgets.TooltipIcon(value="Test", styles={"margin-top": "20px"}),
)
Type Support description
ArrayInput ✔️
AutocompleteInput ✔️
Button ✔️
CheckBoxGroup
CheckButtonGroup ✔️
Checkbox
CodeEditor
ColorPicker ✔️
CrossSelector ✔️
DataFrame
DatePicker ✔️
DateRangeSlider
DateSlider
DatetimeInput ✔️
DatetimePicker ✔️
DatetimeRangeInput
DatetimeRangePicker ✔️
DatetimeRangeSlider
DiscretePlayer
DiscreteSlider
EditableFloatSlider
EditableIntSlider
EditableRangeSlider
FileDownload ✔️
FileInput ✔️
FileSelector
FloatInput ✔️
FloatSlider
IntInput ✔️
IntRangeSlider
IntSlider
JSONEditor
LiteralInput ✔️
MenuButton
MultiChoice ✔️
MultiSelect ✔️
NumberInput ✔️
PasswordInput ✔️
Player
RadioBoxGroup
RadioButtonGroup ✔️
RangeSlider
Select ✔️
Spinner ✔️
StaticText
Tabulator
TextAreaInput ✔️
TextEditor
TextInput ✔️
Toggle
ToggleGroup ✔️
VideoStream
Code
import datetime as dt

import pandas as pd
import panel as pn
from panel.widgets import *
from panel.widgets import __all__ as wlist
from panel.widgets.indicators import __all__ as ilist

pn.extension("codeeditor", "jsoneditor", "tabulator", "texteditor")  # terminal

o = {}
oo = dict(**o, options=list("ABC"))
do = dict(**o, start=dt.datetime(2020, 1, 1), end=dt.datetime(2020, 1, 2))
df = dict(**o, value=pd.DataFrame(range(10)))

widgets = (
    ArrayInput(name="ArrayInput", **o),
    AutocompleteInput(name="AutocompleteInput", **o),
    Button(name="Button", **o),
    Checkbox(name="Checkbox", **o),
    CheckBoxGroup(name="CheckBoxGroup", **oo),
    CheckButtonGroup(name="CheckButtonGroup", **oo),
    CodeEditor(name="CodeEditor", **o),
    ColorPicker(name="ColorPicker", **o),
    CrossSelector(name="CrossSelector", **o),
    DataFrame(name="DataFrame", **df),
    DatePicker(name="DatePicker", **o),
    DateRangeSlider(name="DateRangeSlider", **do),
    DatetimePicker(name="DatetimePicker", **do),
    DatetimeRangeSlider(name="DatetimeRangeSlider", **do),
    DateSlider(name="DateSlider", **do),
    DatetimeInput(name="DatetimeInput", **do),
    DatetimeRangeInput(name="DatetimeRangeInput", **do),
    StaticText(name="StaticText", value="Test", **o),
    DatetimeRangePicker(name="DatetimeRangePicker", **do),
    # Debugger(name="Debugger", **o),
    DiscretePlayer(name="DiscretePlayer", **o),
    DiscreteSlider(name="DiscreteSlider", **oo),
    EditableFloatSlider(name="EditableFloatSlider", **o),
    EditableIntSlider(name="EditableIntSlider", **o),
    EditableRangeSlider(name="EditableRangeSlider", **o),
    FileDownload(name="FileDownload", **o),
    FileInput(name="FileInput", **o),
    FileSelector(name="FileSelector", **o),
    FloatInput(name="FloatInput", **o),
    FloatSlider(name="FloatSlider", **o),
    IntInput(name="IntInput", **o),
    IntRangeSlider(name="IntRangeSlider", **o),
    IntSlider(name="IntSlider", **o),
    JSONEditor(name="JSONEditor", **o),
    LiteralInput(name="LiteralInput", **o),
    MenuButton(name="MenuButton", **o),
    MultiChoice(name="MultiChoice", **o),
    MultiSelect(name="MultiSelect", **o),
    NumberInput(name="NumberInput", **o),
    PasswordInput(name="PasswordInput", **o),
    Player(name="Player", **o),
    RadioBoxGroup(name="RadioBoxGroup", **oo),
    RadioButtonGroup(name="RadioButtonGroup", **oo),
    RangeSlider(name="RangeSlider", **o),
    Select(name="Select", **o),
    Spinner(name="Spinner", **o),
    Tabulator(name="Tabulator", **df),
    # Terminal(name="Terminal", **o),
    TextAreaInput(name="TextAreaInput", **o),
    TextEditor(name="TextEditor", **o),
    TextInput(name="TextInput", **o),
    Toggle(name="Toggle", **o),
    ToggleGroup(name="ToggleGroup", **oo),
    VideoStream(name="VideoStream", **o),
)

widgets = sorted(widgets, key=lambda x: x.name)

layout = []
for w in widgets:
    info = f"<b>{w.name}</b><br>Description: {'description' in w.param}"
    l = pn.Row(pn.pane.HTML(info, width=300), w)
    layout += [l, pn.layout.Divider()]

pn.Column(*layout)

# Cell 2 - Not included
print(set(wlist) - set(ilist) - set(w.name for w in widgets))

# Cell 3 - Generate table
print("| Type | Support description |")
print("| --- | --- |")

for w in widgets:
    print(f"|{w.name}\t|{':heavy_check_mark:' if 'description' in w.param else ':x:'}|")

@johann-petrak
Copy link

johann-petrak commented May 14, 2024

Thanks!

However, when I try to show a tooltip for the Button widget it simply does not work. I am using panel version 1.2.3.

The problem I initially encountered with putting a TooltipIcon into the same row is that it is not shown after the Widget name, like for other widgets. If I just allow for the space the icon needs, and the widget is in a row inside of a WidgetBox, then by default no tooltip is shown for TooltipIcons which are at the far right of the row, because, the tooltip is always shown to the right of the icon, and not automatically moved to the left in case there is no space to the right.

However this can be solved by using a bokeh Tooltip inside of the TooltipIcon and specifying position "left":

date_range_tt = pn.widgets.TooltipIcon(
        value=Tooltip(
            content="the content .... ",
            position="left",),
        styles={"margin-top": "20px"},
        width=10,
    )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bokeh Request is for change in bokeh type: enhancement Minor feature or improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

7 participants