Triggering callback from within Python

Hello,

I’m working with Dash as a really nice way to interact with an embedded system. One thing I keep running into is the need to generate a callback from within the Python code, outside of callback code.

For example, I’m using a progress indicator html component to indicate progress of saving a file. I can update the progress component from within an interval callback, and that works, but it would be more natural to generate a property change from within my Python code – such as:

#  change 'value' property of 'save-progress' indicator -- set it to progVal

dcc.sendOutput('save-progress', 'value', progVal)  

I mostly bring it up because it seems like a way to simplify other parts of my interface as well. I have more examples… but for starters, I’m wondering if there is another way to accomplish this, or if something like this has been discussed before.

FWIW I’m using socketIO (websockets) for a custom video streaming Dash component. It’s given me enough confidence to consider digging in parts of Dash that I have no business digging into.

I may be barking up the wrong tree… let me know :)

thanks!

2 Likes

Just looking for a quick “sounds reasonable” or “this is a bad idea” or “this make no sense” :slight_smile: gracias

I’m not a Dash developer but my understanding of the architecture of the library is all initial calls are made from the JavaScript using classical AJAX-style calls, and therefore it’s all request from browser response from server.

I’m sure it would be possible to re-architect it to have a bi-directional communication using newer web communication technologies, but I’ve not heard anything from the Dash developers that indicate they are working on this. Maybe you could code your own component to do this but I don’t know enough about React to know if it’s reasonable: Build Your Own Components | Dash for Python Documentation | Plotly

Also be aware they accept funding from enterprises to push Dash forward and if those enterprises are anything like the one I work for they insist everything must work in IE 11 :slightly_frowning_face:

thanks!

There have been mentions of websockets in these forums and dispatch emails – never in the “it will happen” context though. Browser compatibility is no longer an issue, not even for IE.

How might this kind of capability take shape within Dash? I’m lacking the background to answer… so just speculating and guessing it would be quite useful.

The django-plotly-dash library does something similar to what it sounds like you are looking for, essentially by sending a message to a UI component via a websocket and then having that component invoke the callback.

This may sound a bit back-to-front, but it means that the data flow follows that of the rest of Dash, and also can be used directly with other existing Dash components and applications. In particular, the existing Dash infrastructure, based on http requests, is unchanged. You do need to run a websocket-capable server, but you are going to have to do that (or something very similar) to get this sort of server push functionality anyway.

1 Like

I implemented this mechanism with a dash component, to test/play with. Here it is – you can modify any dash component directly within python, for example:

change('slider', {'value': 10})

Here, the slider with id=‘slider’ would update and any callbacks would be called.

It uses flask socketio. You put the ‘sockettest’ component in the layout and the right things will happen with the socket connection.

app.layout = html.Div([
    sockettest.sockettest(),
    html.Progress(id='progress', max=10, value=0), 
	dcc.Slider(id='slider', value=0, min=0, max=10, step=1),
    html.Div(id='divspace')
])


def change(id, val):
	socket.emit('call', {'id': id, 'val': val})


def timerCallback():
	Timer(1.0, timerCallback).start()
	change('slider', {'value': timerCallback.i})
	change('progress', {'value': timerCallback.i})
	change('divspace', {'children': 'hello ' + str(timerCallback.i)})
	timerCallback.i += 1;
	if timerCallback.i>10:
		timerCallback.i = 0

timerCallback.i = 0

if __name__ == '__main__':
	timerCallback()
	socket.run(server, debug=False, port=5000, host='0.0.0.0')

Screenshot%20from%202019-07-08%2008-38-46

8 Likes

Thanks for the code @narragansett, I can successfully trigger the callbacks by calling the change function. However I am curious how I trigger them remotely through the SocketiO client.

1 Like

Could a dev eg @chriddyp spread some wisdom on the integration of websockets into a dashboard? Some data is streamed high frequency, thus AJAX/RESt might be inapproriate. HOw to use wss to update a Figures object trace eg?
i came from https://stackoverflow.com/questions/57860270/use-dash-with-websockets

1 Like

There is this really cool project using web sockets, which might inspire a solution,

2 Likes

It took me some time to find this solution, which I think is the best for now. This is really cool, exact what I want, thanks!
However, If I use uwsgi method to launch this server, eg. waitress, it would raise

RuntimeError: You need to use the eventlet server. See the Deployment section of the documentation for more information.

I think this is caused by multiple access threads. Does it means one can only use a single thread with GIL to realize this ‘change’ function? It doesn’t seems to be a problem for now buy I’m curious how to solve that.

dash_devices uses Quart and asyncio, which is ASGI based (not WSGI).

https://asgi.readthedocs.io/en/latest/introduction.html

Hope this helps :slight_smile:

1 Like

That project is so cool! Did you ever get around to writing a package?

1 Like

https://pypi.org/project/dash-devices/ :slight_smile:

3 Likes