Я заменил цикл for на ColumnDataSource и multiline, что облегчает добавление hovertool. Мне также пришлось добавить несколько CustomJS, потому что вызов @ x / @ y из многострочного показывает все значения x / y. CustomJS гарантирует, что он показывает только правильную позицию x / y.
import pandas as pd
from bokeh.plotting import figure, show, reset_output, output_notebook
from bokeh.models import ColumnDataSource
from bokeh.palettes import Category10
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.models.glyphs import MultiLine
import itertools
from bokeh.models import Legend
from bokeh.models.tools import CustomJSHover
url = 'https://www.bp.com/content/dam/bp/business-sites/en/global/corporate/xlsx/energy-economics/statistical-review/bp-stats-review-2018-all-data.xlsx'
df = pd.read_excel(url, sheet_name = 'Gas Consumption - Bcf', skiprows = 2, skipfooter = 15)
df = df.dropna(how='all').transpose()
df = df.rename(columns=df.iloc[0]).drop(df.index[0])
df = df.reset_index()
df.rename(columns = {'index': 'Year'}, inplace=True)
df = df.drop(df.index[[53, 54, 55]])
top_ten = df.tail(1).T.reset_index().iloc[1:,:]
top_ten.columns = ['country', 'value']
top_ten = top_ten[~top_ten.country.str.contains("Total")]
top_ten = top_ten.sort_values(by = 'value', ascending= False)
top_ten_list = top_ten['country'].tolist()[:10]
top_ten = df[top_ten_list]
y = [df[country].tolist() for country in top_ten.columns.tolist()]
x, xLst = [], df['Year'].tolist()
for i in range(10):
x.append(xLst)
x_custom = CustomJSHover(code="""
return '' + special_vars.data_x
""")
y_custom = CustomJSHover(code="""
return '' + special_vars.data_y
""")
data = {'x': x, 'y': y, 'color': Category10[10], 'name': top_ten_list}
source = ColumnDataSource(data)
output_notebook()
q = figure(plot_width=700, plot_height=500)
q.multi_line(xs='x', ys='y', line_color='color', legend='name', line_width = 3, source=source)
q.add_tools(HoverTool(
tooltips=[
('Year', '@x{custom}'),
('Value', '@y{custom}'),
('Country', '@name')],
formatters=dict(x=x_custom, y=y_custom)
))
q.legend.location = "top_left"
q.xaxis.axis_label = "Date"
q.yaxis.axis_label = "billion cubic feet per day"
q.legend.click_policy="hide"
show(q)