Hello.
Hope you are all well.
I have created a Python function which creates a bokeh object.
Using this function, I can generate multiple objects - lines, shapes - on the same figure.
I have been trying to add legends and hover tools to the objects generated by the function, but having issues.
I am providing the code below for your reference:
# Function to generate shapes
def draw_shape(figure, source, x_col_name, y_col_name, shape, size, fill_color, border_color, border_width, alpha, line_dash, line_alpha, line_cap, line_join, line_smoothing,
# legend_location, legend_click_property
):
if shape=='circle' or shape=='c':
figure.circle(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color, line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='square' or shape=='s':
figure.square(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color, line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='diamond' or shape=='d':
figure.diamond(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color, line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='triangle' or shape=='t':
figure.triangle(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color, line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='cross' or shape=='+':
figure.cross(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='X' or shape=='x':
figure.x(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='asterisk' or shape=='*':
figure.asterisk(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='circle_cross' or shape=='c+':
figure.circle_cross(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='circle_x' or shape=='cx':
figure.circle_x(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='inverted_triangle' or shape=='it':
figure.inverted_triangle(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='square_cross' or shape=='s+':
figure.square_cross(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='square_x' or shape=='sx':
figure.square_x(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='plus' or shape=='p':
figure.plus(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='diamond_cross' or shape=='d+':
figure.diamond_cross(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='diamond_x' or shape=='dx':
figure.diamond_x(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='hex' or shape=='h':
figure.hex(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='y':
figure.y(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
elif shape=='-' or shape=='dash':
figure.dash(x=x_col_name, y=y_col_name, source=source, size=size, fill_color=fill_color,
line_color=border_color, line_width=border_width, alpha=alpha)
# Modifying
# elif shape=='line' or shape=='l':
# Line cap / line join : "butt", "round", or "square"
# miter, round or bevel
figure.line(x=x_col_name, y=y_col_name, source=source, #size=size,
# fill_color=fill_color,
line_color='white',
line_width=7,
# alpha=1, line_dash=line_dash,
line_alpha=1,
line_cap=line_cap, line_join=line_join,
# line_smoothing=line_smoothing
)
# figure.legend.location = legend_location
# figure.legend.click_policy = legend_click_property
return figure
# Initializing figure
p = figure(
title="Dhaka Stock Exchange Live Change",
x_axis_type="datetime",
sizing_mode="scale_both",
max_width=900,
max_height=300,
width=900,
height=900
)
# Drawing Shapes :
line1 = draw_shape(x_col_name='x_values', y_col_name='y_1_values', source=source, figure=p, shape='c', size=30, fill_color='blue', border_color='white', border_width=3, alpha=0.3, line_smoothing=0.9, line_join='round', line_cap='round', line_alpha=0.6, line_dash='4 4', )
circle1 = draw_shape(x_col_name='x_values', y_col_name='y_1_values', source=source, figure=p, shape='line', size=30, fill_color='blue', border_color='pink', border_width=3, alpha=0.3, line_smoothing=1, line_join='round', line_cap='round', line_alpha=0.9, line_dash='4 4')
p.xaxis.formatter = DatetimeTickFormatter(hours="%H:%M")
# p.legend.title = 'Lines'
# p.legend.location = "top_left"
# legend = Legend(items=[
# ("Line 1", [line1]),
# ("Line 2", [circle1])
# ])
# p.add_layout(legend, 'right')
curdoc().theme = 'dark_minimal'
show(p)
If I uncomment the legend code, I get this error -
ValueError: failed to validate Legend(id=‘p13230’, …).items: expected an element of List(Instance(LegendItem)), got seq with invalid items [(‘Line 1’, [figure(id=‘p12674’, …)]), (‘Line 2’, [figure(id=‘p12674’, …)])]
In a similar way, if I try to use Hover tools :
from bokeh.models import HoverTool
# Define tooltips
tooltips = [
("Date", "@x_values{%Y-%m-%d %H:%M}"),
("Value", "@y_2_values"),
]
hover_tool = HoverTool(renderers=[line1,
# line2
], tooltips=tooltips, formatters={"@x_values": "datetime"})
p.add_tools(hover_tool)
# Define tooltips
tooltips = [
("Date", "@x_values{%Y-%m-%d %H:%M}"),
("Value", "@y_1_values"),
]
# Add tooltips to both lines
hover_tool_2 = HoverTool(renderers=[circle1,
# line2
], tooltips=tooltips, formatters={"@x_values": "datetime"})
p.add_tools(hover_tool_2)
I get this error:
ValueError: failed to validate HoverTool(id=‘p13006’, …).renderers: expected an element of either Auto or List(Instance(DataRenderer)), got [figure(id=‘p12674’, …)]
Can you please guide me what is wrong here and how to fix it?
Thank you so much.