I've recently got into coding and am now running a data analysis on open source Corona data. I built an interactive graph using Python3 inside of Jupyter Notebook. The only thing is, I built in an interaction but it is only showing inside of the Notebook, not when it is exported into a html. Could someone give me a hint of why this is? Many thanks in advance.
Code:
# Import the necessary packages
import pandas as pd
import numpy as np
import requests
import io
from bokeh.io import push_notebook,output_file
from bokeh.io import show, curdoc
from bokeh.plotting import figure, output_notebook
from bokeh.models import HoverTool, ColumnDataSource, Select
from bokeh.layouts import row
from bokeh.models.tickers import FixedTicker
from bokeh.models.callbacks import CustomJS
from ipywidgets import interact
output_notebook()
#---------------------------------------------------------------------------------------------------
# Import the data
#---------------------------------------------------------------------------------------------------
url = 'https://data.humdata.org/hxlproxy/api/data-preview.csv?url=https%3A%2F%2Fraw.githubusercontent.com%2FCSSEGISandData%2FCOVID-19%2Fmaster%2Fcsse_covid_19_data%2Fcsse_covid_19_time_series%2Ftime_series_covid19_confirmed_global.csv&filename=time_series_covid19_confirmed_global.csv'
s=requests.get(url).content
url2 = 'https://data.humdata.org/hxlproxy/api/data-preview.csv?url=https%3A%2F%2Fraw.githubusercontent.com%2FCSSEGISandData%2FCOVID-19%2Fmaster%2Fcsse_covid_19_data%2Fcsse_covid_19_time_series%2Ftime_series_covid19_deaths_global.csv&filename=time_series_covid19_deaths_global.csv'
s2 =requests.get(url2).content
df = pd.read_csv(io.StringIO(s.decode('utf-8')))
df = df.fillna("")
df2 = pd.read_csv(io.StringIO(s2.decode('utf-8')))
df2 = df2.fillna("")
#---------------------------------------------------------------------------------------------------
# Number of reported Corona cases
#---------------------------------------------------------------------------------------------------
Numb_cases = df.iloc[:,0:2].merge(df.iloc[:,4:],how='inner',right_index=True,left_index=True).fillna("")
Numb_cases.iloc[:,1] = Numb_cases.iloc[:,1]+ " : " + Numb_cases.iloc[:,0]
Numb_cases = Numb_cases.iloc[:,1:]
Numb_cases = Numb_cases.transpose()
Numb_cases.columns = Numb_cases.iloc[0,:]
Numb_cases = Numb_cases.iloc[1:,:]
Numb_cases.index = pd.to_datetime(Numb_cases.index)
#---------------------------------------------------------------------------------------------------
# Number of reported Corona deaths
#---------------------------------------------------------------------------------------------------
Numb_deaths = df2.iloc[:,0:2].merge(df2.iloc[:,4:],how='inner',right_index=True,left_index=True).fillna("")
Numb_deaths.iloc[:,1] = Numb_deaths.iloc[:,1]+ " : " + Numb_deaths.iloc[:,0]
Numb_deaths = Numb_deaths.iloc[:,1:]
Numb_deaths = Numb_deaths.transpose()
Numb_deaths.columns = Numb_deaths.iloc[0,:]
Numb_deaths = Numb_deaths.iloc[1:,:]
dates = pd.DataFrame(Numb_deaths.index)
Numb_deaths.index = pd.to_datetime(Numb_deaths.index)
#---------------------------------------------------------------------------------------------------
# Create the interactive graphs
#---------------------------------------------------------------------------------------------------
x = Numb_deaths.index
countries = list(Numb_cases.columns)
#plot1
source = ColumnDataSource(data={
'x' : Numb_cases.index,
'y' : Numb_cases
})
p = figure(x_axis_type="datetime", plot_width=400, plot_height=400, tools="box_zoom,reset")
p.yaxis.axis_label = "Total Number of Cases"
p.xaxis.axis_label = "Date"
countries = list(Numb_cases.columns)
# Create a HoverTool: hover
hover = HoverTool(tooltips = [('Numb cases:', '@y'),('Date :','$x{%F}')],formatters={'$x': 'datetime'},mode='mouse')
# Add the hover tool to the figure p
p.add_tools(hover)
#Plot2
source2 = ColumnDataSource(data={
'x' : Numb_deaths.index,
'y' : Numb_deaths
})
p2 = figure(x_axis_type="datetime", plot_width=400, plot_height=400,tools="box_zoom,reset")
p2.yaxis.axis_label = "Total Number of Deaths"
p2.xaxis.axis_label = "Date"
countries = list(Numb_deaths.columns)
# Create a HoverTool: hover
hover = HoverTool(tooltips = [('Numb deaths:', '@y'),('Date :','$x{%F}')],formatters={'$x': 'datetime'},mode='mouse')
# Add the hover tool to the figure p
p2.add_tools(hover)
# Define a callback function: update_plot
def update(Country):
source.data = {
'x' : x,
'y' : Numb_cases.loc[:,Country]
}
p.circle('x', 'y',source=source ,size=10,
fill_color='grey', alpha=0.40, line_color='grey',
hover_fill_color='firebrick', hover_alpha=0.90,
hover_line_color='white')
source2.data = {
'x' : x,
'y' : Numb_deaths.loc[:,Country]
}
p2.circle('x', 'y',source=source2 ,size=10,
fill_color='grey', alpha=0.40, line_color=None,
hover_fill_color='firebrick', hover_alpha=0.90,
hover_line_color='white')
push_notebook()
interact(update, Country=countries)
show(row(p,p2),notebook_handle=True)
When you're working with a notebook, you have a server running somewhere that runs that Python code inside the update
function. But when you have just a static HTML page, you don't have anything that runs Python - that's why the function is not working.
You either need to keep using the notebook or use bokeh serve
. It's also possible to embed Bokeh into some existing server, like Flask or Django. The last option is to rewrite the update
function in JavaScript so it can be embedded in HTML.