Background callbacks

Hi,
I have a problem with the using of background callbacks.
the project is to read data from and store it into SQLite that is the background callback
the second callback it to read from db and plot it in real time.
I am trying the background because of the use of dcc.Interval will not allow the user to do anything but to wait for the plot to finish to keep the interval timing accuracy.
The call count of the callback stays by 0 !
has anyone any idea to help ?
Thank you

My code:

 
celery_app = Celery(__name__, broker="redis://localhost:6379/0", backend="redis://localhost:6379/1")
background_callback_manager = CeleryManager(celery_app)


@dash.callback(Output(component_id='background_store', component_property='data'),
              Input(component_id='background_interval', component_property='n_intervals'), 
            
              Input(component_id='switch', component_property='on'), 
              Input(component_id='dropdown', component_property='value'), 
              
              
              background=True,
              manager=background_callback_manager,
              )
            
              
def background_acquisition(n , on, dropdown, ):
	ADC_Value = ADC.ADS1256_GetAll()

	data = [] #array for figure then append data for each dropdown value 
	
	
	
	if on == False: #switch on/off 
		no_update
		return no_update
	else:
		layout = go.Layout( xaxis=dict( title="Zeit [sec]" ), yaxis=dict( title="AD Signal [counts]" ) ) 
		time_stamp = timing
		conn = sqlite3.connect(messen)
		curs = conn.cursor()
		curs.execute("INSERT INTO time (epoch , timing) VALUES ( ?, ?)", (unix_time ,  time_stamp))
		conn.commit()
		increase_time() 
		df_time = pd.read_sql_query("SELECT zeit FROM time ORDER BY zeit ASC ", conn) 
		last_row_time = df_time.iloc[:n,:]
		
		
		curs.execute("INSERT INTO k1 (k1 ) VALUES (?)",  (([(ADC[0])]))) 
		conn.commit()
		df1 = pd.read_sql_query("SELECT * FROM k1 ", conn) 
		row1 = df1.iloc[:n,:]
		data.append(go.Scatter(x = asarray(last_row_time[df_time.columns[0]]) , y = asarray(row1[df1.columns[0]]),))
		
		update_timing() 
		global x2 #update x2 and gloabe waiting time for interval  to subtract process time
		x2  = monotonic() - x1 
		global waiting_time
		waiting_time = 1 - x2 
		
		figure = go.Figure({'data' : data , 'layout' : layout})
		figure
		return figure
		.... #
			
		
		
		
		
		#update x2 and gloabe waiting time for interval  and  subtract process time from waiting time to keep waiting time 1 sec 	
		
		
#callback graphing 
		
@app.callback(Output(component_id='live-graph', component_property='figure'), 
              Input(component_id='update_Graph', component_property='n_intervals'), 
              Input(component_id='switch', component_property='on'), 
              Input(component_id='dropdown', component_property='value'), 
              )
            
def update_graph(n):
	data = []
	layout = go.Layout( xaxis=dict( title="Zeit [sec]" ), yaxis=dict( title="AD Signal [counts]" ) ) 
	conn = sqlite3.connect(messen)
	curs = conn.cursor()
	df_time = pd.read_sql_query("SELECT timing FROM time ORDER BY timing ASC ", conn) 
	last_row_time = df_time.iloc[:n,:]
	
	df1 = pd.read_sql_query("SELECT * FROM k1 ", conn) 
	row1 = df1.iloc[:n,:]
	data.append(go.Scatter(x = asarray(last_row_time[df_time.columns[0]]) , y = asarray(row1[df1.columns[0]]),  ))
	
	figure = go.Figure({'data' : data , 'layout' : layout})
	figure
	return figure
      
	



Hello @raspi,

Just to confirm, I didnt see it above, but you are returning something after you commit to your sqlite db?

Yes, I am trying to build the figure property from Graph and save it into dcc.Store.

In the above example, your else statement is missing a return statement.

I was just clarifying that you actually have a return statement in your real code.

I have a return statement in both callbacks functions. The problem is that the second callback is called while the first (background) not.

You have no errors displaying with debug mode on?

What about errors in the code for the background callback?

Normally, if you don’t see any callbacks increasing it is because it isn’t reading as a valid callback.

As you are not giving your actual code, I cannot verify your exact setup. This is fine, just makes helping harder.

I did not get any errors in debug or in the code. I edited the code above

1 Like

You are trying to return the made figure to the dcc.Store data?

Also, to verify that these are indeed not called, and not just never returned. You need to look at your network tab in developer mode and look for the inputs and outputs that are associated with the callback as the payload in the request.

If it is there, then I’d start by returning a simple figure and make sure the Store is updating.

If it does update, then I’d disable the chunk about updating the time intervals, etc, and see if you can get the figure to the Store.

If it isn’t being called, can you please send an image of your debug menu, the icons where the callback graph icon is.

1 Like

Well, I am running the code on a Raspberry Pi and the main goal is to separate measurement from plotting to keep intervals firing in background.

I will try this.

@raspi,

According to the callback that you gave above, you were returning a figure and not just plain data. I was just going off of what you had updated the code to be in the else clause. :grin:

sorry :sweat_smile:, i dont understand what you mean! I wanted to save the figure into the Store and keep background callback firing to keep the interval with one second!

I simplified the code and made two callbacks:
1- to read and insert data into SQLite db
2- to read the last data from db and plot

once I get the time-function (time counter actually) in the first callback the graph looks like this in the pic, I want to keep interval firing in background with accurate timing that’s why i need background callbacks or any other way to keep timing accurate.


@dash.callback(
               Output(component_id='background_store', component_property='data') , 
              
               inputs = [ 
               Input(component_id='background_interval', component_property='n_intervals'), 
              
              ],
              
              
              background=True,
              manager=background_callback_manager,
               )
             
              
def background_acquisition(  data ):
	ADC_Value = ADC.ADS1256_GetAll()

	data = [] #array for figure then append data for each dropdown value 
	
	
	
	layout = go.Layout( xaxis=dict( title="Zeit [sec]" ), yaxis=dict( title="AD Signal [counts]" ) ) 
	
	 
	conn = sqlite3.connect(messen)
	curs = conn.cursor()
	#time
	storing_time =curs.execute("INSERT INTO time (unix, zeit) VALUES ( ?, ?)", (unix_time ,  zeit))
	storing_time
	conn.commit()
	
	

	
	storing1 =curs.execute("INSERT INTO kanal1 (kanal1 ) VALUES (?)",  (([(ADC_Value[0])]))) 	
	storing1
	conn.commit()
	timing = Timer(1 , update_zeit).start()
	timing2 = Timer(1 , increase_time).start()
	
	return storing1 , storing_time , timing , timing2 
	

		
			
		
		
		
		
		
#callback graphing 
		
@app.callback(Output(component_id='live-graph', component_property='figure'), 
              Input(component_id='update_Graph', component_property='n_intervals'), 
             
             
              )
            
              
def updating_graph( n):
	ADC_Value = ADC.ADS1256_GetAll()

	data = [] #array for figure then append data for each dropdown value 


	
	layout = go.Layout( xaxis=dict( title="Zeit [sec]" ), yaxis=dict( title="AD Signal [counts]" ) ) 
	
	time_stamp = zeit 
	conn = sqlite3.connect(messen)
	curs = conn.cursor()
	
	
	df_time = pd.read_sql_query("SELECT zeit FROM time ORDER BY zeit ASC ", conn) #read time table for x-axe  
	last_row_time = df_time.iloc[:n,:]
	
	
	
	df1 = pd.read_sql_query("SELECT * FROM kanal1 ", conn) 
	row1 = df1.iloc[:n,:]
		
	data.append(go.Scatter(x = asarray(last_row_time[df_time.columns[0]]) , y = asarray(row1[df1.columns[0]]),  mode='lines+markers', name="kanal1" , line_shape='spline'))
	
	figure = go.Figure({'data' : data , 'layout' : layout})
	figure
	
	return figure 


´´´

Ok, so you can’t keep things firing in an endless loop outside of the application.

For updating the graph, instead of using a time interval, use the Store as the input and take the data from there each time it updates.