Dash run_server non-blocking

I have written a very simple code to demonstrate the issue I have been facing with Dash for a while now. maybe the solution is straightforward, but I am relatively new with Dash :slightly_smiling_face:

the issue is that the codes after the app.run_server() function will never be executed. I have tried to add app.run_server() in a thread and faced some errors. Also, when I add it in a process I get different errors.

So is there a simple way to make the codes below app.run_server() get executed ?
or how can I make it behave in an asynchronous way just like javascript?

Here is the simple code (the print statement will never be executed):

from dash import Dash, dcc, html, Input, Output

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Asynchronous Test"),
])

if __name__ == '__main__':
    app.run_server(debug=True)
    print("This should print if the code is non blocking")

Why do you need it to be unblocking? :slight_smile:

I am using opencv library and I want to control some results of my image using Dash.

Here is the opencv code (if you copy and past it it should work with no problem):

# Python program for Detection of a
# specific color(blue here) using OpenCV with Python
import cv2
import numpy as np

# Webcamera no 0 is used to capture the frames. if you have another camera use 1 insted of 0
cap = cv2.VideoCapture(0)

hue_low = 110
hue_high = 130

saturation_low = 50
saturation_high = 255

value_low = 50
value_high = 255


# This drives the program into an infinite loop.
while(True):		
	# Captures the live stream frame-by-frame
	_, frame = cap.read()
	# Converts images from BGR to HSV
	hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
	lower_blue = np.array([hue_low,saturation_low,value_low])
	upper_blue = np.array([hue_high,saturation_high,value_high])

	# Here we are defining range of bluecolor in HSV
	# This creates a mask of blue coloured
	# objects found in the frame.
	mask = cv2.inRange(hsv, lower_blue, upper_blue)

	# The bitwise and of the frame and mask is done so
	# that only the blue coloured objects are highlighted
	# and stored in res
	res = cv2.bitwise_and(frame,frame, mask= mask)
	cv2.imshow('frame',frame)
	cv2.imshow('mask',mask)
	cv2.imshow('res',res)

	# This displays the frame, mask
	# and res which we created in 3 separate windows.
	k = cv2.waitKey(5) & 0xFF
	if k == 27:
		break

# Destroys all of the HighGUI windows.
cv2.destroyAllWindows()

# release the captured frame
cap.release()

and here is the Dash app after adding opencv to it:

#opencv
#############################################
import cv2
import numpy as np
import threading

cap = cv2.VideoCapture(0)

hue_low = 110
hue_high = 130

saturation_low = 50
saturation_high = 255

value_low = 50
value_high = 255




#############################################

#Dash
#############################################
from dash import dcc, html, Input, Output, Dash
import dash
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.Div("hue_low",id="callback"),
    dcc.Slider(0, 180, value=110,id='hue_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(19)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("hue_high"),
    dcc.Slider(0, 180, value=130,id='hue_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(19)},tooltip={"placement": "bottom", "always_visible": True}),
    
    html.Div("saturation_low"),
    dcc.Slider(0, 255, value=50,id='saturation_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("saturation_high"),
    dcc.Slider(0, 255, value=255,id='saturation_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    
    html.Div("value_low"),
    dcc.Slider(0, 255, value=50,id='value_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("value_high"),
    dcc.Slider(0, 255, value=255,id='value_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True})
       
])

@app.callback(
    
    Output('callback', 'children'),
    
    Input('hue_low', 'value'),
    Input('hue_high', 'value'),
    
    Input('saturation_low', 'value'),
    Input('saturation_high', 'value'),
    
    Input('value_low', 'value'),
    Input('value_high', 'value'),
    )
def update_output(hue_low_dash,hue_high_dash,   saturation_low_dash,saturation_high_dash,   value_low_dash, value_high_dash):
#############################################
    

#opencv
#############################################
    global hue_low
    global hue_high
    
    global saturation_low
    global saturation_high
    
    global value_low
    global value_high
    
    hue_low = hue_low_dash
    hue_high = hue_high_dash
    
    saturation_low = saturation_low_dash
    saturation_high = saturation_high_dash
    
    value_low = value_low_dash
    value_high = value_high_dash
#############################################

#Dash
############################################# 
    return dash.no_update

if __name__ == '__main__':
    
  
    app.run_server(debug=True) #if you use threading make sure debug=False otherwise you will face errors
#############################################    

#opencv
#############################################  
    while(True):		

        _, frame = cap.read()
        
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
        lower_blue = np.array([hue_low,saturation_low,value_low])
        upper_blue = np.array([hue_high,saturation_high,value_high])

        mask = cv2.inRange(hsv, lower_blue, upper_blue)

        res = cv2.bitwise_and(frame,frame, mask= mask)
        cv2.imshow('frame',frame)
        cv2.imshow('mask',mask)
        cv2.imshow('res',res)

        k = cv2.waitKey(5) & 0xFF
        if k == 27:
            break

    cv2.destroyAllWindows()

    cap.release()
#############################################

What about running the opencv code in a separate process?

I did and faced some errors.

this is the code:

#opencv
#############################################
import cv2
import numpy as np
import threading
import multiprocessing

cap = cv2.VideoCapture(0)

hue_low = 110
hue_high = 130

saturation_low = 50
saturation_high = 255

value_low = 50
value_high = 255




#############################################

#Dash
#############################################
from dash import dcc, html, Input, Output, Dash
import dash
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.Div("hue_low",id="callback"),
    dcc.Slider(0, 180, value=110,id='hue_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(19)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("hue_high"),
    dcc.Slider(0, 180, value=130,id='hue_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(19)},tooltip={"placement": "bottom", "always_visible": True}),
    
    html.Div("saturation_low"),
    dcc.Slider(0, 255, value=50,id='saturation_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("saturation_high"),
    dcc.Slider(0, 255, value=255,id='saturation_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    
    html.Div("value_low"),
    dcc.Slider(0, 255, value=50,id='value_low',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True}),
    html.Div("value_high"),
    dcc.Slider(0, 255, value=255,id='value_high',step=1,updatemode='drag',marks={i*10: "{}".format(i*10) for i in range(26)},tooltip={"placement": "bottom", "always_visible": True})
       
])

@app.callback(
    
    Output('callback', 'children'),
    
    Input('hue_low', 'value'),
    Input('hue_high', 'value'),
    
    Input('saturation_low', 'value'),
    Input('saturation_high', 'value'),
    
    Input('value_low', 'value'),
    Input('value_high', 'value'),
    )
def update_output(hue_low_dash,hue_high_dash,   saturation_low_dash,saturation_high_dash,   value_low_dash, value_high_dash):
#############################################
    

#opencv
#############################################
    global hue_low
    global hue_high
    
    global saturation_low
    global saturation_high
    
    global value_low
    global value_high
    
    hue_low = hue_low_dash
    hue_high = hue_high_dash
    
    saturation_low = saturation_low_dash
    saturation_high = saturation_high_dash
    
    value_low = value_low_dash
    value_high = value_high_dash
#############################################

#Dash
############################################# 
    return dash.no_update
############################################


#opencv
############################################# 
def opencv_fun():
	while(True):		

		_, frame = cap.read()
		
		hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
		lower_blue = np.array([hue_low,saturation_low,value_low])
		upper_blue = np.array([hue_high,saturation_high,value_high])

		mask = cv2.inRange(hsv, lower_blue, upper_blue)

		res = cv2.bitwise_and(frame,frame, mask= mask)
		cv2.imshow('frame',frame)
		cv2.imshow('mask',mask)
		cv2.imshow('res',res)

		k = cv2.waitKey(5) & 0xFF
		if k == 27:
			break

	cv2.destroyAllWindows()

	cap.release()
#############################################

if __name__ == '__main__':
    
	p1 = multiprocessing.Process(target = opencv_fun)
	p1.start()
 
 
 
	app.run_server(debug=True) #if you use threading make sure debug=False otherwise you will face errors
    
#############################################   

even if it works using another process this means that it would be more difficult to communicate with the variables in the dash function since another process would have its own variables separate from other process.

So is there a simple way other than using multiple process?