How to output a value in an html.div?
Question:
I have a function that prints a random value.
The function is ‘activated’ when the button Start
is pressed.
print("acquisition is on")
print(random.random())
At the moment the random value is printed in the console. But I am wondering how to directly output this value in the html.Div.
Below is the full code
from dash import Dash, html, dcc, Input, Output, ctx
import dash_bootstrap_components as dbc
import time
import threading
import random
app = Dash(
__name__,
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.FONT_AWESOME],
title = 'MT',
prevent_initial_callbacks = "initial_duplicate"
)
class Nanotec(threading.Thread):
def __init__(self, *args, **kwargs):
# When Main is excuted, this does :
super(Nanotec, self).__init__(*args, **kwargs)
self.__flag = threading.Event() # The flag used to pause the thread
self.__flag.set() # Set to True
self.__running = threading.Event() # Used to stop the thread identification
self.__running.set() # Set running to True
def run(self):
while self.__running.isSet():
self.__flag.wait() # return immediately when it is True, block until the internal flag is True when it is False
print("acquisition is on")
print(random.random())
time.sleep(1)
def pause(self):
self.__flag.clear() # Set to False to block the thread
print("pausing")
def resume(self):
self.__flag.set() # Set to True, let the thread stop blocking
print("resuming")
def stop(self):
self.__flag.set() # Resume the thread from the suspended state, if it is already suspended
self.__running.clear() # Set to False
@app.callback(Output('container', 'children'),
Input('btn_start_nanotec', 'n_clicks'),
Input('btn_pause_nanotec', 'n_clicks'),
Input('btn_resume_nanotec', 'n_clicks')
)
def display(btn_start_nanotec, btn_pause_nanotec, btn_resume_nanotec):
button_id = ctx.triggered_id if not None else 'No clicks yet'
if button_id == "btn_start_nanotec" :
my_thread_nanotec.start()
elif button_id == "btn_pause_nanotec" :
my_thread_nanotec.pause()
elif button_id == "btn_resume_nanotec" :
my_thread_nanotec.resume()
my_thread_nanotec = Nanotec()
app.layout = html.Div([
html.Button('Start', id='btn_start_nanotec'),
html.Button('Pause', id='btn_pause_nanotec'),
html.Button('Resume', id='btn_resume_nanotec'),
html.Div(id='container'),
html.Br(),
])
if __name__ == "__main__":
app.run_server(debug = True)
Answers:
I am not quite sure what are you trying to do here regarding that multithreading class. Is it supposed to update html.Div
one time per second? Is text supposed to be updated on button click?
But since the question is "How to put a value…", here’s a quick explanation. I replaced multithreading class with a simple generator to make things clearer.
Your callback is supposed to return the value to put into html.Div
. So here the value is fetched from the generator (when the button is clicked) and returned:
import random
from dash import Dash, html, dcc, Input, Output, ctx
app = Dash(__name__, title="MT", prevent_initial_callbacks="initial_duplicate")
def randoms():
while True:
yield random.random()
random_iter = randoms()
@app.callback(
Output(component_id="container", component_property="children"),
Input("btn_start_nanotec", "n_clicks"),
Input("btn_pause_nanotec", "n_clicks"),
Input("btn_resume_nanotec", "n_clicks"),
)
def display(*_):
button_id = ctx.triggered_id
if button_id == "btn_start_nanotec":
result = next(random_iter)
elif button_id == "btn_pause_nanotec":
result = 'Pause?..'
elif button_id == "btn_resume_nanotec":
result = next(random_iter)
return result
app.layout = html.Div(
[
html.Button("Start", id="btn_start_nanotec"),
html.Button("Pause", id="btn_pause_nanotec"),
html.Button("Resume", id="btn_resume_nanotec"),
html.Div(id="container"),
html.Br(),
]
)
if __name__ == "__main__":
app.run_server(debug=True)
You can replace my super-simple iterator with anything else (threading.Thread
, multiprocessing.Pool
, whatever), but the callback still has to get the value from the source and return it.
Intervals
If you need to update the output periodically (once per second), take a look into Intervals. The same basic principle works just the same (callback returns value), but it would handle periodical updates for you.
Updating Input with Websocket messages
Websocket
component seems to fit the bill quite nicely: data sent by another process/thread and updated in (sort of) real time, even bidirectional communication (pause/resume) is supported.
I have a function that prints a random value.
The function is ‘activated’ when the button Start
is pressed.
print("acquisition is on")
print(random.random())
At the moment the random value is printed in the console. But I am wondering how to directly output this value in the html.Div.
Below is the full code
from dash import Dash, html, dcc, Input, Output, ctx
import dash_bootstrap_components as dbc
import time
import threading
import random
app = Dash(
__name__,
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.FONT_AWESOME],
title = 'MT',
prevent_initial_callbacks = "initial_duplicate"
)
class Nanotec(threading.Thread):
def __init__(self, *args, **kwargs):
# When Main is excuted, this does :
super(Nanotec, self).__init__(*args, **kwargs)
self.__flag = threading.Event() # The flag used to pause the thread
self.__flag.set() # Set to True
self.__running = threading.Event() # Used to stop the thread identification
self.__running.set() # Set running to True
def run(self):
while self.__running.isSet():
self.__flag.wait() # return immediately when it is True, block until the internal flag is True when it is False
print("acquisition is on")
print(random.random())
time.sleep(1)
def pause(self):
self.__flag.clear() # Set to False to block the thread
print("pausing")
def resume(self):
self.__flag.set() # Set to True, let the thread stop blocking
print("resuming")
def stop(self):
self.__flag.set() # Resume the thread from the suspended state, if it is already suspended
self.__running.clear() # Set to False
@app.callback(Output('container', 'children'),
Input('btn_start_nanotec', 'n_clicks'),
Input('btn_pause_nanotec', 'n_clicks'),
Input('btn_resume_nanotec', 'n_clicks')
)
def display(btn_start_nanotec, btn_pause_nanotec, btn_resume_nanotec):
button_id = ctx.triggered_id if not None else 'No clicks yet'
if button_id == "btn_start_nanotec" :
my_thread_nanotec.start()
elif button_id == "btn_pause_nanotec" :
my_thread_nanotec.pause()
elif button_id == "btn_resume_nanotec" :
my_thread_nanotec.resume()
my_thread_nanotec = Nanotec()
app.layout = html.Div([
html.Button('Start', id='btn_start_nanotec'),
html.Button('Pause', id='btn_pause_nanotec'),
html.Button('Resume', id='btn_resume_nanotec'),
html.Div(id='container'),
html.Br(),
])
if __name__ == "__main__":
app.run_server(debug = True)
I am not quite sure what are you trying to do here regarding that multithreading class. Is it supposed to update html.Div
one time per second? Is text supposed to be updated on button click?
But since the question is "How to put a value…", here’s a quick explanation. I replaced multithreading class with a simple generator to make things clearer.
Your callback is supposed to return the value to put into html.Div
. So here the value is fetched from the generator (when the button is clicked) and returned:
import random
from dash import Dash, html, dcc, Input, Output, ctx
app = Dash(__name__, title="MT", prevent_initial_callbacks="initial_duplicate")
def randoms():
while True:
yield random.random()
random_iter = randoms()
@app.callback(
Output(component_id="container", component_property="children"),
Input("btn_start_nanotec", "n_clicks"),
Input("btn_pause_nanotec", "n_clicks"),
Input("btn_resume_nanotec", "n_clicks"),
)
def display(*_):
button_id = ctx.triggered_id
if button_id == "btn_start_nanotec":
result = next(random_iter)
elif button_id == "btn_pause_nanotec":
result = 'Pause?..'
elif button_id == "btn_resume_nanotec":
result = next(random_iter)
return result
app.layout = html.Div(
[
html.Button("Start", id="btn_start_nanotec"),
html.Button("Pause", id="btn_pause_nanotec"),
html.Button("Resume", id="btn_resume_nanotec"),
html.Div(id="container"),
html.Br(),
]
)
if __name__ == "__main__":
app.run_server(debug=True)
You can replace my super-simple iterator with anything else (threading.Thread
, multiprocessing.Pool
, whatever), but the callback still has to get the value from the source and return it.
Intervals
If you need to update the output periodically (once per second), take a look into Intervals. The same basic principle works just the same (callback returns value), but it would handle periodical updates for you.
Updating Input with Websocket messages
Websocket
component seems to fit the bill quite nicely: data sent by another process/thread and updated in (sort of) real time, even bidirectional communication (pause/resume) is supported.