Patch for source

I am a newbie in blokeh, so this can be an easy problem for you perhaps. I am trying to write an app to display stock prices on browser.
In the code I created an source:, open=open, close=close, high=high, low=low, inc=inc, dec=dec))

And with a while loop I am trying to get new price in every 5 seconds and trying to update the price bar.
To do so first I code checks if new price is not same with previous price and if it is different than creates a patch dictionary:

if close_new[-1] != close[-1]:
    patches_1_1 ={'close': [(len(close)-1, close_new[-1])]}

Than, updating the source:


When I write len(close) it throws an index error, which is strange, and I thought it can be different indexing in patch so I chosed (len(close)-1 . There is a len(close)-1 index eventually. This is not a problem in anyway.

But this code creates a very long error:

  File "C:\ProgramData\Anaconda3\lib\", line 932, in _bootstrap_inner
  File "C:\ProgramData\Anaconda3\lib\", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\milik\PycharmProjects\Interview\", line 114, in blocking_task
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\models\", line 684, in patch, self, patches, setter)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\", line 470, in _patch
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\", line 150, in _notify_owners
    descriptor._notify_mutated(owner, old, hint=hint)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\", line 869, in _notify_mutated
    self._real_set(obj, old, value, hint=hint)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\", line 832, in _real_set
    self._trigger(obj, old, value, hint=hint, setter=setter)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\core\property\", line 909, in _trigger
    obj.trigger(, old, value, hint, setter)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\", line 664, in trigger
    super().trigger(attr, old, new, hint=hint, setter=setter)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\util\", line 157, in trigger
    self._document._notify_change(self, attr, old, new, hint, setter, invoke)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 1061, in _notify_change
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 1156, in _trigger_on_change
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 1169, in _with_self_as_curdoc
    return f()
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 1155, in invoke_callbacks
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 723, in <lambda>
    self._callbacks[receiver] = lambda event: event.dispatch(receiver)
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 269, in dispatch
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\document\", line 124, in dispatch
  File "C:\ProgramData\Anaconda3\lib\site-packages\bokeh\server\", line 218, in _document_patched
    raise RuntimeError("_pending_writes should be non-None when we have a document lock, and we should have the lock when the document changes")

In the source there are several columns but I need to update only one value in one column in a time.

What am I missing?

Hi @milikest it’s not possible to speculate without a Minimal Reproducible Example

Hello, to be more clear, here is the code:
As u see get_bars gets the ohlc knowledge from binance api.

def get_bars(symbol='BTCUSDT', interval='1m', limit='500'):
    root_url = ''
    url = root_url + '?symbol=' + symbol + '&interval=' + interval + '&limit=' + limit
    data = json.loads(requests.get(url).text)
    df = pd.DataFrame(data)
    df.columns = ['Open_time',
                  'Open', 'High', 'Low', 'Close', 'Volume',
                  'Close_time', 'Quote_asset_volume', 'Number_of_trades',
                  'Taker_buy_base_asset_volume', 'Taker_buy_quote_asset_volume', 'Ignore']
    df['Open'] = df['Open'].astype('float')
    df['High'] = df['High'].astype('float')
    df['Low'] = df['Low'].astype('float')
    df['Close'] = df['Close'].astype('float')
    df['Volume'] = df['Volume'].astype('float')
    df['Quote_asset_volume'] = df['Quote_asset_volume'].astype('float')
    df['Number_of_trades'] = df['Number_of_trades'].astype('float')
    df['Taker_buy_base_asset_volume'] = df['Taker_buy_base_asset_volume'].astype('float')
    df['Taker_buy_quote_asset_volume'] = df['Taker_buy_quote_asset_volume'].astype('float')
    df['Ignore'] = df['Ignore'].astype('float')

    df.index = [dt.datetime.fromtimestamp(x / 1000.0) for x in df.Close_time]
    df['pre_index'] = df.index
    df.index = pd.RangeIndex(len(df.index))
    return df

df = get_bars()

close_time = np.array(df['Close_time'])
open = np.array(df['Open'])
close = np.array(df['Close'])
high = np.array(df['High'])
low = np.array(df['Low'])
inc = np.array(df.Close > df.Open)
dec = np.array(df.Open > df.Close)
close_time_inc = close_time[inc]
close_time_dec = close_time[dec]
open_dec = open[dec]
open_inc = open[inc]
close_dec = close[dec]
close_inc = close[inc]

This is from the bokeh sample : — Bokeh 2.4.0 Documentation

I created 3 sources because they are going to have different lengths but similar in each:

source = ColumnDataSource(data=dict(close_time=close_time, open=open, close=close, high=high, low=low, inc=inc, dec=dec))
source_2 = ColumnDataSource(data=dict(close_time_inc=close_time_inc, open_inc=open_inc, close_inc=close_inc))
source_3 = ColumnDataSource(data=dict(close_time_dec=close_time_dec, open_dec=open_dec, close_dec=close_dec))
doc = curdoc()


def update(close_time, open, close, high, low, inc, dec, close_time_inc, close_time_dec, open_dec, open_inc, close_dec,

           close_inc):, open=open, close=close, high=high, low=low, inc=inc, dec=dec)), open_inc=open_inc, close_inc=close_inc))      , open_dec=open_dec, close_dec=close_dec)

And here is to while loop:
get_bars limit parameter how many bars it will take from api. limit=1 means get me the last ohlc knowledge of that interval. Interval can be 1minute, 5minute, 1 hour,…etc. df_new will get last ohlc values so in the chart it will be updating only last bar.

def blocking_task():
    while True:
        global df
        global close_time
        global open
        global close
        global high
        global low
        global inc
        global dec
        global close_time_inc
        global close_time_dec
        global open_dec
        global open_inc
        global close_dec
        global close_inc
        df_new = get_bars(limit='1')
        close_time_new = np.array(df_new['Close_time'])
        open_new = np.array(df_new['Open'])
        close_new = np.array(df_new['Close'])
        high_new = np.array(df_new['High'])
        low_new = np.array(df_new['Low'])
        inc_new = np.array(df_new.Close > df_new.Open)
        dec_new = np.array(df_new.Open > df_new.Close)
        close_time_inc_new = close_time_new[inc_new]
        close_time_dec_new = close_time_new[dec_new]
        open_dec_new = open_new[dec_new]
        open_inc_new = open_new[inc_new]
        close_dec_new = close_new[dec_new]
        close_inc_new = close_new[inc_new]
        if close_time_new[-1] == close_time[-1]:
            patches_1 = {}
            patches_2 = {}
            patches_3 = {}
            if close_new[-1] != close[-1]:
                patches_1_1 ={'close': [(len(close)-1, close_new[-1])]}
                if len(patches_1_1)!=0:
            if high_new[-1] != high[-1]:
                patches_1_2 ={'high': [(len(high)-1, high_new[-1])]}
                if len(patches_1_2)!=0:

This if statements goes to end of ‘dec’ variable updating for source and source_2 and source_3 is being updated with same logic.
And when the requested timestamps passes to next time interval:

                partial(update,close_time=close_time, open=open, close=close, high=high, low=low, inc=inc, dec=dec ,
                close_time_inc=close_time_inc, close_time_dec=close_time_dec, open_dec=open_dec, open_inc=open_inc,
                 close_dec=close_dec, close_inc=close_inc))
            df = pd.concat([df, df_new])
            close_time = np.array(df['Close_time'])
            open = np.array(df['Open'])
            close = np.array(df['Close'])
            high = np.array(df['High'])
            low = np.array(df['Low'])
            inc = np.array(df.Close > df.Open)
            dec = np.array(df.Open > df.Close)
            close_time_inc = close_time[inc]
            close_time_dec = close_time[dec]
            open_dec = open[dec]
            open_inc = open[inc]
            close_dec = close[dec]
            close_inc = close[inc]

Last prices (ohlc) are being added to df and df_new will be new values again.
And the plotting last part:

TOOLS = "pan,wheel_zoom,box_zoom,reset,save,crosshair, hover, poly_draw,lasso_select"
p = figure(x_axis_type="datetime", sizing_mode='scale_height', tools=TOOLS, plot_width=1250, title="Candlestick")

w = 12 * 60 * 60 * 1
p.xaxis.major_label_orientation = pi / 4
p.grid.grid_line_alpha = 0.3
p.segment(x0='close_time', y0='high', x1='close_time', y1='low', source=source, color="black")
p.vbar('close_time_inc', w/2, 'open_inc', 'close_inc', source=source_2, fill_color="#077C47", line_color="black")
p.vbar('close_time_dec', w/2, 'open_dec', 'close_dec', source=source_3, fill_color="#ED051F", line_color="black")


thread = Thread(target=blocking_task)

And for sure to run the server on terminal I type : bokeh serve --show
I guess I exceeded the maximum description for a problem…
Sorry for that.
And thanks anyway.