|
From: <lee...@us...> - 2010-05-19 00:32:25
|
Revision: 8320
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8320&view=rev
Author: leejjoon
Date: 2010-05-19 00:32:18 +0000 (Wed, 19 May 2010)
Log Message:
-----------
merge mpl_toolkits.gridspec into the main tree
Modified Paths:
--------------
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/lib/matplotlib/pyplot.py
Added Paths:
-----------
trunk/matplotlib/lib/matplotlib/gridspec.py
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2010-05-18 17:14:45 UTC (rev 8319)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2010-05-19 00:32:18 UTC (rev 8320)
@@ -8039,6 +8039,8 @@
triplot.__doc__ = mtri.triplot.__doc__
+from gridspec import GridSpec, SubplotSpec
+
class SubplotBase:
"""
Base class for subplots, which are :class:`Axes` instances with
@@ -8062,92 +8064,63 @@
self.figure = fig
- if len(args)==1:
- s = str(args[0])
- if len(s) != 3:
- raise ValueError('Argument to subplot must be a 3 digits long')
- rows, cols, num = map(int, s)
+ if len(args) == 1:
+ if isinstance(args[0], SubplotSpec):
+ self._subplotspec = args[0]
+
+ else:
+ s = str(args[0])
+ if len(s) != 3:
+ raise ValueError('Argument to subplot must be a 3 digits long')
+ rows, cols, num = map(int, s)
+ self._subplotspec = GridSpec(rows, cols)[num-1]
+ # num - 1 for converting from matlab to python indexing
elif len(args)==3:
rows, cols, num = args
+ if isinstance(num, tuple) and len(num) == 2:
+ self._subplotspec = GridSpec(rows, cols)[num[0]-1:num[1]]
+ else:
+ self._subplotspec = GridSpec(rows, cols)[num-1]
+ # num - 1 for converting from matlab to python indexing
else:
raise ValueError( 'Illegal argument to subplot')
- total = rows*cols
- num -= 1 # convert from matlab to python indexing
- # ie num in range(0,total)
- if num >= total:
- raise ValueError( 'Subplot number exceeds total subplots')
- self._rows = rows
- self._cols = cols
- self._num = num
-
self.update_params()
# _axes_class is set in the subplot_class_factory
self._axes_class.__init__(self, fig, self.figbox, **kwargs)
+
+
def get_geometry(self):
'get the subplot geometry, eg 2,2,3'
- return self._rows, self._cols, self._num+1
+ rows, cols, num1, num2 = self.get_subplotspec().get_geometry()
+ return rows, cols, num1+1 # for compatibility
# COVERAGE NOTE: Never used internally or from examples
def change_geometry(self, numrows, numcols, num):
'change subplot geometry, eg. from 1,1,1 to 2,2,3'
- self._rows = numrows
- self._cols = numcols
- self._num = num-1
+ self._subplotspec = GridSpec(numrows, numcols)[num-1]
self.update_params()
self.set_position(self.figbox)
+ def get_subplotspec(self):
+ 'get the SubplotSpec instance associated with the subplot'
+ return self._subplotspec
+
+ def set_subplotspec(self, subplotspec):
+ 'set the SubplotSpec instance associated with the subplot'
+ self._subplotspec = subplotspec
+
def update_params(self):
'update the subplot position from fig.subplotpars'
- rows = self._rows
- cols = self._cols
- num = self._num
+ self.figbox, self.rowNum, self.colNum, self.numRows, self.numCols = \
+ self.get_subplotspec().get_position(self.figure,
+ return_all=True)
- pars = self.figure.subplotpars
- left = pars.left
- right = pars.right
- bottom = pars.bottom
- top = pars.top
- wspace = pars.wspace
- hspace = pars.hspace
- totWidth = right-left
- totHeight = top-bottom
- figH = totHeight/(rows + hspace*(rows-1))
- sepH = hspace*figH
-
- figW = totWidth/(cols + wspace*(cols-1))
- sepW = wspace*figW
-
- rowNum, colNum = divmod(num, cols)
-
- figBottom = top - (rowNum+1)*figH - rowNum*sepH
- figLeft = left + colNum*(figW + sepW)
-
- self.figbox = mtransforms.Bbox.from_bounds(figLeft, figBottom,
- figW, figH)
- self.rowNum = rowNum
- self.colNum = colNum
- self.numRows = rows
- self.numCols = cols
-
- if 0:
- print 'rcn', rows, cols, num
- print 'lbrt', left, bottom, right, top
- print 'self.figBottom', self.figBottom
- print 'self.figLeft', self.figLeft
- print 'self.figW', self.figW
- print 'self.figH', self.figH
- print 'self.rowNum', self.rowNum
- print 'self.colNum', self.colNum
- print 'self.numRows', self.numRows
- print 'self.numCols', self.numCols
-
-
def is_first_col(self):
return self.colNum==0
Added: trunk/matplotlib/lib/matplotlib/gridspec.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/gridspec.py (rev 0)
+++ trunk/matplotlib/lib/matplotlib/gridspec.py 2010-05-19 00:32:18 UTC (rev 8320)
@@ -0,0 +1,298 @@
+"""
+:mod:`~matplotlib.gridspec` is a module which specifies the location
+of the subplot in the figure.
+
+ ``GridSpec``
+ specifies the geometry of the grid that a subplot will be
+ placed. The number of rows and number of columns of the grid
+ need to be set. Optionally, the subplot layout parameters
+ (e.g., left, right, etc.) can be tuned.
+
+ ``SubplotSpec``
+ specifies the location of the subplot in the given *GridSpec*.
+
+
+"""
+
+from __future__ import division
+
+import matplotlib
+rcParams = matplotlib.rcParams
+
+import matplotlib.transforms as mtransforms
+
+
+class GridSpec(object):
+ """
+ A class that specifies the geometry of the grid that a subplot
+ will be placed.
+ """
+ def __init__(self, nrows, ncols,
+ left=None, bottom=None, right=None, top=None,
+ wspace=None, hspace=None):
+ """
+ The number of rows and number of columns of the
+ grid need to be set. Optionally, the subplot layout parameters
+ (e.g., left, right, etc.) can be tuned.
+ """
+ #self.figure = figure
+ self._nrows , self._ncols = nrows, ncols
+ self.left=left
+ self.bottom=bottom
+ self.right=right
+ self.top=top
+ self.wspace=wspace
+ self.hspace=hspace
+
+ def get_geometry(self):
+ 'get the geometry of the grid, eg 2,3'
+ return self._nrows, self._ncols
+
+ _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"]
+
+ def update(self, **kwargs):
+ """
+ Update the current values. If any kwarg is None, default to
+ the current value, if set, otherwise to rc.
+ """
+
+ for k, v in kwargs.items():
+ if k in self._AllowedKeys:
+ setattr(self, k, v)
+ else:
+ raise AttributeError("%s is unknown keyword" % (k,))
+
+
+ from matplotlib import _pylab_helpers
+ from matplotlib.axes import SubplotBase
+ for figmanager in _pylab_helpers.Gcf.figs.values():
+ for ax in figmanager.canvas.figure.axes:
+ # copied from Figure.subplots_adjust
+ if not isinstance(ax, SubplotBase):
+ # Check if sharing a subplots axis
+ if ax._sharex is not None and isinstance(ax._sharex, SubplotBase):
+ ax._sharex.update_params()
+ ax.set_position(ax._sharex.figbox)
+ elif ax._sharey is not None and isinstance(ax._sharey,SubplotBase):
+ ax._sharey.update_params()
+ ax.set_position(ax._sharey.figbox)
+ else:
+ ax.update_params()
+ ax.set_position(ax.figbox)
+
+
+ def get_subplot_params(self, fig=None):
+ """
+ return a dictionary of subplot layout parameters. The default
+ parameters are from rcParams unless a figure attribute is set.
+ """
+ from matplotlib.figure import SubplotParams
+ import copy
+ if fig is None:
+ kw = dict([(k, rcParams["figure.subplot."+k]) \
+ for k in self._AllowedKeys])
+ subplotpars = SubplotParams(**kw)
+ else:
+ subplotpars = copy.copy(fig.subplotpars)
+
+ update_kw = dict([(k, getattr(self, k)) for k in self._AllowedKeys])
+ subplotpars.update(**update_kw)
+
+ return subplotpars
+
+
+ def new_subplotspec(self, loc, rowspan=1, colspan=1):
+ """
+ create and return a SuplotSpec instance.
+ """
+ loc1, loc2 = loc
+ subplotspec = self[loc1:loc1+rowspan, loc2:loc2+colspan]
+ return subplotspec
+
+
+ def __getitem__(self, key):
+ """
+ create and return a SuplotSpec instance.
+ """
+ nrows, ncols = self.get_geometry()
+ total = nrows*ncols
+
+ if isinstance(key, tuple):
+ try:
+ k1, k2 = key
+ except ValueError:
+ raise ValueError("unrecognized subplot spec")
+
+ if isinstance(k1, slice):
+ row1, row2, _ = k1.indices(nrows)
+ else:
+ if k1 < 0:
+ k1 += nrows
+ row1, row2 = k1, k1+1
+
+
+ if isinstance(k2, slice):
+ col1, col2, _ = k2.indices(ncols)
+ else:
+ if k2 < 0:
+ k2 += ncols
+ col1, col2 = k2, k2+1
+
+
+ num1 = row1*nrows + col1
+ num2 = (row2-1)*nrows + (col2-1)
+
+ # single key
+ else:
+ if isinstance(key, slice):
+ num1, num2, _ = key.indices(total)
+ num2 -= 1
+ else:
+ if key < 0:
+ key += total
+ num1, num2 = key, None
+
+
+ return SubplotSpec(self, num1, num2)
+
+
+class GridSpecFromSubplotSpec(GridSpec):
+ """
+ GridSpec whose subplot layout parameters are inherited from the
+ location specified by a given SubplotSpec.
+ """
+ def __init__(self, nrows, ncols,
+ subplot_spec,
+ wspace=None, hspace=None):
+ """
+ The number of rows and number of columns of the grid need to
+ be set. An instance of SubplotSpec is also need to be set from
+ which the layout parameters will be inheirted. The wspace and
+ hspace of the layout can be optionally specified or the
+ default values (from the figure or rcParams) will be used.
+ """
+ self._nrows , self._ncols = nrows, ncols
+ self._wspace=wspace
+ self._hspace=hspace
+
+ self._subplot_spec = subplot_spec
+
+ def get_subplot_params(self, fig=None):
+
+ if fig is None:
+ hspace = rcParams["figure.subplot.hspace"]
+ wspace = rcParams["figure.subplot.wspace"]
+ else:
+ hspace = fig.subplotpars.hspace
+ wspace = fig.subplotpars.wspace
+
+ if self._hspace is not None:
+ hspace = self._hspace
+
+ if self._wspace is not None:
+ wspace = self._wspace
+
+ figbox = self._subplot_spec.get_position(fig, return_all=False)
+
+ left, bottom, right, top = figbox.extents
+
+ from matplotlib.figure import SubplotParams
+ sp = SubplotParams(left=left,
+ right=right,
+ bottom=bottom,
+ top=top,
+ wspace=wspace,
+ hspace=hspace)
+
+ return sp
+
+
+
+
+class SubplotSpec(object):
+ """
+ specifies the location of the subplot in the given *GridSpec*.
+ """
+
+ def __init__(self, gridspec, num1, num2=None):
+ """
+ The subplot will occupy the num1-th cell of the given
+ gridspec. If num2 is provided, the subplot will span between
+ num1-th cell and num2-th cell.
+
+ The index stars from 0.
+ """
+
+ rows, cols = gridspec.get_geometry()
+ total = rows*cols
+
+ self._gridspec = gridspec
+ self.num1 = num1
+ self.num2 = num2
+
+ def get_gridspec(self):
+ return self._gridspec
+
+
+ def get_geometry(self):
+ """
+ get the subplot geometry, eg 2,2,3. Unlike SuplorParams,
+ index is 0-based
+ """
+ rows, cols = self.get_gridspec().get_geometry()
+ return rows, cols, self.num1, self.num2
+
+
+ def get_position(self, fig, return_all=False):
+ """
+ update the subplot position from fig.subplotpars
+ """
+
+ gridspec = self.get_gridspec()
+ rows, cols = gridspec.get_geometry()
+
+ subplot_params = gridspec.get_subplot_params(fig)
+ left = subplot_params.left
+ right = subplot_params.right
+ bottom = subplot_params.bottom
+ top = subplot_params.top
+ wspace = subplot_params.wspace
+ hspace = subplot_params.hspace
+ totWidth = right-left
+ totHeight = top-bottom
+
+ figH = totHeight/(rows + hspace*(rows-1))
+ sepH = hspace*figH
+
+ figW = totWidth/(cols + wspace*(cols-1))
+ sepW = wspace*figW
+
+ rowNum, colNum = divmod(self.num1, cols)
+ figBottom = top - (rowNum+1)*figH - rowNum*sepH
+ figLeft = left + colNum*(figW + sepW)
+ figTop = figBottom + figH
+ figRight = figLeft + figW
+
+ if self.num2 is not None:
+
+ rowNum2, colNum2 = divmod(self.num2, cols)
+ figBottom2 = top - (rowNum2+1)*figH - rowNum2*sepH
+ figLeft2 = left + colNum2*(figW + sepW)
+ figTop2 = figBottom2 + figH
+ figRight2 = figLeft2 + figW
+
+ figBottom = min(figBottom, figBottom2)
+ figLeft = min(figLeft, figLeft2)
+ figTop = max(figTop, figTop2)
+ figRight = max(figRight, figRight2)
+
+ figbox = mtransforms.Bbox.from_extents(figLeft, figBottom,
+ figRight, figTop)
+
+
+ if return_all:
+ return figbox, rowNum, colNum, rows, cols
+ else:
+ return figbox
+
+
Modified: trunk/matplotlib/lib/matplotlib/pyplot.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/pyplot.py 2010-05-18 17:14:45 UTC (rev 8319)
+++ trunk/matplotlib/lib/matplotlib/pyplot.py 2010-05-19 00:32:18 UTC (rev 8320)
@@ -12,7 +12,7 @@
from matplotlib.rcsetup import interactive_bk as _interactive_bk
from matplotlib.artist import getp, get, Artist
from matplotlib.artist import setp as _setp
-from matplotlib.axes import Axes
+from matplotlib.axes import Axes, Subplot
from matplotlib.projections import PolarAxes
from matplotlib import mlab # for csv2rec, detrend_none, window_hanning
from matplotlib.scale import get_scale_docs, get_scale_names
@@ -764,6 +764,44 @@
return fig, axarr.reshape(nrows, ncols)
+from gridspec import GridSpec
+def subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs):
+ """
+
+ It creates a subplot in a grid of *shape*, at location of *loc*,
+ spanning *rowspan*, *colspan* cells in each direction.
+ The index for loc is 0-based. ::
+
+ subplot2grid(shape, loc, rowspan=1, colspan=1)
+
+ is identical to ::
+
+ gridspec=GridSpec(shape[0], shape[2])
+ subplotspec=gridspec.new_subplotspec(loc, rowspan, colspan)
+ subplot(subplotspec)
+
+
+ """
+
+ fig = gcf()
+ s1, s2 = shape
+ subplotspec = GridSpec(s1, s2).new_subplotspec(loc,
+ rowspan=rowspan,
+ colspan=colspan)
+ a = Subplot(fig, subplotspec, **kwargs)
+ fig.add_subplot(a)
+ bbox = a.bbox
+ byebye = []
+ for other in fig.axes:
+ if other==a: continue
+ if bbox.fully_overlaps(other.bbox):
+ byebye.append(other)
+ for ax in byebye: delaxes(ax)
+
+ draw_if_interactive()
+ return a
+
+
def twinx(ax=None):
"""
Make a second axes overlay *ax* (or the current axes if *ax* is
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|