使用 HoverTool() 工具时仅显示一个工具提示

Posted

技术标签:

【中文标题】使用 HoverTool() 工具时仅显示一个工具提示【英文标题】:Displaying only one tooltip when using the HoverTool() tool 【发布时间】:2017-06-02 00:58:04 【问题描述】:

我在 Bokeh 中绘制了很多点,我已将 HoverTool 添加到图形的工具列表中,以便鼠标在靠近字形时显示鼠标的 x,y 坐标。

当鼠标靠近一组紧密排列在一起的字形时,我会得到与字形一样多的工具提示。我只想要一个工具提示,即最接近的字形之一。这不仅仅是一个演示细节,因为在很多方面都会产生这样的结果:

与绘图的交互缓慢,在生成所有工具提示时浏览器卡住 在一个很长的工具提示中,其中相同的信息重复的次数与光标附近的字形一样多

下面是一个示例,其中包含复制行为的代码:

import numpy.random
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import HoverTool
output_notebook()

hover = HoverTool()
hover.tooltips = [("(x,y)", "($x, $y)")]

x = numpy.random.randn(500)
y = numpy.random.randn(500)

p = figure(tools=[hover])
p.circle(x,y, color='red', size=14, alpha=0.4)

show(p)

【问题讨论】:

有一个开放的 PR 可以为悬停工具提示首选项添加改进的基于策略的选项,这些选项将进入 0.12 版本。 对此有何更新,即如何限制 HoverTool 中显示的数据点数量? 恐怕old issue 还在打开 【参考方案1】:

我遇到了类似的问题,并使用自定义工具提示提出了解决方案。我在顶部插入了一个样式标签,它只显示.bk-tooltip 类下的第一个子div,这是第一个工具提示。

这是一个工作示例:

from bokeh.plotting import figure, show
from bokeh.models import HoverTool, Range1d

custom_hover = HoverTool()

custom_hover.tooltips = """
    <style>
        .bk-tooltip>div:not(:first-child) display:none;
    </style>

    <b>X: </b> @x <br>
    <b>Y: </b> @y
"""

p = figure(tools=[custom_hover]) #Custom behavior
#p = figure(tools=['hover'])  #Default behavior 

p.circle(x=[0.75,0.75,1.25,1.25], y=[0.75,1.25,0.75,1.25], size=230, color='red', fill_alpha=0.2)
p.y_range = Range1d(0,2)
p.x_range = Range1d(0,2)

show(p)

这是一种 hacky 解决方案,但它适用于 Safari、Firefox 和 Chrome。我认为他们会推出更长期的solution soon。

【讨论】:

通过更新存在一个问题,即添加一个用户可配置的挂钩以限制计划于今年晚些时候发布的 2.0 版的命中测试结果github.com/bokeh/bokeh/issues/9087【参考方案2】:

发布的 CSS 解决方案不适用于 Bokeh 2.2.2。以下是:

    div.bk-tooltip.bk-right>div.bk>div:not(:first-child) 
        display:none !important;
    
    div.bk-tooltip.bk-left>div.bk>div:not(:first-child) 
        display:none !important;
    

这不是最优雅的解决方案,但它结束了我对垂直堆叠的 40 个工具提示的挫败感。这是使用自定义 CSS 的网站上的嵌入式图表实现的。

【讨论】:

【参考方案3】:

感谢 pst0101 提供了一个出色的答案,它在 2018 年仍然有效。由于开发人员看起来他们不会很快得到这个答案,我想我会添加一个关于如何制作的简短说明pst 的解决方案适用于基本/标准工具提示,因为我自己修改它需要反复试验。

由于代码值一千字,这里是我自己的精简版:

hoverToolTip = [
        ("Item" + nbs + "Number/s", "@ItemNumber"),
        ("Description/s", "@Descriptionsafe"),
        ("Virtual" + nbs + "Item", """@IsVirtual
        <style>
            .bk-tooltip>div:not(:first-child) display:none;
        </style>""")
]

hover = HoverTool(tooltips=hoverToolTip)

nbs 包含一个不间断空格的 unicode 字符串,并且 safe 告诉散景从我的描述字段中呈现 html(特别是换行符)是安全的。与问题无关,但很有用,因为悬停有一些损坏的换行行为,其中包含许多人需要处理的长文本。

【讨论】:

优先级很多,开发者很少。让更多人参与进来是让事情更快完成的唯一方法 嘿,我不是在批评。但是由于我没有时间或技能为存储库做出有意义的贡献,我认为下一个最好的事情是贡献我的 hacky 变通方法来解决堆栈溢出问题。 我无法让它工作。 HoverTool 的行为是否发生了变化?我正在使用 Bokeh 2.2.3。 我也无法正常工作。此外,@ChrisBrace 你不能在你的代码 sn-p 中添加一个 nbs 的声明吗?这将使示例更清晰。【参考方案4】:

我知道这可能已经过时了,但现在有一种更好的方法可以做到这一点。更好的是,我的意思是这种方法可以扩展到任何阈值数(如 4 个工具提示)。 所以,步骤:

    定义一个CustomJSHover。您可以在其中编写 JS 代码。此外,您可以访问当前悬停的所有索引。在代码中,您应该设置阈值并删除其他索引(将删除本地副本)。在此之后,您应该检查是否可以在该列表中找到当前索引。如果找到,则返回一个空字符串,否则 - 返回一个隐藏单词的字符串(将在 html 解析期间使用)

     custom_hov = CustomJSHover(code="""
         special_vars.indices = special_vars.indices.slice(0,4)
         if (special_vars.indices.indexOf(special_vars.index) >= 0)
         
             return " "
         
         else
         
             return " hidden "
         
     """)
    

i)在您的绘图中添加一个 HoverTool 并定义一个 html 工具提示 + 定义一个格式化程序。 ii) 对于 html 工具提示,向主 div 添加一个变量,该变量将映射到我们的 CustomJSHover。让它成为y。在我们的例子中,它看起来像这样

。 (对于映射变量,custom 是强制性的)诀窍是,由于我们的 CustomJSHover 将在索引不在索引中时返回 'hidden',因此整个工具提示将变为隐藏。

iii)对于格式化程序,您应该添加一个从您的 var (@y) 到 CustomJSHover 的 dict 映射。在我们的例子中:formatters='@y':custom_hov

figure.add_tools(HoverTool(tooltips=("""  
<div @ycustom>
    <div>
        <img src='@image' alt='@image' style='float: top; width:128px;height:128px; margin: 5px 5px 5px 5px'/>
    </div>
    <div>
        <span style='font-size: 16px; color: #224499'>Some text</span>
        <span style='font-size: 18px'>@dataFrameText</span>
    </div>
</div>
"""), formatters='@y':custom_hov))

就是这样。现在,只会显示 4 个工具提示。您可以将 4 更改为任意数字

【讨论】:

【参考方案5】:

上面的解决方案很好。特别感谢 Chris Brace。 我在时间序列数据中遇到了工具提示问题,其中数据点的数量非常多并且无法进行二次抽样。由于圆圈的紧密性,显示了多个工具提示。 我需要将工具提示分别添加到与 pandas DataFrame 中的特定列相对应的多个字形中。因此,我将 Chris Brace 的解决方案扩展如下(应用程序要求在执行期间动态选择列名;不幸的是,这里很难提供完整的代码,但我即使这个子集也会对某人有所帮助):

renderer = data_plot.circle(x=my_x_axis_col_name, y=my_y_axis_col_name, source=<my_data_source>, size=2)
hover_var = '@'+my_y_axis_col_name+"<style>.bk-tooltip>div:not(:first-child) display:none;</style>"
hover = HoverTool(renderers=[renderer], tooltips=[(my_y_axis_col_name, hover_var)])

Bokeh 的未来版本中预计会有更好的解决方案。恳请 Bokeh 开发人员在用户指南中包含一个代码 sn-p 以及可用时。

【讨论】:

我无法让它工作。 HoverTool 的行为是否发生了变化?我正在使用 Bokeh 2.2.3。【参考方案6】:

感谢 @bachree 更新的 CSS 代码,该代码适用于 2.3.0。 使用该代码,您可以简单地添加以下行,例如在您的导入下方,到您的 jupyter 笔记本:

### your imports
from IPython.core.display import display, HTML
from bokeh.plotting import figure, output_notebook, show
from bokeh.models import HoverTool
output_notebook()
### end of imports

# fix bokeh showing multiple values on hover in notebooks
display(HTML("""
<style>
    div.bk-tooltip.bk-right>div.bk>div:not(:first-child) 
        display:none !important;
    
    div.bk-tooltip.bk-left>div.bk>div:not(:first-child) 
        display:none !important;
    
</style>
"""))

### your code

在撰写本文时,散景方面没有任何进展,这似乎仍然是解决此问题的“方法”。

【讨论】:

HTMLdisplay从何而来? jupyter notebook 已经为我提供了这些功能/类。

以上是关于使用 HoverTool() 工具时仅显示一个工具提示的主要内容,如果未能解决你的问题,请参考以下文章

具有半透明背景的 Python Bokeh Hovertool

如何使用HoverTool显示Bokeh中两个不同字形的两点之间的差异?

带有 HoverTool 的散景线图

Python Bokeh HoverTool 格式化程序错误:“HoverTool 的意外属性‘格式化程序’”

Python Bokeh - HoverTool:图形的坐标而不是数据点

DialogFragment:创建片段时仅显示一次动画