Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 936c80a

Browse filesBrowse files
committed
DOC : move MEP27
1 parent f4b589b commit 936c80a
Copy full SHA for 936c80a

File tree

Expand file treeCollapse file tree

2 files changed

+226
-0
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+226
-0
lines changed

‎doc/devel/MEP/MEP27.rst

Copy file name to clipboard
+225Lines 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

Copy file name to clipboardExpand all lines: doc/devel/MEP/index.rst
+1Lines 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)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.