From 329085ed74e0ea8f8e374c01d896db1842b065e9 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 17 Mar 2012 14:46:51 -1000 Subject: [PATCH 1/2] Allow automatic use of tight_layout. In common interactive usage, stretching a figure across the screen leaves too much wasted space; Figure.tight_layout() can solve this problem at least for simple plots. This changeset uses a previously existing but unused rcParam and a Figure kwarg to allow the user to have tight_layout executed automatically with every Figure.draw(). --- lib/matplotlib/figure.py | 26 +++++++++++++++++++++++++- lib/matplotlib/rcsetup.py | 2 +- matplotlibrc.template | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index a9c0b3300f69..df16dc7efc33 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -240,7 +240,7 @@ class Figure(Artist): For multiple figure images, the figure will make composite images depending on the renderer option_image_nocomposite function. If suppressComposite is True|False, this will - override the renderer + override the renderer. """ def __str__(self): @@ -254,6 +254,7 @@ def __init__(self, linewidth = 0.0, # the default linewidth of the frame frameon = True, # whether or not to draw the figure frame subplotpars = None, # default to rc + tight = None, # whether to apply tight_layout ): """ *figsize* @@ -276,6 +277,11 @@ def __init__(self, *subplotpars* A :class:`SubplotParams` instance, defaults to rc + + *tight* + If *False* use *subplotpars*; if *True* adjust subplot + parameters using :meth:`tight_layout`. Defaults to + rc ``figure.autolayout``. """ Artist.__init__(self) @@ -311,6 +317,7 @@ def __init__(self, subplotpars = SubplotParams() self.subplotpars = subplotpars + self._set_tight(tight) self._axstack = AxesStack() # track all figure axes and current axes self.clf() @@ -329,6 +336,16 @@ def _set_dpi(self, dpi): self.callbacks.process('dpi_changed', self) dpi = property(_get_dpi, _set_dpi) + def _get_tight(self): + return self._tight + def _set_tight(self, tight): + if tight is None: + tight = rcParams['figure.autolayout'] + tight = bool(tight) + self._tight = tight + tight = property(_get_tight, _set_tight, + doc="If *True*, use :meth:`tight_layout`") + def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ Date ticklabels often overlap, so it is useful to rotate them @@ -863,6 +880,13 @@ def draw(self, renderer): if not self.get_visible(): return renderer.open_group('figure') + if self.tight and self.axes: + try: + self.tight_layout(renderer) + except ValueError: + pass + # ValueError can occur when resizing a window. + if self.frameon: self.patch.draw(renderer) # a list of (zorder, func_to_call, list_of_args) diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index ec9c3e7136ca..9f908e22ceda 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -544,7 +544,7 @@ def __call__(self, s): 'figure.dpi' : [ 80, validate_float], # DPI 'figure.facecolor' : [ '0.75', validate_color], # facecolor; scalar gray 'figure.edgecolor' : [ 'w', validate_color], # edgecolor; white - 'figure.autolayout' : [ False, validate_autolayout], + 'figure.autolayout' : [ False, validate_bool], 'figure.subplot.left' : [0.125, ValidateInterval(0, 1, closedmin=True, closedmax=True)], 'figure.subplot.right' : [0.9, ValidateInterval(0, 1, closedmin=True, closedmax=True)], diff --git a/matplotlibrc.template b/matplotlibrc.template index b35b77272721..86238c090173 100644 --- a/matplotlibrc.template +++ b/matplotlibrc.template @@ -301,6 +301,8 @@ text.hinting_factor : 8 # Specifies the amount of softness for hinting in the #figure.dpi : 80 # figure dots per inch #figure.facecolor : 0.75 # figure facecolor; 0.75 is scalar gray #figure.edgecolor : white # figure edgecolor +#figure.autolayout : False # When True, automatically adjust subplot + # parameters to make the plot fit the figure # The figure subplot parameters. All dimensions are a fraction of the # figure width or height From ea0630a2369c12cd7b22cc00d966c05dae686a64 Mon Sep 17 00:00:00 2001 From: Eric Firing Date: Sat, 21 Jul 2012 17:01:11 -1000 Subject: [PATCH 2/2] figure: improved auto tight_layout support 1) Use getter and setter instead of property 2) in tight_layout, don't proceed if an Axes is not a SubplotBase 3) in colorbar, make use_gridspec default to True. --- lib/matplotlib/figure.py | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index df16dc7efc33..e3142526fef1 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -254,7 +254,7 @@ def __init__(self, linewidth = 0.0, # the default linewidth of the frame frameon = True, # whether or not to draw the figure frame subplotpars = None, # default to rc - tight = None, # whether to apply tight_layout + tight_layout = None, # default to rc figure.autolayout ): """ *figsize* @@ -278,7 +278,7 @@ def __init__(self, *subplotpars* A :class:`SubplotParams` instance, defaults to rc - *tight* + *tight_layout* If *False* use *subplotpars*; if *True* adjust subplot parameters using :meth:`tight_layout`. Defaults to rc ``figure.autolayout``. @@ -317,7 +317,7 @@ def __init__(self, subplotpars = SubplotParams() self.subplotpars = subplotpars - self._set_tight(tight) + self.set_tight_layout(tight_layout) self._axstack = AxesStack() # track all figure axes and current axes self.clf() @@ -336,15 +336,23 @@ def _set_dpi(self, dpi): self.callbacks.process('dpi_changed', self) dpi = property(_get_dpi, _set_dpi) - def _get_tight(self): + def get_tight_layout(self): + """ + Return the Boolean flag, True to use :meth`tight_layout` when drawing. + """ return self._tight - def _set_tight(self, tight): + + def set_tight_layout(self, tight): + """ + Set whether :meth:`tight_layout` is used upon drawing. + If None, the rcParams['figure.autolayout'] value will be set. + + ACCEPTS: [True | False | None] + """ if tight is None: tight = rcParams['figure.autolayout'] tight = bool(tight) self._tight = tight - tight = property(_get_tight, _set_tight, - doc="If *True*, use :meth:`tight_layout`") def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): """ @@ -880,7 +888,7 @@ def draw(self, renderer): if not self.get_visible(): return renderer.open_group('figure') - if self.tight and self.axes: + if self.get_tight_layout() and self.axes: try: self.tight_layout(renderer) except ValueError: @@ -1262,7 +1270,7 @@ def colorbar(self, mappable, cax=None, ax=None, **kw): """ if ax is None: ax = self.gca() - use_gridspec = kw.pop("use_gridspec", False) + use_gridspec = kw.pop("use_gridspec", True) if cax is None: if use_gridspec and isinstance(ax, SubplotBase): cax, kw = cbar.make_axes_gridspec(ax, **kw) @@ -1405,6 +1413,12 @@ def tight_layout(self, renderer=None, pad=1.08, h_pad=None, w_pad=None, rect=Non from tight_layout import get_renderer, get_tight_layout_figure + no_go = [ax for ax in self.axes if not isinstance(ax, SubplotBase)] + if no_go: + warnings.Warn("Cannot use tight_layout;" + " all Axes must descend from SubplotBase") + return + if renderer is None: renderer = get_renderer(self)