It seems to only show the repr
from bokeh.models.ui import SVGIcon, TablerIcon
import panel as pn
pn.extension()
pn.panel(TablerIcon("heart", size="1.2em"))
It seems to only show the repr
from bokeh.models.ui import SVGIcon, TablerIcon
import panel as pn
pn.extension()
pn.panel(TablerIcon("heart", size="1.2em"))
Hi @ahuang11,
Seems like it’s not supported, I tried something like
from bokeh.models import SVGIcon, TablerIcon
import panel as pn
pn.extension()
bokeh_pane = pn.pane.Bokeh()
bokeh_pane
from bokeh.models import Div
bokeh_pane.object = Div(text='<h2>This text replaced the pie chart</h2>')
The above works but then when I try with the TablerIcon (I have no idea if it is right to try and add it to the object) but I get the following error which may help:
from bokeh.models.ui import SVGIcon, TablerIcon
import panel as pn
pn.extension()
bokeh_pane = pn.pane.Bokeh()
bokeh_pane
bokeh_pane.object = TablerIcon("heart", size="1.2em")
ValueError: failed to validate Row(id=‘a660a70d-921b-4de2-88b6-99f3ecb98f06’, …).children: expected an element of List(Instance(UIElement)), got seq with invalid items [TablerIcon(id=‘71588166-442a-454b-bb42-eddf2cc1b5a3’, …)]
Yeah I was wondering how it gets rendered in Button.
have you tried wrapping it into a bokeh column?
Good idea! I suppose it doesn’t work.
from bokeh.models.ui import SVGIcon, TablerIcon
from bokeh.layouts import Column
import panel as pn
pn.extension()
pn.panel(Column(TablerIcon("heart", size="1.2em")))
ValueError: failed to validate Column(id='eaaf0083-4d13-4a00-9710-365da722ab15', ...).children: expected an element of List(Instance(UIElement)), got seq with invalid items [TablerIcon(id='1d34a545-4d6e-4b9d-add9-841d092211df', ...)
I came across this message in the bokeh docs
from bokeh.models.ui import SVGIcon, TablerIcon
from bokeh.models import Button
import panel as pn
pn.extension()
icon = list()
icon = TablerIcon("heart",size="1.2em")
button = Button(label="Foo", button_type="success", icon=icon)
pn.panel(button).show()
Thanks for investigating; it’s also possible to simply do
pn.widgets.Button(icon='heart')
or even pn.widgets.Toggle(icon='heart')
However, I don’t want it as a button. An alternative is an pn.pane.Image of the tabler icon URL.
Seems like it should be very similar to
https://panel.holoviz.org/reference/indicators/TooltipIcon.html
I see. So I suppose it needs a panel model to support it:
import param
from panel.reactive import ReactiveHTML
class ChatReaction(ReactiveHTML):
value = param.String(default="", doc="""
The alt text for the icon.""")
icon = param.String(default=None, doc="""
An icon to use when inactive. An icon name which
is loaded from https://tabler-icons.io.""")
active_icon = param.String(default=None, doc="""
An icon to use when active. An icon name which
is loaded from https://tabler-icons.io.
If this is not set, the '-filled' suffix is
added to `icon`.""")
active = param.Boolean(default=False, doc="""
Whether the reaction is active.""")
icon_size = param.String(default="10px", doc="""
The size of the icon.""")
_icon_url = param.Parameter(doc="The current displayed icon.")
_template = """
<div>
<img id="icon" alt="${value}" src="${_icon_url}"
style="width: ${icon_size}; height: ${icon_size}; cursor: pointer;"
onclick="${script('update_layout')}">
</img>
</div>
"""
_scripts = {
"render": "self.update_layout()",
"update_layout": """
const tabler_base_url = "https://tabler-icons.io/static/tabler-icons/icons-png/";
data.active = !data.active;
if (data.active && data.active_icon) {
icon.src = `${tabler_base_url}${data.active_icon}.png`;
} else if (data.active && !data.active_icon) {
icon.src = `${tabler_base_url}${data.icon}-filled.png`;
} else {
icon.src = `${tabler_base_url}${data.icon}.png`;
}
"""
}
def __init__(self, value: str, **params):
super().__init__(value=value, **params)
import panel as pn
pn.extension()
ChatReaction(value="dislike", icon="thumb-up", active_icon="thumb-down", styles={"background": "white"})
I like this implementation better;
class ChatReactionIcons(ReactiveHTML):
value = param.List(doc="The selected reactions.")
options = param.Dict(default={"favorite": "heart"}, doc="""
A key-value pair of reaction values and their corresponding tabler icon names
found on https://tabler-icons.io.""")
icon_size = param.String(default="15px", doc="""
The size of each icon.""")
icon_toggle_mapping = param.Dict(default={}, doc="""
The mapping of tabler icon names to their corresponding toggled icon names;
if not set, the toggled icon name will default to its "filled" version.""")
_icon_base_url = param.String("https://tabler-icons.io/static/tabler-icons/icons-png/")
_template = """
<div id="reactions" class="reactions">
{% for reaction, icon_name in options.items() %}
<img id="icon-{{ reaction }}" alt="{{ reaction }}"
{% if reaction in value %}
src="${_icon_base_url}{{ icon_name }}-filled.png"
{% else %}
src="${_icon_base_url}{{ icon_name }}.png"
{% endif %}
style="width: {{ icon_size }}; height: {{ icon_size }}; cursor: pointer;"
onclick="${script('update_value')}">
</img>
{% endfor %}
</div>
"""
_scripts = {
"update_value": """
const reaction = event.target.alt;
const iconName = data.options[reaction];
if (data.value.includes(reaction)) {
data.value = data.value.filter(r => r !== reaction);
event.target.src = data._icon_base_url + iconName + ".png";
} else {
data.value = [...data.value, reaction];
if (iconName in data.icon_toggled_names) {
event.target.src = data._icon_base_url + data.icon_toggled_names[iconName] + ".png";
} else {
event.target.src = data._icon_base_url + iconName + "-filled.png";
}
}
"""
}