Asyncio, Tk, and matplotlib

Hi Juan,

Funny that you should mention it... I was busy with the exact same thing
today :slight_smile:

It is as you said: the matplotlib GUI has to run on the main thread. The
trick seems to be to start the asyncio loop in a second background thread
and communicate with the GUI running on the main thread via a queue. I
found this <http://stackoverflow.com/a/34882411> StackOverflow answer very
helpful.

As an aside, I eventually ditched asyncio for an even simpler threading +
queue solution (being stuck in Python 2.7...).

Cheers,

Ludwig

P.P.S. I have an old matplotlib GUI app that used to disable the button
during the long-running task (run from the on_clicked callback) to indicate
when the GUI becomes available again. This behaviour does not seem to work
anymore on modern matplotlib, hence my need to investigate background
threads :slight_smile:
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20170223/28651b44/attachment.html>

Sorry I don't have time to write out a longer answer (with, you know,
working code), but a of couple of rough thoughts from recent experience.

- all GUI stuff must happen on the main thread (if you do threads), but
for some backends `draw_idle()` maybe thread safe.
- for asyncio no blocking part of the task should be slower than 1/10 a
second (that is the time between subsequent calls to `yield
from`/`yield`/`await`). Anything slower and you will need to push it out
of the main thread/process. It brings a bunch of complexity, but I would
look at something like dask. The futures look to have a
`add_done_callback` method which you can use to bridge to an asyncio.Event
that you can await on, (although you might run into some tornado vs asyncio
issues). Looks like someone has already done the work of hiding
multiprocess behind asyncio (https://github.com/dano/aioprocessing). Would
not go with threads unless you have a lot of gil releasing code.
- integrating asyncio and GUIs are about the same problem as integrating
GUIs and the command line, you have two infinite loops that both want to
run the show (and block while waiting for the slow human). I have been
using https://github.com/NSLS-II/bluesky/blob/master/bluesky/utils.py#L684 to
good effect at my day-job for keeping figures alive under asyncio, but we
are mostly waiting for (motion control related) network / motion. You
install a self-perpetuating 'call_later' on to the asyncio event loop that
drains the GUI events (which lets all of their callbacks run and re-draws
the figure).
- A super embarrassing (but functional) qt example is where I use qt
threads + ipyparallel is
https://github.com/tacaswell/leidenfrost/blob/master/leidenfrost/gui/proc_gui.py
In
this case I let the GUI event loop run the show.

Tom

···

On Thu, Feb 23, 2017 at 3:45 PM Ludwig Schwardt <ludwig.schwardt at gmail.com> wrote:

Hi Juan,

Funny that you should mention it... I was busy with the exact same thing
today :slight_smile:

It is as you said: the matplotlib GUI has to run on the main thread. The
trick seems to be to start the asyncio loop in a second background thread
and communicate with the GUI running on the main thread via a queue. I
found this <http://stackoverflow.com/a/34882411> StackOverflow answer
very helpful.

As an aside, I eventually ditched asyncio for an even simpler threading +
queue solution (being stuck in Python 2.7...).

Cheers,

Ludwig

P.P.S. I have an old matplotlib GUI app that used to disable the button
during the long-running task (run from the on_clicked callback) to indicate
when the GUI becomes available again. This behaviour does not seem to work
anymore on modern matplotlib, hence my need to investigate background
threads :slight_smile:

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
https://mail.python.org/mailman/listinfo/matplotlib-users

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20170224/4f55ddf1/attachment.html>