HoverTool prints extra values on the graph

I want to display a tooltip whenever the cursor is vertically in line with a glyph for that I am using HoverTool but when I move cursor on the graph, in the right side it shows all index value as well shown below. How to solve this problem?

p.add_tools(HoverTool(
        tooltips = [
            ( 'index', '$index'),
            ( 'Value', '$y'),
        ],
        
    formatters={
            'index'      : 'numeral',         # use 'datetime' formatter for 'date' field
            'Value'      : 'numeral',         # use default 'numeral' formatter for other fields
    },
    
    mode='vline'
    ))```

I haven’t seen anything like that before, so we would need a complete Minimal Reproducible Example to actually run and investigate.

1 Like

I think I found what cause to that thing. In my code, when I close the “scatter_render” section HoverTool works properly but then I cannot use my selection tool on my graph. Is it a bug inside of the library or that causes because of my coding style?

import read_val as rv
import pandas as pd
from bokeh.plotting import figure,show,gridplot,output_file
from bokeh.models import ColumnDataSource,CustomJS, HoverTool


def plot1 (Value1, Value2, Value3): 
    
        dataset1       = pd.DataFrame(data={'time1':range(len(Value1)),'data1':Value1})
        dataset2       = pd.DataFrame(data={'time2':range(len(Value2)),'data2':Value2})
        dataset3       = pd.DataFrame(data={'time3':range(len(Value3)),'data3':Value3})
        
        s1          = ColumnDataSource(data=dataset1) 
        s2          = ColumnDataSource(data=dataset2)
        s3          = ColumnDataSource(data=dataset3)
        
        TOOLS       ="pan,wheel_zoom,reset,poly_select,xbox_select,lasso_select"

        p1          = figure(title = 'Plot1' ,x_axis_label = 'time'
                         , y_axis_label='Voltage (V)',plot_width=1000, plot_height=300,tools=TOOLS)
       
        p2          = figure(title = 'Plot2' ,x_axis_label = 'time'
                         , y_axis_label='Voltage (V)',plot_width=1000, plot_height=300,tools=TOOLS)
       
        p3          = figure(title = 'Plot3' ,x_axis_label = 'time'
                       , y_axis_label='Voltage (V)',plot_width=1000, plot_height=300,tools=TOOLS)
        
        p1.add_tools(HoverTool(
            tooltips = [
                ( 'index', '$index'),
                ( 'Value', '@data1'),
            ],
            
        formatters={
                'Index'      : 'numeral',         # use 'datetime' formatter for 'date' field
                'Value'      : 'numeral',         # use default 'numeral' formatter for other fields
        },
        
        mode='vline'
        ))
        
        
        
        
        line_rend1 = p1.line('time1', 'data1', color="black",legend_label="V1", line_width=1,source=s1)
        line_rend1.selection_glyph = line_rend1.glyph
        line_rend1.nonselection_glyph = line_rend1.glyph
        
        line_rend2 = p2.line('time2', 'data2',color="blue", legend_label="V2", line_width=1,source=s2)
        line_rend2.selection_glyph = line_rend2.glyph
        line_rend2.nonselection_glyph = line_rend2.glyph
        
        line_rend3 = p3.line('time3', 'data3', color="green",legend_label="V3", line_width=1,source=s3)
        line_rend3.selection_glyph = line_rend3.glyph
        line_rend3.nonselection_glyph = line_rend3.glyph
        
        """ 
        
        scatter_rend1 = p1.scatter('time1','data1',fill_alpha=0,source=s1,line_alpha=0)
        scatter_rend1.selection_glyph = scatter_rend1.glyph
        scatter_rend1.nonselection_glyph = scatter_rend1.glyph
        
        scatter_rend2 = p2.scatter('time2','data2',fill_alpha=0,source=s2,line_alpha=0)
        scatter_rend2.selection_glyph = scatter_rend2.glyph
        scatter_rend2.nonselection_glyph = scatter_rend2.glyph
        
        scatter_rend3 = p3.scatter('time3','data3',fill_alpha=0,source=s3,line_alpha=0)
        scatter_rend3.selection_glyph = scatter_rend3.glyph
        scatter_rend3.nonselection_glyph = scatter_rend3.glyph
        
        """
        
        sel_src1 = ColumnDataSource(data={'time1':[],'data1':[]})
        sel_line_render1 = p1.line('time1','data1',legend_label='Selected',line_color='orange',source=sel_src1)

        sel_src2 = ColumnDataSource(data={'time2':[],'data2':[]})
        sel_line_render2 = p2.line('time2','data2',legend_label='Selected',line_color='orange',source=sel_src2)

        sel_src3 = ColumnDataSource(data={'time3':[],'data3':[]})
        sel_line_render3 = p3.line('time3','data3',legend_label='Selected',line_color='orange',source=sel_src3)

        cb1=CustomJS(args=dict(s1=s1,sel_src=sel_src1)
                ,code='''
                var sel_inds = s1.selected.indices
                var sel_time = []
                var sel_data = []
                for (var i=0;i<s1.selected.indices.length;i++){
                        sel_time.push(s1.data['time1'][sel_inds[i]])
                        sel_data.push(s1.data['data1'][sel_inds[i]])}
                console.log('Min Selection of V1:')
                console.log(Math.min(...sel_data))
                console.log('Max Selection of V1:')
                console.log(Math.max(...sel_data))
                sel_src.data['time1']= sel_time
                sel_src.data['data1'] = sel_data
                sel_src.change.emit()
                ''')
        s1.selected.js_on_change('indices',cb1)
        
        cb2=CustomJS(args=dict(s2=s2,sel_src=sel_src2)
                ,code='''
                var sel_inds = s2.selected.indices
                var sel_time = []
                var sel_data = []
                for (var i=0;i<s2.selected.indices.length;i++){
                        sel_time.push(s2.data['time2'][sel_inds[i]])
                        sel_data.push(s2.data['data2'][sel_inds[i]])}
                console.log('Min Selection of V2:')
                console.log(Math.min(...sel_data))
                console.log('Max Selection of V2:')
                console.log(Math.max(...sel_data))
                sel_src.data['time2']= sel_time
                sel_src.data['data2'] = sel_data
                sel_src.change.emit()
                ''')
        s2.selected.js_on_change('indices',cb2)

        cb3=CustomJS(args=dict(s3=s3,sel_src=sel_src3)
            ,code='''
            var sel_inds = s3.selected.indices
            var sel_time = []
            var sel_data = []
            for (var i=0;i<s3.selected.indices.length;i++){
                    sel_time.push(s3.data['time3'][sel_inds[i]])
                    sel_data.push(s3.data['data3'][sel_inds[i]])}
            console.log('Min Selection of V3:')
            console.log(Math.min(...sel_data))
            console.log('Max Selection of V3:')
            console.log(Math.max(...sel_data))
            sel_src.data['time3']= sel_time
            sel_src.data['data3'] = sel_data
            sel_src.change.emit()
            ''')
        s3.selected.js_on_change('indices',cb3)
         
        #grid = gridplot([[p1, p2], [None, p3]])
        
        
        output_file("MultiplePlottingTest.html")
        
        grid = gridplot([[p1],[p2],[p3]])
        show(grid)

@araratcetinkaya that is not a complete Minimal Reproducible Example:

  • It is not complete: it relies on imports, data, and code that is not present. It cannot be executed to investigate
  • It is not minimal. Chances are your problem will show with one line instead of three, for instance. There are thousands of users and only a few of us working the support forum. You need to do your part to help streamline things, by making the MRE absolutely as small as possible with only enough code to reproduce the issue and no more.

I can’t say anything more until I have actual minimal code I can run.

I try to minimize the code as much as possible, now it works without importing any other script and error is still recognizable. I think I found what cause to that thing. In my code, when I close the “scatter_render” section HoverTool works properly but then I cannot use my selection tool on my graph. I hope this helps to investigate the problem.

import numpy as np
import pandas as pd
from bokeh.plotting import figure,show
from bokeh.models import ColumnDataSource,CustomJS, HoverTool


    

dataset1     = pd.DataFrame(data={'time1':range(1000),'data1':np.random.random(1000)*100+np.arange(1000)})

s1          = ColumnDataSource(data=dataset1)
TOOLS       ="pan,wheel_zoom,reset,poly_select,xbox_select,lasso_select"

p1          = figure(title = 'Plot1' ,x_axis_label = 'time'
                 , y_axis_label='Voltage (V)',plot_width=1000, plot_height=300,tools=TOOLS)
    
p1.add_tools(HoverTool(
        tooltips = [
            ( 'index', '$index'),
            ( 'Value', '@data1'),
        ],
        
    formatters={
            'Index'      : 'numeral',         
            'Value'      : 'numeral',        
    },
    
    mode='vline'
    ))
    
    
line_rend1 = p1.line('time1', 'data1', color="black",legend_label="V1", line_width=1,source=s1)
line_rend1.selection_glyph = line_rend1.glyph
line_rend1.nonselection_glyph = line_rend1.glyph
 #      
scatter_rend1 = p1.scatter('time1','data1',fill_alpha=0,source=s1,line_alpha=0)
scatter_rend1.selection_glyph = scatter_rend1.glyph
scatter_rend1.nonselection_glyph = scatter_rend1.glyph
 #   
sel_src1 = ColumnDataSource(data={'time1':[],'data1':[]})
sel_line_render1 = p1.line('time1','data1',legend_label='Selected',line_color='orange',source=sel_src1)

cb1=CustomJS(args=dict(s1=s1,sel_src=sel_src1)
                ,code='''
                var sel_inds = s1.selected.indices
                var sel_time = []
                var sel_data = []
                for (var i=0;i<s1.selected.indices.length;i++){
                        sel_time.push(s1.data['time1'][sel_inds[i]])
                        sel_data.push(s1.data['data1'][sel_inds[i]])}
                console.log('Min Selection of V1:')
                console.log(Math.min(...sel_data))
                console.log('Max Selection of V1:')
                console.log(Math.max(...sel_data))
                sel_src.data['time1']= sel_time
                sel_src.data['data1'] = sel_data
                sel_src.change.emit()
                ''')
s1.selected.js_on_change('indices',cb1)
show (p1)

Ah. This one’s a classic :slight_smile: . You are adding the hovertool before you add the renderers, and you don’t specify which renderer you want the hovertools to trigger on. So the default is for bokeh to trigger that hovertool on all renderers you’ve added to the figure, which in your case is a line and a scatter. That is both why you get “extra” tooltips appearing and why turning off scatter rend seems to fix it.

You can specify which renderer(s) you want the hovertool to trigger for by specifying them when instantiating the hovertool:

p1.add_tools(HoverTool(renderers=[line_rend],tooltips = ... )

This would required rearranging your code a bit as you are instantiating the HoverTool before the renderers. The other option if you want to avoid rearranging them is to set the renderers property for the HoverTool after the renderers are made available:

my_hover = HoverTool(tooltips=....)
p1.add_tools(my_hover)
line_rend = p1.line(.....)
my_hover.renderers = [line_rend]
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.