# Reload a static html plot

**URL:** <https://discourse.bokeh.org/t/reload-a-static-html-plot/11726>\
**Category:** Community Support\
**Created:** [July 30, 2024, 11:22pm UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726 "2024-07-30T23:22:31Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![dukebot](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/d/9d8465/32.png) [@dukebot](https://discourse.bokeh.org/u/dukebot)\
**Post date:** [July 30, 2024, 11:22pm UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726/1 "2024-07-30T23:22:32Z")

</div>

Lets say I am creating a plot from OHLC data and adding some customizations. I am also adding other figures like Volume and creating a gridplot with the plots

I am then running **show(fig)** and all is well. The static html page pops up with my candlestick chart no problem. This plot is being invoked from a plot function which is called from an outside module. that is collecting data every 5 minutes for new candles. Once a new candle arrive I update the dataFrame and would then like to automatically update the static html plot with the new data from that dataframe. I am not adding a new bar but replacing the whole dataFrame

Here is my code implementation:

```auto
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

```

Now once a new bar of data comes in I would like to reload the plot instead of opening a new browser instance. I am not sure how but i believe itll be something with **js\_on\_change** function for a source change. and then calling some callback like so

```auto
    def refresh_plot():
        # This will execute once when the document changes
        print("Document changed, triggering reload.")
        return """
            window.location.reload(); // Reload the page
        """

```

**EDIT:** When calling this function again and saving the fig instead of showing the fig after an update, I can just refresh the browser window myself and the new chart populates. At the end of my file I added this

```auto
    if (update_plot):
        save(fig)
    else:
        show(fig)
    return fig

```

But I am asking how to automatically refresh that browser window instead of manually doing it

---

<div class="post-metadata">

**Author:** ![smith666](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/smith666/32/6656_2.png) [@smith666](https://discourse.bokeh.org/u/smith666)\
**Post date:** [August 6, 2024, 10:38am UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726/2 "2024-08-06T10:38:42Z")

</div>

Hi,

I’m not sure, but updating standalone html is not posible.  
You can do this using Bokeh Server, using for example add\_next\_tick\_callback or add\_periodic\_callback moethods for Document calss.  
[https://docs.bokeh.org/en/latest/docs/reference/document.html](https://docs.bokeh.org/en/latest/docs/reference/document.html)

---

<div class="post-metadata">

**Author:** ![Bryan](https://discourse.bokeh.org/user_avatar/discourse.bokeh.org/bryan/32/3625_2.png) [@Bryan](https://discourse.bokeh.org/u/Bryan)\
**Post date:** [August 6, 2024, 3:20pm UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726/3 "2024-08-06T15:20:02Z")

</div>

You can add a non-Bokeh, plain-JavaScript repeating `setTimeout` callback on your page by using a custom HTML template. A `setTimeout` callback could call `reload()` and if the content on the server has changed since the last reload, the possibly the content on the page might update. I say possibly because I can imagine that things like browser caching might complicate matters or make things not work as expected. So, I don’t really recommend such approaches because they seem fragile and kludgy.

As @smith666 mentions, this kind of use-case is the reason that the Bokeh server exists.

Now, it is _very_ recently possible to “compile” Python to the browser using tools like PyScript, and this even includes demonstrations of “running” Bokeh server apps purely in a browser. But I am not up to date on those developments, I am only passingly aware they exist, so I can’t offer any more information about that possibility. cc @James_A_Bednar1

---

<div class="post-metadata">

**Author:** ![dukebot](https://discourse.bokeh.org/letter_avatar_proxy/v4/letter/d/9d8465/32.png) [@dukebot](https://discourse.bokeh.org/u/dukebot)\
**Post date:** [August 7, 2024, 6:30pm UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726/4 "2024-08-07T18:30:05Z")

</div>

thanks for the reply. I decided I will not need this functionality at the moment as I can just add a button to refresh the plot and or refresh the browser and itll have the most up to date chart.

---

<div class="post-metadata">

**Author:** ![system](https://discourse-uploads.bokeh.org/original/2X/1/14eb24f9e10e4e9b78e3f10f66c04ffa96446e5a.svg) [@system](https://discourse.bokeh.org/u/system)\
**Post date:** [November 5, 2024, 6:30pm UTC](https://discourse.bokeh.org/t/reload-a-static-html-plot/11726/5 "2024-11-05T18:30:45Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
