8000 backend_template fix. · matplotlib/matplotlib@23f2c3b · GitHub
[go: up one dir, main page]

Skip to content

Commit 23f2c3b

Browse files
committed
backend_template fix.
Update the docs to be mildly more relevant to third-party backend implementers. Add entry for rendered docs. Make backend_template "work" (in the do-nothing sense) with usetex, by super-initing the Renderer class and by not assuming the presence of a `.height` attribute in FigureCanvasBase.
1 parent 918b691 commit 23f2c3b

File tree

5 files changed

+56
-92
lines changed

5 files changed

+56
-92
lines changed

doc/api/backend_template_api.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
:mod:`matplotlib.backends.backend_template`
3+
===========================================
4+
5+
.. automodule:: matplotlib.backends.backend_template
6+
:members:
7+
:undoc-members:
8+
:show-inheritance:

doc/api/index_backend_api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
:maxdepth: 1
77

88
backend_mixed_api.rst
9+
backend_template_api.rst
910
backend_agg_api.rst
1011
backend_cairo_api.rst
1112
backend_gtk3agg_api.rst

lib/matplotlib/backend_bases.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -569,9 +569,10 @@ def _get_text_path_transform(self, x, y, s, prop, angle, ismath):
569569
path = Path(verts, codes)
570570
angle = np.deg2rad(angle)
571571
if self.flipy():
572+
width, height = self.get_canvas_width_height()
572573
transform = Affine2D().scale(fontsize / text2path.FONT_SCALE,
573574
fontsize / text2path.FONT_SCALE)
574-
transform = transform.rotate(angle).translate(x, self.height - y)
575+
transform = transform.rotate(angle).translate(x, height - y)
575576
else:
576577
transform = Affine2D().scale(fontsize / text2path.FONT_SCALE,
577578
fontsize / text2path.FONT_SCALE)
@@ -2467,7 +2468,7 @@ class NonGuiException(Exception):
24672468

24682469
class FigureManagerBase:
24692470
"""
2470-
Helper class for pyplot mode, wraps everything up into a neat bundle
2471+
Helper class for pyplot mode, wraps everything up into a neat bundle.
24712472
24722473
Attributes
24732474
----------
@@ -3278,8 +3279,7 @@ class _Backend:
32783279

32793280
@classmethod
32803281
def new_figure_manager(cls, num, *args, **kwargs):
3281-
"""Create a new figure manager instance.
3282-
"""
3282+
"""Create a new figure manager instance."""
32833283
# This import needs to happen here due to circular imports.
32843284
from matplotlib.figure import Figure
32853285
fig_cls = kwargs.pop('FigureClass', Figure)
@@ -3288,8 +3288,7 @@ def new_figure_manager(cls, num, *args, **kwargs):
32883288

32893289
@classmethod
32903290
def new_figure_manager_given_figure(cls, num, figure):
3291-
"""Create a new figure manager instance for the given figure.
3292-
"""
3291+
"""Create a new figure manager instance for the given figure."""
32933292
canvas = cls.FigureCanvas(figure)
32943293
manager = cls.FigureManager(canvas, num)
32953294
return manager

lib/matplotlib/backends/backend_template.py

Lines changed: 40 additions & 77 deletions
< 6D40 col width="100%"/>
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,32 @@
11
"""
2-
This is a fully functional do nothing backend to provide a template to
3-
backend writers. It is fully functional in that you can select it as
4-
a backend with
5-
6-
import matplotlib
7-
matplotlib.use('Template')
8-
9-
and your matplotlib scripts will (should!) run without error, though
10-
no output is produced. This provides a nice starting point for
11-
backend writers because you can selectively implement methods
12-
(draw_rectangle, draw_lines, etc...) and slowly see your figure come
13-
to life w/o having to have a full blown implementation before getting
14-
any results.
15-
16-
Copy this to backend_xxx.py and replace all instances of 'template'
17-
with 'xxx'. Then implement the class methods and functions below, and
18-
add 'xxx' to the switchyard in matplotlib/backends/__init__.py and
19-
'xxx' to the backends list in the validate_backend method in
20-
matplotlib/__init__.py and you're off. You can use your backend with::
21-
22-
import matplotlib
23-
matplotlib.use('xxx')
24-
import matplotlib.pyplot as plt
25-
plt.plot([1,2,3])
26-
plt.show()
27-
28-
matplotlib also supports external backends, so you can place you can
29-
use any module in your PYTHONPATH with the syntax::
30-
31-
import matplotlib
32-
matplotlib.use('module://my_backend')
33-
34-
where my_backend.py is your module name. This syntax is also
35-
recognized in the rc file and in the -d argument in pylab, e.g.,::
36-
37-
python simple_plot.py -dmodule://my_backend
38-
39-
If your backend implements support for saving figures (i.e. has a print_xyz()
40-
method) you can register it as the default handler for a given file type
41-
42-
from matplotlib.backend_bases import register_backend
43-
register_backend('xyz', 'my_backend', 'XYZ File Format')
44-
...
45-
plt.savefig("figure.xyz")
46-
47-
The files that are most relevant to backend_writers are
48-
49-
matplotlib/backends/backend_your_backend.py
50-
matplotlib/backend_bases.py
51-
matplotlib/backends/__init__.py
52-
matplotlib/__init__.py
53-
matplotlib/_pylab_helpers.py
54-
55-
Naming Conventions
56-
57-
* classes Upper or MixedUpperCase
58-
59-
* variables lower or lowerUpper
60-
61-
* functions lower or underscore_separated
62-
2+
This is a fully functional do nothing backend to provide a template to backend
3+
writers. It is fully functional in that you can select it as a backend e.g.
4+
with ::
5+
6+
import matplotlib
7+
matplotlib.use("template")
8+
9+
and your program will (should!) run without error, though no output is
10+
produced. This provides a starting point for backend writers; you can
11+
selectively implement drawing methods (`draw_path`, `draw_image`, etc.) and
12+
slowly see your figure come to life instead having to have a full blown
13+
implementation before getting any results.
14+
15+
Copy this file to a directory outside of the Matplotlib source tree, somewhere
16+
where Python can import it (by adding the directory to your ``sys.path`` or by
17+
packaging it as a normal Python package); if the backend is importable as
18+
``import my.backend`` you can then select it using ::
19+
20+
import matplotlib
21+
matplotlib.use("module://my.backend")
22+
23+
If your backend implements support for saving figures (i.e. has a `print_xyz`
24+
method), you can register it as the default handler for a given file type::
25+
26+
from matplotlib.backend_bases import register_backend
27+
register_backend('xyz', 'my_backend', 'XYZ File Format')
28+
...
29+
plt.savefig("figure.xyz")
6330
"""
6431

6532
from matplotlib._pylab_helpers import Gcf
@@ -73,10 +40,12 @@ class RendererTemplate(RendererBase):
7340
The renderer handles drawing/rendering operations.
7441
7542
This is a minimal do-nothing class that can be used to get started when
76-
writing a new backend. Refer to backend_bases.RendererBase for
77-
documentation of the classes methods.
43+
writing a new backend. Refer to `backend_bases.RendererBase` for
44+
documentation of the methods.
7845
"""
46+
7947
def __init__(self, dpi):
48+
super().__init__()
8049
self.dpi = dpi
8150

8251
def draw_path(self, gc, path, transform, rgbFace=None):
@@ -160,11 +129,12 @@ class GraphicsContextTemplate(GraphicsContextBase):
160129

161130
########################################################################
162131
#
163-
# The following functions and classes are for pylab and implement
132+
# The following functions and classes are for pyplot and implement
164133
# window/figure managers, etc...
165134
#
166135
########################################################################
167136

137+
168138
def draw_if_interactive():
169139
"""
170140
For image backends - is not required.
@@ -186,9 +156,7 @@ def show(*, block=None):
186156

187157

188158
def new_figure_manager(num, *args, FigureClass=Figure, **kwargs):
189-
"""
190-
Create a new figure manager instance
191-
"""
159+
"""Create a new figure manager instance."""
192160
# If a main-level app must be created, this (and
193161
# new_figure_manager_given_figure) is the usual place to do it -- see
194162
# backend_wx, backend_wxagg and backend_tkagg for examples. Not all GUIs
@@ -199,9 +167,7 @@ def new_figure_manager(num, *args, FigureClass=Figure, **kwargs):
199167

200168

201169
def new_figure_manager_given_figure(num, figure):
202-
"""
203-
Create a new figure manager instance for the given figure.
204-
"""
170+
"""Create a new figure manager instance for the given figure."""
205171
canvas = FigureCanvasTemplate(figure)
206172
manager = FigureManagerTemplate(canvas, num)
207173
return manager
@@ -225,9 +191,7 @@ class methods button_press_event, button_release_event,
225191
"""
226192

227193
def draw(self):
228-
"""
229-
Draw the figure using the renderer
230-
"""
194+
"""Draw the figure using the renderer."""
231195
renderer = RendererTemplate(self.figure.dpi)
232196
self.figure.draw(renderer)
233197

@@ -245,19 +209,18 @@ def print_foo(self, filename, *args, **kwargs):
245209
to their original values after this call, so you don't need to
246210
save and restore them.
247211
"""
248-
pass
249212

250213
def get_default_filetype(self):
251214
return 'foo'
252215

253216

254217
class FigureManagerTemplate(FigureManagerBase):
255218
"""
256-
Wrap everything up into a window for the pylab interface
219+
Helper class for pyplot mode, wraps everything up into a neat bundle.
257220
258-
For non interactive backends, the base class does all the work
221+
For non-interactive backends, the base class is sufficient.
259222
"""
260-
pass
223+
261224

262225
########################################################################
263226
#

lib/matplotlib/patheffects.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,6 @@ def __init__(self, path_effects, renderer):
9393
self._path_effects = path_effects
9494
self._renderer = renderer
9595

96-
def new_gc(self):
97-
# docstring inherited
98-
return self._renderer.new_gc()
99-
10096
def copy_with_path_effect(self, path_effects):
10197
return self.__class__(path_effects, self._renderer)
10298

@@ -143,10 +139,6 @@ def draw_path_collection(self, gc, master_transform, paths, *args,
143139
renderer.draw_path_collection(gc, master_transform, paths,
144140
*args, **kwargs)
145141

146-
def points_to_pixels(self, points):
147-
# docstring inherited
148-
return self._renderer.points_to_pixels(points)
149-
150142
def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
151143
# Implements the naive text drawing as is found in RendererBase.
152144
path, transform = self._get_text_path_transform(x, y, s, prop,
@@ -156,7 +148,8 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
156148
self.draw_path(gc, path, transform, rgbFace=color)
157149

158150
def __getattribute__(self, name):
159-
if name in ['_text2path', 'flipy', 'height', 'width']:
151+
if name in ['flipy', 'get_canvas_width_height', 'new_gc',
152+
'points_to_pixels', '_text2path', 'height', 'width']:
160153
return getattr(self._renderer, name)
161154
else:
162155
return object.__getattribute__(self, name)

0 commit comments

Comments
 (0)
0