Issues with streaming time series data and updating the x_range values

Hi,

I have time series data which I am streaming to a time plot and I would like to visualise the last x seconds of the time series (like a sliding window). I have provided an MRE. The issue with it is that when it initially starts up, the animation is very chopped up, this is until I pan around, when the choppiness stops. The MRE is as such:

from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, DatetimeTickFormatter
from bokeh.driving import linear
from datetime import datetime, timedelta
import random

# Create a ColumnDataSource
source = ColumnDataSource(data=dict(x=[], y=[]))

# Create a plot with DatetimeAxis
p = figure(x_axis_type="datetime", title="Streaming Time Series with Sliding Window")

# Add a line glyph to the plot
p.line(x='x', y='y', source=source, line_width=2)
p.toolbar_location = None
p.y_range.max_interval = 1.5
p.y_range.min_interval = 0

# Define the sliding window size (in seconds)
window_size = 30

# Define the update function
def update():
    # Get the current timestamp
    current_time = datetime.now()

    # Generate random data
    random_value = random.random()

    # Add new data to the source
    new_data = {'x': [current_time], 'y': [random_value]}
    source.stream(new_data)

    # Calculate the start and end time of the sliding window
    start_time = current_time - timedelta(seconds=window_size)
    end_time = current_time

    # Update the x_range to create the sliding window effect
    p.x_range.start = start_time
    p.x_range.end = end_time

# Add the plot to the current document
curdoc().add_root(p)
curdoc().add_periodic_callback(update, 100)  # Update every 1 second

I have tried attaching a video to show what Iā€™m talking about but the file is seemingly too big.

Thanks,

Jack

@JackFrench2001 Could you try and see if using follow and follow_interval on the x_range object works:

p.x_range.follow = "end"
p.x_range.follow_interval = timedelta(seconds=window_size)

(ref example).

And comment out the update of start and end of x_range object in your callback.

One minor comment, if you want 1 s update of the callback you would have to change the 100 to 1000 (milliseconds).

1 Like

That worked perfectly, thank you!