11.. _plotting-guide-interactive :
22
3- ************************************************
4- Interactive Figures and Asynchronous Programming
5- ************************************************
6-
7- One of the most powerful uses of matplotlib is interactive
8- figures. At the most basic matplotlib has the ability to zoom and pan
9- a figure to inspect your data, however there is also a full mouse and
10- keyboard event handling system to enable building sophisticated interactive
3+ .. currentmodule :: matplotlib
4+
5+
6+ ==================================================
7+ Interactive Figures and Asynchronous Programming
8+ ==================================================
9+
10+ Matplotlib supports rich interactive figures. At the most basic
11+ matplotlib has the ability to zoom and pan a figure to inspect your
12+ data 'baked in', but this is backed by a full mouse and keyboard event
13+ handling system to enable users to build sophisticated interactive
1114graphs.
1215
13- This page is meant to be a rapid introduction to the relevant details
14- of integrating the matplotlib with a GUI event loop. For further
15- details see `Interactive Applications using Matplotlib
16+ This is meant to be a rapid introduction to the relevant details of
17+ integrating the matplotlib with a GUI event loop. For further details
18+ see `Interactive Applications using Matplotlib
1619<http://www.amazon.com/Interactive-Applications-using-Matplotlib-Benjamin/dp/1783988843> `__.
1720
1821Fundamentally, all user interaction (and networking) is implemented as
19- an infinite loop waiting for events from the OS and then doing
20- something about it. For example, a minimal Read Evaluate Print Loop
21- (REPL) is ::
22+ an infinite loop waiting for events from the user (via the OS) and
23+ then doing something about it. For example, a minimal Read Evaluate
24+ Print Loop (REPL) is ::
2225
2326 exec_count = 0
2427 while True:
@@ -33,108 +36,167 @@ exception!), but is representative of the event loops that underlie
3336all terminals, GUIs, and servers [#f1 ]_. In general the *Read * step is
3437waiting on some sort of I/O, be it user input from a keyboard or mouse
3538or the network while the *Evaluate * and *Print * are responsible for
36- interpreting the input and then doing something about it.
37-
38- In practice most users do not work directly with these loops, and
39- instead framework that provides a mechanism to register callbacks
40- [#2 ]_. This allows users to write reactive, event-driven, programs
41- without having to delve into the nity-grity [#f3 ]_ details of I/O.
42- Examples include ``observe `` and friends in `traitlets `, the
43- ``Signal `` / ``Slot `` framework in Qt and the analogs in Gtk / Tk /
44- Wx, the request functions in web frameworks, or Matplotlib's
45- native :ref: `event handling system <event-handling-tutorial >`.
46-
47-
39+ interpreting the input and then **doing ** something about it.
40+
41+ In practice users do not work directly with these loops and instead
42+ use a framework that provides a mechanism to register callbacks [#2 ]_.
43+ This allows users to write reactive, event-driven, programs without
44+ having to delve into the nity-grity [#f3 ]_ details of I/O. Examples
45+ include ``observe `` and friends in `traitlets `, the ``Signal `` /
46+ ``Slot `` framework in Qt (and the analogs in other GUI frameworks),
47+ the 'request' functions in web frameworks, and Matplotlib's native
48+ :ref: `event handling system <event-handling-tutorial >`.
49+
50+ All GUI frameworks (Qt, Wx, Gtk, tk, QSX, or web) have some method of
51+ capturing user interactions and passing them back to the application,
52+ although the exact details vary between frameworks. Matplotlib has a
53+ 'backend' (see :ref: `what-is-a-backend `) for each GUI framework which
54+ converts the native UI events into Matplotlib events. This allows
55+ Matplotlib user to write GUI-independent interactive figures.
4856
4957references to trackdown:
50- - link to cpython REPL loop
58+ - link to cpython REPL loop (pythonrun.c::PyRunInteractiveLoopFlags)
59+ - link to IPython repl loop (Ipython.terminal.interactiveshell.py :: TerminalInteractiveShell.mainloop
60+ and Ipython.terminal.interactiveshell.py :: TerminalInteractiveShell.interact)
5161 - curio / trio / asycio / twisted / tornado event loops
5262 - Beazly talk or two on asyncio
5363
64+ Command Prompt Integration
65+ ==========================
5466
55- GUI to Matplotlib Bridge
56- ------------------------
67+ Integrating a GUI window and a CLI introduces a conflict: there are
68+ two infinite loops that want to be waiting for user input in the same
69+ process. In order for both the prompt and the GUI widows to be responsive
70+ we need a method to allow the loops to 'timeshare'.
5771
58- When using
72+ 1. let the GUI main loop block the python process
73+ 2. intermittently run the GUI loop
5974
6075
61- Command Prompt
62- --------------
76+ Blocking
77+ --------
6378
64- To handle asynchronous user input every GUI framework has an event
65- loop. At the most basic this is a stack that can have events to be
66- processed. In order for the GUI to be responsive this loop must be
67- run. To manage this in python there are two basic methods:
79+ The simplest "integration" is to start the GUI event loop in
80+ 'blocking' mode and take over the CLI. While the GUI event loop is
81+ running you can not enter new commands into the prompt (your terminal
82+ may show the charters entered into stdin, but they will not be
83+ processed by python), but the figure windows will be responsive. Once
84+ the event loop is stopped (leaving any still open figure windows
85+ non-responsive) you will be able to use the prompt again. Re-starting
86+ the event will make any open figure responsive again.
6887
69- 1. let the GUI main loop block the python process
70- 2. intermittently run the GUI loop for a period of time
7188
89+ To start the event loop until all open figures are closed us
90+ `pyplot.show(block=True) `. To start the event loop for a fixed amount
91+ of time use `pyplot.pause `.
92+
93+ Without using ``pyplot `` you can start and stop the event loops via
94+ ``fig.canvas.start_event_loop `` and ``fig.canvas.stop_event_loop ``.
95+
96+
97+ .. warning
98+
99+ By using `Figure.show` it is possible to display a figure on the
100+ screen with out starting the event loop and not being in
101+ interactive mode. This will likely result in a non-responsive
102+ figure and may not even display the rendered plot.
103+
104+
105+
106+ .. autosummary ::
107+ :template: autosummary.rst
108+ :nosignatures:
109+
110+ pyplot.show
111+ pyplot.pause
112+
113+ backend_bases.FigureCanvasBase.start_event_loop
114+ backend_bases.FigureCanvasBase.stop_event_loop
115+
116+ figure.Figure.show
72117
73- Blocking
74- ********
75118
119+ Explicitly
120+ ----------
121+
122+ If you have open windows (either due to a `plt.pause ` timing out or
123+ from calling `figure.Figure.show `) that have pending UI events (mouse
124+ clicks, button presses, or draws) you can explicitly process them by
125+ calling ``fig.canvas.flush_events() ``. This will not run the GUI
126+ event loop, but instead synchronously processes all UI events current
127+ waiting to be processed. The exact behavior is backend-dependent but
128+ typically events on all figure are processed and only events waiting
129+ to be processed (not those added during processing) will be handled.
130+
131+ .. autosummary ::
132+ :template: autosummary.rst
133+ :nosignatures:
134+
135+ backend_bases.FigureCanvasBase.flush_events
76136
77137Interactive
78- ***********
138+ -----------
139+
140+ While running the GUI event loop in a blocking mode or explicitly
141+ handling UI events is useful, we can do better! We really want to be
142+ able to have a usable prompt **and ** interactive figure windows. We
143+ can do this using the concept of 'input hook' (see :ref: `below
144+ <Eventloop integration mechanism>` for implementation details) that
145+ allows the GUI event loop to run and process events while the prompt
146+ is waiting for the user to type (even for an extremely fast typist, a
147+ vast majority of the time the prompt is simple idle waiting for human
148+ finders to move). This effectively gives us a simultaneously GUI
149+ windows and prompt.
150+
151+ This time-share technique only allows the event loop to run while
152+ python is otherwise idle and waiting for user input. If you want the
153+ GUI to be responsive during long running code it is necessary to
154+ periodically flush the GUI event queue as described :ref: `above
155+ <Explicitly>`. In this case it is your code, not the REPL, which is
156+ blocking process so you need to handle the time-share manually.
157+ Conversely, a very slow figure draw will block the prompt until it
158+ finishes.
159+
160+ Full embedding
161+ ==============
162+
163+ It is also possible to go the other direction and fully embed figures
164+ it a rich native application. Matplotlib provides classes which can
165+ be directly embedded in GUI applications (this is how the built-in
166+ windows are implemented!). See :ref: `user_interfaces ` for more details
167+ on how to do this.
168+
79169
80170Scripts
81- -------
171+ =======
82172
83- - if you want always reactive figures while the script runs, you have to
84- call `flush_event `
85- - if you want to have reactive figures that block the script until they are closed (ex for
86- collecting user input before continuing use
173+ There are several use-cases for using interactive figures in scripts:
87174
175+ - progress updates as a long running script progresses
176+ - capture user input to steer the script
177+ - streaming updates from a data source
88178
89- Full embedding
90- --------------
179+ In the first case, it is the same as :ref: ` above
180+ <Explicitly>` where you explicitly call ::
91181
92- - just let the underlying GUI event loop handle eve
182+ fig.canvas.flush_events()
93183
94- Web
95- ---
184+ periodically to allow the event loop to process UI and draw events and
185+ ::
96186
97- The Weeds
98- =========
187+ fig.canvas.draw_idle()
99188
189+ when you have updated the contents of the figure.
100190
101- The GUI event loop
102- ------------------
191+ The more frequently you call ``flush_events `` the more responsive your
192+ figure will feel but at the cost of spending more resource on the
193+ visualization and less on your computation.
103194
195+ The second case is very much like :ref: `Blocking ` above. By using ``plt.show(block=True) `` or
104196
105- The python capi provides a hook, `PyOS_InputHook `, to register a
106- function to be run "The function will be called when Python's
107- interpreter prompt is about to become idle and wait for user input
108- from the terminal.". This hook can be used to integrate a second
109- event loop (the GUI event loop) with the python input prompt loop.
110- Such hooks are usually included with the python bindings for GUI
111- toolkits and may be registered on import. IPython also includes hooks
112- for all of the GUI frameworks supported by matplotlib. The hook
113- functions typically exhaust all pending events on the GUI event queue,
114- run the main loop for a short fixed amount of time, or run the event
115- loop until a key is pressed on stdin.
116-
117- matplotlib does not currently do any management of `PyOS_InputHook `
118- due to the wide range of ways that matplotlib is used. This
119- management is left to the code using matplotlib. Interactive figures,
120- even with matplotlib in 'interactive mode', may not work in the
121- vanilla python repl if an appropriate `PyOS_InputHook ` is not
122- registered. We suggest using ``IPython ``, which in addition to
123- improving the command line, ensures that such a `PyOS_InputHook `
124- function is registered for you GUI backend of choice.
125-
126- A drawback of relying on `PyOS_InputHook ` is that the GUI event loop
127- is only processing events while python is otherwise idle and waiting
128- for user input. If you want the GUI to be responsive during long
129- running code it is necessary to periodically flush the GUI event
130- queue. To achieve this, almost all of the of the GUI-based ``Canvas ``
131- classes provide a `flush_event ` method. By periodically calling this
132- method the GUI will be updated and appear to be responsive.
133-
134- In both cases, to schedule a re-draw of the figure at some point in
135- the future use ``fig.canvas.draw_idle() ``. This will defer the actual
136- rendering of the figure until the GUI is ready to update its
137- on-screen representation.
197+ The third case you will have to integrate updating the ``Aritist ``
198+ instances, calling ``draw_idle ``, and the GUI event loop with your
199+ data I/O.
138200
139201Stale Artists
140202=============
@@ -150,14 +212,100 @@ figure.
150212
151213
152214Interactive Mode
153- ----------------
215+ ================
216+
217+
218+ Draw Idle
219+ =========
220+
221+ In almost all cases, we recommend using
222+ `backend_bases.FigureCanvasBae.draw_idle ` over
223+ `backend_bases.FigureCanvasBae.draw `. ``draw `` forces a rendering of
224+ the figure where as ``draw_idle `` schedules a rendering the next time
225+ the GUI window is going to re-paint the screen. This improves
226+ performance by only rendering pixels that will be shown on the screen. If
227+ you want to be sure that the screen is updated as soon as possible do ::
228+
229+ fig.canvas.draw_idle()
230+ fig.canvas.flush_events()
231+
232+
233+
234+ .. autosummary ::
235+ :template: autosummary.rst
236+ :nosignatures:
237+
238+ backend_bases.FigureCanvasBase.draw
239+ backend_bases.FigureCanvasBase.draw_idle
240+ backend_bases.FigureCanvasBase.flush_events
241+
242+ Threading
243+ =========
244+
245+ Unfortunately, most GUI frameworks require that all updates to the
246+ screen happen on the main thread which makes pushing periodic updates
247+ to the window to a background thread problematic. Although it seems
248+ backwards, it is easier to push your computations to a background
249+ thread and periodically update the figure from the main thread.
250+
251+ In general Matplotlib is not thread safe, but the consequences of
252+ drawing while updating artists from another thread should not be worse
253+ than a failed draw. This should not be fatal and so long as the
254+ Artists end up consistent the figure can eventually be drawn cleanly.
255+
256+ Web
257+ ===
258+
259+
260+
261+ The Weeds
262+ =========
263+
264+
265+ Eventloop integration mechanism
266+ -------------------------------
267+
268+ CPython / readline
269+ ~~~~~~~~~~~~~~~~~~
270+
271+ The python capi provides a hook, `PyOS_InputHook `, to register a
272+ function to be run "The function will be called when Python's
273+ interpreter prompt is about to become idle and wait for user input
274+ from the terminal.". This hook can be used to integrate a second
275+ event loop (the GUI event loop) with the python input prompt loop.
276+ The hook functions typically exhaust all pending events on the GUI
277+ event queue, run the main loop for a short fixed amount of time, or
278+ run the event loop until a key is pressed on stdin.
279+
280+
281+ Matplotlib does not currently do any management of `PyOS_InputHook `
282+ due to the wide range of ways that matplotlib is used. This
283+ management is left to the code using Matplotlib. Interactive figures,
284+ even with matplotlib in 'interactive mode', may not work in the
285+ vanilla python repl if an appropriate `PyOS_InputHook ` is not
286+ registered.
287+
288+ Input hooks, and helpers to install them, are usually included with
289+ the python bindings for GUI toolkits and may be registered on import.
290+ IPython also ships input hook functions for all of the GUI frameworks
291+ Matplotlib supports which can be installed via ``%matplotlib ``. This
292+ is the recommended method of integrating Matplotlib and a prompt.
293+
294+
295+
296+ IPython / prompt toolkit
297+ ~~~~~~~~~~~~~~~~~~~~~~~~
154298
299+ With IPython >= 5.0 IPython has changed from using cpython's readline
300+ based prompt to a ``prompt_toolkit `` based prompt. ``prompt_toolkit ``
301+ has the same conceptual input hook, which is feed into pt via the
302+ :meth: `IPython.terminal.interactiveshell.TerminalInteractiveShell.inputhook `
303+ method. The source for the prompt_toolkit input hooks lives at
304+ :mod: `IPython.terminal.pt_inputhooks `
155305
156- Blitting
157- ========
158306
159307
160- .. ruberic :: Fotenotes
308+ .. rubric :: Fotenotes
161309
162310.. [#f1 ] A limitation of this design is that you can only wait for one
163311 input, if there is a need to multiplex between multiple sources
0 commit comments