Revision: 6804
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6804&view=rev
Author: leejjoon
Date: 2009-01-17 10:28:48 +0000 (Sat, 17 Jan 2009)
Log Message:
-----------
bbox_inches option for savefig
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backend_bases.py
trunk/matplotlib/lib/matplotlib/figure.py
trunk/matplotlib/lib/matplotlib/transforms.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-01-17 05:47:42 UTC (rev 6803)
+++ trunk/matplotlib/CHANGELOG 2009-01-17 10:28:48 UTC (rev 6804)
@@ -1,3 +1,6 @@
+2009-01-16 Implement bbox_inches option for savefig. If bbox_inches is
+ "tight", try to determine the tight bounding box. - JJL
+
2009-01-16 Fix bug in is_string_like so it doesn't raise an
unnecessary exception. - EF
Modified: trunk/matplotlib/lib/matplotlib/backend_bases.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backend_bases.py 2009-01-17 05:47:42 UTC
(rev 6803)
+++ trunk/matplotlib/lib/matplotlib/backend_bases.py 2009-01-17 10:28:48 UTC
(rev 6804)
@@ -33,6 +33,9 @@
import matplotlib.path as path
from matplotlib import rcParams
+from matplotlib.transforms import Bbox, TransformedBbox, Affine2D
+import cStringIO
+
class RendererBase:
"""An abstract base class to handle drawing/rendering operations.
@@ -1419,6 +1422,28 @@
self.figure.set_facecolor(facecolor)
self.figure.set_edgecolor(edgecolor)
+ bbox_inches = kwargs.pop("bbox_inches", None)
+
+ if bbox_inches:
+ # call adjust_bbox to save only the given area
+ if bbox_inches == "tight":
+ # save the figure to estimate the bounding box
+ result = getattr(self, method_name)(
+ cStringIO.StringIO(),
+ dpi=dpi,
+ facecolor=facecolor,
+ edgecolor=edgecolor,
+ orientation=orientation,
+ **kwargs)
+ renderer = self.figure._cachedRenderer
+ bbox_inches = self.figure.get_tightbbox(renderer)
+ pad = kwargs.pop("pad_inches", 0.1)
+ bbox_inches = bbox_inches.padded(pad)
+
+ restore_bbox = self._adjust_bbox(self.figure, format,
+ bbox_inches)
+
+
try:
result = getattr(self, method_name)(
filename,
@@ -1428,6 +1453,9 @@
orientation=orientation,
**kwargs)
finally:
+ if bbox_inches and restore_bbox:
+ restore_bbox()
+
self.figure.dpi = origDPI
self.figure.set_facecolor(origfacecolor)
self.figure.set_edgecolor(origedgecolor)
@@ -1435,6 +1463,91 @@
#self.figure.canvas.draw() ## seems superfluous
return result
+
+ def _adjust_bbox(self, fig, format, bbox_inches):
+ """
+ Temporarily adjust the figure so that only the specified area
+ (bbox_inches) is saved.
+
+ It modifies fig.bbox, fig.bbox_inches,
+ fig.transFigure._boxout, and fig.patch. While the figure size
+ changes, the scale of the original figure is conserved. A
+ function whitch restores the original values are returned.
+ """
+
+ origBbox = fig.bbox
+ origBboxInches = fig.bbox_inches
+ _boxout = fig.transFigure._boxout
+
+ def restore_bbox():
+ fig.bbox = origBbox
+ fig.bbox_inches = origBboxInches
+ fig.transFigure._boxout = _boxout
+ fig.transFigure.invalidate()
+ fig.patch.set_bounds(0, 0, 1, 1)
+
+ if format in ["png", "raw", "rgba"]:
+ self._adjust_bbox_png(fig, bbox_inches)
+ return restore_bbox
+ elif format in ["pdf", "eps"]:
+ self._adjust_bbox_pdf(fig, bbox_inches)
+ return restore_bbox
+ else:
+ warnings.warn("bbox_inches option for %s backend is not
implemented yet." % (format))
+ return None
+
+
+ def _adjust_bbox_png(self, fig, bbox_inches):
+ """
+ _adjust_bbox for png (Agg) format
+ """
+
+ tr = fig.dpi_scale_trans
+
+ _bbox = TransformedBbox(bbox_inches,
+ tr)
+ x0, y0 = _bbox.x0, _bbox.y0
+ fig.bbox_inches = Bbox.from_bounds(0, 0,
+ bbox_inches.width,
+ bbox_inches.height)
+
+ x0, y0 = _bbox.x0, _bbox.y0
+ w1, h1 = fig.bbox.width, fig.bbox.height
+ self.figure.transFigure._boxout = Bbox.from_bounds(-x0, -y0,
+ w1, h1)
+ self.figure.transFigure.invalidate()
+
+ fig.bbox = TransformedBbox(fig.bbox_inches, tr)
+
+ fig.patch.set_bounds(x0/w1, y0/h1,
+ fig.bbox.width/w1, fig.bbox.height/h1)
+
+
+ def _adjust_bbox_pdf(self, fig, bbox_inches):
+ """
+ _adjust_bbox for pdf & eps format
+ """
+
+ tr = Affine2D().scale(72)
+
+ _bbox = TransformedBbox(bbox_inches, tr)
+
+ fig.bbox_inches = Bbox.from_bounds(0, 0,
+ bbox_inches.width,
+ bbox_inches.height)
+ x0, y0 = _bbox.x0, _bbox.y0
+ f = 72. / fig.dpi
+ w1, h1 = fig.bbox.width*f, fig.bbox.height*f
+ self.figure.transFigure._boxout = Bbox.from_bounds(-x0, -y0,
+ w1, h1)
+ self.figure.transFigure.invalidate()
+
+ fig.bbox = TransformedBbox(fig.bbox_inches, tr)
+
+ fig.patch.set_bounds(x0/w1, y0/h1,
+ fig.bbox.width/w1, fig.bbox.height/h1)
+
+
def get_default_filetype(self):
raise NotImplementedError
Modified: trunk/matplotlib/lib/matplotlib/figure.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/figure.py 2009-01-17 05:47:42 UTC (rev
6803)
+++ trunk/matplotlib/lib/matplotlib/figure.py 2009-01-17 10:28:48 UTC (rev
6804)
@@ -33,6 +33,7 @@
import matplotlib.cbook as cbook
+
class SubplotParams:
"""
A class to hold the parameters for a subplot
@@ -971,6 +972,16 @@
a plot on top of a colored background on a web page. The
transparency of these patches will be restored to their
original values upon exit of this function.
+
+ *bbox_inches*:
+ Bbox in inches. Only the given portion of the figure is
+ saved. If 'tight', try to figure out the tight bbox of
+ the figure.
+
+ *pad_inches*:
+ Amount of padding around the figure when bbox_inches is
+ 'tight'.
+
"""
for key in ('dpi', 'facecolor', 'edgecolor'):
@@ -1091,6 +1102,41 @@
return blocking_input(timeout=timeout)
+
+ def get_tightbbox(self, renderer):
+ """
+ Return a (tight) bounding box of the figure in inches.
+
+ It only accounts axes title, axis labels, and axis
+ ticklabels. Needs improvement.
+ """
+
+ artists = []
+ bb = []
+ for ax in self.axes:
+
+ artists.append(ax.xaxis.label)
+ artists.append(ax.yaxis.label)
+ artists.append(ax.title)
+ artists.append(ax)
+
+ bbx1, bbx2 = ax.xaxis.get_ticklabel_extents(renderer)
+ bby1, bby2 = ax.yaxis.get_ticklabel_extents(renderer)
+ bb.extend([bbx1, bbx2, bby1, bby2])
+
+
+ bb.extend([c.get_window_extent(renderer) for c in artists \
+ if c.get_visible()])
+
+ _bbox = Bbox.union([b for b in bb if b.width!=0 or b.height!=0])
+
+ bbox_inches = TransformedBbox(_bbox,
+ Affine2D().scale(1./self.dpi))
+
+ return bbox_inches
+
+
+
def figaspect(arg):
"""
Create a figure with specified aspect ratio. If *arg* is a number,
Modified: trunk/matplotlib/lib/matplotlib/transforms.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/transforms.py 2009-01-17 05:47:42 UTC
(rev 6803)
+++ trunk/matplotlib/lib/matplotlib/transforms.py 2009-01-17 10:28:48 UTC
(rev 6804)
@@ -635,7 +635,7 @@
Return a new :class:`Bbox` that is padded on all four sides by
the given value.
"""
- points = self._points
+ points = self.get_points()
return Bbox(points + [[-p, -p], [p, p]])
def translated(self, tx, ty):
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
This SF.net email is sponsored by:
SourcForge Community
SourceForge wants to tell your story.
http://p.sf.net/sfu/sf-spreadtheword
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins