Bokeh plot not showing with show(p) or p.show() - python

Trying to get a Bokeh chart to show with this code, I either get nothing if I use show(p) or
AttributeError: 'Figure' object has no attribute 'show'
How can I fix this?
from math import pi
import pandas as pd
from bokeh.plotting import figure, show, output_notebook
from bokeh.models.annotations import Title
from nsepy import get_history
from datetime import date
from datetime import datetime
from pykalman import KalmanFilter
df = get_history(symbol="TCS", start = date(2018,1,1),end = date(2018,7,22))
print(df)
kf = KalmanFilter(transition_matrices = [1],
observation_matrices = [1],
initial_state_mean = df['Close'].values[0],
initial_state_covariance = 1,
observation_covariance=1,
transition_covariance=.01)
state_means,_ = kf.filter(df[['Close']].values)
state_means = state_means.flatten()
df["date"] = pd.to_datetime(df.index)
mids = (df.Open + df.Close)/2
spans = abs(df.Close-df.Open)
inc = df.Close > df.Open
dec = df.Open > df.Close
w = 12*60*60*1000 # half day in ms
output_notebook()
TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
#This causes an exception tol with p.show() no show in figure
p = figure(x_axis_type="datetime", tools=TOOLS, plot_width=1000, toolbar_location="left",y_axis_label = "Price",
x_axis_label = "Date")
p.segment(df.date, df.High, df.date, df.Low, color="black")
p.rect(df.date[inc], mids[inc], w, spans[inc], fill_color='green', line_color="green")
p.rect(df.date[dec], mids[dec], w, spans[dec], fill_color='red', line_color="red")
p.line(df.date,state_means,line_width=1,line_color = 'blue',legend="Kalman filter")
t = Title()
t.text = 'Kalman Filter Estimation'
p.title = t
p.xaxis.major_label_orientation = pi/4
p.grid.grid_line_alpha=0.3
p.show() #Throws attribute error show does not exist
#show(p) #Nothing happens on this

Here is the the code I added to the start to get visualization working. I often found that using output_notebook alone will sometimes still not be enough to get show() to display figures as it should. This is a work around using INLINE which has not failed for me yet.
# allows visualisation in notebook
from bokeh.io import output_notebook
from bokeh.resources import INLINE
output_notebook(INLINE)
<your code>
show(p)

There is no show method on plots in Bokeh, and never has been. There is a show function that you can pass plots (or layouts of plots and widgets) to.
from bokeh.io import output_file, show
from bokeh.plotting import figure
p = figure(...)
p.circle(...)
output_file("foo.html")
show(p)
This is the very first thing explained in the Quickstart: Getting Started section and this pattern is also repeated in hundreds of examples throughout the docs.

from math import pi
import pandas as pd
from bokeh.plotting import figure, show, output_file
from bokeh.models.annotations import Title
from nsepy import get_history
from datetime import date
from datetime import datetime
from pykalman import KalmanFilter
df = get_history(symbol="TCS", start = date(2018,1,1),end = date(2018,7,22))
print(df)
kf = KalmanFilter(transition_matrices = [1],
observation_matrices = [1],
initial_state_mean = df['Close'].values[0],
initial_state_covariance = 1,
observation_covariance=1,
transition_covariance=.01)
state_means,_ = kf.filter(df[['Close']].values)
state_means = state_means.flatten()
df["date"] = pd.to_datetime(df.index)
mids = (df.Open + df.Close)/2
spans = abs(df.Close-df.Open)
inc = df.Close > df.Open
dec = df.Open > df.Close
w = 12*60*60*1000 # half day in ms
#output_notebook()
#please note in the import statement above, I have changed it from
output_notebook to output_file
output_file=("TCS.html", title = "Kalman Filter Estimation", mode="cdn")
TOOLS = "pan,wheel_zoom,box_zoom,reset,save"
#This causes an exception tol with p.show() no show in figure
p = figure(x_axis_type="datetime", tools=TOOLS, plot_width=1000,
toolbar_location="left",y_axis_label = "Price",
x_axis_label = "Date")
p.segment(df.date, df.High, df.date, df.Low, color="black")
p.rect(df.date[inc], mids[inc], w, spans[inc], fill_color='green',
line_color="green")
p.rect(df.date[dec], mids[dec], w, spans[dec], fill_color='red', line_color="red")
p.line(df.date,state_means,line_width=1,line_color = 'blue',legend="Kalman filter")
#t = Title()
#t.text = 'Kalman Filter Estimation'
#p.title = t
p.xaxis.major_label_orientation = pi/4
p.grid.grid_line_alpha=0.3
p.show()
This should open up the html file in google or edge or whichever is your default browser you have set

Your import is wrong:
change "from bokeh.plotting import output_notebook" to "from bokeh.io import output_notebook"

Related

Creating map with date slider to show the progression of values

I am trying to create a map showing the progressive lockdown measures globally using a date slider. So far I was able to create the map for a static date but my attempt at the slider doesn't work because it seems to only accept integers or floats instead of a date range (Date_slider = pnw.IntSlider(start=0,end=365,value=0)
Essentially, i want to create the map found here: https://www.bsg.ox.ac.uk/research/research-projects/coronavirus-government-response-tracker
import pandas as pd
import geopandas as gpd
import json
import matplotlib as mpl
import pylab as plt
from bokeh.io import output_file, show, output_notebook, export_png
from bokeh.models import ColumnDataSource, GeoJSONDataSource, LinearColorMapper, ColorBar
from bokeh.plotting import figure
from bokeh.palettes import brewer
import panel as pn
import panel.widgets as pnw
import descartes
output_notebook()
pn.extension()
Read shape file
shapefile = '/Users/sam/Desktop/ne_110m_admin_0_countries/ne_110m_admin_0_countries.shp'
gdf = gpd.read_file(shapefile)[['ADMIN', 'ADM0_A3', 'geometry']]
gdf.columns = ['country', 'country_code', 'geometry']
gdf = gdf.drop(gdf.index[159])
Read data
def get_dataset(name,key=None,Date=None):
df = pd.read_csv(r'/Users/sam/Desktop/Big Data Project/covid-stringency-index-2.csv')
if Date is not None:
df = df[df['Date'] == Date]
#Merge dataframes gdf and df_2016.
if key is None:
key = df.columns[2]
merged = gdf.merge(df, left_on = 'country', right_on = 'Entity', how = 'left')
merged[key] = merged[key].fillna(0)
return merged, key
plot with matplotlib
datasetname='Lockdown Measures'
df,key = get_dataset(datasetname, Date='Jul 10, 2020')
fig, ax = plt.subplots(1, figsize=(14, 8))
df.plot(column=key, cmap='OrRd', linewidth=1.0, ax=ax, edgecolor='Black')
ax.axis('off')
ax.set_title('%s Jul 10, 2020' %datasetname, fontsize=25)
plt.tight_layout()
plt.savefig('test_map.png',dpi=150)
Output: https://i.stack.imgur.com/6GrbF.png
Plot with Bokeh
def get_geodatasource(gdf):
"""Get getjsondatasource from geopandas object"""
json_data = json.dumps(json.loads(gdf.to_json()))
return GeoJSONDataSource(geojson = json_data)
def map_dash():
"""Map dashboard"""
from bokeh.models.widgets import DataTable
map_pane = pn.pane.Bokeh(width=600)
data_select = pnw.Select(name='dataset',options=list(df))
Date_slider = pnw.IntSlider(start=0,end=365,value=0)
def update_map(event):
gdf,key = get_dataset(name=data_select.value,Date=Date_slider.value)
map_pane.object = bokeh_plot_map(gdf, key)
return
Date_slider.param.watch(update_map,'value')
Date_slider.param.trigger('value')
data_select.param.watch(update_map,'value')
app = pn.Column(pn.Row(data_select,Date_slider),map_pane)
return app
app = map_dash()
app
You have to use a pn.widgets.DateRangeSlider(...)
https://panel.holoviz.org/reference/widgets/DateRangeSlider.html#widgets-gallery-daterangeslider

Bokeh figure doesn't updates on dropdown.on_change

I have some problem with updating Bokeh plot. It's simple piece of code, one figure with one curve and one dropdown, which can changes time period, 7,10 and 30 days. When i change dropdown value, nothing happens.
I already have gone through various articles, but i didn't find clear answer for me.
Code example is presented below.
Thanks
from bokeh.plotting import figure
from bokeh.layouts import row
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Dropdown
from pandas_datareader import data
import datetime
TIME_PERIOD = 30
def get_data(period):
today = datetime.date.today()
timedelta = datetime.timedelta(days=period)
start = today - timedelta
df = data.DataReader(name="BTC-USD", data_source="yahoo", start=start)
dates = df.loc[str(start):str(today)].index
y = df["Volume"]
data1 = dict(
xaxis=dates,
yaxis=y
)
source = ColumnDataSource(data1)
return source
def update_date(attr, old, new):
global TIME_PERIOD
temp = new
TIME_PERIOD = int(temp)
def get_plot(data_source):
p = figure(title="Cryptocurrencies volumes", x_axis_label="Дни", y_axis_label="Volume 24hr",
x_axis_type="datetime")
p.line(x="xaxis", y="yaxis", color="green", source=data_source)
return p
dropdown_menu = [("7","7"),("10","10"),("30","30")]
dropdown = Dropdown(label="Выбор временного интервала",button_type="success",menu=dropdown_menu, value="30")
dropdown.on_change("value", update_date)
data1 = get_data(TIME_PERIOD)
plot = get_plot(data1)
image = row(dropdown,plot)
curdoc().add_root(image)
curdoc().title = "Plot"
Simply setting your time period is not enough. You have to call the get_data() function again and set the data of the ColumnDataSource it returns as the data of the ColumnDataSource that is used by your line glyph.
from bokeh.plotting import figure
from bokeh.layouts import row
from bokeh.io import curdoc
from bokeh.models import ColumnDataSource
from bokeh.models.widgets import Dropdown
from pandas_datareader import data
import datetime
TIME_PERIOD = 30
def get_data(period):
today = datetime.date.today()
timedelta = datetime.timedelta(days=period)
start = today - timedelta
df = data.DataReader(name="BTC-USD", data_source="yahoo", start=start)
dates = df.loc[str(start):str(today)].index
y = df["Volume"]
data1 = dict(
xaxis=dates,
yaxis=y
)
source = ColumnDataSource(data1)
return source
def update_date(attr, old, new):
TIME_PERIOD = int(new)
newdata = get_data(TIME_PERIOD)
source.data = newdata.data
dropdown_menu = [("7","7"),("10","10"),("30","30")]
dropdown = Dropdown(label="Выбор временного интервала",button_type="success",menu=dropdown_menu, value="30")
dropdown.on_change("value", update_date)
source = get_data(TIME_PERIOD)
p = figure(title="Cryptocurrencies volumes", x_axis_label="Дни", y_axis_label="Volume 24hr",
x_axis_type="datetime")
p.line(x="xaxis", y="yaxis", color="green", source=source)
image = row(dropdown,p)
curdoc().add_root(image)
curdoc().title = "Plot"

Points plotted by DateTimeTick Formatter in a bokeh scatter plot move in xaxis

When using Bokeh plot I find the following issues:
1) The plot does not show the points immediately.
2) When I zoom out using mouse wheel 3 times the points become visible.
3) When I zoom out 7 times the points are shifted to the next/previous minute(In my case they are between 40m:54s and 41m originally after 7th zoom they go to 40:38 to 40:44)
I have tried setting
g.x_range.range_padding = 0.1
to 0 with no luck
import pandas as pd
import bokeh
from bokeh.plotting import *
from bokeh.io import output_file,show,save
from bokeh.resources import CDN,INLINE
from bokeh.embed import file_html
from bokeh.models.ranges import *
from bokeh.palettes import Spectral6
from bokeh.transform import factor_cmap
from bokeh.transform import dodge
from bokeh.core.properties import value
from bokeh.embed import components
from bokeh.layouts import row,column
from bokeh.models import DatetimeTickFormatter
myPandas = pd.read_pickle("myPanda.pickle")
source=ColumnDataSource(data=myPandas)
yaxis="yaxis"
xaxis="xaxis"
def getTitle(graphDet):
return graphDet
graphDet="Dummy"
g = figure(plot_width=450, plot_height=300, y_axis_label=yaxis, x_axis_label=xaxis, output_backend="webgl", title=getTitle(graphDet), x_axis_type="datetime")
x="time"
y="col1"
g.circle(myPandas[x],myPandas[y], size=5,legend=value(y))
g.xaxis[0].formatter=DatetimeTickFormatter(milliseconds = ['%3Nms']
,seconds = ['%Ss']
)
g.x_range.range_padding = 0.1
g.xgrid.grid_line_color = None
g.legend.location = "top_right"
g.legend.orientation = "vertical"
show(g)
The pickle file for input can be found in
https://www.dropbox.com/s/4fe11kdu00nbcjp/myPanda.pickle?dl=0
My expectation is the plot must be visible right from the start.It must not jump across time.
Looks like a bug introduced wheh webgl is used. Removing it solves the problem but is this acceptable for you? (tested on bokeh v1.0.4)
import pandas as pd
import bokeh
import numpy as np
from bokeh.plotting import *
from bokeh.io import output_file, show, save
from bokeh.resources import CDN, INLINE
from bokeh.embed import file_html
from bokeh.models.ranges import *
from bokeh.palettes import Spectral6
from bokeh.transform import factor_cmap
from bokeh.transform import dodge
from bokeh.core.properties import value
from bokeh.embed import components
from bokeh.layouts import row, column
from bokeh.models import DatetimeTickFormatter
from datetime import datetime, timedelta
d_start = datetime(2016, 6, 1)
d_step = timedelta(milliseconds = 100)
t = [d_start + (i * d_step) for i in range(0, 100)]
myPandas = pd.DataFrame(columns = ['time', 'col1'], data = {'time': t, 'col1': np.arange(100)}, index = t)
source = ColumnDataSource(data = myPandas)
def getTitle(graphDet):
return graphDet
graphDet = "Dummy"
g = figure(plot_width = 450, plot_height = 300, y_axis_label = "yaxis", x_axis_label = "xaxis", title = getTitle(graphDet), x_axis_type = "datetime")
x = "time"
y = "col1"
g.circle(myPandas[x], myPandas[y], size = 5, legend = value(y))
g.xaxis[0].formatter = DatetimeTickFormatter(seconds = ['%Ss'], milliseconds = ['%3Nms'])
g.x_range.range_padding = 0.1
g.xgrid.grid_line_color = None
g.legend.location = "top_right"
g.legend.orientation = "vertical"
show(g)

Bokeh plot not updating

I would love some help, I'm going in circles here. I know I'm doing something stupid but my plot isn't updating. I can't debug to see if my filter function isn't working or there's a problem that my inputs for the plot aren't linked the dynamic source input. Since even the starting plot doesn't take the initialized parameters I think it's something there. PS- any advice on having a select all, including all in the categorical choices for the select boxes would be amazing too.
Cheers,
Tom
import pandas as pd
import numpy as np
from bokeh.io import show, output_notebook, push_notebook, curdoc
from bokeh.plotting import figure
from bokeh.models import CategoricalColorMapper, HoverTool, ColumnDataSource, Panel, Div
from bokeh.models.widgets import (CheckboxGroup, Slider, Select, TextInput, RangeSlider, Tabs, CheckboxButtonGroup, TableColumn, DataTable, Select)
from bokeh.layouts import layout, column, row, Widgetbox
from bokeh.layouts import widgetbox, row, column
from bokeh.palettes import Category20_16
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
weather = pd.read_csv('YYYYYY.csv', dayfirst=True, parse_dates=True, index_col=[1], encoding = "ISO-8859-1")
def style(p):
# Title
p.title.align = 'center'
p.title.text_font_size = '20pt'
p.title.text_font = 'serif'
# Axis titles
p.xaxis.axis_label_text_font_size = '14pt'
p.xaxis.axis_label_text_font_style = 'bold'
p.yaxis.axis_label_text_font_size = '14pt'
p.yaxis.axis_label_text_font_style = 'bold'
# Tick labels
p.xaxis.major_label_text_font_size = '12pt'
p.yaxis.major_label_text_font_size = '12pt'
return p
def make_plot(src):
p = figure(plot_height=600, plot_width=700, title="'2018'", toolbar_location="below", tooltips=TOOLTIPS)
p.circle(x="Deal_Number", y="USD_Base", source=src, size=7, line_color=None)
p = style(p)
return p
TOOLTIPS=[
("Name", "#Target"),
("$", "#Round"),
("Country", "#CC")
]
def get_dataset(deal_num, ccstring, descstring, vertstring):
df_filter = weather[weather['USD_Base'] >=(deal_num) & weather['CC'].str.contains(ccstring) & weather['Description'].str.contains(descstring) & weather['Vertical Market'].str.contains(vertstring)]
return ColumnDataSource(df_filter)
def update_plot(attr, old, new):
deal_num = int(deal_select.value)
ccstring = str(cc_select.value)
descstring = str(description_select.value)
vertstring = str(vert_select.value)
new_src = get_dataset(deal_num, ccstring, descstring, vertstring)
src.data.update(new_src.data)
# Create Input controls
deal_select = Slider(title="$ Invested", value=0, start=0, end=200, step=2)
cclist = weather["CC"].unique().tolist()
cc_select = Select(title="Country Name:", options= cclist, value='GB')
description_select = TextInput(title="Company description contains")
vertlist = weather["Vertical Market"].unique().tolist()
vert_select = Select(title="Vertical:", options= ['All'] + vertlist, value='None')
controls = widgetbox(deal_select, cc_select, description_select, vert_select)
deal_select.on_change('value', update_plot)
cc_select.on_change('value',update_plot)
description_select.on_change('value',update_plot)
vert_select.on_change('value',update_plot)
# Make the deal data source
src = get_dataset(deal_num = deal_select.value,
ccstring = cc_select.value,
descstring = description_select.value,
vertstring = vert_select.value)
# Make the deal plot
p = make_plot(src)
layout = row(controls, p)
# Make a tab with the layout
tab = Panel(child=layout, title = '2018')
# Put all the tabs into one application
tabs = Tabs(tabs = [tab])
# Put the tabs in the current document for display
curdoc().add_root(tabs)
If you are updating a glyph, you need to change the datasource for that glyph directly. In your case, you should assign the circle glyph to a variable, such as:
circle = p.circle(x="Deal_Number", y="USD_Base", source=src, size=7, line_color=None)
Then in your update_plot(attr, old, new) function try this:
circle = p.select_one({'name':'circle'})
circle.data_source.data = new_src.data
For selecting all, possibly the MultiSelect Widget would work?

bokeh hover multiline with datetime axis

I want to create a multiline Bokeh plot with datetime axis and a hover tool that shows the datetime of the data point. This should be supported and I have tried to obtain the intended behaviour in two ways:
Use hover.formatters to format the x-value. This has no effect on the plot.
Add a description variable with the correctly formatted date/time values. This results in a hover tool where all date/time values are displayed in a list for each point.
I have included a smaller example of my code that illustrates my approach and the result. It is used in conjunction with a checkboxgroup that updates the data. This is why a new ColumnDataSource is made from the dataframe.
import pandas as pd
import numpy as np
from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import HoverTool, ColumnDataSource
from bokeh.palettes import Spectral4
from bokeh.layouts import column
#output_file("demo.html")
available_quant = ["LACTIC_ACID", "GLUCOSE", "XYLOSE", "FORMIC_ACID"]
quant_legend = ["Lactic acid", "Glucose", "Xylose", "Formic acid"]
Create a dataframe with 4 quantities and the time
datelist = pd.date_range(end = pd.datetime.today(), periods=100).tolist()
desc = datelist
for i, date in enumerate(datelist):
desc[i] = str(date)
RT_x = np.linspace(-5, 5, num=100)
lactic = RT_x**2
data = {'time': datelist, 'desc': desc, 'LACTIC_ACID': RT_x**2 + 2, 'GLUCOSE': RT_x**2, 'XYLOSE': RT_x**2 - 2, 'FORMIC_ACID': RT_x**2 - 4}
df = pd.DataFrame.from_dict(data)
df['time'] = pd.to_datetime(df['time'], format = "%Y-%m-%d %H:%M:%S")
Copy the relevant data to a columndatasource
substance_colors = Spectral4
quant_to_plot = available_quant
xs = []
ys = []
xsprint = []
colors = []
labels = []
for i, substance in enumerate(quant_to_plot):
xs.append(list(df['time']))
ys.append(list(df[substance]))
xsprint.append(list(df['desc']))
index = available_quant.index(substance)
colors.append(substance_colors[index])
labels.append(quant_legend[index])
new_src = ColumnDataSource(data={'x': xs, 'y': ys, 'desc': xsprint, 'color': colors, 'label': labels})
Make the first plot using hover.formatters
p = figure(plot_width=800, plot_height=400, x_axis_type="datetime", title = 'Demo', x_axis_label = 'Time', y_axis_label = 'c [g/mL]')
p.multi_line('x','y', color = 'color', legend = 'label', source = new_src)
hover = HoverTool(tooltips=[('Type','#label'),
('Time','$x'),
('Conc','$y')],
formatters={'Time': 'datetime'},
mode = 'mouse',
line_policy='next')
p.add_tools(hover)
p.legend.location = "top_left"
p.legend.orientation = "horizontal"
Make second plot using description variable
p2 = figure(plot_width=800, plot_height=400, x_axis_type="datetime", title = 'Demo', x_axis_label = 'Time', y_axis_label = 'c [g/mL]')
p2.multi_line('x','y', color = 'color', legend = 'label', source = new_src)
hover = HoverTool(tooltips=[('Type','#label'),
('Time','#desc'),
('Conc','$y')],
mode = 'mouse',
line_policy='nearest')
p2.add_tools(hover)
mylayout = column(p, p2)
show(mylayout)
Am I missing something trivial? I am running Bokeh 0.13.0 and python 3.6.4.
The first approach works with the following modification of the hovertool:
hover = HoverTool(tooltips=[('Type','#label'),
('Time','$x{%F}'),
('Conc','$y')],
formatters={'$x': 'datetime'},
mode = 'mouse',
line_policy='nearest')

Categories