From a4996439aa0675c81fecd3382a4d281cbe675f3f Mon Sep 17 00:00:00 2001 From: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com> Date: Thu, 3 Apr 2025 13:38:47 +0200 Subject: [PATCH] Backport PR #29773: DOC: Improve interactive figures guide / Blocking input --- .../figure/interactive_guide.rst | 78 ++++++++++--------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/galleries/users_explain/figure/interactive_guide.rst b/galleries/users_explain/figure/interactive_guide.rst index 5cc55edc0955..6cbdca4ab3f9 100644 --- a/galleries/users_explain/figure/interactive_guide.rst +++ b/galleries/users_explain/figure/interactive_guide.rst @@ -11,7 +11,7 @@ Interactive figures and asynchronous programming Matplotlib supports rich interactive figures by embedding figures into a GUI window. The basic interactions of panning and zooming in an -Axes to inspect your data is "baked in" to Matplotlib. This is +Axes to inspect your data is available out-of-the-box. This is supported by a full mouse and keyboard event handling system that you can use to build sophisticated interactive graphs. @@ -23,6 +23,21 @@ handling system `, `Interactive Tutorial `Interactive Applications using Matplotlib `__. + +GUI events +========== + +All GUI frameworks (Qt, Wx, Gtk, Tk, macOS, or web) have some method of +capturing user interactions and passing them back to the application, but +the exact details depend on the toolkit (for example callbacks in Tk or +the ``Signal`` / ``Slot`` framework in Qt). The Matplotlib :ref:`backends +` encapsulate the details of the GUI frameworks and +provide a framework-independent interface to GUI events through Matplotlib's +:ref:`event handling system `. By connecting functions +to the event handling system (see `.FigureCanvasBase.mpl_connect`), you can +interactively respond to user actions in a GUI toolkit agnostic way. + + Event loops =========== @@ -58,19 +73,6 @@ depending on the library, by methods with names like ``exec``, ``run``, or ``start``. -All GUI frameworks (Qt, Wx, Gtk, tk, macOS, or web) have some method of -capturing user interactions and passing them back to the application -(for example ``Signal`` / ``Slot`` framework in Qt) but the exact -details depend on the toolkit. Matplotlib has a :ref:`backend -` for each GUI toolkit we support which uses the -toolkit API to bridge the toolkit UI events into Matplotlib's :ref:`event -handling system `. You can then use -`.FigureCanvasBase.mpl_connect` to connect your function to -Matplotlib's event handling system. This allows you to directly -interact with your data and write GUI toolkit agnostic user -interfaces. - - .. _cp_integration: Command prompt integration @@ -81,16 +83,16 @@ lets us interactively send code to the interpreter and get results back. We also have the GUI toolkit that runs an event loop waiting for user input and lets us register functions to be run when that happens. However, if we want to do both we have a problem: the prompt -and the GUI event loop are both infinite loops that each think *they* -are in charge! In order for both the prompt and the GUI windows to be +and the GUI event loop are both infinite loops and cannot run in +parallel. In order for both the prompt and the GUI windows to be responsive we need a method to allow the loops to "timeshare" : -1. let the GUI main loop block the python process when you want - interactive windows -2. let the CLI main loop block the python process and intermittently - run the GUI loop -3. fully embed python in the GUI (but this is basically writing a full - application) +1. **Blocking the prompt**: let the GUI main loop block the python + process when you want interactive windows +2. **Input hook integration**: let the CLI main loop block the python + process and intermittently run the GUI loop +3. **Full embedding**: fully embed python in the GUI + (but this is basically writing a full application) .. _cp_block_the_prompt: @@ -108,24 +110,26 @@ Blocking the prompt backend_bases.FigureCanvasBase.stop_event_loop -The simplest "integration" is to start the GUI event loop in -"blocking" mode and take over the CLI. While the GUI event loop is -running you cannot enter new commands into the prompt (your terminal -may echo the characters typed into the terminal, but they will not be -sent to the Python interpreter because it is busy running the GUI -event loop), but the figure windows will be responsive. Once the -event loop is stopped (leaving any still open figure windows -non-responsive) you will be able to use the prompt again. Re-starting -the event loop will make any open figure responsive again (and will -process any queued up user interaction). +The simplest solution is to start the GUI event loop and let it run +exclusively, which results in responsive figure windows. However, the +CLI event loop will not run, so that you cannot enter new commands. +We call this "blocking" mode. (Your terminal may echo the typed characters, +but they will not yet be processed by the CLI event loop because the Python +interpreter is busy running the GUI event loop). + +It is possible to stop the GUI event loop and return control to the CLI +event loop. You can then use the prompt again, but any still open figure +windows are non-responsive. Re-starting the GUI event loop will make these +figure responsive again (and will process any queued up user interaction). + -To start the event loop until all open figures are closed, use -`.pyplot.show` as :: +The typical command to show all figures and run the GUI event loop +exclusively until all figures are closed is :: - pyplot.show(block=True) + plt.show() -To start the event loop for a fixed amount of time (in seconds) use -`.pyplot.pause`. +Alternatively, you can start the GUI event loop for a fixed amount of time +using `.pyplot.pause`. If you are not using `.pyplot` you can start and stop the event loops via `.FigureCanvasBase.start_event_loop` and