Recently I have one requirement to visualize some collected data with chart plot, we want users to inspect the exact data when mouse/cursor hover over the chart line.
I understand we can do this via Bokeh HoverTool. One issue we faced now is when there are multiple lines especially when they are close to each other, hover tool showing as labels would make this even more crowded. Thus I was wondering if we can show these hover tips in the legend area and update the corresponding legend data when mouse hover over different line.
I have spent a lot of time on this topic in recent weeks and come up with following two solutions but still not perfect, that's why I was wondering if we can show these hover tips in legend label, screenshot and sample code is attached as follows, thanks!
Solution 1 was we can now set hover.mode to vline, so we can exactly nominate different renders for different lines, but this would make as many labels as lines.
#! /usr/bin/env python import numpy as np import pandas as pd from datetime import datetime import time from bokeh.io import output_file, show, save from bokeh.plotting import figure from bokeh.plotting import ColumnDataSource from bokeh.layouts import gridplot from bokeh.models import LinearAxis, Range1d from bokeh.models.widgets import Tabs, Panel from bokeh.models import HoverTool from bokeh.models import CrosshairTool def get_data(): df = pd.DataFrame(np.array([['08:00:00', 11, 13, 15, 17], ['08:30:00', 13, 15, 17, 19], ['09:00:00', 11, 13, 15, 17], ['09:30:00', 13, 15, 17, 19], ['10:00:00', 11, 13, 15, 17], ['10:30:00', 13, 15, 17, 19], ['14:00:00', 11, 13, 15, 17], ['14:30:00', 13, 15, 17, 19], ['15:00:00', 11, 13, 15, 17], ['15:30:00', 13, 15, 17, 19], ['16:00:00', 11, 13, 15, 17], ['16:30:00', 13, 15, 17, 19], ['19:00:00', 11, 13, 15, 17], ['19:30:00', 13, 15, 17, 19], ['20:00:00', 11, 13, 15, 17], ['20:30:00', 13, 15, 17, 19], ['21:00:00', 11, 13, 15, 17], ['21:30:00', 13, 15, 17, 19], ['22:00:00', 11, 13, 15, 17], ['22:30:00', 13, 15, 17, 19]]), columns=['time', 'red', 'white', 'blue', 'yellow']) column_data_source = ColumnDataSource(data={ 'x': pd.to_datetime(df['time'], format='%H:%M:%S'), 'x0': pd.Series([x.strftime('%H:%M') for x in pd.to_datetime(df['time'], format='%H:%M:%S')]), 'y_red': df['red'], 'y_white': df['white'], 'y_blue': df['blue'], 'y_yellow': df['yellow'] }) return column_data_source def plot_figure(cds): plot = figure(plot_width=1200, plot_height=600, x_axis_type='datetime', y_range=(10, 20)) cross = CrosshairTool() cross.line_color = 'white' cross.line_alpha = 0.7 plot.add_tools(cross) plot.title.text = 'Number of Cars Collected at Different Time' plot.background_fill_color = 'black' plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.xaxis.axis_label = 'time' line_red = plot.line(x='x', y='y_red', source=cds, color='red', legend_label='red') line_white = plot.line(x='x', y='y_white', source=cds, color='white', legend_label='white') line_black = plot.line(x='x', y='y_blue', source=cds, color='blue', legend_label='blue') line_yellow = plot.line(x='x', y='y_yellow', source=cds, color='yellow', legend_label='yellow') plot.add_tools(HoverTool(renderers=[line_red], tooltips=[('time', '@x0'), ('number', '@y_red')], mode='vline')) plot.add_tools(HoverTool(renderers=[line_white], tooltips=[('time', '@x0'), ('number', '@y_white')], mode='vline')) plot.add_tools(HoverTool(renderers=[line_black], tooltips=[('time', '@x0'), ('number', '@y_blue')], mode='vline')) plot.add_tools(HoverTool(renderers=[line_yellow], tooltips=[('time', '@x0'), ('number', '@y_yellow')], mode='vline')) plot.legend.location = 'bottom_left' # plot.legend.orientation = 'horizontal' plot.legend.label_text_color = 'white' plot.legend.background_fill_color = 'black' plot.legend.background_fill_alpha = 0.1 show(plot) if __name__ == "__main__": cds = get_data() plot_figure(cds) Solution 2 was set hover.mode to mouse and use HoverTool in general which means we didn't nominate renders for exact line. However, in this case, we have to touch the line, if still keep hover.mode as vline, there would be as many copies as line numbers.
def plot_figure(cds): hover = HoverTool(tooltips=[ ("time", "@x0"), ('red', '@y_red'), ('white', '@y_white'), ('blue', '@y_blue'), ('yellow', '@y_yellow'), ]) hover.mode = 'mouse' # hover.mode = 'vline' plot = figure(plot_width=1200, plot_height=600, tools=[hover], x_axis_type='datetime', y_range=(10, 20)) cross = CrosshairTool() cross.line_color = 'white' cross.line_alpha = 0.7 plot.add_tools(cross) plot.title.text = 'Number of Cars Collected at Different Time' plot.background_fill_color = 'black' plot.xgrid.grid_line_color = None plot.ygrid.grid_line_color = None plot.xaxis.axis_label = 'time' line_red = plot.line(x='x', y='y_red', source=cds, color='red', legend_label='red') line_white = plot.line(x='x', y='y_white', source=cds, color='white', legend_label='white') line_black = plot.line(x='x', y='y_blue', source=cds, color='blue', legend_label='blue') line_yellow = plot.line(x='x', y='y_yellow', source=cds, color='yellow', legend_label='yellow') plot.legend.location = 'bottom_left' # plot.legend.orientation = 'horizontal' plot.legend.label_text_color = 'white' plot.legend.background_fill_color = 'black' plot.legend.background_fill_alpha = 0.1 show(plot) https://stackoverflow.com/questions/66722437/bokeh-hovertool-display-too-crowded-for-multiple-chart-lines March 20, 2021 at 09:57PM


没有评论:
发表评论