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

Skip to content

Commit 67f1dc2

Browse files
committed
Refactoring of FigureCanvas*.print_figure so that each backend does
not have to track all other possible filetypes. This should make it easier to add new filetype backends without updating lots of places. All GUI backends have the same base set of filetypes they support, defined in FigureCanvasBase. Non-GUI backends, for the most part will still only write to their own file format (and not do any switch_backend magic.) All GUI backends (where possible) now generate a list of file patterns for their file chooser dialogs, rather than having hard-coded lists. See FILETYPES for matrix of filetypes supported by each backend. svn path=/trunk/matplotlib/; revision=3798
1 parent 3a7c864 commit 67f1dc2

25 files changed

Lines changed: 740 additions & 884 deletions

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
2007-09-06 Refactored image saving code so that all GUI backends can
2+
save most image types. See FILETYPES for a matrix of
3+
backends and their supported file types.
4+
Backend canvases should no longer write their own print_figure()
5+
method -- instead they should write a print_xxx method for
6+
each filetype they can output and add an entry to their
7+
class-scoped filetypes dictionary. - MGD
8+
19
2007-09-05 Fixed Qt version reporting in setupext.py - DSD
210

311
2007-09-04 Embedding Type 1 fonts in PDF, and thus usetex support

FILETYPES

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
This is a table of the output formats supported by each backend.
2+
3+
You may need to expand your terminal window to read this table
4+
correctly. It may be edited with emacs' table mode.
5+
6+
Each cell specifies the backend that actually handles the file format.
7+
A cell with a '+' in it denotes the rasterizer and the file writing
8+
infrastructure as separate pieces.
9+
10+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
11+
| |bmp |emf |eps |jpeg |pcx |pdf |png |ps |raw |svg |tiff |xpm |
12+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
13+
|Agg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
14+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
15+
|Cairo | |emf |ps | | |cairo |cairo |cairo|agg |cairo| | |
16+
|[1] | | |[2] | | | |* | | | | | |
17+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
18+
|CocoaAgg| |emf |ps | | |pdf |agg * |ps |agg |svg | | |
19+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
20+
|Emf | |emf *| | | | | | | | | | |
21+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
22+
|FltkAgg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
23+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
24+
|Gd | | | | | | |gd * | | | | | |
25+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
26+
|Gtk | |emf |ps |gdk + | |pdf |gdk + |ps |agg |svg | | |
27+
|(gdk) | | | |pixbuf | | |pixbuf| | | | | |
28+
| | | | | | | |* | | | | | |
29+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
30+
|GtkAgg | |emf |ps |agg + | |pdf |agg + |ps |agg |svg | | |
31+
| | | | |pixbuf | | |pixbuf| | | | | |
32+
| | | | | | | |* | | | | | |
33+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
34+
|GtkCairo| |emf |ps |cairo +| |cairo |cairo |cairo|agg |svg | | |
35+
| | | | |pixbuf | | |* | | | | | |
36+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
37+
|Paint | | | | | | |libart| | | | | |
38+
|(libart)| | | | | | |* | | | | | |
39+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
40+
|Pdf | | | | | |pdf * | | | | | | |
41+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
42+
|Ps | | |ps | | | | |ps * | | | | |
43+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
44+
|QtAgg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
45+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
46+
|Qt4Agg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
47+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
48+
|Svg | | | | | | | | | |svg *| | |
49+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
50+
|TkAgg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
51+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
52+
|Wx |wx + |emf |ps |wx + wx|wx + |pdf |wx + |ps |agg |svg |wx + |wx + |
53+
| |wx | | | |wx | |wx * | | | |wx |wx |
54+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
55+
|WxAgg | |emf |ps | | |pdf |agg * |ps |agg |svg | | |
56+
+--------+-----+-----+-----+-------+-----+------+------+-----+-----+-----+-----+-----+
57+
58+
* Default filetype for the backend
59+
[1] Cairo's default filetype is specified in rcParams['cairo.format']
60+
[2] Cairo does not produce .eps files, and instead falls back on backend_ps.py

lib/matplotlib/backend_bases.py

Lines changed: 115 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
"""
55

66
from __future__ import division
7-
import sys, warnings
7+
import os, sys, warnings
88

99
import numpy as npy
1010
import matplotlib.numerix.npyma as ma
1111
import matplotlib.cbook as cbook
1212
import matplotlib.colors as colors
1313
import matplotlib.transforms as transforms
1414
import matplotlib.widgets as widgets
15+
from matplotlib import rcParams
1516

1617
class RendererBase:
1718
"""An abstract base class to handle drawing/rendering operations
@@ -1071,8 +1072,70 @@ def get_width_height(self):
10711072
(depending on the backend), truncated to integers"""
10721073
return int(self.figure.bbox.width()), int(self.figure.bbox.height())
10731074

1075+
filetypes = {
1076+
'emf': 'Enhanced Metafile',
1077+
'eps': 'Encapsulated Postscript',
1078+
'pdf': 'Portable Document Format',
1079+
'png': 'Portable Network Graphics',
1080+
'ps' : 'Postscript',
1081+
'raw': 'Raw RGBA bitmap',
1082+
'rgb': 'Raw RGBA bitmap',
1083+
'svg': 'Scalable Vector Graphics',
1084+
}
1085+
1086+
# All of these print_* functions do a lazy import because
1087+
# a) otherwise we'd have cyclical imports, since all of these
1088+
# classes inherit from FigureCanvasBase
1089+
# b) so we don't import a bunch of stuff the user may never use
1090+
1091+
def print_emf(self, *args, **kwargs):
1092+
from backends.backend_emf import FigureCanvasEMF # lazy import
1093+
emf = self.switch_backends(FigureCanvasEMF)
1094+
return emf.print_emf(*args, **kwargs)
1095+
1096+
def print_eps(self, *args, **kwargs):
1097+
from backends.backend_ps import FigureCanvasPS # lazy import
1098+
ps = self.switch_backends(FigureCanvasPS)
1099+
return ps.print_eps(*args, **kwargs)
1100+
1101+
def print_pdf(self, *args, **kwargs):
1102+
from backends.backend_pdf import FigureCanvasPdf # lazy import
1103+
pdf = self.switch_backends(FigureCanvasPdf)
1104+
return pdf.print_pdf(*args, **kwargs)
1105+
1106+
def print_png(self, *args, **kwargs):
1107+
from backends.backend_agg import FigureCanvasAgg # lazy import
1108+
agg = self.switch_backends(FigureCanvasAgg)
1109+
return agg.print_png(*args, **kwargs)
1110+
1111+
def print_ps(self, *args, **kwargs):
1112+
from backends.backend_ps import FigureCanvasPS # lazy import
1113+
ps = self.switch_backends(FigureCanvasPS)
1114+
return ps.print_ps(*args, **kwargs)
1115+
1116+
def print_raw(self, *args, **kwargs):
1117+
from backends.backend_agg import FigureCanvasAgg # lazy import
1118+
agg = self.switch_backends(FigureCanvasAgg)
1119+
return agg.print_raw(*args, **kwargs)
1120+
print_bmp = print_rgb = print_raw
1121+
1122+
def print_svg(self, *args, **kwargs):
1123+
from backends.backend_svg import FigureCanvasSVG # lazy import
1124+
svg = self.switch_backends(FigureCanvasSVG)
1125+
return svg.print_svg(*args, **kwargs)
1126+
1127+
def get_supported_filetypes(self):
1128+
return self.filetypes
1129+
1130+
def get_supported_filetypes_grouped(self):
1131+
groupings = {}
1132+
for ext, name in self.filetypes.items():
1133+
groupings.setdefault(name, []).append(ext)
1134+
groupings[name].sort()
1135+
return groupings
1136+
10741137
def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
1075-
orientation='portrait', **kwargs):
1138+
orientation='portrait', format=None, **kwargs):
10761139
"""
10771140
Render the figure to hardcopy. Set the figure patch face and edge
10781141
colors. This is useful because some of the GUIs have a gray figure
@@ -1085,9 +1148,57 @@ def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
10851148
facecolor - the facecolor of the figure
10861149
edgecolor - the edgecolor of the figure
10871150
orientation - 'landscape' | 'portrait' (not supported on all backends)
1088-
"""
1089-
pass
1151+
format - when set, forcibly set the file format to save to
1152+
"""
1153+
if format is None:
1154+
if cbook.is_string_like(filename):
1155+
format = os.path.splitext(filename)[1][1:]
1156+
if format is None or format == '':
1157+
format = self.get_default_filetype()
1158+
if cbook.is_string_like(filename):
1159+
filename = filename.rstrip('.') + '.' + format
1160+
format = format.lower()
1161+
1162+
method_name = 'print_%s' % format
1163+
if (format not in self.filetypes or
1164+
not hasattr(self, method_name)):
1165+
formats = self.filetypes.keys()
1166+
formats.sort()
1167+
raise ValueError(
1168+
'Format "%s" is not supported.\n'
1169+
'Supported formats: '
1170+
'%s.' % (format, ', '.join(formats)))
1171+
1172+
if dpi is None:
1173+
dpi = rcParams['savefig.dpi']
1174+
1175+
origDPI = self.figure.dpi.get()
1176+
origfacecolor = self.figure.get_facecolor()
1177+
origedgecolor = self.figure.get_edgecolor()
1178+
1179+
self.figure.dpi.set(dpi)
1180+
self.figure.set_facecolor(facecolor)
1181+
self.figure.set_edgecolor(edgecolor)
10901182

1183+
try:
1184+
result = getattr(self, method_name)(
1185+
filename,
1186+
dpi=dpi,
1187+
facecolor=facecolor,
1188+
edgecolor=edgecolor,
1189+
orientation=orientation,
1190+
**kwargs)
1191+
finally:
1192+
self.figure.dpi.set(origDPI)
1193+
self.figure.set_facecolor(origfacecolor)
1194+
self.figure.set_edgecolor(origedgecolor)
1195+
self.figure.set_canvas(self)
1196+
1197+
return result
1198+
1199+
def get_default_filetype(self):
1200+
raise NotImplementedError
1201+
10911202
def switch_backends(self, FigureCanvasClass):
10921203
"""
10931204
instantiate an instance of FigureCanvasClass

lib/matplotlib/backends/backend_agg.py

Lines changed: 10 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -405,95 +405,15 @@ def buffer_rgba(self,x,y):
405405
'debug-annoying')
406406
return self.renderer.buffer_rgba(x,y)
407407

408-
def print_figure(self, filename, dpi=None, facecolor='w', edgecolor='w',
409-
orientation='portrait', **kwargs):
410-
"""
411-
Render the figure to hardcopy. Set the figure patch face and
412-
edge colors. This is useful because some of the GUIs have a
413-
gray figure face color background and you'll probably want to
414-
override this on hardcopy
415-
416-
If the extension matches PNG, write a PNG file
417-
418-
If the extension matches BMP or RAW, write an RGBA bitmap file
419-
420-
If filename is a fileobject, write png to file object (thus
421-
you can, for example, write the png to stdout
422-
"""
423-
if __debug__: verbose.report('FigureCanvasAgg.print_figure',
424-
'debug-annoying')
425-
if dpi is None: dpi = matplotlib.rcParams['savefig.dpi']
426-
427-
# store the orig figure dpi, color and size information so we
428-
# can restore them later. For image creation alone, this is
429-
# not important since after the print the figure is done. But
430-
# backend_agg may be used as a renderer for a GUI figure, and
431-
# restoring figure props will be important in that case.
432-
# TODO: move most of this functionality into backend_bases
433-
434-
origDPI = self.figure.dpi.get()
435-
origfacecolor = self.figure.get_facecolor()
436-
origedgecolor = self.figure.get_edgecolor()
408+
def get_default_filetype(self):
409+
return 'png'
437410

438-
self.figure.dpi.set(dpi)
439-
self.figure.set_facecolor(facecolor)
440-
self.figure.set_edgecolor(edgecolor)
441-
442-
# render the printed figure
411+
def print_raw(self, filename, *args, **kwargs):
443412
self.draw()
444-
445-
printfunc = None
446-
if not is_string_like(filename):
447-
# assume png and write to fileobject
448-
self.renderer._renderer.write_png(filename)
449-
#pass
450-
else:
451-
# take a look at the extension and choose the print handler
452-
basename, ext = os.path.splitext(filename)
453-
if not len(ext):
454-
ext = '.png'
455-
filename += ext
456-
457-
ext = ext.lower()
458-
if (ext.find('rgb')>=0 or
459-
ext.find('raw')>=0 or
460-
ext.find('bmp')>=0 ):
461-
# agg doesn't handle unicode yet
462-
self.renderer._renderer.write_rgba(str(filename))
463-
elif ext.find('png')>=0:
464-
# agg doesn't handle unicode yet
465-
self.renderer._renderer.write_png(str(filename))
466-
#pass
467-
elif ext.find('svg')>=0:
468-
from backend_svg import FigureCanvasSVG
469-
svg = self.switch_backends(FigureCanvasSVG)
470-
printfunc = svg.print_figure
471-
elif ext.find('ps')>=0 or ext.find('ep')>=0:
472-
from backend_ps import FigureCanvasPS # lazy import
473-
ps = self.switch_backends(FigureCanvasPS)
474-
printfunc = ps.print_figure
475-
elif ext.find('pdf')>=0:
476-
from backend_pdf import FigureCanvasPdf
477-
pdf = self.switch_backends(FigureCanvasPdf)
478-
printfunc = pdf.print_figure
479-
else:
480-
raise IOError('Do not know know to handle extension *%s' % ext)
481-
482-
if printfunc is not None:
483-
try:
484-
printfunc(filename, dpi, facecolor, edgecolor, orientation, **kwargs)
485-
except:
486-
# restore the original figure properties
487-
self.figure.dpi.set(origDPI)
488-
self.figure.set_facecolor(origfacecolor)
489-
self.figure.set_edgecolor(origedgecolor)
490-
self.figure.set_canvas(self)
491-
raise
492-
493-
# restore the original figure properties
494-
self.figure.dpi.set(origDPI)
495-
self.figure.set_facecolor(origfacecolor)
496-
self.figure.set_edgecolor(origedgecolor)
497-
self.figure.set_canvas(self)
498-
499-
413+
self.get_renderer()._renderer.write_rgba(str(filename))
414+
print_rgba = print_raw
415+
416+
def print_png(self, filename, *args, **kwargs):
417+
self.draw()
418+
self.get_renderer()._renderer.write_png(str(filename))
419+

lib/matplotlib/backends/backend_cairo.py

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -488,41 +488,7 @@ def new_figure_manager(num, *args, **kwargs): # called by backends/__init__.py
488488

489489

490490
class FigureCanvasCairo (FigureCanvasBase):
491-
def print_figure(self, fo, dpi=150, facecolor='w', edgecolor='w',
492-
orientation='portrait', format=None, **kwargs):
493-
if _debug: print '%s.%s()' % (self.__class__.__name__, _fn_name())
494-
# settings for printing
495-
self.figure.dpi.set(dpi)
496-
self.figure.set_facecolor(facecolor)
497-
self.figure.set_edgecolor(edgecolor)
498-
499-
if format is None and isinstance (fo, basestring):
500-
# get format from filename extension
501-
format = os.path.splitext(fo)[1][1:]
502-
if format == '':
503-
format = rcParams['cairo.format']
504-
fo = '%s.%s' % (fo, format)
505-
506-
if format is not None:
507-
format = format.lower()
508-
509-
if format == 'png':
510-
self._save_png (fo)
511-
elif format in ('pdf', 'ps', 'svg'):
512-
self._save (fo, format, orientation, **kwargs)
513-
elif format == 'eps': # backend_ps for eps
514-
warnings.warn('eps format is printed by ps backend, not cairo')
515-
from backend_ps import FigureCanvasPS as FigureCanvas
516-
fc = FigureCanvas(self.figure)
517-
fc.print_figure (fo, dpi, facecolor, edgecolor,
518-
orientation, **kwargs)
519-
else:
520-
warnings.warn('Format "%s" is not supported.\n'
521-
'Supported formats: '
522-
'%s.' % (format, ', '.join(IMAGE_FORMAT)))
523-
524-
525-
def _save_png (self, fobj):
491+
def print_png(self, fobj, *args, **kwargs):
526492
width, height = self.get_width_height()
527493

528494
renderer = RendererCairo (self.figure.dpi)
@@ -532,9 +498,20 @@ def _save_png (self, fobj):
532498

533499
self.figure.draw (renderer)
534500
surface.write_to_png (fobj)
501+
502+
def print_pdf(self, fobj, *args, **kwargs):
503+
return self._save(fobj, 'pdf', *args, **kwargs)
504+
505+
def print_ps(self, fobj, *args, **kwargs):
506+
return self._save(fobj, 'ps', *args, **kwargs)
535507

508+
def print_svg(self, fobj, *args, **kwargs):
509+
return self._save(fobj, 'svg', *args, **kwargs)
536510

537-
def _save (self, fo, format, orientation, **kwargs):
511+
def get_default_filetype(self):
512+
return rcParams['cairo.format']
513+
514+
def _save (self, fo, format, **kwargs):
538515
# save PDF/PS/SVG
539516
orientation = kwargs.get('orientation', 'portrait')
540517

0 commit comments

Comments
 (0)