Execute sequense between set button label and draw the plot

Hi,

I wrote one dashboad with 3 plots ,one datetable,one datepicker and one button.
Suppose ,to click the button to query data is slow ,say 10 seconds to finish.(Please see the script below:time.sleep(10))
10 seconds is long,I’d like to make a little interative act to set the button’s label to “querying”.
When I click the button in the webpage,it seems the button’s label changed after 10s’ data querying finished ,instead of before the data querying start.
How can i make the change of the button’s label happen before the 10s’ data querying?
Thanks!

###Here is my script code !

from bokeh.models import Slider,Button, ColumnDataSource,PreText,DatePicker, DataTable, DateFormatter, TableColumn
from bokeh.io import curdoc
from bokeh.layouts import row,gridplot
from bokeh.plotting import figure
from numpy.random import random
from datetime import date
from random import randint
import time
#Define the points that create the line plot
x = [1,2,3,4,5,6,7,8,9]
y = [2,3,4,5,6,7,8,9,10]
points=5
data_points = ColumnDataSource(data = {'x': x, 'y': y,})
plot0 = figure(title = 'Random Line plot generator',height=300,width=530)
plot0.line('x', 'y', source = data_points, color = 'red')
plot1 = figure(title = 'Random circle plot generator',height=300,width=530)
plot1.circle('x', 'y', source = data_points, color = 'blue',size=5)
plot2 = figure(title = 'Random circle plot generator',height=300,width=530)
#plot2.vbar(x=data_points.data['x'], width=0.5, bottom=0,       top=data_points.data['y'], color="firebrick")
plot2.vbar(x='x', width=0.05, bottom=0,       top='y', color="firebrick", source = data_points)
def get_table_data(points):
    table_data = dict(
        dates0=[date(2014, 3, i+1) for i in range(10)],         downloads0=[randint(0, 100*points) for i in range(10)],
        dates1=[date(2014, 3, i+1) for i in range(10)],        downloads1=[randint(0, 100*points) for i in range(10)],
        dates2=[date(2014, 3, i+1) for i in range(10)],        downloads2=[randint(0, 100*points) for i in range(10)],
        dates3=[date(2014, 3, i+1) for i in range(10)],        downloads3=[randint(0, 100*points) for i in range(10)],
        dates4=[date(2014, 3, i+1) for i in range(10)],        downloads4=[randint(0, 100*points) for i in range(10)],
        dates5=[date(2014, 3, i+1) for i in range(10)],        downloads5=[randint(0, 100*points) for i in range(10)],
        dates6=[date(2014, 3, i+1) for i in range(10)],        downloads6=[randint(0, 100*points) for i in range(10)],
        dates7=[date(2014, 3, i+1) for i in range(10)],        downloads7=[randint(0, 100*points) for i in range(10)],
    )
    return table_data
table_data =get_table_data(points)  
columns = [ ]
for i in range(8):
    columns.append(TableColumn(field="dates"+str(i), title="Date"+str(i), formatter=DateFormatter()))
    columns.append(TableColumn(field="downloads"+str(i), title="Downloads"+str(i)))

table_source = ColumnDataSource(table_data)
data_table0 = DataTable(source=table_source, columns=columns, width=1600, height=280)
pre_geshu = PreText(text="""chooser date:""",width=100, height=10)
date_picker = DatePicker(title='', value="2022-01-01", min_date="2022-01-01", max_date="2022-12-31")
button0 = Button(label="click", button_type="success",width=30)

def callback_date(attr, old, new):
    global points 
    points= date_picker.value
    points=int(points[-2:])
    print('date_picker:'+str(points))
 
def callback_button0():
    global button0
    button0.label="querying..."  
    time.sleep(10)
    print('!!!!!!!!!!start to drawing the image with '+str(points)+' points!!!!!')
    global data_points
    global table_data
    global data_table0
    data_points.data = {'x': random(points), 'y': random(points)} 
    table_data =get_table_data(points)  
    #print('!!!!inner table_data:',table_data)	
    table_source.data=table_data
    button0.label="click"
    button0.disabled =False
	
#print('!!!!outer table_data:',table_data)
date_picker.on_change('value', callback_date)
button0.on_click(callback_button0)
layout =  gridplot([[row(pre_geshu,date_picker, button0)], [row( plot0,plot1,plot2)],[row(data_table0)]])
curdoc().add_root(layout)
curdoc().title = "test_report"

Hi @baijingui please edit your post to use code formatting so that the code is intelligible (either with the </> icon on the editing toolbar, or triple backtick ``` fences around the code blocks)

Thank You for your reply.
Code is already formatted.

Bokeh callbacks synchronize to the browser at the the end. You will need to split your callback up into two parts:

def remaining_work():
    time.sleep(10)
    button.label = ""

def first_work():
    button.label="querying..."  
    curdoc().add_next_tick_callback(remaining_work)
    # button will update at this exit, next callback will do the rest

button.on_click(first_work)

Hi,Bryan,

It worked! Now I got the expected sequense.

Thank you!

1 Like