Хорошо, поэтому я нашел решение, главным образом, благодаря этому: Как правильно обрабатывать дату-время и категориальные оси на графике тепловой карты bokeh / holoviews?
У моего кода было две проблемы: когда я был преобразование pandas dataframe в ColumnDataSource
Мне нужно было преобразовать дату в объект datetime.
x_green = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df_green.index.to_list()
]
И потом мне нужно было понять, что я не могу выполнить ту же (математическую) операцию между ColumnDataSource
столбцами, как это возможно с pandas столбцами. Поэтому мне нужно было подготовить данные (словарь) из столбцов pandas, затем сделать ColumnDataSource
, и тогда мне было разрешено наконец использовать HoverTool
, который был основным всегда. Тогда это наконец сработало. Весь код здесь:
from datetime import datetime
from pandas_datareader import data
import pandas as pd
from bokeh.plotting import figure, show, ColumnDataSource, output_file
from bokeh.io import output_notebook
from bokeh.models import HoverTool
output_notebook()
start=datetime(2020,1,1)
end=datetime(2020,4,3)
name="NSRGY" #nestle
#getting stock data from yahoo
df=(data.DataReader(name=name,data_source="yahoo",start=start,end=end))
#making two datasets based on criteria
df_green=df[df.Close > df.Open]
df_red=df[df.Close < df.Open]
#converting date to datetime : otherwise ColumnDataSource is not working
x_green = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df_green.index.to_list()
]
x_red = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df_red.index.to_list()
]
#preparing data for each of CDS
data_green= {
'date':x_green,
'open':df_green.Open.tolist(),
'close':df_green.Close.tolist(),
'y':((df_green.Open + df_green.Close)/2).tolist(),
'height':((df_green.Close - df_green.Open)).tolist(),
'low':df_green.Low.tolist(),
'high':df_green.High.tolist(),
}
data_red= {
'date':x_red,
'open':df_red.Open.tolist(),
'close':df_red.Close.tolist(),
'y':((df_red.Open + df_red.Close)/2).tolist(),
'height':((df_red.Close - df_red.Open)).tolist(),
'low':df_red.Low.tolist(),
'high':df_red.High.tolist(),
}
source_green=ColumnDataSource(data=data_green)
source_red=ColumnDataSource(data=data_red)
p=figure(x_axis_type="datetime", height=300,sizing_mode="scale_width")
p.title.text = "Candlestick Chart"
hours_12=12*60*60*1000
ciara_green = p.segment(x0="date", y0='low', x1="date", y1='high', color='black', source=source_green)
ciara_red = p.segment(x0="date", y0='low', x1="date", y1='high', color='black', source=source_red)
rect_green = p.rect(x='date',y = 'y', width = hours_12,height = ('height'), fill_color="green", source=source_green)
rect_red = p.rect(x='date',y = 'y', width = hours_12,height = ('height'), fill_color="red", source=source_red)
rect_hover = HoverTool(renderers=[rect_green,rect_red],
tooltips=[("Company",name),('Open value','@{open}'),('Close value','@{close}'),('Date','@date{%F}')], formatters={'date':'datetime'})
p.add_tools(rect_hover)
show(p)
Полагаю, есть более элегантный способ сделать это, но это то, что я смог сделать. Помните, большая часть этого кода выполняется из-за HoverTool
, который требует ColumnDataSource
. В противном случае это легко сделать с помощью pandas dataframe и всего лишь двух (более длинных) строк кода, которые есть в моем первоначальном вопросе. Если вы знакомы с сюжетом: это то же самое, что внедрить функцию наведения в граф? Спасибо