How to change x_range of a figure periodically?

My objective: I have to monitor a machine performance by a figure. The performance data is a time series. I wish the width of the x_range is two-hours wide.
My tools: I used a periodical callback function to change the x_range in the beginning of every single hour.
Testing: The following program is a testing code.
Executing command: bokeh serve --show allMachineEffiencyTest.py --address 120.xxx.xxx.xxx --allow-websocket-origin=120.xxx.xxx.xx:xxxx --port xxxx
My problem: Why the x_range was changed just for a split second at every updating moment, and then quickly restore to the original range?

from bokeh.layouts import gridplot, column
from bokeh.models import ColumnDataSource, Div, HoverTool, BoxAnnotation
from bokeh.plotting import curdoc, figure
import numpy as np
from datetime import datetime, timedelta
from numpy import arange, linspace, pi, sin

print(allMachineEffiencyToday())
x = 0.0
def allMachineEffiencyToday():
	ratioPlot = list()
	timeAxisStr = []
	dataSource = []

	itemInfos = "Machine 001"
	y = sin(x)
	
	plot = figure(title="Machine 001", toolbar_location=None, tools="hover", tooltips="@y")
	plot.background_fill_color = "#efefef"
	plot.xgrid.grid_line_color=None
	plot.xaxis.axis_label = 'x'
	plot.yaxis.axis_label = 'sin(x)'
	
	line_data = {"x":[],"y":[]}
	line_data['x'].append(x)
	line_data['y'].append(y)
	dataSource = ColumnDataSource(data=line_data)
	plot.line(x='x', y= 'y', source=dataSource, color='blue')
	plot.x_range.start = 0.0
	plot.x_range.end = 5.0
	plot.y_range.start = -1.0
	plot.y_range.end = 1.0

	ratioPlot.append(plot)

	def update_data():
		global x
		x = x + 0.1
		y = sin(x)
		
		dataSource.data['y'].append(y)
		dataSource.data['x'].append(x)
		dataSource.trigger('data', dataSource.data, dataSource.data)
		plot.x_range.start = int(x*5)/5 - 1.0
		plot.x_range.end = int(x*5)/5 + 1.0
		
	grid = gridplot(ratioPlot, ncols=1)
	curdoc().add_root(grid)
	curdoc().add_periodic_callback(update_data, 1000)
	
	return 'end of allMachineEffiencyToday()'

I found the reason why x_range restores to the original range might be that the “focus” was still locating at the beginning position. So, if we can change the “focus” of figure to the current time position, then the x_range might not flip to the original range after every x_range updated moment. But, I don’t know how to change the focus of the figure?

FYI it would be much better to use dataSource.stream that to do this.

Regarding the other, I am not seeing anything like you describe with Bokeh 2.4. You have not stated what version you are using (please: always provide version information on any support question to any open source project, every time) so all I can suggest is that you make sure your version is up to date. Otherwise, you may need to supply a screen capture video that shows exactly what you are seeing.

My Bokeh server version 2.3.0
Thanks your advice, it really help me very much. The new code is as follows. But there is a new problem.

from bokeh.layouts import gridplot, column
from bokeh.models import ColumnDataSource, Div, HoverTool, BoxAnnotation
from bokeh.plotting import curdoc, figure
from userRight import mac_is_valid
import numpy as np
from datetime import datetime, timedelta
from numpy import arange, linspace, pi, sin

print(allMachineEffiencyToday())
x = 0.0
def allMachineEffiencyToday():

	ratioPlot = list()
	timeAxisStr = []
	dataSource = []

	itemInfos = "Machine 001"
	y = sin(x)
	
	plot = figure(title="Machine 001", toolbar_location=None, tools="hover, pan", tooltips="@y")
	plot.background_fill_color = "#efefef"
	plot.xgrid.grid_line_color=None
	plot.xaxis.axis_label = 'x'
	plot.yaxis.axis_label = 'sin(x)'
	
	line_data = {"x":[],"y":[]}
	line_data['x'].append(x)
	line_data['y'].append(y)
	dataSource = ColumnDataSource(data=line_data)
	dataSource.stream(line_data)#new code
	plot.line(x='x', y= 'y', source=dataSource, color='blue')
	plot.y_range.start = -1.0
	plot.y_range.end = 1.0

	ratioPlot.append(plot)

	def update_data():
		global x
		x = x + 0.5
		y = sin(x)
		
		line_data['x'].append(x)#new code
		line_data['y'].append(y)#new code
		dataSource.data = line_data#new code
		plot.x_range.follow = "end"#new code
		plot.x_range.follow_interval = 4#new code
		
	grid = gridplot(ratioPlot, ncols=1)
	curdoc().add_root(grid)
	curdoc().add_periodic_callback(update_data, 500)
	
	return 'end of allMachineEffiencyToday()'

Very good, x_range is dynamically changed like the following vedio, but there is seems a lag of data curve, so the curve is finally not seen at the figure. Do I need do something else?

The example which is shown on the bokeh.org seems has the same problem.

@yvechang When i run that example, everything updates smoothly, I don’t see any stuttering. All I can suggest at this point is to file a GitHub Issue with very detailed information about your OS, browser, python environment, etc.

I tested the “Streaming Noisy” example in the Jupyter. Does the Jupyter environment cause the stuttering? My project running in Bokeh server seems not appeared any lag.

By default Bokeh server apps in the notebook run on the same IOLoop as the notebook itself, so if the notebook IOLoop is busy/loaded then that could explain things. Currently showing an app in the notebook always uses this default IOLoop, and it is not configurable. You could try manually doing the steps in this function below, except in a thread on a new IOLoop (just an untested idea, no guarantees)

bokeh/notebook.py at branch-3.0 · bokeh/bokeh · GitHub

OK, I see, thank you very much.

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