8000 DOC : move MEP27 · matplotlib/matplotlib@936c80a · GitHub
[go: up one dir, main page]

Skip to content

Commit 936c80a

Browse files
committed
DOC : move MEP27
1 parent f4b589b commit 936c80a

File tree

2 files changed

+226
-0
lines changed

2 files changed

+226
-0
lines changed

doc/devel/MEP/MEP27.rst

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
======================================
2+
MEP27: decouple pyplot from backends
3+
======================================
4+
5+
.. contents::
6+
:local:
7+
8+
9+
Status
10+
======
11+
**Discussion**
12+
13+
Branches and Pull requests
14+
==========================
15+
Main PR (including GTK3):
16+
+ https://github.com/matplotlib/matplotlib/pull/4143
17+
18+
Backend specific branch diffs:
19+
+ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...OceanWolf:backend-refactor-tkagg
20+
+ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...OceanWolf:backend-refactor-qt
21+
+ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...backend-refactor-wx
22+
23+
Abstract
24+
========
25+
26+
This MEP refactors the backends to give a more structured and
27+
consistent API, removing generic code and consolidate existing code.
28+
To do this we propose splitting:
29+
30+
1. ``FigureManagerBase`` and its derived classes into the core
31+
functionality class ``FigureManager`` and a backend specific class
32+
``WindowBase`` and
33+
2. ``ShowBase`` and its derived classes into ``Gcf.show_all`` and ``MainLoopBase``.
34+
35+
Detailed description
36+
====================
37+
38+
This MEP aims to consolidate the backends API into one single uniform
39+
API, removing generic code out of the backend (which includes
40+
``_pylab_helpers`` and ``Gcf``), and push code to a more appropriate
41+
level in matplotlib. With this we automatically remove
42+
inconsistencies that appear in the backends, such as
43+
``FigureManagerBase.resize(w, h)`` which sometimes sets the canvas,
44+
and other times set the entire window to the dimensions given,
45+
depending on the backend.
46+
47+
Two main places for generic code appear in the classes derived from
48+
``FigureManagerBase`` and ``ShowBase``.
49+
50+
1. ``FigureManagerBase`` has **three** jobs at the moment:
51+
1. The documentation describes it as a *``Helper class for pyplot
52+
mode, wraps everything up into a neat bundle''*
53+
2. But it doesn't just wrap the canvas and toolbar, it also does
54+
all of the windowing tasks itself. The conflation of these two
55+
tasks gets seen the best in the following line: ```python
56+
self.set_window_title("Figure %d" % num) ``` This combines
57+
backend specific code ``self.set_window_title(title)`` with
58+
matplotlib generic code ``title = "Figure %d" % num``.
59+
60+
3. Currently the backend specific subclass of ``FigureManager``
61+
decides when to end the mainloop. This also seems very wrong
62+
as the figure should have no control over the other figures.
63+
64+
65+
2. ``ShowBase`` has two jobs:
66+
1. It has the job of going through all figure managers registered
67+
in ``_pylab_helpers.Gcf`` and telling them to show themselves.
68+
2. And secondly it has the job of performing the backend specific
69+
``mainloop`` to block the main programme and thus keep the
70+
figures from dying.
71+
72+
Implementation
73+
==============
74+
75+
The description of this MEP gives us most of the solution:
76+
77+
1. To remove the windowing aspect out of ``FigureManagerBase`` letting
78+
it simply wrap this new class along with the other backend classes.
79+
Create a new ``WindowBase`` class that can handle this
80+
functionality, with pass-through methods (:arrow_right:) to
81+
``WindowBase``. Classes that subclass ``WindowBase`` should also
82+
subclass the GUI specific window class to ensure backward
83+
compatibility (``manager.window == manager.window``).
84+
2. Refactor the mainloop of ``ShowBase`` into ``MainLoopBase``, which
85+
encapsulates the end of the loop as well. We give an instance of
86+
``MainLoop`` to ``FigureManager`` as a key unlock the exit method
87+
(requiring all keys returned before the loop can die). Note this
88+
opens the possibility for multiple backends to run concurrently.
89+
3. Now that ``FigureManagerBase`` has no backend specifics in it, to
90+
rename it to ``FigureManager``, and move to a new file
91+
``backend_managers.py`` noting that:
92+
1. This allows us to break up the conversion of backends into
93+
separate PRs as we can keep the existing ``FigureManagerBase``
94+
class and its dependencies intact.
95+
2. and this also anticipates MEP22 where the new
96+
``NavigationBase`` has morphed into a backend independent
97+
``ToolManager``.
98+
99+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
100+
|FigureManagerBase(canvas, num) |FigureManager(figure, num) |``WindowBase(title)``|Notes |
101+
| | | | |
102+
+======================================+==============================+=====================+================================+
103+
|show |:arrow_right: |show | |
104+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
105+
|destroy |calls destroy on all |destroy | |
106+
| |components | | |
107+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
108+
|full_screen_toggle |handles logic |set_fullscreen | |
109+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
110+
|resize |:arrow_right: |resize | |
111+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
112+
|key_press |key_press |:no_entry: | |
113+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
114+
|show_popup |show_poup |:no_entry: |Not used anywhere in mpl, and |
115+
| | | |does nothing. |
116+
| | | | |
117+
| | | | |
118+
| | | | |
119+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
120+
|get_window_title |:arrow_right: |get_window_title | |
121+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
122+
|set_window_title |:arrow_right: |set_window_title | |
123+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
124+
|:no_entry: |_get_toolbar | |A common method to all |
125+
| | | |subclasses of FigureManagerBase |
126+
| | | | |
127+
| | | | |
128+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
129+
|:no_entry: |:no_entry: |set_default_size | |
130+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
131+
|:no_entry: |:no_entry: |add_element_to_window| |
132+
+--------------------------------------+------------------------------+---------------------+--------------------------------+
133+
134+
135+
+----------+------------+-------------+
136+
|ShowBase |MainLoopBase|Notes |
137+
+==========+============+=============+
138+
|mainloop |begin | |
139+
+----------+------------+-------------+
140+
|:no_entry:|end |Gets called |
141+
| | |automagically|
142+
| | |when no more |
143+
| | |instances of |
144+
| | |the subclass |
145+
| | |exist |
146+
+----------+------------+-------------+
147+
|__call__ |:no_entry: |Method moved |
148+
| | |to |
149+
| | |Gcf.show_all |
150+
+----------+------------+-------------+
151+
152+
Future compatibility
153+
====================
154+
155+
As eluded to above when discussing MEP 22, this refactor makes it easy
156+
to add in new generic features. At the moment, MEP 22 has to make
157+
ugly hacks to each class extending from ``FigureManagerBase``. With
158+
this code, this only needs to get made in the single ``FigureManager``
159+
class. This also makes the later deprecation of
160+
``NavigationToolbar2`` very straightforward, only needing to touch the
161+
single ``FigureManager`` class
162+
163+
MEP 23 makes for another use case where this refactored code will come
164+
in very handy.
165+
166+
Backward compatibility
167+
======================
168+
169+
As we leave all backend code intact, only adding missing methods to
170+
existing classes, this should work seamlessly for all use cases. The
171+
only difference will lie for backends that used
172+
``FigureManager.resize`` to resize the canvas and not the window, due
173+
to the standardisation of the API.
174+
175+
I would envision that the classes made obsolete by this refactor get
176+
deprecated and removed on the same timetable as
177+
``NavigationToolbar2``, also note that the change in call signature to
178+
the ``FigureCanvasWx`` constructor, while backward compatible, I think
179+
the old (imho ugly style) signature should get deprecated and removed
180+
in the same manner as everything else.
181+
182+
+-------------------------+-------------------------+-------------------------+
183+
|backend |manager.resize(w,h) |Extra |
184+
+=========================+=========================+=========================+
185+
|gtk3 |window | |
186+
+-------------------------+-------------------------+-------------------------+
187+
|Tk |canvas | |
188+
+-------------------------+-------------------------+-------------------------+
189+
|Qt |window | |
190+
+-------------------------+-------------------------+-------------------------+
191+
|Wx |canvas |FigureManagerWx had |
192+
| | |``frame`` as an alias to |
193+
| | |window, so this also |
194+
| | |breaks BC. |
195+
+-------------------------+-------------------------+-------------------------+
196+
197+
198+
Alternatives
199+
============
200+
201+
If there were any alternative solutions to solving the same problem,
202+
they should be discussed here, along with a justification for the
203+
chosen approach.
204+
205+
Questions
206+
=========
207+
208+
Mdehoon: Can you elaborate on how to run multiple backends
209+
concurrently?
210+
211+
OceanWolf: @mdehoon, as I say, not for this MEP, but I see this MEP
212+
opens it up as a future possibility. Basically the ``MainLoopBase``
213+
class acts a per backend Gcf, in this MEP it tracks the number of
214+
figures open per backend, and manages the mainloops for those
215+
backends. It closes the backend specific mainloop when it detects
216+
that no figures remain open for that backend. Because of this I
217+
imagine that with only a small amount of tweaking that we can do
218+
full-multi-backend matplotlib. No idea yet why one would want to, but
219+
I leave the possibility there in MainLoopBase. With all the
220+
backend-code specifics refactored out of ``FigureManager`` also aids
221+
in this, one manager to rule them (the backends) all.
222+
223+
Mdehoon: @OceanWolf, OK, thanks for the explanation. Having a uniform
224+
API for the backends is very important for the maintainability of
225+
matplotlib. I think this MEP is a step in the right direction.

doc/devel/MEP/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ Matplotlib Enhancement Proposals
2828
MEP24
2929
MEP25
3030
MEP26
31+
MEP27

0 commit comments

Comments
 (0)
0