Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 98ae26c

Browse files
committed
WIP: Lots of text changes to interactive guide
1 parent 7189eed commit 98ae26c

File tree

1 file changed

+240
-92
lines changed

1 file changed

+240
-92
lines changed

doc/users/interactive_guide.rst

Lines changed: 240 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
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
1114
graphs.
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

1821
Fundamentally, 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
3336
all terminals, GUIs, and servers [#f1]_. In general the *Read* step is
3437
waiting on some sort of I/O, be it user input from a keyboard or mouse
3538
or 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

4957
references 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

77137
Interactive
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

80170
Scripts
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

139201
Stale Artists
140202
=============
@@ -150,14 +212,100 @@ figure.
150212

151213

152214
Interactive 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

Comments
 (0)