I am creating a plot and then updating a dataframe everytime a new bar is pulled from the broker. I am actually replacing the dataframe with a fresh 400 bars (really only 1 should be added to the end) so that the plot is always 400 bars long. I am having issues updating a reloading my static html plot. How can i add a callback or function to reload the window whenever I save a new fig to the document?
This plot function is called from another module that is actually pulling new bar data from the broker. I am thinking about just running through this below function again with the new dataframe and instead calling save(fig) instead of show(fig) but then again how can i tell the document that a new saved version is available and to reload the current page. I do not want a new browser instance to be pulled up everytime I update a dataframe.
EDIT: Code has been updated to work, sorry!
import numpy as np
import os
from functools import partial
from itertools import cycle
from typing import Dict
# from data_objects import Indicator
from bokeh.palettes import Category10
from bokeh.layouts import gridplot
from bokeh.transform import factor_cmap
from bokeh.models import (
Range1d,
ColumnDataSource,
CustomJSTickFormatter,
DatetimeTickFormatter,
HoverTool,
NumeralTickFormatter,
CrosshairTool,
WheelZoomTool,
Span,
CustomJS
)
from bokeh.plotting import figure, show, curdoc, save
from bokeh.io.state import curstate
from bokeh.io import output_file
from bokeh.colors.named import (
lime as BULL_COLOR,
tomato as BEAR_COLOR
)
OHLCV_LIST = ['Open', 'High', 'Low', 'Close', 'Volume']
def _bokeh_reset(filename=None):
curstate().reset()
if filename:
if not filename.endswith('.html'):
filename += '.html'
output_file(filename, title=filename)
else:
output_file('default.html', title='')
def plot(df: pd.DataFrame, indicators: Dict[str, str]=None, update_plot=False):
# reset the current state and create an html output
_bokeh_reset('test_plot')
COLORS = [BEAR_COLOR, BULL_COLOR]
BAR_WIDTH = .8
is_datetime_index = isinstance(df.index, pd.DatetimeIndex)
# copy dataframe without indicators
plot_df = df[list(OHLCV_LIST)].copy(deep=False)
# get indicators for plot
indicator_columns = df.columns.difference(plot_df.columns)
plot_df.index.name = None # Provides source name @index
plot_df['datetime'] = plot_df.index # Save original, maybe datetime index
plot_df = plot_df.reset_index(drop=True)
index = plot_df.index
# Initialize Bokeh figure function
new_bokeh_figure = partial(
figure,
x_axis_type='linear',
width=500,
height=400,
tools="xpan,xwheel_zoom,box_zoom,undo,redo,reset,save",
active_drag='xpan',
sizing_mode='stretch_both',
active_scroll='xwheel_zoom')
pad = (index[-1] - index[0]) / 20
_kwargs = dict(x_range=Range1d(index[0], index[-1],
min_interval=10,
bounds=(index[0] - pad,
index[-1] + pad))) if index.size > 1 else {}
# create bokeh figure instance
fig_ohlc = new_bokeh_figure(**_kwargs)
# used for volume and can be extended in the future
figs_below_ohlc = []
# create source object
source = ColumnDataSource(plot_df)
source.add((plot_df.Close >= plot_df.Open).values.astype(np.uint8).astype(str), 'inc')
# map colors
inc_cmap = factor_cmap('inc', COLORS, ['0', '1'])
def new_indicator_figure(**kwargs):
kwargs.setdefault('height', 150)
fig = new_bokeh_figure(x_range=fig_ohlc.x_range,
active_scroll='xwheel_zoom',
active_drag='xpan',
sizing_mode='stretch_width',
**kwargs)
fig.xaxis.visible = False
fig.yaxis.minor_tick_line_color = None
return fig
# create function to add candlesticks for OHLC
def _plot_ohlc():
"""Main OHLC bars"""
fig_ohlc.segment('index', 'High', 'index', 'Low', source=source, color="black")
fig_ohlc.vbar('index', BAR_WIDTH, 'Open', 'Close', source=source,
line_color="black", fill_color=inc_cmap)
def _plot_volume_section():
"""Volume section"""
fig = new_indicator_figure(y_axis_label="Volume")
fig.xaxis.formatter = fig_ohlc.xaxis[0].formatter
fig.xaxis.visible = True
fig_ohlc.xaxis.visible = False # Show only Volume's xaxis
fig.vbar('index', BAR_WIDTH, 'Volume', source=source, color='red')
return fig
fig_volume = _plot_volume_section()
figs_below_ohlc.append(fig_volume)
ohlc_bars = _plot_ohlc()
plots = [fig_ohlc] + figs_below_ohlc # where figs_below holds the volume figure
fig = gridplot(
plots,
ncols=1,
toolbar_location='right',
toolbar_options=dict(logo=None),
merge_tools=True,
sizing_mode='stretch_both'
)
show(fig)
return fig