You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bokeh HoverTool仅显示单个tooltip问题求助

Got it, let's fix that multiple tooltip issue you're seeing with Bokeh's HoverTool! The problem here is that you've added three separate vbar glyphs to your plot, and the HoverTool is triggering on each one individually—even with mode='vline', it's picking up every glyph that intersects the vertical line and showing a tooltip for each.

Here are two straightforward ways to get that single-tooltip behavior you want:

Option 1: Explicitly tell HoverTool which glyph to target

You can assign your vbar glyphs to variables, then set the renderers parameter on the HoverTool to only one of them. Since all your glyphs use the same ColumnDataSource, the tooltip will still pull all the relevant data (IN, OUT, STOCK, DT) from the source, but only show once.

Modify your code like this:

from bokeh.models import (HoverTool, ColumnDataSource, Title, DatetimeTickFormatter)
import pandas as pd
from bokeh.io import show, output_file
from bokeh.plotting import figure

def assembly_chart(df, complements):
    """function to assembly the chart"""
    output_file("movigrama_chart.html")
    source = ColumnDataSource(df)
    p = figure(x_axis_type='datetime', x_axis_label='days of moviment', y_axis_label='unities movimented', plot_width=1230, plot_height=500, active_scroll='wheel_zoom')
    
    # Assign each vbar to a variable
    stock_bar = p.vbar(x='DT', bottom=0, top='STOCK', width=pd.Timedelta(days=1), fill_alpha=0.4, color='#99d8c9', source=source)
    out_bar = p.vbar(x='DT', bottom=0, top='SOMA_SAI', width=pd.Timedelta(days=1), fill_alpha=0.8, color='crimson', source=source)
    in_bar = p.vbar(x='DT', bottom=0, top='SOMA_ENTRA', width=pd.Timedelta(days=1), fill_alpha=0.8, color='seagreen', source=source)
    
    # Keep all your existing plot styling code here
    p.add_layout(Title(text=complements['warehouse'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above')
    p.add_layout(Title(text=complements['product'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above')
    p.add_layout(Title(text='Movigrama Endicon', text_font='helvetica', text_font_size='16pt', text_color='orangered', text_alpha=0.9, align='center', text_font_style="bold"), 'above')
    p.x_range.range_padding = 0.1
    p.y_range.range_padding = 0.1
    p.outline_line_width = 4
    p.outline_line_alpha = 0.1
    p.outline_line_color = 'orangered'
    p.axis.major_label_text_color = 'gray'
    p.axis.major_label_text_font_style = 'bold'
    p.axis.axis_label_text_color = 'gray'
    p.axis.axis_label_text_font_style = 'bold'
    p.axis.major_tick_out = 10
    p.axis.minor_tick_in = -3
    p.axis.minor_tick_out = 6
    p.axis.minor_tick_line_color = 'gray'
    p.xaxis.formatter = DatetimeTickFormatter(
        days=['%d/%m'],
        months=['%m/%Y'],
        years=['%Y'])
    
    # Configure HoverTool to target only one glyph
    hover = HoverTool()
    hover.mode = 'vline' # activate hover by vertical line
    hover.tooltips = [("IN", "@SOMA_ENTRA"), ("OUT", "@SOMA_SAI"), ("STOCK", "@STOCK"), ("DT", "@DT{%d/%m/%Y}")]
    hover.formatters = {"DT": 'datetime'}
    # Only target one glyph (any will work since they share the same data source)
    hover.renderers = [stock_bar]
    p.add_tools(hover)
    show(p)

Option 2: Add a hidden dummy glyph to trigger the tooltip

If you don't want to tie the tooltip to a specific visible bar, you can add an invisible glyph (like a circle with size 0) that covers the x-range, and set the HoverTool to only trigger on that. This ensures the tooltip shows exactly once per vertical line, regardless of the visible bars:

from bokeh.models import (HoverTool, ColumnDataSource, Title, DatetimeTickFormatter)
import pandas as pd
from bokeh.io import show, output_file
from bokeh.plotting import figure

def assembly_chart(df, complements):
    """function to assembly the chart"""
    output_file("movigrama_chart.html")
    source = ColumnDataSource(df)
    p = figure(x_axis_type='datetime', x_axis_label='days of moviment', y_axis_label='unities movimented', plot_width=1230, plot_height=500, active_scroll='wheel_zoom')
    
    # Add invisible dummy glyph to trigger tooltip
    dummy = p.circle(x='DT', y=0, size=0, source=source)
    
    # Your existing vbar code
    p.vbar(x='DT', bottom=0, top='STOCK', width=pd.Timedelta(days=1), fill_alpha=0.4, color='#99d8c9', source=source)
    p.vbar(x='DT', bottom=0, top='SOMA_SAI', width=pd.Timedelta(days=1), fill_alpha=0.8, color='crimson', source=source)
    p.vbar(x='DT', bottom=0, top='SOMA_ENTRA', width=pd.Timedelta(days=1), fill_alpha=0.8, color='seagreen', source=source)
    
    # Keep all your existing plot styling code here
    p.add_layout(Title(text=complements['warehouse'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above')
    p.add_layout(Title(text=complements['product'], text_font='helvetica', text_font_size='10pt', text_color='orangered', text_alpha=0.5, align='center', text_font_style="italic"), 'above')
    p.add_layout(Title(text='Movigrama Endicon', text_font='helvetica', text_font_size='16pt', text_color='orangered', text_alpha=0.9, align='center', text_font_style="bold"), 'above')
    p.x_range.range_padding = 0.1
    p.y_range.range_padding = 0.1
    p.outline_line_width = 4
    p.outline_line_alpha = 0.1
    p.outline_line_color = 'orangered'
    p.axis.major_label_text_color = 'gray'
    p.axis.major_label_text_font_style = 'bold'
    p.axis.axis_label_text_color = 'gray'
    p.axis.axis_label_text_font_style = 'bold'
    p.axis.major_tick_out = 10
    p.axis.minor_tick_in = -3
    p.axis.minor_tick_out = 6
    p.axis.minor_tick_line_color = 'gray'
    p.xaxis.formatter = DatetimeTickFormatter(
        days=['%d/%m'],
        months=['%m/%Y'],
        years=['%Y'])
    
    # Configure HoverTool to use the dummy glyph
    hover = HoverTool()
    hover.mode = 'vline'
    hover.tooltips = [("IN", "@SOMA_ENTRA"), ("OUT", "@SOMA_SAI"), ("STOCK", "@STOCK"), ("DT", "@DT{%d/%m/%Y}")]
    hover.formatters = {"DT": 'datetime'}
    hover.renderers = [dummy]
    p.add_tools(hover)
    show(p)

Why this works:

By default, HoverTool listens to all renderers in the plot. When you set renderers to a single glyph, it only triggers that one tooltip—since all your glyphs share the same ColumnDataSource, the tooltip still pulls all the data points for the current x-value (DT) from the source, giving you all the info you need in one place.

Either approach will give you that clean single-tooltip look you're aiming for with the vertical line mode.

内容的提问来源于stack exchange,提问作者Arnold Souza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:53:32