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

Skip to content

Commit 086c046

Browse files
committed
All backends can write to file-like objects rather than only regular files.
svn path=/trunk/matplotlib/; revision=4243
1 parent ce2d116 commit 086c046

6 files changed

Lines changed: 80 additions & 28 deletions

File tree

CHANGELOG

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2007-11-13 All backends now support writing to a file-like object, not
2+
just a regular file. savefig() can be passed a file-like
3+
object in place of a file path. - MGD
4+
15
2007-11-13 Improved the default backend selection at build time:
26
SVG -> Agg -> TkAgg -> WXAgg -> GTK -> GTKAgg. The last usable
37
backend in this progression will be chosen in the default

lib/matplotlib/backends/backend_gtk.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,24 @@ def _print_image(self, filename, format):
365365
pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(),
366366
0, 0, 0, 0, width, height)
367367

368-
try:
369-
pixbuf.save(filename, format)
370-
except gobject.GError, exc:
371-
error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
372-
368+
if is_string_like(filename):
369+
try:
370+
pixbuf.save(filename, format)
371+
except gobject.GError, exc:
372+
error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
373+
elif hasattr(filename, 'write') and callable(filename.write):
374+
if hasattr(pixbuf, 'save_to_callback'):
375+
def save_callback(buf, data=None):
376+
data.write(buf)
377+
try:
378+
pixbuf.save_to_callback(save_callback, format, user_data=filename)
379+
except gobject.GError, exc:
380+
error_msg_gtk('Save figure failure:\n%s' % (exc,), parent=self)
381+
else:
382+
raise ValueError("Saving to a Python file-like object is only supported by PyGTK >= 2.8")
383+
else:
384+
raise ValueError("filename must be a path or a file-like object")
385+
373386
def get_default_filetype(self):
374387
return 'png'
375388

lib/matplotlib/backends/backend_pdf.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,15 @@ def __init__(self, width, height, filename):
325325
self.width, self.height = width, height
326326
self.nextObject = 1 # next free object id
327327
self.xrefTable = [ [0, 65535, 'the zero object'] ]
328-
fh = file(filename, 'wb')
328+
self.passed_in_file_object = False
329+
if is_string_like(filename):
330+
fh = file(filename, 'wb')
331+
elif hasattr(filename, 'write') and callable(filename.write):
332+
fh = filename
333+
self.passed_in_file_object = True
334+
else:
335+
raise ValueError("filename must be a path or a file-like object")
336+
329337
self.fh = fh
330338
self.currentstream = None # stream object to write to, if any
331339
fh.write("%PDF-1.4\n") # 1.4 is the first version to have alpha
@@ -423,7 +431,8 @@ def close(self):
423431
self.writeMarkers()
424432
self.writeXref()
425433
self.writeTrailer()
426-
self.fh.close()
434+
if not self.passed_in_file_object:
435+
self.fh.close()
427436

428437
def write(self, data):
429438
if self.currentstream is None:

lib/matplotlib/backends/backend_ps.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,16 @@ def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
10471047
written into this file object.
10481048
"""
10491049
isEPSF = format == 'eps'
1050-
title = outfile
1051-
1052-
# write to a temp file, we'll move it to outfile when done
1053-
tmpfile = os.path.join(gettempdir(), md5.md5(outfile).hexdigest())
1050+
passed_in_file_object = False
1051+
if is_string_like(outfile):
1052+
title = outfile
1053+
tmpfile = os.path.join(gettempdir(), md5.md5(outfile).hexdigest())
1054+
elif hasattr(outfile, 'write') and callable(outfile.write):
1055+
title = None
1056+
tmpfile = os.path.join(gettempdir(), md5.md5(str(hash(outfile))).hexdigest())
1057+
passed_in_file_object = True
1058+
else:
1059+
raise ValueError("outfile must be a path or a file-like object")
10541060
fh = file(tmpfile, 'w')
10551061

10561062
# find the appropriate papertype
@@ -1168,10 +1174,11 @@ def _print_figure(self, outfile, format, dpi=72, facecolor='w', edgecolor='w',
11681174
elif rcParams['ps.usedistiller'] == 'xpdf':
11691175
xpdf_distill(tmpfile, isEPSF, ptype=papertype, bbox=bbox)
11701176

1171-
if isinstance(outfile, file):
1177+
if passed_in_file_object:
11721178
fh = file(tmpfile)
11731179
print >>outfile, fh.read()
1174-
else: shutil.move(tmpfile, outfile)
1180+
else:
1181+
shutil.move(tmpfile, outfile)
11751182

11761183
def _print_figure_tex(self, outfile, format, dpi, facecolor, edgecolor,
11771184
orientation, isLandscape, papertype):

lib/matplotlib/backends/backend_svg.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from matplotlib import verbose, __version__, rcParams
66
from matplotlib.backend_bases import RendererBase, GraphicsContextBase,\
77
FigureManagerBase, FigureCanvasBase
8+
from matplotlib.cbook import is_string_like
89
from matplotlib.colors import rgb2hex
910
from matplotlib.figure import Figure
1011
from matplotlib.font_manager import findfont, FontProperties
@@ -458,23 +459,36 @@ class FigureCanvasSVG(FigureCanvasBase):
458459
'svgz': 'Scalable Vector Graphics'}
459460

460461
def print_svg(self, filename, *args, **kwargs):
461-
svgwriter = codecs.open(filename, 'w', 'utf-8')
462-
return self._print_svg(filename, svgwriter)
463-
462+
if is_string_like(filename):
463+
fh_to_close = svgwriter = codecs.open(filename, 'w', 'utf-8')
464+
elif hasattr(filename, 'write') and callable(filename.write):
465+
svgwriter = codecs.EncodedFile(filename, 'utf-8')
466+
fh_to_close = None
467+
else:
468+
raise ValueError("filename must be a path or a file-like object")
469+
return self._print_svg(filename, svgwriter, fh_to_close)
470+
464471
def print_svgz(self, filename, *args, **kwargs):
465-
gzipwriter = gzip.GzipFile(filename, 'w')
466-
svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8')
467-
return self._print_svg(filename, svgwriter)
472+
if is_string_like(filename):
473+
gzipwriter = gzip.GzipFile(filename, 'w')
474+
fh_to_close = svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8')
475+
elif hasattr(filename, 'write') and callable(filename.write):
476+
fh_to_close = gzipwriter = gzip.GzipFile(fileobj=filename, mode='w')
477+
svgwriter = codecs.EncodedFile(gzipwriter, 'utf-8')
478+
else:
479+
raise ValueError("filename must be a path or a file-like object")
480+
return self._print_svg(filename, svgwriter, fh_to_close)
468481

469-
def _print_svg(self, filename, svgwriter):
482+
def _print_svg(self, filename, svgwriter, fh_to_close=None):
470483
self.figure.dpi.set(72)
471484
width, height = self.figure.get_size_inches()
472485
w, h = width*72, height*72
473486

474487
renderer = RendererSVG(w, h, svgwriter, filename)
475488
self.figure.draw(renderer)
476489
renderer.finish()
477-
svgwriter.close()
490+
if fh_to_close is not None:
491+
svgwriter.close()
478492

479493
def get_default_filetype(self):
480494
return 'svg'

lib/matplotlib/backends/backend_wx.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def write(self, msg):
152152
cursors
153153
from matplotlib._pylab_helpers import Gcf
154154
from matplotlib.artist import Artist
155-
from matplotlib.cbook import exception_to_str
155+
from matplotlib.cbook import exception_to_str, is_string_like
156156
from matplotlib.figure import Figure
157157
from matplotlib.text import _process_text_args, Text
158158
from matplotlib.widgets import SubplotTool
@@ -1030,12 +1030,17 @@ def _print_image(self, filename, filetype, *args, **kwargs):
10301030

10311031
# Now that we have rendered into the bitmap, save it
10321032
# to the appropriate file type and clean up
1033-
if not self.bitmap.SaveFile(filename, filetype):
1034-
DEBUG_MSG('print_figure() file save error', 4, self)
1035-
# note the error must be displayed here because trapping
1036-
# the error on a call or print_figure may not work because
1037-
# printing can be qued and called from realize
1038-
raise RuntimeError('Could not save figure to %s\n' % (filename))
1033+
if is_string_like(filename):
1034+
if not self.bitmap.SaveFile(filename, filetype):
1035+
DEBUG_MSG('print_figure() file save error', 4, self)
1036+
# note the error must be displayed here because trapping
1037+
# the error on a call or print_figure may not work because
1038+
# printing can be qued and called from realize
1039+
raise RuntimeError('Could not save figure to %s\n' % (filename))
1040+
elif hasattr(filename, 'write') and callable(filename.write):
1041+
if not self.bitmap.ConvertToImage().SaveStream(filename, filetype):
1042+
DEBUG_MSG('print_figure() file save error', 4, self)
1043+
raise RuntimeError('Could not save figure to %s\n' % (filename))
10391044

10401045
# Restore everything to normal
10411046
self.bitmap = origBitmap

0 commit comments

Comments
 (0)