I have a script that plots a few series voltage vs. speed on a bokeh plot for comparison. It includes hover functionality for easier review of the data. It ran successfully when i used python 3.8.5 but recently, I've needed to move to a more recent version of python, so I started using 3.9.7.
The way the script works is it pulls data from an excel file I've already populated, after which it plots each series that I've specified the voltage and speed column names for. It creates a linear regression line for the data, then adds a 95% confidence interval to the plot by calculating an upper and lower bound for the dataset and passing a linear regression line through each of those bounds. The regression line and confidence band are based on a different set of columns in the excel. Those columns are comprehensive so they basically just include all the data from all the series that are being plotted. And thats what's used for the regression line & confidence interval that is representative of the whole the dataset. Then the hover tool is added for the confidence band (this is where my issue is). Finally, I append my renderers and open the plot in the browser.
That's the gist of the script, minus some unrelated extras like printing a data table for the confidence band values and shading the confidence interval.
This is the error i get:
ValueError: failed to validate HoverTool(id='1986', ...).renderers: expected an element of either Auto or List(Instance(DataRenderer)), got [Band(id='1908', ...)]
This is the script:
import pandas as pd import numpy as np from scipy import stats from bokeh.plotting import figure, show, output_file, output_notebook from bokeh.models import HoverTool, ColumnDataSource, Band, CustomJS, Label from bokeh.layouts import column, gridplot from bokeh.palettes import Category10 from bokeh.models.widgets import CheckboxGroup import matplotlib.pyplot as plt import seaborn as sns from scipy.stats import norm from bokeh.io import push_notebook from sklearn.linear_model import LinearRegression def plot_voltage_vs_speed(excel_file, sheet_name, series_info, plot_title, ci_info): df = pd.read_excel(excel_file, sheet_name=sheet_name) specified_speeds = np.array([3000, 5250, 10500, 14500, 15750, 16250, 18000, 20581, 21000]) renderers = [] checkbox_labels = [] p = figure(title=plot_title, x_axis_label='Speed (RPM)', y_axis_label='Voltage (V)', width=800, height=600) for series in series_info: voltage_col = series['voltage_col'] speed_col = series['speed_col'] label = series['label'] x = df[speed_col] y = df[voltage_col] circle_renderer = p.circle(x, y, legend_label=label, fill_color="white", size=6, color=Category10[10][series_info.index(series)]) renderers.append((circle_renderer,)) checkbox_labels.append(label) # Adding hover tool for the circles; this hover doesnt give me errors hover = HoverTool(tooltips=[ ("Speed", "@x"), ("Voltage", "@y") ]) p.add_tools(hover) ... # skipping to next relevant portion of script # Perform linear regression model = LinearRegression(fit_intercept=False) model.fit(x_filtered.values.reshape(-1, 1), y_filtered) line = model.predict(x_filtered.values.reshape(-1, 1)) # Calc standard deviation and mean for each speed std_devs = df_filtered.groupby('mapped_speed')[ci_info['voltage_col']].std() means = df_filtered.groupby('mapped_speed')[ci_info['voltage_col']].mean() # Calculate confidence bands upper_bound = means.loc[x_filtered].values + 1.96 * std_devs.loc[x_filtered].values lower_bound = means.loc[x_filtered].values - 1.96 * std_devs.loc[x_filtered].values # Perform linear regression for upper and lower bounds model_upper = LinearRegression(fit_intercept=False) model_upper.fit(x_filtered.values.reshape(-1, 1), upper_bound) upper_line = model_upper.predict(x_filtered.values.reshape(-1, 1)) model_lower = LinearRegression(fit_intercept=False) model_lower.fit(x_filtered.values.reshape(-1, 1), lower_bound) lower_line = model_lower.predict(x_filtered.values.reshape(-1, 1)) sorted_indices = np.argsort(x_filtered) x_sorted = x_filtered.values[sorted_indices] line_sorted = line[sorted_indices] lower_sorted = lower_bound[sorted_indices] upper_sorted = upper_bound[sorted_indices] # Create regression line and confidence band source = ColumnDataSource(data={ 'x': x_sorted, 'line': line_sorted, 'lower': lower_sorted, 'upper': upper_sorted }) line_renderer = p.line('x', 'line', source=source, legend_label="Regression Line", line_width=1, color="black") # This is where band comes in. I used it later when adding the hover tool for the confidence band. band = Band(base='x', lower='lower', upper='upper', source=source, level='underlay', fill_alpha=0.2, line_width=1, line_color="black", fill_color="gray") p.add_layout(band) ''' Adding hover tool for confidence band; this is the hover that gives me an error, specifically the renderers=[band] part of it.''' hover_band = HoverTool(renderers=[band], tooltips=[ ("Speed", "@x"), ("Lower Bound", "@lower"), ("Upper Bound", "@upper") ]) p.add_tools(hover_band) renderers.append((line_renderer,)) renderers.append((band,)) checkbox_labels.append("Regression Line") checkbox_labels.append("Prediction Interval") checkbox_group = CheckboxGroup(labels=checkbox_labels, active=list(range(len(renderers)))) checkbox_callback = CustomJS(args=dict(renderers=renderers, checkbox_group=checkbox_group), code=""" for (let i = 0; i < renderers.length; i++) { const elements = renderers[i]; const visible = checkbox_group.active.includes(i); for (let elem of elements) { elem.visible = visible; } } """) checkbox_group.js_on_change('active', checkbox_callback) layout = column(checkbox_group, p) # Show plot in notebook + browser output_notebook() show(layout) output_file("Machine_Compare.html") excel_file = 'Machine_Comparison.xlsx' sheet_name = 'Voltage_Comparison' # Specify sheet series_info = [ {'voltage_col': 'Voltage1', 'speed_col': 'Speed1', 'label': 'Machine 1'}, {'voltage_col': 'Voltage2', 'speed_col': 'Speed2', 'label': 'Machine 2'} ] plot_title = 'Machine Comparison with 95% Prediction Interval' # Columns for prediction interval calc ci_info = {'voltage_col': 'Voltages', 'speed_col': 'Speeds'} plot_voltage_vs_speed(excel_file, sheet_name, series_info, plot_title, ci_info) Sorry its a bit long. The relevant parts were spread out around the script and only copying those over made it somewhat confusing to read, without the steps in between.
I tried removing renderers=[band], from the hover tool that causes the error to ensure I had the cause of the error right, and though it did run and generate the plot successfully, the hover information showed ?? for both speed and voltage values.
Bandis not a valid target for a hover tool, only glyphs (e.g. scatter, line, patch, bars, etc) are. And that???in the hover output means that the column name you configured for the tool is missing from theColumnDataSourcebacking the glyph.