Dynamic X range for scatter plot

Thanks for the help!

Last question, I can open up a new thread if needed but I’m trying to remove the periodic call back. I did some searching and found your post a little while back on removing callbacks from a document.

Here’s my new test code using that source as a baseline to remove a callback as soon as the generator is exhausted:

from random import randint
from collections import Counter

from bokeh.layouts import column
from bokeh.models import Button, ColumnDataSource, FactorRange
from bokeh.driving import count
from bokeh.plotting import figure, curdoc

# create a plot and style its properties
p = figure()
ds = ColumnDataSource(data=dict(count=[], l4=[]))

# add a text renderer to our plot (no data yet)
r = p.circle(x='count', y='l4', source=ds)

i = 0
data_amount = 250

L4_test = (randint(9232, 9235) for _ in range(data_amount))


# create a callback that will get "l4" data for the next count
def button_callback():
    curdoc().add_periodic_callback(update, 20)

def update():
    global i
    global data_amount
    if i == data_amount:
        curdoc().remove_periodic_callback(update)
        return
    new_data = stream_l4_data()
    ds.stream(new_data)
    i = i + 1


def stream_l4_data() -> dict:
    global i
    return dict(count=[i + 1], l4=[next(L4_test)])



# add a button widget and configure with the call back
button = Button(label="Start")
button.on_click(button_callback)

# put the button and plot in a layout and add to the document
curdoc().add_root(column(button, p))

When I run this snippet using bokeh serve test.py it runs as expected until the generator exhausts. When the generator exhausts the remove_periodic_callback(update) function runs, but now my terminal shows ValueError: callback already ran or was already removed, cannot be removed again. How is the update function still running in the event loop when I specifically turned it off?