I have been trying to incorporate Bokeh plots into my Flask web app and have ran into issues where my plots work fine when rendered as an html file, but show ??? in the Hovertool when running in my Flask app. The rest of the plot functions normally.
At first, I thought it was a problem how my html files rendered the plot, but then I noticed that if I restructure my code and run it directly in Sublime instead of starting my app and run from the page, I get the same issue. The weird thing is if I keep everything in one .py file without importing, the plot will work fine as a standalone .html file. I would prefer not to do this to keep my code more manageable seeing that I will be generating numerous plots. Below is my code for the files. Please let me know if there is something that you see with the way I am importing that would cause the issue in the state_trend_month_mean() method/function.
Also, I will be moving my plot formatting into its own function once I get this working. Sorry for the crappy looking code. Still learning. Another thing, I am converting my df to dictionary due to a similar issue and this was the only way I was able to get my plots to render properly. I'm sure its due to my lack of experience.
Here is my code that will generate the graph. The final_df.two_year_df() is a dataframe that is returned and imported from another .py. The tooltips @nti_per_day is a column in the df/dict, but bokeh shows it as ??? in the hovertool
import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColumnDataSource, FactorRange, Label, Title, NumeralTickFormatter, BasicTickFormatter
from bokeh.models.tools import HoverTool
from bokeh.models.tickers import MonthsTicker
from bokeh.models.widgets import DataTable, DateFormatter, TableColumn
from bokeh.layouts import widgetbox, column
from datetime import date, datetime
from dateutil.relativedelta import relativedelta
from vgt_web_app.final_df import FinalDF as final_df
from math import pi
class Graphs():
def state_trend_month_mean():
df = final_df.two_year_df()
dict_1 = df.groupby(['month_year'], as_index=False).sum().to_dict('list')
y_max = max(dict_1['nti_per_day_yoy']) * 1.1
y_min = y_max * -.25
source = ColumnDataSource(data=dict(dict_1))
tooltips = [("Daily NTI", "@nti_per_day")]
tools_to_show = 'pan,box_zoom, wheel_zoom,save,reset'
p = figure(plot_width=600, plot_height=300, x_axis_type="datetime", name="bar1", sizing_mode='scale_both',
toolbar_location='below', toolbar_sticky=False, tools=tools_to_show, y_range=(y_min, y_max))
p.vbar(x='month_year', top='nti_per_day_yoy', width=1800000000, source=source, color='#5886a5')
p.title.text = 'Year over Year (YoY) - State Avg NTI Trend'
p.xaxis.axis_label = 'Month/Year'
p.yaxis.axis_label = 'Avg NTI YoY'
p.xaxis.major_label_orientation = pi/4
p.xaxis.ticker = MonthsTicker(months=list(range(1,13)))
p.xaxis.fixed_location = 0
p.yaxis.formatter = NumeralTickFormatter(format='$0,0')
p.background_fill_alpha = 0.80
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None
p.add_tools(HoverTool(tooltips=tooltips, mode='mouse'))
return(p)
Here is the routes.py
from flask import render_template, request, Blueprint
from bokeh.embed import components
from vgt_web_app.graphs import Graphs as graphs
reports = Blueprint('reports', __name__)
@reports.route('/reports')
def il_reports():
g = graphs.state_trend_month_mean()
# graph_data = g
graph_data = g
script, div = components(graph_data)
return render_template('reports.html', title='Reports', graph_data=graph_data, script=script, div=div)
Here is the html. Still basic and will refine once I can show this plot properly
{% extends "layout.html" %}
{% block content %}
<!DOCTYPE html>
<html lang="en">
<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/2.1.1/bokeh.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/2.1.1/bokeh-widgets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bokeh/2.1.1/bokeh-tables.min.js"></script>
<body>
<h1>Reports</h1>
{{ div | safe }}
{{ script | safe }}
</body>
{% endblock content %}
Again chart has all functionality except it has the ??? in the hover
Seeing ???
only ever indicates one thing: the column name you have specfied in the tooltip does not exist in the ColumnDataSource
. Considering that in the question you specify one column name:
@nti_per_day_yoy is a column in the df/dict
But in the actual code you specify something slightly different:
tooltips = [("Daily NTI", "@nti_per_day")]
The most likely explanation is that you have given the wrong column name in the tooltip.