python - 散景悬停工具显示过于拥挤,无法显示多条图表线
问题描述
最近我有一个需求,用图表来可视化一些收集的数据,我们希望用户在鼠标/光标悬停在图表线上时检查确切的数据。
我知道我们可以通过 Bokeh 做到这一点HoverTool
。我们现在面临的一个问题是当有多条线时,尤其是当它们彼此靠近时,显示为标签的悬停工具会使它更加拥挤。因此我想知道我们是否可以在图例区域显示这些悬停提示,并在鼠标悬停在不同的行上时更新相应的图例数据。
最近几周我在这个话题上花了很多时间,并提出了以下两个解决方案,但仍然不完美,这就是为什么我想知道我们是否可以在图例标签中显示这些悬停提示,截图和示例代码如下所示,谢谢!
解决方案 1是我们现在可以将 hover.mode 设置为vline
,因此我们可以准确地为不同的线条指定不同的渲染,但这会使标签与线条一样多。
#! /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)
解决方案 2设置为 hover.modemouse
并HoverTool
在一般情况下使用,这意味着我们没有为精确线指定渲染。但是,在这种情况下,我们必须触摸行,如果仍然保持 hover.mode 为vline
,那么副本将与行号一样多。
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)
解决方案
推荐阅读
- javascript - 如果页面在端口上运行,则反应侦听
- django - Django - 将一个模型字段链接到另一个模型的字段
- settings - 如何更改 JetBrains IDE 中 HEX 颜色的显示方式
- react-native - 更新的代码未在 React Native Simulator 中显示
- android - 在 kotlin 中从片段转移到另一个片段
- android - 如何使用 kotlin flow 实现完整的存储库
- php - php合并两个不同查询的结果并删除重复项
- python - 使用 Drive API v3 复制文件不会更改标题或位置
- swift - swiftui将变量传递到另一个视图
- javascript - VSCode 键盘问题