I have an simple example, run in jupyter notebook:
packages:
python 3.12
bokeh 3.3.2
hvplot 0.9.0
holoviews 1.18.1
import pandas as pd
import hvplot.pandas
data = pd.DataFrame({
"Open": [100.00, 101.25, 102.75],
"High": [104.10, 105.50, 110.00],
"Low": [94.00, 97.10, 99.20],
"Close": [101.15, 99.70, 109.50],
"Volume": [10012, 5000, 18000],
}, index=[pd.Timestamp("2022-08-01"), pd.Timestamp("2022-08-03"), pd.Timestamp("2022-08-04")])
df = pd.DataFrame(data)
# remove datetime gaps
df = df.reset_index(names="Date")
df['Idx'] = pd.RangeIndex(0, df.shape[0], 1)
# fix hover ------
from bokeh.models import HoverTool
hover = HoverTool(
tooltips=[
('Date', '@Date{%Y-%m-%d}'),
('Open', '@Open{0.00}'),
('High', '@High{0.00}'),
('Low', '@Low{0.00}'),
('Close', '@Close{0.00}'),
('Volume', '@Volume{0}'),
],
formatters={'@Date': 'datetime'},
mode='vline'
)
# fix hover ------
ohlc_cols = ["Open", "High", "Low", "Close"]
ohlc = df.hvplot.ohlc(x='Idx', y=ohlc_cols, hover_cols=["Date", *ohlc_cols, "Volume"], tools=[hover])
# fix x tick labels ------
import holoviews as hv
from bokeh.io import show
fig = hv.render(ohlc)
fig.xaxis.major_label_overrides = {
i: dt.strftime("%b %d") for i, dt in enumerate(df['Date'])
}
# fix x tick labels ------
show(fig)
The solution, or more a workaround, is to manupilate the ColumnDataSource of the first renderer in the bokeh figure.
You can do so b adding the line below:
fig.renderers[0].data_source.data['Volume'] = df['Volume'].values
To understand why the line above is the solution, I want to explain, what df.hvplot.ohlc()
does.
This function creates a bokeh figure with 2 renderers, the first rederer is for all whiskers, which gets the HoverTool, and the seconde renderer draws the boxes. The DataFrame is converted to a ColumnsDataSource
in the inside. The ColumnsDataSource
s don't have any information about the "Volume"
, because only used columns used by the whiskers and boxes are stored inside the ColumnDataSource
. The HoverTool can't find information for the Volumne
, so it prints ???
. But we can extend the source by this information.
I adapted your example, because I think it is simpler, but the downside is, that there is one empty date.
import pandas as pd
import hvplot.pandas
import holoviews as hv
from bokeh.io import show
from bokeh.models import HoverTool
df= pd.DataFrame({
"Open": [100.00, 101.25, 102.75],
"High": [104.10, 105.50, 110.00],
"Low": [94.00, 97.10, 99.20],
"Close": [101.15, 99.70, 109.50],
"Volume": [10012, 5000, 18000],
},
index=[pd.Timestamp("2022-08-01"), pd.Timestamp("2022-08-03"), pd.Timestamp("2022-08-04")]
)
df.index.name = "Date"
fig = hv.render(ohlc)
# add missing values to the source for the HoverTool
fig.renderers[0].data_source.data['Volume'] = df['Volume'].values
show(fig)