|
From: <lee...@us...> - 2010-12-29 05:22:03
|
Revision: 8850
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8850&view=rev
Author: leejjoon
Date: 2010-12-29 05:21:56 +0000 (Wed, 29 Dec 2010)
Log Message:
-----------
implement axes_divider.HBox and VBox
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_divider.py
trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_grid.py
trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_size.py
Added Paths:
-----------
trunk/matplotlib/examples/axes_grid/demo_axes_hbox_divider.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2010-12-29 03:01:10 UTC (rev 8849)
+++ trunk/matplotlib/CHANGELOG 2010-12-29 05:21:56 UTC (rev 8850)
@@ -1,3 +1,5 @@
+2010-12-29 Implment axes_divider.HBox and VBox. -JJL
+
2010-11-22 Fixed error with Hammer projection. - BVR
2010-11-12 Fixed the placement and angle of axis labels in 3D plots. - BVR
Added: trunk/matplotlib/examples/axes_grid/demo_axes_hbox_divider.py
===================================================================
--- trunk/matplotlib/examples/axes_grid/demo_axes_hbox_divider.py (rev 0)
+++ trunk/matplotlib/examples/axes_grid/demo_axes_hbox_divider.py 2010-12-29 05:21:56 UTC (rev 8850)
@@ -0,0 +1,48 @@
+import numpy as np
+import matplotlib.pyplot as plt
+from mpl_toolkits.axes_grid1.axes_divider import HBoxDivider
+import mpl_toolkits.axes_grid1.axes_size as Size
+
+def make_heights_equal(fig, ax1, ax2, pad):
+ # pad in inches
+
+ h1, v1 = Size.AxesX(ax1), Size.AxesY(ax1)
+ h2, v2 = Size.AxesX(ax2), Size.AxesY(ax2)
+
+ pad_v = Size.Scaled(1)
+ pad_h = Size.Fixed(pad)
+
+ my_divider = HBoxDivider(fig, 111,
+ horizontal=[h1, pad_h, h2],
+ vertical=[v1, pad_v, v2])
+
+
+ ax1.set_axes_locator(my_divider.new_locator(0))
+ ax2.set_axes_locator(my_divider.new_locator(2))
+
+
+if __name__ == "__main__":
+
+ fig1 = plt.figure()
+
+ arr1 = np.arange(20).reshape((4,5))
+ arr2 = np.arange(20).reshape((5,4))
+
+ ax1 = plt.subplot(121)
+ ax2 = plt.subplot(122)
+
+ ax1.imshow(arr1, interpolation="nearest")
+ ax2.imshow(arr2, interpolation="nearest")
+
+ make_heights_equal(fig1, ax1, ax2, pad=0.5)
+
+ for ax in [ax1, ax2]:
+ ax.locator_params(nbins=4)
+
+ # annotate
+ ax3 = plt.axes([0.5, 0.5, 0.001, 0.001], frameon=False)
+ ax3.xaxis.set_visible(False)
+ ax3.yaxis.set_visible(False)
+ ax3.annotate("Location of two axes are adjusted\n so that they have an equal height\n while maintaining their aspect ratios", (0.5, 0.5),
+ xycoords="axes fraction", va="center", ha="center",
+ bbox=dict(fc="w"))
Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_divider.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_divider.py 2010-12-29 03:01:10 UTC (rev 8849)
+++ trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_divider.py 2010-12-29 05:21:56 UTC (rev 8850)
@@ -59,15 +59,30 @@
self._aspect = aspect
self._xrefindex = 0
self._yrefindex = 0
+ self._locator = None
+ def get_horizontal_sizes(self, renderer):
+ return [s.get_size(renderer) for s in self.get_horizontal()]
+ def get_vertical_sizes(self, renderer):
+ return [s.get_size(renderer) for s in self.get_vertical()]
+
+ def get_vsize_hsize(self):
+
+ from axes_size import AddList
+
+ vsize = AddList(self.get_vertical())
+ hsize = AddList(self.get_horizontal())
+
+ return vsize, hsize
+
+
@staticmethod
- def _calc_k(l, total_size, renderer):
+ def _calc_k(l, total_size):
rs_sum, as_sum = 0., 0.
- for s in l:
- _rs, _as = s.get_size(renderer)
+ for _rs, _as in l:
rs_sum += _rs
as_sum += _as
@@ -79,12 +94,13 @@
@staticmethod
- def _calc_offsets(l, k, renderer):
+ def _calc_offsets(l, k):
offsets = [0.]
- for s in l:
- _rs, _as = s.get_size(renderer)
+ #for s in l:
+ for _rs, _as in l:
+ #_rs, _as = s.get_size(renderer)
offsets.append(offsets[-1] + _rs*k + _as)
return offsets
@@ -168,8 +184,19 @@
"return aspect"
return self._aspect
+ def set_locator(self, _locator):
+ self._locator = _locator
- def locate(self, nx, ny, nx1=None, ny1=None, renderer=None):
+ def get_locator(self):
+ return self._locator
+
+ def get_position_runtime(self, ax, renderer):
+ if self._locator is None:
+ return self.get_position()
+ else:
+ return self._locator(ax, renderer).bounds
+
+ def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
"""
:param nx, nx1: Integers specifying the column-position of the
@@ -182,15 +209,17 @@
figW,figH = self._fig.get_size_inches()
- x, y, w, h = self.get_position()
+ x, y, w, h = self.get_position_runtime(axes, renderer)
- k_h = self._calc_k(self._horizontal, figW*w, renderer)
- k_v = self._calc_k(self._vertical, figH*h, renderer)
+ hsizes = self.get_horizontal_sizes(renderer)
+ vsizes = self.get_vertical_sizes(renderer)
+ k_h = self._calc_k(hsizes, figW*w)
+ k_v = self._calc_k(vsizes, figH*h)
if self.get_aspect():
k = min(k_h, k_v)
- ox = self._calc_offsets(self._horizontal, k, renderer)
- oy = self._calc_offsets(self._vertical, k, renderer)
+ ox = self._calc_offsets(hsizes, k)
+ oy = self._calc_offsets(vsizes, k)
ww = (ox[-1] - ox[0])/figW
hh = (oy[-1] - oy[0])/figH
@@ -200,8 +229,8 @@
x0, y0 = pb1_anchored.x0, pb1_anchored.y0
else:
- ox = self._calc_offsets(self._horizontal, k_h, renderer)
- oy = self._calc_offsets(self._vertical, k_v, renderer)
+ ox = self._calc_offsets(hsizes, k_h)
+ oy = self._calc_offsets(vsizes, k_v)
x0, y0 = x, y
@@ -274,6 +303,7 @@
self._ny + _yrefindex,
self._nx1 + _xrefindex,
self._ny1 + _yrefindex,
+ axes,
renderer)
@@ -378,13 +408,20 @@
Divider based on the pre-existing axes.
"""
- def __init__(self, axes):
+ def __init__(self, axes, xref=None, yref=None):
"""
:param axes: axes
"""
self._axes = axes
- self._xref = Size.AxesX(axes)
- self._yref = Size.AxesY(axes)
+ if xref==None:
+ self._xref = Size.AxesX(axes)
+ else:
+ self._xref = xref
+ if yref==None:
+ self._yref = Size.AxesY(axes)
+ else:
+ self._yref = yref
+
Divider.__init__(self, fig=axes.get_figure(), pos=None,
horizontal=[self._xref], vertical=[self._yref],
aspect=None, anchor="C")
@@ -553,203 +590,255 @@
-class LocatableAxesBase:
- def __init__(self, *kl, **kw):
- self._axes_class.__init__(self, *kl, **kw)
- self._locator = None
- self._locator_renderer = None
- def set_axes_locator(self, locator):
- self._locator = locator
+class HBoxDivider(SubplotDivider):
- def get_axes_locator(self):
- return self._locator
- def apply_aspect(self, position=None):
+ def __init__(self, fig, *args, **kwargs):
+ SubplotDivider.__init__(self, fig, *args, **kwargs)
- if self.get_axes_locator() is None:
- self._axes_class.apply_aspect(self, position)
- else:
- pos = self.get_axes_locator()(self, self._locator_renderer)
- self._axes_class.apply_aspect(self, position=pos)
+ @staticmethod
+ def _determine_karray(equivalent_sizes, appended_sizes,
+ max_equivalent_size,
+ total_appended_size):
- def draw(self, renderer=None, inframe=False):
- self._locator_renderer = renderer
+ n = len(equivalent_sizes)
+ import numpy as np
+ A = np.mat(np.zeros((n+1, n+1), dtype="d"))
+ B = np.zeros((n+1), dtype="d")
+ # AxK = B
- self._axes_class.draw(self, renderer, inframe)
+ # populated A
+ for i, (r, a) in enumerate(equivalent_sizes):
+ A[i,i] = r
+ A[i,-1] = -1
+ B[i] = -a
+ A[-1,:-1] = [r for r, a in appended_sizes]
+ B[-1] = total_appended_size - sum([a for rs, a in appended_sizes])
+ karray_H = (A.I*np.mat(B).T).A1
+ karray = karray_H[:-1]
+ H = karray_H[-1]
+ if H > max_equivalent_size:
+ karray = (max_equivalent_size - \
+ np.array([a for r, a in equivalent_sizes])) \
+ / np.array([r for r, a in equivalent_sizes])
+ return karray
-_locatableaxes_classes = {}
-def locatable_axes_factory(axes_class):
- new_class = _locatableaxes_classes.get(axes_class)
- if new_class is None:
- new_class = new.classobj("Locatable%s" % (axes_class.__name__),
- (LocatableAxesBase, axes_class),
- {'_axes_class': axes_class})
- _locatableaxes_classes[axes_class] = new_class
+ @staticmethod
+ def _calc_offsets(appended_sizes, karray):
+ offsets = [0.]
- return new_class
+ #for s in l:
+ for (r, a), k in zip(appended_sizes, karray):
+ offsets.append(offsets[-1] + r*k + a)
-#if hasattr(maxes.Axes, "get_axes_locator"):
-# LocatableAxes = maxes.Axes
-#else:
+ return offsets
-def make_axes_locatable(axes):
- if not hasattr(axes, "set_axes_locator"):
- new_class = locatable_axes_factory(type(axes))
- axes.__class__ = new_class
- divider = AxesDivider(axes)
- locator = divider.new_locator(nx=0, ny=0)
- axes.set_axes_locator(locator)
+ def new_locator(self, nx, nx1=None):
+ """
+ returns a new locator
+ (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for
+ specified cell.
- return divider
+ :param nx, nx1: Integers specifying the column-position of the
+ cell. When nx1 is None, a single nx-th column is
+ specified. Otherwise location of columns spanning between nx
+ to nx1 (but excluding nx1-th column) is specified.
+ :param ny, ny1: same as nx and nx1, but for row positions.
+ """
+ return AxesLocator(self, nx, 0, nx1, None)
-#from matplotlib.axes import Axes
-from mpl_axes import Axes
-LocatableAxes = locatable_axes_factory(Axes)
+ def _locate(self, x, y, w, h,
+ y_equivalent_sizes, x_appended_sizes,
+ figW, figH):
+ """
+ :param nx, nx1: Integers specifying the column-position of the
+ cell. When nx1 is None, a single nx-th column is
+ specified. Otherwise location of columns spanning between nx
+ to nx1 (but excluding nx1-th column) is specified.
-def get_demo_image():
- # prepare image
- delta = 0.5
+ :param ny, ny1: same as nx and nx1, but for row positions.
+ """
- extent = (-3,4,-4,3)
- import numpy as np
- x = np.arange(-3.0, 4.001, delta)
- y = np.arange(-4.0, 3.001, delta)
- X, Y = np.meshgrid(x, y)
- import matplotlib.mlab as mlab
- Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
- Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
- Z = (Z1 - Z2) * 10
- return Z, extent
+ equivalent_sizes = y_equivalent_sizes
+ appended_sizes = x_appended_sizes
-def demo_locatable_axes():
- import matplotlib.pyplot as plt
+ max_equivalent_size = figH*h
+ total_appended_size = figW*w
+ karray = self._determine_karray(equivalent_sizes, appended_sizes,
+ max_equivalent_size,
+ total_appended_size)
- fig1 = plt.figure(1, (6, 6))
- fig1.clf()
+ ox = self._calc_offsets(appended_sizes, karray)
- ## PLOT 1
- # simple image & colorbar
- ax = fig1.add_subplot(2, 2, 1)
+ ww = (ox[-1] - ox[0])/figW
+ ref_h = equivalent_sizes[0]
+ hh = (karray[0]*ref_h[0] + ref_h[1])/figH
+ pb = mtransforms.Bbox.from_bounds(x, y, w, h)
+ pb1 = mtransforms.Bbox.from_bounds(x, y, ww, hh)
+ pb1_anchored = pb1.anchored(self.get_anchor(), pb)
+ x0, y0 = pb1_anchored.x0, pb1_anchored.y0
- Z, extent = get_demo_image()
+ return x0, y0, ox, hh
- im = ax.imshow(Z, extent=extent, interpolation="nearest")
- cb = plt.colorbar(im)
- plt.setp(cb.ax.get_yticklabels(), visible=False)
+ def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
+ """
+ :param nx, nx1: Integers specifying the column-position of the
+ cell. When nx1 is None, a single nx-th column is
+ specified. Otherwise location of columns spanning between nx
+ to nx1 (but excluding nx1-th column) is specified.
- ## PLOT 2
- # image and colorbar whose location is adjusted in the drawing time.
- # a hard way
+ :param ny, ny1: same as nx and nx1, but for row positions.
+ """
- divider = SubplotDivider(fig1, 2, 2, 2, aspect=True)
- # axes for image
- ax = LocatableAxes(fig1, divider.get_position())
+ figW,figH = self._fig.get_size_inches()
+ x, y, w, h = self.get_position_runtime(axes, renderer)
- # axes for coloarbar
- ax_cb = LocatableAxes(fig1, divider.get_position())
+ y_equivalent_sizes = self.get_vertical_sizes(renderer)
+ x_appended_sizes = self.get_horizontal_sizes(renderer)
+ x0, y0, ox, hh = self._locate(x, y, w, h,
+ y_equivalent_sizes, x_appended_sizes,
+ figW, figH)
+ if nx1 is None:
+ nx1=nx+1
- h = [Size.AxesX(ax), # main axes
- Size.Fixed(0.05), # padding, 0.1 inch
- Size.Fixed(0.2), # colorbar, 0.3 inch
- ]
+ x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW
+ y1, h1 = y0, hh
- v = [Size.AxesY(ax)]
+ return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
- divider.set_horizontal(h)
- divider.set_vertical(v)
- ax.set_axes_locator(divider.new_locator(nx=0, ny=0))
- ax_cb.set_axes_locator(divider.new_locator(nx=2, ny=0))
- fig1.add_axes(ax)
- fig1.add_axes(ax_cb)
+class VBoxDivider(HBoxDivider):
+ """
+ The Divider class whose rectangle area is specified as a subplot grometry.
+ """
- ax_cb.yaxis.set_ticks_position("right")
- Z, extent = get_demo_image()
+ def new_locator(self, ny, ny1=None):
+ """
+ returns a new locator
+ (:class:`mpl_toolkits.axes_grid.axes_divider.AxesLocator`) for
+ specified cell.
- im = ax.imshow(Z, extent=extent, interpolation="nearest")
- plt.colorbar(im, cax=ax_cb)
- plt.setp(ax_cb.get_yticklabels(), visible=False)
+ :param nx, nx1: Integers specifying the column-position of the
+ cell. When nx1 is None, a single nx-th column is
+ specified. Otherwise location of columns spanning between nx
+ to nx1 (but excluding nx1-th column) is specified.
- plt.draw()
- #plt.colorbar(im, cax=ax_cb)
+ :param ny, ny1: same as nx and nx1, but for row positions.
+ """
+ return AxesLocator(self, 0, ny, None, ny1)
- ## PLOT 3
- # image and colorbar whose location is adjusted in the drawing time.
- # a easy way
+ def locate(self, nx, ny, nx1=None, ny1=None, axes=None, renderer=None):
+ """
- ax = fig1.add_subplot(2, 2, 3)
- divider = make_axes_locatable(ax)
+ :param nx, nx1: Integers specifying the column-position of the
+ cell. When nx1 is None, a single nx-th column is
+ specified. Otherwise location of columns spanning between nx
+ to nx1 (but excluding nx1-th column) is specified.
- ax_cb = divider.new_horizontal(size="5%", pad=0.05)
- fig1.add_axes(ax_cb)
+ :param ny, ny1: same as nx and nx1, but for row positions.
+ """
- im = ax.imshow(Z, extent=extent, interpolation="nearest")
- plt.colorbar(im, cax=ax_cb)
- plt.setp(ax_cb.get_yticklabels(), visible=False)
+ figW,figH = self._fig.get_size_inches()
+ x, y, w, h = self.get_position_runtime(axes, renderer)
- ## PLOT 4
- # two images side by sied with fixed padding.
+ x_equivalent_sizes = self.get_horizontal_sizes(renderer)
+ y_appended_sizes = self.get_vertical_sizes(renderer)
- ax = fig1.add_subplot(2, 2, 4)
- divider = make_axes_locatable(ax)
+ y0, x0, oy, ww = self._locate(y, x, h, w,
+ x_equivalent_sizes, y_appended_sizes,
+ figH, figW)
+ if ny1 is None:
+ ny1=ny+1
- ax2 = divider.new_horizontal(size="100%", pad=0.05)
- fig1.add_axes(ax2)
+ x1, w1 = x0, ww
+ y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH
- ax.imshow(Z, extent=extent, interpolation="nearest")
- ax2.imshow(Z, extent=extent, interpolation="nearest")
- plt.setp(ax2.get_yticklabels(), visible=False)
- plt.draw()
- plt.show()
+ return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
-def demo_fixed_size_axes():
- import matplotlib.pyplot as plt
- fig2 = plt.figure(2, (6, 6))
- # The first items are for padding and the second items are for the axes.
- # sizes are in inch.
- h = [Size.Fixed(1.0), Size.Fixed(4.5)]
- v = [Size.Fixed(0.7), Size.Fixed(5.)]
- divider = Divider(fig2, (0.0, 0.0, 1., 1.), h, v, aspect=False)
- # the width and height of the rectangle is ignored.
+class LocatableAxesBase:
+ def __init__(self, *kl, **kw):
- ax = LocatableAxes(fig2, divider.get_position())
- ax.set_axes_locator(divider.new_locator(nx=1, ny=1))
+ self._axes_class.__init__(self, *kl, **kw)
- fig2.add_axes(ax)
+ self._locator = None
+ self._locator_renderer = None
- ax.plot([1,2,3])
+ def set_axes_locator(self, locator):
+ self._locator = locator
- plt.draw()
- plt.show()
- #plt.colorbar(im, cax=ax_cb)
+ def get_axes_locator(self):
+ return self._locator
+ def apply_aspect(self, position=None):
+ if self.get_axes_locator() is None:
+ self._axes_class.apply_aspect(self, position)
+ else:
+ pos = self.get_axes_locator()(self, self._locator_renderer)
+ self._axes_class.apply_aspect(self, position=pos)
+ def draw(self, renderer=None, inframe=False):
-if __name__ == "__main__":
- demo_locatable_axes()
- demo_fixed_size_axes()
+ self._locator_renderer = renderer
+
+ self._axes_class.draw(self, renderer, inframe)
+
+
+
+_locatableaxes_classes = {}
+def locatable_axes_factory(axes_class):
+
+ new_class = _locatableaxes_classes.get(axes_class)
+ if new_class is None:
+ new_class = new.classobj("Locatable%s" % (axes_class.__name__),
+ (LocatableAxesBase, axes_class),
+ {'_axes_class': axes_class})
+ _locatableaxes_classes[axes_class] = new_class
+
+ return new_class
+
+#if hasattr(maxes.Axes, "get_axes_locator"):
+# LocatableAxes = maxes.Axes
+#else:
+
+def make_axes_locatable(axes):
+ if not hasattr(axes, "set_axes_locator"):
+ new_class = locatable_axes_factory(type(axes))
+ axes.__class__ = new_class
+
+ divider = AxesDivider(axes)
+ locator = divider.new_locator(nx=0, ny=0)
+ axes.set_axes_locator(locator)
+
+ return divider
+
+
+#from matplotlib.axes import Axes
+from mpl_axes import Axes
+LocatableAxes = locatable_axes_factory(Axes)
+
+
Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_grid.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_grid.py 2010-12-29 03:01:10 UTC (rev 8849)
+++ trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_grid.py 2010-12-29 05:21:56 UTC (rev 8850)
@@ -413,7 +413,25 @@
ax = self.axes_llc
_tick_only(ax, bottom_on=False, left_on=False)
+ def set_axes_locator(self, locator):
+ self._divider.set_locator(locator)
+ def get_axes_locator(self):
+ return self._divider.get_locator()
+
+ def get_vsize_hsize(self):
+
+ return self._divider.get_vsize_hsize()
+# from axes_size import AddList
+
+# vsize = AddList(self._divider.get_vertical())
+# hsize = AddList(self._divider.get_horizontal())
+
+# return vsize, hsize
+
+
+
+
class ImageGrid(Grid):
"""
A class that creates a grid of Axes. In matplotlib, the axes
Modified: trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_size.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_size.py 2010-12-29 03:01:10 UTC (rev 8849)
+++ trunk/matplotlib/lib/mpl_toolkits/axes_grid1/axes_size.py 2010-12-29 05:21:56 UTC (rev 8850)
@@ -16,8 +16,40 @@
class _Base(object):
"Base class"
- pass
+ def __rmul__(self, other):
+ float(other) # just to check if number if given
+ return Fraction(other, self)
+
+ def __add__(self, other):
+ if isinstance(other, _Base):
+ return Add(self, other)
+ else:
+ float(other)
+ other = Fixed(other)
+ return Add(self, other)
+
+
+class Add(_Base):
+ def __init__(self, a, b):
+ self._a = a
+ self._b = b
+
+ def get_size(self, renderer):
+ a_rel_size, a_abs_size = self._a.get_size(renderer)
+ b_rel_size, b_abs_size = self._b.get_size(renderer)
+ return a_rel_size + b_rel_size, a_abs_size + b_abs_size
+
+class AddList(_Base):
+ def __init__(self, add_list):
+ self._list = add_list
+
+ def get_size(self, renderer):
+ sum_rel_size = sum([a.get_size(renderer)[0] for a in self._list])
+ sum_abs_size = sum([a.get_size(renderer)[1] for a in self._list])
+ return sum_rel_size, sum_abs_size
+
+
class Fixed(_Base):
"Simple fixed size with absolute part = *fixed_size* and relative part = 0"
def __init__(self, fixed_size):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|