You can subscribe to this list here.
| 2007 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(115) |
Aug
(120) |
Sep
(137) |
Oct
(170) |
Nov
(461) |
Dec
(263) |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2008 |
Jan
(120) |
Feb
(74) |
Mar
(35) |
Apr
(74) |
May
(245) |
Jun
(356) |
Jul
(240) |
Aug
(115) |
Sep
(78) |
Oct
(225) |
Nov
(98) |
Dec
(271) |
| 2009 |
Jan
(132) |
Feb
(84) |
Mar
(74) |
Apr
(56) |
May
(90) |
Jun
(79) |
Jul
(83) |
Aug
(296) |
Sep
(214) |
Oct
(76) |
Nov
(82) |
Dec
(66) |
| 2010 |
Jan
(46) |
Feb
(58) |
Mar
(51) |
Apr
(77) |
May
(58) |
Jun
(126) |
Jul
(128) |
Aug
(64) |
Sep
(50) |
Oct
(44) |
Nov
(48) |
Dec
(54) |
| 2011 |
Jan
(68) |
Feb
(52) |
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
(1) |
| 2018 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
|
From: <lee...@us...> - 2008-12-19 22:48:15
|
Revision: 6687
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6687&view=rev
Author: leejjoon
Date: 2008-12-19 22:48:11 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
axes_locator in the Axes class
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/axes.py
Added Paths:
-----------
trunk/matplotlib/examples/pylab_examples/axes_divider.py
trunk/matplotlib/examples/pylab_examples/axes_grid.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 21:41:11 UTC (rev 6686)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 22:48:11 UTC (rev 6687)
@@ -1,3 +1,6 @@
+2008-12-19 Add axes_locator attribute in Axes. Two examples are added.
+ - JJL
+
2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
updated to describe chages in keyword parameters.
Issue a warning if old keyword parameters are used. - JJL
Added: trunk/matplotlib/examples/pylab_examples/axes_divider.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/axes_divider.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/axes_divider.py 2008-12-19 22:48:11 UTC (rev 6687)
@@ -0,0 +1,638 @@
+
+import matplotlib.axes as maxes
+import matplotlib.transforms as mtransforms
+
+import matplotlib.cbook as cbook
+
+import new
+
+
+class Size(object):
+
+ @classmethod
+ def from_any(self, size, fraction_ref=None):
+ if cbook.is_numlike(size):
+ return Size.Fixed(size)
+ elif cbook.is_string_like(size):
+ if size[-1] == "%":
+ return Size.Fraction(fraction_ref, float(size[:-1])/100.)
+
+ raise ValueError("")
+
+
+
+ class _Base(object):
+ pass
+
+ class Fixed(_Base):
+ def __init__(self, fixed_size):
+ self._fixed_size = fixed_size
+
+ def get_size(self, renderer):
+ rel_size = 0.
+ abs_size = self._fixed_size
+ return rel_size, abs_size
+
+ class Scalable(_Base):
+ def __init__(self, scalable_size):
+ self._scalable_size = scalable_size
+
+ def get_size(self, renderer):
+ rel_size = self._scalable_size
+ abs_size = 0.
+ return rel_size, abs_size
+
+
+ class AxesX(_Base):
+ def __init__(self, axes, aspect=1.):
+ self._axes = axes
+ self._aspect = aspect
+
+ def get_size(self, renderer):
+ l1, l2 = self._axes.get_xlim()
+ rel_size = abs(l2-l1)*self._aspect
+ abs_size = 0.
+ return rel_size, abs_size
+
+ class AxesY(_Base):
+ def __init__(self, axes, aspect=1.):
+ self._axes = axes
+ self._aspect = aspect
+
+ def get_size(self, renderer):
+ l1, l2 = self._axes.get_ylim()
+ rel_size = abs(l2-l1)*self._aspect
+ abs_size = 0.
+ return rel_size, abs_size
+
+
+ class MaxExtent(_Base):
+ def __init__(self, artist_list, w_or_h):
+ self._artist_list = artist_list
+
+ if w_or_h not in ["width", "height"]:
+ raise ValueError()
+
+ self._w_or_h = w_or_h
+
+ def add_artist(self, a):
+ self._artist_list.append(a)
+
+ def get_size(self, renderer):
+ rel_size = 0.
+ w_list, h_list = [], []
+ for a in self._artist_list:
+ bb = a.get_window_extent(renderer)
+ w_list.append(bb.width)
+ h_list.append(bb.height)
+ dpi = a.get_figure().get_dpi()
+ if self._w_or_h == "width":
+ abs_size = max(w_list)/dpi
+ elif self._w_or_h == "height":
+ abs_size = max(h_list)/dpi
+
+ return rel_size, abs_size
+
+ class Fraction(_Base):
+ def __init__(self, size, fraction):
+ self._size = size
+ self._fraction = fraction
+
+ def get_size(self, renderer):
+ r, a = self._size.get_size(renderer)
+ rel_size = r*self._fraction
+ abs_size = a*self._fraction
+ return rel_size, abs_size
+
+ class Padded(_Base):
+ def __init__(self, size, pad):
+ self._size = size
+ self._pad = pad
+
+ def get_size(self, renderer):
+ r, a = self._size.get_size(renderer)
+ rel_size = r
+ abs_size = a + self._pad
+ return rel_size, abs_size
+
+
+
+class AxesLocator(object):
+ def __init__(self, axes_divider, nx, ny, nx1=None, ny1=None):
+
+ self._axes_divider = axes_divider
+
+ _xrefindex = axes_divider._xrefindex
+ _yrefindex = axes_divider._yrefindex
+
+ self._nx, self._ny = nx - _xrefindex, ny - _yrefindex
+
+ if nx1 is None:
+ nx1 = nx+1
+ if ny1 is None:
+ ny1 = ny+1
+
+ self._nx1 = nx1 - _xrefindex
+ self._ny1 = ny1 - _yrefindex
+
+
+ def __call__(self, axes, renderer):
+
+ _xrefindex = self._axes_divider._xrefindex
+ _yrefindex = self._axes_divider._yrefindex
+
+ return self._axes_divider.locate(self._nx + _xrefindex, self._ny + _yrefindex,
+ self._nx1 + _xrefindex, self._ny1 + _yrefindex,
+ renderer)
+
+
+class Divider(object):
+
+ def __init__(self, fig, pos, horizontal, vertical, aspect=None, anchor="C"):
+ self._fig = fig
+ self._pos = pos
+ self._horizontal = horizontal
+ self._vertical = vertical
+ self._anchor = anchor
+ self._aspect = aspect
+ self._xrefindex = 0
+ self._yrefindex = 0
+
+
+ @staticmethod
+ def _calc_k(l, total_size, renderer):
+
+ rs_sum, as_sum = 0., 0.
+
+ for s in l:
+ rs, as = s.get_size(renderer)
+ rs_sum += rs
+ as_sum += as
+
+ k = (total_size - as_sum) / rs_sum
+ return k
+
+
+ @staticmethod
+ def _calc_offsets(l, k, renderer):
+
+ offsets = [0.]
+
+ for s in l:
+ rs, as = s.get_size(renderer)
+ offsets.append(offsets[-1] + rs*k + as)
+
+ return offsets
+
+
+ def set_position(self, pos):
+ self._pos = pos
+
+ def get_position(self):
+ return self._pos
+
+ def set_anchor(self, anchor):
+ """
+ *anchor*
+
+ ===== ============
+ value description
+ ===== ============
+ 'C' Center
+ 'SW' bottom left
+ 'S' bottom
+ 'SE' bottom right
+ 'E' right
+ 'NE' top right
+ 'N' top
+ 'NW' top left
+ 'W' left
+ ===== ============
+
+ """
+ if anchor in mtransforms.Bbox.coefs.keys() or len(anchor) == 2:
+ self._anchor = anchor
+ else:
+ raise ValueError('argument must be among %s' %
+ ', '.join(mtransforms.BBox.coefs.keys()))
+
+
+ def set_horizontal(self, h):
+ self._horizontal = h
+
+ def get_horizontal(self):
+ return self._horizontal
+
+ def set_vertical(self, v):
+ self._vertical = v
+
+ def get_vertical(self):
+ return self._vertical
+
+
+ def get_anchor(self):
+ return self._anchor
+
+
+ def set_aspect(self, aspect=False):
+ """
+ *aspect* : True or False
+ """
+ self._aspect = aspect
+
+ def get_aspect(self):
+ return self._aspect
+
+
+ def locate(self, nx, ny, nx1=None, ny1=None, renderer=None):
+
+
+ figW,figH = self._fig.get_size_inches()
+ x, y, w, h = self.get_position()
+
+ k_h = self._calc_k(self._horizontal, figW*w, renderer)
+ k_v = self._calc_k(self._vertical, figH*h, renderer)
+
+ 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)
+ else:
+ ox = self._calc_offsets(self._horizontal, k_h, renderer)
+ oy = self._calc_offsets(self._vertical, k_v, renderer)
+
+
+ ww = (ox[-1] - ox[0])/figW
+ hh = (oy[-1] - oy[0])/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)
+
+ if nx1 is None:
+ nx1=nx+1
+ if ny1 is None:
+ ny1=ny+1
+
+ x0, y0 = pb1_anchored.x0, pb1_anchored.y0
+ x1, w1 = x0 + ox[nx]/figW, (ox[nx1] - ox[nx])/figW
+ y1, h1 = y0 + oy[ny]/figH, (oy[ny1] - oy[ny])/figH
+
+ return mtransforms.Bbox.from_bounds(x1, y1, w1, h1)
+
+
+ def new_locator(self, nx, ny, nx1=None, ny1=None):
+ return AxesLocator(self, nx, ny, nx1, ny1)
+
+
+class SubplotDivider(Divider):
+
+ def __init__(self, fig, *args, **kwargs):
+ """
+ *fig* is a :class:`matplotlib.figure.Figure` instance.
+
+ *args* is the tuple (*numRows*, *numCols*, *plotNum*), where
+ the array of subplots in the figure has dimensions *numRows*,
+ *numCols*, and where *plotNum* is the number of the subplot
+ being created. *plotNum* starts at 1 in the upper left
+ corner and increases to the right.
+
+ If *numRows* <= *numCols* <= *plotNum* < 10, *args* can be the
+ decimal integer *numRows* * 100 + *numCols* * 10 + *plotNum*.
+ """
+
+ 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)
+ elif len(args)==3:
+ rows, cols, num = args
+ 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()
+
+ pos = self.figbox.bounds
+ horizontal = kwargs.pop("horizontal", [])
+ vertical = kwargs.pop("vertical", [])
+ aspect = kwargs.pop("aspect", None)
+ anchor = kwargs.pop("anchor", "C")
+
+ if kwargs:
+ raise Exception("")
+
+ Divider.__init__(self, fig, pos, horizontal, vertical,
+ aspect=aspect, anchor=anchor)
+
+
+ def get_position(self):
+ self.update_params()
+ return self.figbox.bounds
+
+
+ def update_params(self):
+ 'update the subplot position from fig.subplotpars'
+
+ rows = self._rows
+ cols = self._cols
+ num = self._num
+
+ 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)
+
+class AxesDivider(Divider):
+
+
+ def __init__(self, axes):
+ self._axes = axes
+ self._xref = Size.AxesX(axes)
+ self._yref = Size.AxesY(axes)
+ Divider.__init__(self, fig=axes.get_figure(), pos=None,
+ horizontal=[self._xref], vertical=[self._yref],
+ aspect=None, anchor="C")
+
+ def new_horizontal(self, size, pad=None, pack_start=False):
+
+ if pad:
+ if not isinstance(pad, Size._Base):
+ pad = Size.from_any(pad,
+ fraction_ref=self._xref)
+ if pack_start:
+ self._horizontal.insert(0, pad)
+ self._xrefindex += 1
+ else:
+ self._horizontal.append(pad)
+
+ if not isinstance(size, Size._Base):
+ size = Size.from_any(size,
+ fraction_ref=self._xref)
+
+ if pack_start:
+ self._horizontal.insert(0, pad)
+ self._xrefindex += 1
+ locator = self.new_locator(nx=0, ny=0)
+ else:
+ self._horizontal.append(size)
+ locator = self.new_locator(nx=len(self._horizontal)-1, ny=0)
+
+ ax = LocatableAxes(self._axes.get_figure(),
+ self._axes.get_position(original=True))
+ locator = self.new_locator(nx=len(self._horizontal)-1, ny=0)
+ ax.set_axes_locator(locator)
+
+ return ax
+
+ def new_vertical(self, size, pad=None, pack_start=False):
+
+ if pad:
+ if not isinstance(pad, Size._Base):
+ pad = Size.from_any(pad,
+ fraction_ref=self._yref)
+ if pack_start:
+ self._vertical.insert(0, pad)
+ self._yrefindex += 1
+ else:
+ self._vertical.append(pad)
+
+ if not isinstance(size, Size._Base):
+ size = Size.from_any(size,
+ fraction_ref=self._yref)
+
+ if pack_start:
+ self._vertical.insert(0, pad)
+ self._yrefindex += 1
+ locator = self.new_locator(nx=0, ny=0)
+ else:
+ self._vertical.append(size)
+ locator = self.new_locator(nx=0, ny=len(self._vertical)-1)
+
+ ax = LocatableAxes(self._axes.get_figure(),
+ self._axes.get_position(original=True))
+ ax.set_axes_locator(locator)
+
+ return ax
+
+
+ def get_aspect(self):
+ if self._aspect is None:
+ aspect = self._axes.get_aspect()
+ if aspect == "auto":
+ return False
+ else:
+ return True
+ else:
+ return self._aspect
+
+ def get_position(self):
+ if self._pos is None:
+ bbox = self._axes.get_position(original=True)
+ return bbox.bounds
+ else:
+ return self._pos
+
+ def get_anchor(self):
+ if self._anchor is None:
+ return self._axes.get_anchor()
+ else:
+ return self._anchor
+
+
+
+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
+
+ 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_apsect(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):
+
+ 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:
+ LocatableAxes = locatable_axes_factory(maxes.Axes)
+
+
+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
+
+
+def get_demo_image():
+ # prepare image
+ delta = 0.5
+
+ 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
+
+def demo_locatable_axes():
+ import matplotlib.pyplot as plt
+
+ fig1 = plt.figure(1, (6, 6))
+ fig1.clf()
+
+ ## PLOT 1
+ # simple image & colorbar
+ ax = fig1.add_subplot(2, 2, 1)
+
+ Z, extent = get_demo_image()
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ cb = plt.colorbar(im)
+ plt.setp(cb.ax.get_yticklabels(), visible=False)
+
+
+ ## PLOT 2
+ # image and colorbar whose location is adjusted in the drawing time.
+ # a hard way
+
+ divider = SubplotDivider(fig1, 2, 2, 2, aspect=True)
+
+ # axes for image
+ ax = LocatableAxes(fig1, divider.get_position())
+
+ # axes for coloarbar
+ ax_cb = LocatableAxes(fig1, divider.get_position())
+
+ h = [Size.AxesX(ax), # main axes
+ Size.Fixed(0.05), # padding, 0.1 inch
+ Size.Fixed(0.2), # colorbar, 0.3 inch
+ ]
+
+ v = [Size.AxesY(ax)]
+
+ 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)
+
+ ax_cb.yaxis.set_ticks_position("right")
+
+ Z, extent = get_demo_image()
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax=ax_cb)
+ plt.setp(ax_cb.get_yticklabels(), visible=False)
+
+ plt.draw()
+ #plt.colorbar(im, cax=ax_cb)
+
+
+ ## PLOT 3
+ # image and colorbar whose location is adjusted in the drawing time.
+ # a easy way
+
+ ax = fig1.add_subplot(2, 2, 3)
+ divider = make_axes_locatable(ax)
+
+ ax_cb = divider.new_horizontal(size="5%", pad=0.05)
+ fig1.add_axes(ax_cb)
+
+ im = ax.imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax=ax_cb)
+ plt.setp(ax_cb.get_yticklabels(), visible=False)
+
+
+ ## PLOT 4
+ # two images side by sied with fixed padding.
+
+ ax = fig1.add_subplot(2, 2, 4)
+ divider = make_axes_locatable(ax)
+
+ ax2 = divider.new_horizontal(size="100%", pad=0.05)
+ fig1.add_axes(ax2)
+
+ ax.imshow(Z, extent=extent, interpolation="nearest")
+ ax2.imshow(Z, extent=extent, interpolation="nearest")
+ plt.setp(ax2.get_yticklabels(), visible=False)
+ plt.draw()
+
+if __name__ == "__main__":
+ demo_locatable_axes()
Added: trunk/matplotlib/examples/pylab_examples/axes_grid.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/axes_grid.py (rev 0)
+++ trunk/matplotlib/examples/pylab_examples/axes_grid.py 2008-12-19 22:48:11 UTC (rev 6687)
@@ -0,0 +1,343 @@
+import matplotlib.cbook as cbook
+
+import matplotlib.pyplot as plt
+
+from axes_divider import Size, SubplotDivider, LocatableAxes, Divider, get_demo_image
+
+class AxesGrid(object):
+
+ def __init__(self, fig, rect,
+ nrows_ncols,
+ ngrids = None,
+ direction="row",
+ axes_pad = 0.02,
+ axes_class=None,
+ add_all=True,
+ share_all=False,
+ aspect=True,
+ label_mode="L",
+ colorbar_mode=None,
+ colorbar_location="right",
+ colorbar_pad=None,
+ colorbar_size="5%",
+ ):
+
+ self._nrows, self._ncols = nrows_ncols
+
+ if ngrids is None:
+ ngrids = self._nrows * self._ncols
+ else:
+ if (ngrids > self._nrows * self._ncols) or (ngrids <= 0):
+ raise Exception("")
+
+ self.ngrids = ngrids
+
+ self._axes_pad = axes_pad
+
+ self._colorbar_mode = colorbar_mode
+ self._colorbar_location = colorbar_location
+ if colorbar_pad is None:
+ self._colorbar_pad = axes_pad
+ else:
+ self._colorbar_pad = colorbar_pad
+
+ self._colorbar_size = colorbar_size
+
+ if direction not in ["column", "row"]:
+ raise Exception("")
+
+ self._direction = direction
+
+
+ if axes_class is None:
+ axes_class = LocatableAxes
+
+
+ self.axes_all = []
+ self.axes_column = [[] for i in range(self._ncols)]
+ self.axes_row = [[] for i in range(self._nrows)]
+
+ self.cbar_axes = []
+
+ h = []
+ v = []
+ if cbook.is_string_like(rect) or cbook.is_numlike(rect):
+ self._divider = SubplotDivider(fig, rect, horizontal=h, vertical=v,
+ aspect=aspect)
+ elif len(rect) == 3:
+ kw = dict(horizontal=h, vertical=v, aspect=aspect)
+ self._divider = SubplotDivider(fig, *rect, **kw)
+ elif len(rect) == 4:
+ self._divider = Divider(fig, rect, horizontal=h, vertical=v,
+ aspect=aspect)
+ else:
+ raise Exception("")
+
+
+ rect = self._divider.get_position()
+
+ # reference axes
+ self._column_refax = [None for i in range(self._ncols)]
+ self._row_refax = [None for i in range(self._nrows)]
+ self._refax = None
+
+ for i in range(self.ngrids):
+
+ col, row = self.get_col_row(i)
+
+ if share_all:
+ sharex = self._refax
+ sharey = self._refax
+ else:
+ sharex = self._column_refax[col]
+ sharey = self._row_refax[row]
+
+ ax = axes_class(fig, rect, sharex=sharex, sharey=sharey)
+
+ if share_all:
+ if self._refax is None:
+ self._refax = ax
+ else:
+ if sharex is None:
+ self._column_refax[col] = ax
+ if sharey is None:
+ self._row_refax[row] = ax
+
+ self.axes_all.append(ax)
+ self.axes_column[col].append(ax)
+ self.axes_row[row].append(ax)
+
+ cax = axes_class(fig, rect)
+ self.cbar_axes.append(cax)
+
+ self.axes_llc = self.axes_column[0][-1]
+
+ self._update_locators()
+
+ if add_all:
+ for ax in self.axes_all+self.cbar_axes:
+ fig.add_axes(ax)
+
+ self.set_label_mode(label_mode)
+
+
+ def _update_locators(self):
+
+ h = []
+
+ h_ax_pos = []
+ h_cb_pos = []
+ for ax in self._column_refax:
+ if h: h.append(Size.Fixed(self._axes_pad))
+
+ h_ax_pos.append(len(h))
+
+ if ax:
+ sz = Size.AxesX(ax)
+ else:
+ sz = Size.AxesX(self.axes_llc)
+ h.append(sz)
+
+ if self._colorbar_mode == "each" and self._colorbar_location == "right":
+ h.append(Size.from_any(self._colorbar_pad, sz))
+ h_cb_pos.append(len(h))
+ h.append(Size.from_any(self._colorbar_size, sz))
+
+
+ v = []
+
+ v_ax_pos = []
+ v_cb_pos = []
+ for ax in self._row_refax[::-1]:
+ if v: v.append(Size.Fixed(self._axes_pad))
+ v_ax_pos.append(len(v))
+ if ax:
+ sz = Size.AxesY(ax)
+ else:
+ sz = Size.AxesY(self.axes_llc)
+ v.append(sz)
+
+
+ if self._colorbar_mode == "each" and self._colorbar_location == "top":
+ v.append(Size.from_any(self._colorbar_pad, sz))
+ v_cb_pos.append(len(v))
+ v.append(Size.from_any(self._colorbar_size, sz))
+
+
+ for i in range(self.ngrids):
+ col, row = self.get_col_row(i)
+ #locator = self._divider.new_locator(nx=4*col, ny=2*(self._nrows - row - 1))
+ locator = self._divider.new_locator(nx=h_ax_pos[col],
+ ny=v_ax_pos[self._nrows -1 - row])
+ self.axes_all[i].set_axes_locator(locator)
+
+ if self._colorbar_mode == "each":
+ if self._colorbar_location == "right":
+ locator = self._divider.new_locator(nx=h_cb_pos[col],
+ ny=v_ax_pos[self._nrows -1 - row])
+ elif self._colorbar_location == "top":
+ locator = self._divider.new_locator(nx=h_ax_pos[col],
+ ny=v_cb_pos[self._nrows -1 - row])
+ self.cbar_axes[i].set_axes_locator(locator)
+
+
+ if self._colorbar_mode == "single":
+ if self._colorbar_location == "right":
+ sz = Size.Fraction(Size.AxesX(self.axes_llc), self._nrows)
+ h.append(Size.from_any(self._colorbar_pad, sz))
+ h.append(Size.from_any(self._colorbar_size, sz))
+ locator = self._divider.new_locator(nx=-2, ny=0, ny1=-1)
+ elif self._colorbar_location == "top":
+ sz = Size.Fraction(Size.AxesY(self.axes_llc), self._ncols)
+ v.append(Size.from_any(self._colorbar_pad, sz))
+ v.append(Size.from_any(self._colorbar_size, sz))
+ locator = self._divider.new_locator(nx=0, nx1=-1, ny=-2)
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(False)
+ self.cbar_axes[0].set_axes_locator(locator)
+ self.cbar_axes[0].set_visible(True)
+ elif self._colorbar_mode == "each":
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(True)
+ else:
+ for i in range(self.ngrids):
+ self.cbar_axes[i].set_visible(False)
+
+ self._divider.set_horizontal(h)
+ self._divider.set_vertical(v)
+
+
+
+ def get_col_row(self, n):
+ if self._direction == "column":
+ col, row = divmod(n, self._nrows)
+ else:
+ row, col = divmod(n, self._ncols)
+
+ return col, row
+
+
+ def __getitem__(self, i):
+ return self.axes_all[i]
+
+
+ def get_geometry(self):
+ return self._nrows, self._ncols
+
+ def set_axes_pad(self, axes_pad):
+ self._axes_pad = axes_pad
+
+ def get_axes_pad(self):
+ return self._axes_pad
+
+ def set_aspect(self, aspect):
+ self._divider.set_aspect(aspect)
+
+ def get_aspect(self):
+ return self._divider.get_aspect()
+
+ def set_label_mode(self, mode):
+ if mode == "all":
+ for ax in self.axes_all:
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ elif mode == "L":
+ for ax in self.axes_column[0][:-1]:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ ax = self.axes_column[0][-1]
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+ for col in self.axes_column[1:]:
+ for ax in col[:-1]:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ ax = col[-1]
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ elif mode == "1":
+ for ax in self.axes_all:
+ [l.set_visible(False) for l in ax.get_xticklabels()]
+ [l.set_visible(False) for l in ax.get_yticklabels()]
+ ax = self.axes_llc
+ [l.set_visible(True) for l in ax.get_xticklabels()]
+ [l.set_visible(True) for l in ax.get_yticklabels()]
+
+
+
+if __name__ == "__main__":
+ F = plt.figure(1, (9, 3.5))
+ F.clf()
+
+ F.subplots_adjust(left=0.05, right=0.98)
+
+ grid = AxesGrid(F, 131, # similar to subplot(111)
+ nrows_ncols = (2, 2),
+ direction="row",
+ axes_pad = 0.05,
+ add_all=True,
+ label_mode = "1",
+ )
+
+ Z, extent = get_demo_image()
+ plt.ioff()
+ for i in range(4):
+ im = grid[i].imshow(Z, extent=extent, interpolation="nearest")
+
+ # This only affects axes in first column and second row as share_all = False.
+ grid.axes_llc.set_xticks([-2, 0, 2])
+ grid.axes_llc.set_yticks([-2, 0, 2])
+ plt.ion()
+
+
+ grid = AxesGrid(F, 132, # similar to subplot(111)
+ nrows_ncols = (2, 2),
+ direction="row",
+ axes_pad = 0.0,
+ add_all=True,
+ share_all=True,
+ label_mode = "1",
+ colorbar_mode="single",
+ )
+
+ Z, extent = get_demo_image()
+ plt.ioff()
+ for i in range(4):
+ im = grid[i].imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax = grid.cbar_axes[0])
+ plt.setp(grid.cbar_axes[0].get_yticklabels(), visible=False)
+
+ # This affects all axes as share_all = True.
+ grid.axes_llc.set_xticks([-2, 0, 2])
+ grid.axes_llc.set_yticks([-2, 0, 2])
+
+ plt.ion()
+
+
+
+ grid = AxesGrid(F, 133, # similar to subplot(122)
+ nrows_ncols = (2, 2),
+ direction="row",
+ axes_pad = 0.1,
+ add_all=True,
+ label_mode = "1",
+ share_all = True,
+ colorbar_location="top",
+ colorbar_mode="each",
+ colorbar_size="7%",
+ colorbar_pad="2%",
+ )
+ plt.ioff()
+ for i in range(4):
+ im = grid[i].imshow(Z, extent=extent, interpolation="nearest")
+ plt.colorbar(im, cax = grid.cbar_axes[i],
+ orientation="horizontal")
+ grid.cbar_axes[i].xaxis.set_ticks_position("top")
+ plt.setp(grid.cbar_axes[i].get_xticklabels(), visible=False)
+
+ # This affects all axes as share_all = True.
+ grid.axes_llc.set_xticks([-2, 0, 2])
+ grid.axes_llc.set_yticks([-2, 0, 2])
+
+ plt.ion()
+ plt.draw()
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 21:41:11 UTC (rev 6686)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 22:48:11 UTC (rev 6687)
@@ -545,6 +545,8 @@
self.set_navigate(True)
self.set_navigate_mode(None)
+ self._axes_locator = None
+
if len(kwargs): martist.setp(self, **kwargs)
if self.xaxis is not None:
@@ -793,6 +795,21 @@
pos = self.get_position(original=True)
self.set_position(pos, which='active')
+ def set_axes_locator(self, locator):
+ """
+ set axes_locator
+
+ ACCEPT : a callable object which takes an axes instance and renderer and
+ returns a bbox.
+ """
+ self._axes_locator = locator
+
+ def get_axes_locator(self):
+ """
+ return axes_locator
+ """
+ return self._axes_locator
+
def _set_artist_props(self, a):
'set the boilerplate props for artists added to axes'
a.set_figure(self.figure)
@@ -1531,7 +1548,12 @@
if not self.get_visible(): return
renderer.open_group('axes')
- self.apply_aspect()
+ locator = self.get_axes_locator()
+ if locator:
+ pos = locator(self, renderer)
+ self.apply_aspect(pos)
+ else:
+ self.apply_aspect()
# the patch draws the background rectangle -- the frame below
# will draw the edges
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <lee...@us...> - 2008-12-19 22:03:12
|
Revision: 6686
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6686&view=rev
Author: leejjoon
Date: 2008-12-19 21:41:11 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
Merged revisions 6685 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6685 | leejjoon | 2008-12-19 16:24:32 -0500 (Fri, 19 Dec 2008) | 1 line
update legend-related document
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/api/api_changes.rst
trunk/matplotlib/lib/matplotlib/__init__.py
trunk/matplotlib/lib/matplotlib/axes.py
trunk/matplotlib/lib/matplotlib/legend.py
trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
trunk/matplotlib/lib/matplotlib/rcsetup.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6681
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6685
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 21:41:11 UTC (rev 6686)
@@ -1,3 +1,7 @@
+2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
+ updated to describe chages in keyword parameters.
+ Issue a warning if old keyword parameters are used. - JJL
+
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
Modified: trunk/matplotlib/doc/api/api_changes.rst
===================================================================
--- trunk/matplotlib/doc/api/api_changes.rst 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/doc/api/api_changes.rst 2008-12-19 21:41:11 UTC (rev 6686)
@@ -15,6 +15,22 @@
Changes for 0.98.x
==================
+* Following keyword parameters for :class:`matplotlib.label.Label` are now
+ deprecated and new set of parameters are introduced. The new parameters
+ are given as a fraction of the font-size. Also, *scatteryoffsets*,
+ *fancybox* and *columnspacing* are added as keyword parameters.
+
+ ================ ================
+ Deprecated New
+ ================ ================
+ pad borderpad
+ labelsep labelspacing
+ handlelen handlelength
+ handlestextsep handletextpad
+ axespad borderaxespad
+ ================ ================
+
+
* Removed the configobj and experiemtnal traits rc support
* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`,
Modified: trunk/matplotlib/lib/matplotlib/__init__.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/__init__.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/__init__.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -582,7 +582,15 @@
'tick.size' : 'tick.major.size',
}
+_deprecated_ignore_map = {
+ 'legend.pad' : 'legend.borderpad',
+ 'legend.labelsep' : 'legend.labelspacing',
+ 'legend.handlelen' : 'legend.handlelength',
+ 'legend.handletextsep' : 'legend.handletextpad',
+ 'legend.axespad' : 'legend.borderaxespad',
+ }
+
class RcParams(dict):
"""
@@ -602,6 +610,10 @@
warnings.warn('%s is deprecated in matplotlibrc. Use %s \
instead.'% (key, alt))
key = alt
+ elif key in _deprecated_ignore_map:
+ alt = _deprecated_ignore_map[key]
+ warnings.warn('%s is deprecated. Use %s instead.'% (key, alt))
+ return
cval = self.validate[key](val)
dict.__setitem__(self, key, cval)
except KeyError:
@@ -665,6 +677,9 @@
except Exception, msg:
warnings.warn('Bad val "%s" on line #%d\n\t"%s"\n\tin file \
"%s"\n\t%s' % (val, cnt, line, fname, msg))
+ elif key in _deprecated_ignore_map:
+ warnings.warn('%s is deprecated. Update your matplotlibrc to use %s instead.'% (key, _deprecated_ignore_map[key]))
+
else:
print >> sys.stderr, """
Bad key "%s" on line %d in
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/axes.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -3740,10 +3740,6 @@
A :class:`matplotlib.font_manager.FontProperties`
instance, or *None* to use rc settings.
- *pad*: [ None | scalar ]
- The fractional whitespace inside the legend border, between 0 and 1.
- If *None*, use rc settings.
-
*markerscale*: [ None | scalar ]
The relative size of legend markers vs. original. If *None*, use rc
settings.
@@ -3751,21 +3747,21 @@
*shadow*: [ None | False | True ]
If *True*, draw a shadow behind legend. If *None*, use rc settings.
- *labelsep*: [ None | scalar ]
- The vertical space between the legend entries. If *None*, use rc
- settings.
+ Padding and spacing between various elements use following keywords
+ parameters. The dimensions of these values are given as a fraction
+ of the fontsize. Values from rcParams will be used if None.
- *handlelen*: [ None | scalar ]
- The length of the legend lines. If *None*, use rc settings.
+ ================ ==================================================================
+ Keyword Description
+ ================ ==================================================================
+ borderpad the fractional whitespace inside the legend border
+ labelspacing the vertical space between the legend entries
+ handlelength the length of the legend handles
+ handletextpad the pad between the legend handle and text
+ borderaxespad the pad between the axes and legend border
+ columnspacing the spacing between columns
+ ================ ==================================================================
- *handletextsep*: [ None | scalar ]
- The space between the legend line and legend text. If *None*, use rc
- settings.
-
- *axespad*: [ None | scalar ]
- The border between the axes and legend edge. If *None*, use rc
- settings.
-
**Example:**
.. plot:: mpl_examples/api/legend_demo.py
Modified: trunk/matplotlib/lib/matplotlib/legend.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/legend.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/legend.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -98,7 +98,7 @@
handletextsep = None, # deprecated; use handletextpad
axespad = None, # deprecated; use borderaxespad
- # spacing & pad defined as a fractionof the font-size
+ # spacing & pad defined as a fraction of the font-size
borderpad = None, # the whitespace inside the legend border
labelspacing=None, #the vertical space between the legend entries
handlelength=None, # the length of the legend handles
Modified: trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template
===================================================================
--- trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 21:41:11 UTC (rev 6686)
@@ -233,19 +233,11 @@
origin = 'upper'
[legend]
- # a float
- axespad = 0.02
# a float or 'xx-small' or 'x-small' or 'small' or 'medium' or 'large' or
# 'x-large' or 'xx-large'
fontsize = 'medium'
- # a float
- handlelen = 0.050000000000000003
- # a float
- handletextsep = 0.02
# a boolean
isaxes = True
- # a float
- labelsep = 0.01
# 'best' or 'upper right' or 'upper left' or 'lower left' or 'lower right'
# or 'right' or 'center left' or 'center right' or 'lower center' or
# 'upper center' or 'center'
@@ -254,11 +246,22 @@
markerscale = 1.0
# an integer
numpoints = 3
- # a float
- pad = 0.20000000000000001
# a boolean
shadow = False
+ # float
+ borderpad = 0.4
+ # float
+ labelspacing = 0.5
+ # float
+ handlelength = 2.
+ # float
+ handletextpad = 0.8
+ # float
+ borderaxespad = 0.5
+ # float
+ columnspacing = 2.
+
[lines]
# a boolean
antialiased = True
Modified: trunk/matplotlib/lib/matplotlib/rcsetup.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-19 21:24:32 UTC (rev 6685)
+++ trunk/matplotlib/lib/matplotlib/rcsetup.py 2008-12-19 21:41:11 UTC (rev 6686)
@@ -432,18 +432,12 @@
'legend.isaxes' : [True,validate_bool], # this option is internally ignored - it never served any useful purpose
'legend.numpoints' : [2, validate_int], # the number of points in the legend line
'legend.fontsize' : ['large', validate_fontsize],
- 'legend.pad' : [0, validate_float], # was 0.2, deprecated; the fractional whitespace inside the legend border
- 'legend.borderpad' : [0.4, validate_float], # units are fontsize
'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original
-
- # the following dimensions are in axes coords
- 'legend.labelsep' : [0.010, validate_float], # the vertical space between the legend entries
- 'legend.handlelen' : [0.05, validate_float], # the length of the legend lines
- 'legend.handletextsep' : [0.02, validate_float], # the space between the legend line and legend text
- 'legend.axespad' : [0.02, validate_float], # the border between the axes and legend edge
'legend.shadow' : [False, validate_bool],
+ # the following dimensions are in fraction of the font size
+ 'legend.borderpad' : [0.4, validate_float], # units are fontsize
'legend.labelspacing' : [0.5, validate_float], # the vertical space between the legend entries
'legend.handlelength' : [2., validate_float], # the length of the legend lines
'legend.handletextpad' : [.8, validate_float], # the space between the legend line and legend text
@@ -453,11 +447,6 @@
'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original
- # the following dimensions are in axes coords
- 'legend.labelsep' : [0.010, validate_float], # the vertical space between the legend entries
- 'legend.handlelen' : [0.05, validate_float], # the length of the legend lines
- 'legend.handletextsep' : [0.02, validate_float], # the space between the legend line and legend text
- 'legend.axespad' : [0.5, validate_float], # the border between the axes and legend edge
'legend.shadow' : [False, validate_bool],
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <lee...@us...> - 2008-12-19 21:24:41
|
Revision: 6685
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6685&view=rev
Author: leejjoon
Date: 2008-12-19 21:24:32 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
update legend-related document
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
branches/v0_98_5_maint/doc/api/api_changes.rst
branches/v0_98_5_maint/lib/matplotlib/__init__.py
branches/v0_98_5_maint/lib/matplotlib/axes.py
branches/v0_98_5_maint/lib/matplotlib/legend.py
branches/v0_98_5_maint/lib/matplotlib/mpl-data/matplotlib.conf.template
branches/v0_98_5_maint/lib/matplotlib/rcsetup.py
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-19 21:24:32 UTC (rev 6685)
@@ -1,3 +1,6 @@
+2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also
+ updated to describe chages in keyword parameters.
+ Issue a warning if old keyword parameters are used. - JJL
=======================================================================
Re-Released 0.98.5.2 at r6679
Modified: branches/v0_98_5_maint/doc/api/api_changes.rst
===================================================================
--- branches/v0_98_5_maint/doc/api/api_changes.rst 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/doc/api/api_changes.rst 2008-12-19 21:24:32 UTC (rev 6685)
@@ -8,6 +8,22 @@
Changes for 0.98.x
==================
+* Following keyword parameters for :class:`matplotlib.label.Label` are now
+ deprecated and new set of parameters are introduced. The new parameters
+ are given as a fraction of the font-size. Also, *scatteryoffsets*,
+ *fancybox* and *columnspacing* are added as keyword parameters.
+
+ ================ ================
+ Deprecated New
+ ================ ================
+ pad borderpad
+ labelsep labelspacing
+ handlelen handlelength
+ handlestextsep handletextpad
+ axespad borderaxespad
+ ================ ================
+
+
* Removed the configobj and experiemtnal traits rc support
* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`,
Modified: branches/v0_98_5_maint/lib/matplotlib/__init__.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/__init__.py 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/lib/matplotlib/__init__.py 2008-12-19 21:24:32 UTC (rev 6685)
@@ -582,7 +582,15 @@
'tick.size' : 'tick.major.size',
}
+_deprecated_ignore_map = {
+ 'legend.pad' : 'legend.borderpad',
+ 'legend.labelsep' : 'legend.labelspacing',
+ 'legend.handlelen' : 'legend.handlelength',
+ 'legend.handletextsep' : 'legend.handletextpad',
+ 'legend.axespad' : 'legend.borderaxespad',
+ }
+
class RcParams(dict):
"""
@@ -602,6 +610,10 @@
warnings.warn('%s is deprecated in matplotlibrc. Use %s \
instead.'% (key, alt))
key = alt
+ elif key in _deprecated_ignore_map:
+ alt = _deprecated_ignore_map[key]
+ warnings.warn('%s is deprecated. Use %s instead.'% (key, alt))
+ return
cval = self.validate[key](val)
dict.__setitem__(self, key, cval)
except KeyError:
@@ -665,6 +677,9 @@
except Exception, msg:
warnings.warn('Bad val "%s" on line #%d\n\t"%s"\n\tin file \
"%s"\n\t%s' % (val, cnt, line, fname, msg))
+ elif key in _deprecated_ignore_map:
+ warnings.warn('%s is deprecated. Update your matplotlibrc to use %s instead.'% (key, _deprecated_ignore_map[key]))
+
else:
print >> sys.stderr, """
Bad key "%s" on line %d in
Modified: branches/v0_98_5_maint/lib/matplotlib/axes.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/axes.py 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/lib/matplotlib/axes.py 2008-12-19 21:24:32 UTC (rev 6685)
@@ -3728,10 +3728,6 @@
A :class:`matplotlib.font_manager.FontProperties`
instance, or *None* to use rc settings.
- *pad*: [ None | scalar ]
- The fractional whitespace inside the legend border, between 0 and 1.
- If *None*, use rc settings.
-
*markerscale*: [ None | scalar ]
The relative size of legend markers vs. original. If *None*, use rc
settings.
@@ -3739,21 +3735,21 @@
*shadow*: [ None | False | True ]
If *True*, draw a shadow behind legend. If *None*, use rc settings.
- *labelsep*: [ None | scalar ]
- The vertical space between the legend entries. If *None*, use rc
- settings.
+ Padding and spacing between various elements use following keywords
+ parameters. The dimensions of these values are given as a fraction
+ of the fontsize. Values from rcParams will be used if None.
- *handlelen*: [ None | scalar ]
- The length of the legend lines. If *None*, use rc settings.
+ ================ ==================================================================
+ Keyword Description
+ ================ ==================================================================
+ borderpad the fractional whitespace inside the legend border
+ labelspacing the vertical space between the legend entries
+ handlelength the length of the legend handles
+ handletextpad the pad between the legend handle and text
+ borderaxespad the pad between the axes and legend border
+ columnspacing the spacing between columns
+ ================ ==================================================================
- *handletextsep*: [ None | scalar ]
- The space between the legend line and legend text. If *None*, use rc
- settings.
-
- *axespad*: [ None | scalar ]
- The border between the axes and legend edge. If *None*, use rc
- settings.
-
**Example:**
.. plot:: mpl_examples/api/legend_demo.py
Modified: branches/v0_98_5_maint/lib/matplotlib/legend.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/legend.py 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/lib/matplotlib/legend.py 2008-12-19 21:24:32 UTC (rev 6685)
@@ -98,7 +98,7 @@
handletextsep = None, # deprecated; use handletextpad
axespad = None, # deprecated; use borderaxespad
- # spacing & pad defined as a fractionof the font-size
+ # spacing & pad defined as a fraction of the font-size
borderpad = None, # the whitespace inside the legend border
labelspacing=None, #the vertical space between the legend entries
handlelength=None, # the length of the legend handles
Modified: branches/v0_98_5_maint/lib/matplotlib/mpl-data/matplotlib.conf.template
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/lib/matplotlib/mpl-data/matplotlib.conf.template 2008-12-19 21:24:32 UTC (rev 6685)
@@ -233,19 +233,11 @@
origin = 'upper'
[legend]
- # a float
- axespad = 0.02
# a float or 'xx-small' or 'x-small' or 'small' or 'medium' or 'large' or
# 'x-large' or 'xx-large'
fontsize = 'medium'
- # a float
- handlelen = 0.050000000000000003
- # a float
- handletextsep = 0.02
# a boolean
isaxes = True
- # a float
- labelsep = 0.01
# 'best' or 'upper right' or 'upper left' or 'lower left' or 'lower right'
# or 'right' or 'center left' or 'center right' or 'lower center' or
# 'upper center' or 'center'
@@ -254,11 +246,22 @@
markerscale = 1.0
# an integer
numpoints = 3
- # a float
- pad = 0.20000000000000001
# a boolean
shadow = False
+ # float
+ borderpad = 0.4
+ # float
+ labelspacing = 0.5
+ # float
+ handlelength = 2.
+ # float
+ handletextpad = 0.8
+ # float
+ borderaxespad = 0.5
+ # float
+ columnspacing = 2.
+
[lines]
# a boolean
antialiased = True
Modified: branches/v0_98_5_maint/lib/matplotlib/rcsetup.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/rcsetup.py 2008-12-19 20:27:18 UTC (rev 6684)
+++ branches/v0_98_5_maint/lib/matplotlib/rcsetup.py 2008-12-19 21:24:32 UTC (rev 6685)
@@ -422,18 +422,12 @@
'legend.isaxes' : [True,validate_bool], # this option is internally ignored - it never served any useful purpose
'legend.numpoints' : [2, validate_int], # the number of points in the legend line
'legend.fontsize' : ['large', validate_fontsize],
- 'legend.pad' : [0, validate_float], # was 0.2, deprecated; the fractional whitespace inside the legend border
- 'legend.borderpad' : [0.4, validate_float], # units are fontsize
'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original
-
- # the following dimensions are in axes coords
- 'legend.labelsep' : [0.010, validate_float], # the vertical space between the legend entries
- 'legend.handlelen' : [0.05, validate_float], # the length of the legend lines
- 'legend.handletextsep' : [0.02, validate_float], # the space between the legend line and legend text
- 'legend.axespad' : [0.02, validate_float], # the border between the axes and legend edge
'legend.shadow' : [False, validate_bool],
+ # the following dimensions are in fraction of the font size
+ 'legend.borderpad' : [0.4, validate_float], # units are fontsize
'legend.labelspacing' : [0.5, validate_float], # the vertical space between the legend entries
'legend.handlelength' : [2., validate_float], # the length of the legend lines
'legend.handletextpad' : [.8, validate_float], # the space between the legend line and legend text
@@ -443,11 +437,6 @@
'legend.markerscale' : [1.0, validate_float], # the relative size of legend markers vs. original
- # the following dimensions are in axes coords
- 'legend.labelsep' : [0.010, validate_float], # the vertical space between the legend entries
- 'legend.handlelen' : [0.05, validate_float], # the length of the legend lines
- 'legend.handletextsep' : [0.02, validate_float], # the space between the legend line and legend text
- 'legend.axespad' : [0.5, validate_float], # the border between the axes and legend edge
'legend.shadow' : [False, validate_bool],
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 20:27:23
|
Revision: 6684
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6684&view=rev
Author: jdh2358
Date: 2008-12-19 20:27:18 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
added ringbuf license
Modified Paths:
--------------
trunk/py4science/examples/pyrex/trailstats/ringbuf.h
trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx
trunk/py4science/examples/pyrex/trailstats/ringbufnan.c
Added Paths:
-----------
trunk/py4science/examples/pyrex/trailstats/LICENSE.ringbuf
Added: trunk/py4science/examples/pyrex/trailstats/LICENSE.ringbuf
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/LICENSE.ringbuf (rev 0)
+++ trunk/py4science/examples/pyrex/trailstats/LICENSE.ringbuf 2008-12-19 20:27:18 UTC (rev 6684)
@@ -0,0 +1,32 @@
+Copyright (c) 2008, Eric Firing
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of the copyright holder nor the names of
+ subsequent contributors may be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+
Modified: trunk/py4science/examples/pyrex/trailstats/ringbuf.h
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbuf.h 2008-12-19 19:31:23 UTC (rev 6683)
+++ trunk/py4science/examples/pyrex/trailstats/ringbuf.h 2008-12-19 20:27:18 UTC (rev 6684)
@@ -1,5 +1,5 @@
+//See LICENSE.ringbuf for license (BSD)
-
typedef struct {
int N_size;
int N_filled;
Modified: trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx 2008-12-19 19:31:23 UTC (rev 6683)
+++ trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx 2008-12-19 20:27:18 UTC (rev 6684)
@@ -3,6 +3,8 @@
Ringbuf, on which various statistics are calculated as each entry is
added and a method runstats for computing a host of trailing
statistics over a numpy array
+
+See LICENSE.ringbuf for license (BSD)
"""
include "c_ringbuf.pxi"
Modified: trunk/py4science/examples/pyrex/trailstats/ringbufnan.c
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbufnan.c 2008-12-19 19:31:23 UTC (rev 6683)
+++ trunk/py4science/examples/pyrex/trailstats/ringbufnan.c 2008-12-19 20:27:18 UTC (rev 6684)
@@ -10,6 +10,7 @@
2003/07/28 EF
+See LICENSE.ringbuf for license (BSD)
*/
#include <stdlib.h>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 19:31:29
|
Revision: 6683
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6683&view=rev
Author: jdh2358
Date: 2008-12-19 19:31:23 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
fixed a min/max bug when initial values all nan
Modified Paths:
--------------
trunk/py4science/examples/pyrex/trailstats/c_ringbuf.pxi
trunk/py4science/examples/pyrex/trailstats/movavg_fast.py
trunk/py4science/examples/pyrex/trailstats/ringbuf.h
trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx
trunk/py4science/examples/pyrex/trailstats/ringbufnan.c
trunk/py4science/examples/pyrex/trailstats/setup.py
Modified: trunk/py4science/examples/pyrex/trailstats/c_ringbuf.pxi
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/c_ringbuf.pxi 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/c_ringbuf.pxi 2008-12-19 19:31:23 UTC (rev 6683)
@@ -18,6 +18,7 @@
double ringbuf_min(ringbuf_t *rb_ptr)
double ringbuf_max(ringbuf_t *rb_ptr)
double ringbuf_median(ringbuf_t *rb_ptr)
+ double ringbuf_ptile(ringbuf_t *rb_ptr, double x)
int ringbuf_N_good(ringbuf_t *rb_ptr)
int ringbuf_N_added(ringbuf_t *rb_ptr)
int ringbuf_N_filled(ringbuf_t *rb_ptr)
@@ -28,8 +29,12 @@
double *dstd,
double *dmin,
double *dmax,
- double *dmed, int *ng)
+ double *dmed,
+ double *dptile5,
+ double *dptile95,
+ int *ng)
void c_runstats2(int nrb, int nd, int step, int ofs,
double *data, double *dmean, double *dstd,
- double *dmin, double *dmax, double *dmed, int *ng)
+ double *dmin, double *dmax, double *dmed, double *dptile5,
+ double *dptile95, int *ng)
Modified: trunk/py4science/examples/pyrex/trailstats/movavg_fast.py
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/movavg_fast.py 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/movavg_fast.py 2008-12-19 19:31:23 UTC (rev 6683)
@@ -5,10 +5,10 @@
import ringbuf
x = numpy.random.rand(10000)
-dmean, dstd, dmin, dmax, dmedian, ng = ringbuf.runstats(x, 30)
+dmean, dstd, dmin, dmax, dmedian, ptile5, ptile95, ng = ringbuf.runstats(x, 30)
r = numpy.rec.fromarrays([dmean, dstd, dmin, dmax, dmedian, ng],
- names='dmean,dstd,dmin,dmax,dmedian,ngood')
+ names='dmean,dstd,dmin,dmax,dmedian,ptile5,ptile95,ngood')
Modified: trunk/py4science/examples/pyrex/trailstats/ringbuf.h
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbuf.h 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/ringbuf.h 2008-12-19 19:31:23 UTC (rev 6683)
@@ -25,6 +25,7 @@
double ringbuf_min(ringbuf_t *rb_ptr);
double ringbuf_max(ringbuf_t *rb_ptr);
double ringbuf_median(ringbuf_t *rb_ptr);
+double ringbuf_ptile(ringbuf_t *rb_ptr, double val);
int ringbuf_N_added(ringbuf_t *rb_ptr);
int ringbuf_N_filled(ringbuf_t *rb_ptr);
int ringbuf_N_good(ringbuf_t *rb_ptr);
@@ -32,10 +33,10 @@
double ringbuf_sd(ringbuf_t *rb_ptr);
void c_runstats(int nrb, int nd, double *data, double *dmean, double *dstd,
- double *dmin, double *dmax, double *dmed, int *ng);
+ double *dmin, double *dmax, double *dmed, double *dptile5, double *dptile95, int *ng);
void c_runstats2(int nrb, int nd, int step, int ofs,
double *data, double *dmean, double *dstd,
- double *dmin, double *dmax, double *dmed, int *ng);
+ double *dmin, double *dmax, double *dmed, double *dptile5, double *dptile95, int *ng);
Modified: trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/ringbuf.pyx 2008-12-19 19:31:23 UTC (rev 6683)
@@ -14,7 +14,7 @@
cdef class Ringbuf:
cdef ringbuf_t *rb_ptr
- def __new__(self, N):
+ def __cinit__(self, N):
self.rb_ptr = new_ringbuf(N)
def __dealloc__(self):
@@ -55,6 +55,9 @@
def median(self):
return ringbuf_median(self.rb_ptr)
+ def ptile(self, x):
+ return ringbuf_ptile(self.rb_ptr, x)
+
def N_added(self):
return ringbuf_N_added(self.rb_ptr)
@@ -73,7 +76,7 @@
cdef object records
- def __new__(self, N):
+ def __cinit__(self, N):
self.rb_ptr = new_ringbuf(N)
self.records = []
@@ -122,6 +125,9 @@
def median(self):
return ringbuf_median(self.rb_ptr)
+ def ptile(self, x):
+ return ringbuf_ptile(self.rb_ptr, x)
+
def N_added(self):
return ringbuf_N_added(self.rb_ptr)
@@ -160,6 +166,8 @@
cdef c_numpy.ndarray c_dmin
cdef c_numpy.ndarray c_dmax
cdef c_numpy.ndarray c_dmedian
+ cdef c_numpy.ndarray c_dptile5
+ cdef c_numpy.ndarray c_dptile95
cdef c_numpy.ndarray c_ng
# make sure that the input array is a 1D numpy array of floats.
@@ -181,6 +189,8 @@
dmin = numpy.empty_like(data)
dmax = numpy.empty_like(data)
dmedian = numpy.empty_like(data)
+ dptile5 = numpy.empty_like(data)
+ dptile95 = numpy.empty_like(data)
ng = numpy.empty(data.shape, dtype=numpy.int_)
# now we have to assign the c_data structures and friends to their
@@ -191,6 +201,8 @@
c_dmin = dmin
c_dmax = dmax
c_dmedian = dmedian
+ c_dptile5 = dptile5
+ c_dptile95 = dptile95
c_ng = ng
# now we call the function and pass in the c data pointers to the
@@ -202,7 +214,9 @@
<double *>c_dmin.data,
<double *>c_dmax.data,
<double *>c_dmedian.data,
+ <double *>c_dptile5.data,
+ <double *>c_dptile95.data,
<int *>c_ng.data)
# all done, return the arrays
- return dmean, dstd, dmin, dmax, dmedian, ng
+ return dmean, dstd, dmin, dmax, dmedian, dptile5, dptile95, ng
Modified: trunk/py4science/examples/pyrex/trailstats/ringbufnan.c
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/ringbufnan.c 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/ringbufnan.c 2008-12-19 19:31:23 UTC (rev 6683)
@@ -121,7 +121,7 @@
d_old = rb_ptr->data[rb_ptr->i_oldest];
rb_ptr->data[i_new] = d;
good_new = !isnan(d);
-#if 0
+#if 1
printf("new value: %lf good_new: %d\n", d, good_new);
printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
rb_ptr->i_next, rb_ptr->i_oldest,
@@ -183,7 +183,7 @@
{
resum_ringbuf(rb_ptr);
}
-#if 0
+#if 1
printf("i_next: %d i_oldest: %d N_filled: %d N_good: %d\n",
rb_ptr->i_next, rb_ptr->i_oldest,
rb_ptr->N_filled, rb_ptr->N_good);
@@ -221,13 +221,21 @@
double ringbuf_min(ringbuf_t *rb_ptr)
{
+ if (rb_ptr->N_good==0)
+ return NaN;
return rb_ptr->data[rb_ptr->i_sorted[0]];
}
double ringbuf_max(ringbuf_t *rb_ptr)
{
- int i_end;
+
+ int i_end;
+
+ if (rb_ptr->N_good==0)
+ return NaN;
+
i_end = rb_ptr->N_good - 1;
+
return rb_ptr->data[rb_ptr->i_sorted[i_end]];
}
@@ -248,6 +256,16 @@
}
}
+double ringbuf_ptile(ringbuf_t *rb_ptr, double ptile)
+{
+ int i, N;
+
+ N = rb_ptr->N_good;
+ if (N == 0) return NaN;
+ i = (int)(ptile*N);
+ return rb_ptr->data[rb_ptr->i_sorted[i]];
+}
+
int ringbuf_N_good(ringbuf_t *rb_ptr)
{
return rb_ptr->N_good;
@@ -272,6 +290,7 @@
{
int N;
+
N = rb_ptr->N_good;
if (N > 0)
{
@@ -286,6 +305,7 @@
double ringbuf_sd(ringbuf_t *rb_ptr)
{
double m, s;
+
int N;
N = rb_ptr->N_good;
@@ -304,7 +324,7 @@
}
void c_runstats(int nrb, int nd, double *data, double *dmean, double *dstd,
- double *dmin, double *dmax, double *dmed, int *ng)
+ double *dmin, double *dmax, double *dmed, double *dptile5, double *dptile95, int *ng)
{
int i, j;
ringbuf_t *rb_ptr;
@@ -319,6 +339,8 @@
dmin[j] = ringbuf_min(rb_ptr);
dmax[j] = ringbuf_max(rb_ptr);
dmed[j] = ringbuf_median(rb_ptr);
+ dptile5[j] = ringbuf_ptile(rb_ptr, 0.05);
+ dptile95[j] = ringbuf_ptile(rb_ptr, 0.95);
ng[j] = rb_ptr->N_good;
}
delete_ringbuf(rb_ptr);
@@ -327,7 +349,8 @@
void c_runstats2(int nrb, int nd, int step, int ofs,
double *data, double *dmean, double *dstd,
- double *dmin, double *dmax, double *dmed, int *ng)
+ double *dmin, double *dmax, double *dmed, double
+*dptile5, double *dptile95, int *ng)
{
int i, j;
int npad = (nrb - 1) / 2;
@@ -339,6 +362,8 @@
dmin += ofs;
dmax += ofs;
dmed += ofs;
+ dptile5 += ofs;
+ dptile95 += ofs;
ng += ofs;
rb_ptr = new_ringbuf(nrb);
@@ -355,6 +380,8 @@
dmin[j*step] = ringbuf_min(rb_ptr);
dmax[j*step] = ringbuf_max(rb_ptr);
dmed[j*step] = ringbuf_median(rb_ptr);
+ dptile5[j*step] = ringbuf_ptile(rb_ptr, 0.05);
+ dptile95[j*step] = ringbuf_ptile(rb_ptr, 0.95);
ng[j*step] = rb_ptr->N_good;
}
delete_ringbuf(rb_ptr);
Modified: trunk/py4science/examples/pyrex/trailstats/setup.py
===================================================================
--- trunk/py4science/examples/pyrex/trailstats/setup.py 2008-12-19 12:40:09 UTC (rev 6682)
+++ trunk/py4science/examples/pyrex/trailstats/setup.py 2008-12-19 19:31:23 UTC (rev 6683)
@@ -4,11 +4,8 @@
# Make this usable by people who don't have pyrex installed (I've committed
# the generated C sources to SVN).
-try:
- from Pyrex.Distutils import build_ext
- has_pyrex = True
-except ImportError:
- has_pyrex = False
+from Cython.Distutils import build_ext
+has_pyrex = True
import numpy
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 12:40:16
|
Revision: 6682
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6682&view=rev
Author: jdh2358
Date: 2008-12-19 12:40:09 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
Merged revisions 6679-6680 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6679 | jdh2358 | 2008-12-19 06:29:49 -0600 (Fri, 19 Dec 2008) | 1 line
added macosx.m to manifest
........
r6680 | jdh2358 | 2008-12-19 06:30:33 -0600 (Fri, 19 Dec 2008) | 1 line
added macosx.m to manifest; released 98.5.2 tarball
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/MANIFEST.in
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6676
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6681
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-19 12:38:33 UTC (rev 6681)
+++ trunk/matplotlib/CHANGELOG 2008-12-19 12:40:09 UTC (rev 6682)
@@ -1,7 +1,7 @@
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
-2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6675
+2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6679
Released 0.98.5.2 from v0_98_5_maint at r6667
2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
Modified: trunk/matplotlib/MANIFEST.in
===================================================================
--- trunk/matplotlib/MANIFEST.in 2008-12-19 12:38:33 UTC (rev 6681)
+++ trunk/matplotlib/MANIFEST.in 2008-12-19 12:40:09 UTC (rev 6682)
@@ -16,7 +16,7 @@
recursive-include license LICENSE*
recursive-include examples *
recursive-include doc *
-recursive-include src *.cpp *.c *.h
+recursive-include src *.cpp *.c *.h *.m
recursive-include CXX *.cxx *.hxx *.c *.h
recursive-include agg24 *
recursive-include lib *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 12:38:36
|
Revision: 6681
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6681&view=rev
Author: jdh2358
Date: 2008-12-19 12:38:33 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
minor tweaks to makefile for osx release
Modified Paths:
--------------
trunk/matplotlib/release/osx/Makefile
Modified: trunk/matplotlib/release/osx/Makefile
===================================================================
--- trunk/matplotlib/release/osx/Makefile 2008-12-19 12:30:33 UTC (rev 6680)
+++ trunk/matplotlib/release/osx/Makefile 2008-12-19 12:38:33 UTC (rev 6681)
@@ -95,7 +95,7 @@
rm -rf upload &&\
mkdir upload &&\
cp matplotlib-${MPLVERSION}.tar.gz upload/ &&\
- cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py2.5-macosx-10.5-i386.egg upload/matplotlib-${MPLVERSION}-py2.5.egg &&\
+ cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py2.5-macosx-10.3-fat.egg upload/matplotlib-${MPLVERSION}-py2.5.egg &&\
cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}-py2.5-macosx10.5.zip upload/matplotlib-${MPLVERSION}-py2.5-mpkg.zip&&\
scp upload/* jd...@fr...:uploads/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 12:30:36
|
Revision: 6680
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6680&view=rev
Author: jdh2358
Date: 2008-12-19 12:30:33 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
added macosx.m to manifest; released 98.5.2 tarball
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-19 12:29:49 UTC (rev 6679)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-19 12:30:33 UTC (rev 6680)
@@ -1,6 +1,6 @@
=======================================================================
-Re-Released 0.98.5.2 at r6675
+Re-Released 0.98.5.2 at r6679
Release 0.98.5.2 at r6667
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-19 12:29:52
|
Revision: 6679
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6679&view=rev
Author: jdh2358
Date: 2008-12-19 12:29:49 +0000 (Fri, 19 Dec 2008)
Log Message:
-----------
added macosx.m to manifest
Modified Paths:
--------------
branches/v0_98_5_maint/MANIFEST.in
Modified: branches/v0_98_5_maint/MANIFEST.in
===================================================================
--- branches/v0_98_5_maint/MANIFEST.in 2008-12-18 20:20:18 UTC (rev 6678)
+++ branches/v0_98_5_maint/MANIFEST.in 2008-12-19 12:29:49 UTC (rev 6679)
@@ -16,7 +16,7 @@
recursive-include license LICENSE*
recursive-include examples *
recursive-include doc *
-recursive-include src *.cpp *.c *.h
+recursive-include src *.cpp *.c *.h *.m
recursive-include CXX *.cxx *.hxx *.c *.h
recursive-include agg24 *
recursive-include lib *
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <js...@us...> - 2008-12-18 20:20:21
|
Revision: 6678
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6678&view=rev
Author: jswhit
Date: 2008-12-18 20:20:18 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
check for already installed pyshapelib
Modified Paths:
--------------
trunk/toolkits/basemap/Changelog
trunk/toolkits/basemap/README
trunk/toolkits/basemap/setup.cfg
trunk/toolkits/basemap/setup.py
Modified: trunk/toolkits/basemap/Changelog
===================================================================
--- trunk/toolkits/basemap/Changelog 2008-12-18 19:40:26 UTC (rev 6677)
+++ trunk/toolkits/basemap/Changelog 2008-12-18 20:20:18 UTC (rev 6678)
@@ -1,4 +1,6 @@
version 0.99.3 (not yet released)
+ * have setup.py check for already installed pyshapelib (just
+ like it does for httplib2 and pydap).
* Basemap will now look for it's data in BASEMAPDATA.
If that env var not set, it will fall back to it's
default location.
Modified: trunk/toolkits/basemap/README
===================================================================
--- trunk/toolkits/basemap/README 2008-12-18 19:40:26 UTC (rev 6677)
+++ trunk/toolkits/basemap/README 2008-12-18 20:20:18 UTC (rev 6678)
@@ -100,11 +100,11 @@
by running "from mpl_toolkits.basemap import Basemap" at the python
prompt.
-Basemap includes two auxilliary packages, pydap (http://pydap.org, just
-the client is included) and httplib2. By default, setup.py checks to
+Basemap includes three auxilliary packages, pydap (http://pydap.org, just
+the client is included), httplib2 and pyshapelib. By default, setup.py checks to
see if these are already installed, and if so does not try to overwrite
them. If you get import errors related to either of these two packages,
-edit setup.cfg and set pydap and/or httplib2 to True to force
+edit setup.cfg and set pydap, httplib2 and/or pyshapelib to True to force
installation of the included versions.
4) To test, cd to the examples directory and run 'python simpletest.py'.
Modified: trunk/toolkits/basemap/setup.cfg
===================================================================
--- trunk/toolkits/basemap/setup.cfg 2008-12-18 19:40:26 UTC (rev 6677)
+++ trunk/toolkits/basemap/setup.cfg 2008-12-18 20:20:18 UTC (rev 6678)
@@ -2,9 +2,10 @@
# By default, basemap checks for a few dependencies and
# installs them if missing. This feature can be turned off
# by uncommenting the following lines. Acceptible values are:
-# True: install, overwrite an existing installation
+# auto: install, overwrite an existing installation
# False: do not install
# auto: install only if the package is unavailable. This
# is the default behavior
pydap = auto
httplib2 = auto
+pyshapelib = auto
Modified: trunk/toolkits/basemap/setup.py
===================================================================
--- trunk/toolkits/basemap/setup.py 2008-12-18 19:40:26 UTC (rev 6677)
+++ trunk/toolkits/basemap/setup.py 2008-12-18 20:20:18 UTC (rev 6678)
@@ -99,25 +99,6 @@
include_dirs=geos_include_dirs,
libraries=['geos_c','geos']))
-# install shapelib and dbflib.
-packages = packages + ['shapelib','dbflib']
-package_dirs['shapelib'] = os.path.join('lib','shapelib')
-package_dirs['dbflib'] = os.path.join('lib','dbflib')
-extensions = extensions + \
- [Extension("shapelibc",
- ["pyshapelib/shapelib_wrap.c",
- "pyshapelib/shapelib/shpopen.c",
- "pyshapelib/shapelib/shptree.c"],
- include_dirs = ["pyshapelib/shapelib"]),
- Extension("shptree",
- ["pyshapelib/shptreemodule.c"],
- include_dirs = ["pyshapelib/shapelib"]),
- Extension("dbflibc",
- ["pyshapelib/dbflib_wrap.c",
- "pyshapelib/shapelib/dbfopen.c"],
- include_dirs = ["pyshapelib/shapelib"],
- define_macros = dbf_macros()) ]
-
# check setup.cfg file to see how to install auxilliary packages.
options = {}
if os.path.exists("setup.cfg"):
@@ -128,10 +109,14 @@
except: options['provide_pydap'] = 'auto'
try: options['provide_httplib2'] = config.getboolean("provide_packages", "httplib2")
except: options['provide_httplib2'] = 'auto'
+ try: options['provide_pyshapelib'] = config.getboolean("provide_packages", "pyshapelib")
+ except: options['provide_pyshapelib'] = 'auto'
else:
options['provide_pydap'] = 'auto'
options['provide_httplib2'] = 'auto'
+ options['provide_pyshapelib'] = 'auto'
+
provide_pydap = options['provide_pydap']
if provide_pydap == 'auto': # install pydap stuff if not already available.
# only the client is installed (not the server).
@@ -171,16 +156,65 @@
except ImportError:
print 'httplib2 not installed, will be installed'
packages = packages + ['httplib2']
- package_dirs['httlib2'] = os.path.join('lib','httplib2')
+ package_dirs['httplib2'] = os.path.join('lib','httplib2')
else:
print 'httplib2 installed'
elif provide_httplib2: # force install of httplib2
print 'forcing install of included httplib2'
packages = packages + ['httplib2']
- package_dirs['httlib2'] = os.path.join('lib','httplib2')
+ package_dirs['httplib2'] = os.path.join('lib','httplib2')
else:
print 'will not install httplib2'
+provide_pyshapelib = options['provide_pyshapelib']
+if provide_pyshapelib == 'auto':
+ print 'checking to see if pyshapelib installed ..'
+ try:
+ import shapelib
+ import dbflib
+ except ImportError:
+ print 'shapelib/dbflib not installed, will be installed'
+ packages = packages + ['shapelib','dbflib']
+ package_dirs['shapelib'] = os.path.join('lib','shapelib')
+ package_dirs['dbflib'] = os.path.join('lib','dbflib')
+ extensions = extensions + \
+ [Extension("shapelibc",
+ ["pyshapelib/shapelib_wrap.c",
+ "pyshapelib/shapelib/shpopen.c",
+ "pyshapelib/shapelib/shptree.c"],
+ include_dirs = ["pyshapelib/shapelib"]),
+ Extension("shptree",
+ ["pyshapelib/shptreemodule.c"],
+ include_dirs = ["pyshapelib/shapelib"]),
+ Extension("dbflibc",
+ ["pyshapelib/dbflib_wrap.c",
+ "pyshapelib/shapelib/dbfopen.c"],
+ include_dirs = ["pyshapelib/shapelib"],
+ define_macros = dbf_macros()) ]
+ else:
+ print 'pyshapelib installed'
+elif provide_pyshapelib: # force install of shapelib
+ print 'forcing install of included pyshapelib'
+ packages = packages + ['shapelib','dbflib']
+ package_dirs['shapelib'] = os.path.join('lib','shapelib')
+ package_dirs['dbflib'] = os.path.join('lib','dbflib')
+ extensions = extensions + \
+ [Extension("shapelibc",
+ ["pyshapelib/shapelib_wrap.c",
+ "pyshapelib/shapelib/shpopen.c",
+ "pyshapelib/shapelib/shptree.c"],
+ include_dirs = ["pyshapelib/shapelib"]),
+ Extension("shptree",
+ ["pyshapelib/shptreemodule.c"],
+ include_dirs = ["pyshapelib/shapelib"]),
+ Extension("dbflibc",
+ ["pyshapelib/dbflib_wrap.c",
+ "pyshapelib/shapelib/dbfopen.c"],
+ include_dirs = ["pyshapelib/shapelib"],
+ define_macros = dbf_macros()) ]
+else:
+ print 'will not install pyshapelib'
+
# Specify all the required mpl data
pyproj_datafiles = ['data/epsg', 'data/esri', 'data/esri.extra', 'data/GL27', 'data/nad.lst', 'data/nad27', 'data/nad83', 'data/ntv2_out.dist', 'data/other.extra', 'data/pj_out27.dist', 'data/pj_out83.dist', 'data/proj_def.dat', 'data/README', 'data/td_out.dist', 'data/test27', 'data/test83', 'data/testntv2', 'data/testvarious', 'data/world','data/bmng.jpg','data/bmng_low.jpg']
boundaryfiles = []
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 19:40:36
|
Revision: 6677
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6677&view=rev
Author: jdh2358
Date: 2008-12-18 19:40:26 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Merged revisions 6675-6676 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6675 | jdh2358 | 2008-12-18 11:19:26 -0800 (Thu, 18 Dec 2008) | 1 line
fixed a small_docs bug when no args present
........
r6676 | jdh2358 | 2008-12-18 11:28:46 -0800 (Thu, 18 Dec 2008) | 1 line
pushed out new 98.5.2 tarball with smalldocs fix
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/make.py
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6673
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6676
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-18 19:28:46 UTC (rev 6676)
+++ trunk/matplotlib/CHANGELOG 2008-12-18 19:40:26 UTC (rev 6677)
@@ -1,7 +1,8 @@
2008-12-18 add new arrow style, a line + filled triangles. -JJL
==================================================================
-2008-12-18 Released 0.98.5.2 from v0_98_5_maint at r6667
+2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6675
+ Released 0.98.5.2 from v0_98_5_maint at r6667
2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
Modified: trunk/matplotlib/doc/make.py
===================================================================
--- trunk/matplotlib/doc/make.py 2008-12-18 19:28:46 UTC (rev 6676)
+++ trunk/matplotlib/doc/make.py 2008-12-18 19:40:26 UTC (rev 6677)
@@ -105,4 +105,5 @@
arg, funcd.keys()))
func()
else:
+ small_docs = False
all()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 19:29:00
|
Revision: 6676
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6676&view=rev
Author: jdh2358
Date: 2008-12-18 19:28:46 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
pushed out new 98.5.2 tarball with smalldocs fix
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-18 19:19:26 UTC (rev 6675)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-18 19:28:46 UTC (rev 6676)
@@ -1,6 +1,9 @@
+
=======================================================================
-Release 0.98.5.3 at r6667
+Re-Released 0.98.5.2 at r6675
+Release 0.98.5.2 at r6667
+
2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
2008-12-18 Fix bug where a line with NULL data limits prevents
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 19:19:33
|
Revision: 6675
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6675&view=rev
Author: jdh2358
Date: 2008-12-18 19:19:26 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
fixed a small_docs bug when no args present
Modified Paths:
--------------
branches/v0_98_5_maint/doc/make.py
Modified: branches/v0_98_5_maint/doc/make.py
===================================================================
--- branches/v0_98_5_maint/doc/make.py 2008-12-18 19:10:38 UTC (rev 6674)
+++ branches/v0_98_5_maint/doc/make.py 2008-12-18 19:19:26 UTC (rev 6675)
@@ -105,4 +105,5 @@
arg, funcd.keys()))
func()
else:
+ small_docs = False
all()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-18 19:10:43
|
Revision: 6674
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6674&view=rev
Author: mdboom
Date: 2008-12-18 19:10:38 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Merged revisions 6672-6673 via svnmerge from
https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6672 | mdboom | 2008-12-18 14:07:08 -0500 (Thu, 18 Dec 2008) | 2 lines
Fix how example files are added to the build. Saves about 1MB in html output.
........
r6673 | mdboom | 2008-12-18 14:08:45 -0500 (Thu, 18 Dec 2008) | 1 line
removing examples from svn
........
Modified Paths:
--------------
trunk/matplotlib/doc/conf.py
trunk/matplotlib/doc/make.py
trunk/matplotlib/doc/sphinxext/plot_directive.py
trunk/matplotlib/lib/matplotlib/pyplot.py
Added Paths:
-----------
trunk/matplotlib/doc/sphinxext/gen_rst.py
Removed Paths:
-------------
trunk/matplotlib/doc/examples/
Property Changed:
----------------
trunk/matplotlib/
trunk/matplotlib/doc/pyplots/README
trunk/matplotlib/doc/sphinxext/gen_gallery.py
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6668
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6673
Modified: svn:mergeinfo
- /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662
+ /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673
Modified: trunk/matplotlib/doc/conf.py
===================================================================
--- trunk/matplotlib/doc/conf.py 2008-12-18 19:08:45 UTC (rev 6673)
+++ trunk/matplotlib/doc/conf.py 2008-12-18 19:10:38 UTC (rev 6674)
@@ -29,7 +29,7 @@
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['mathmpl', 'math_symbol_table', 'sphinx.ext.autodoc',
'only_directives', 'plot_directive', 'inheritance_diagram',
- 'gen_gallery']
+ 'gen_gallery', 'gen_rst']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Modified: trunk/matplotlib/doc/make.py
===================================================================
--- trunk/matplotlib/doc/make.py 2008-12-18 19:08:45 UTC (rev 6673)
+++ trunk/matplotlib/doc/make.py 2008-12-18 19:10:38 UTC (rev 6674)
@@ -34,15 +34,12 @@
def html():
check_build()
- if not os.path.exists('examples/index.rst'):
- examples()
shutil.copy('../lib/matplotlib/mpl-data/matplotlibrc', '_static/matplotlibrc')
- #figs()
if small_docs:
options = "-D plot_formats=\"['png']\""
else:
options = ''
- if os.system('sphinx-build %s -b html -d build/doctrees . build/html' % options):
+ if os.system('sphinx-build %s -P -b html -d build/doctrees . build/html' % options):
raise SystemExit("Building HTML failed.")
figures_dest_path = 'build/html/pyplots'
Property changes on: trunk/matplotlib/doc/pyplots/README
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662
+ /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662,6672-6673
Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662
+ /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662,6672-6673
Copied: trunk/matplotlib/doc/sphinxext/gen_rst.py (from rev 6673, branches/v0_98_5_maint/doc/sphinxext/gen_rst.py)
===================================================================
--- trunk/matplotlib/doc/sphinxext/gen_rst.py (rev 0)
+++ trunk/matplotlib/doc/sphinxext/gen_rst.py 2008-12-18 19:10:38 UTC (rev 6674)
@@ -0,0 +1,155 @@
+"""
+generate the rst files for the examples by iterating over the pylab examples
+"""
+import os, glob
+
+import os
+import re
+import sys
+fileList = []
+
+def out_of_date(original, derived):
+ """
+ Returns True if derivative is out-of-date wrt original,
+ both of which are full file paths.
+
+ TODO: this check isn't adequate in some cases. Eg, if we discover
+ a bug when building the examples, the original and derived will be
+ unchanged but we still want to force a rebuild.
+ """
+ return (not os.path.exists(derived) or
+ os.stat(derived).st_mtime < os.stat(original).st_mtime)
+
+noplot_regex = re.compile(r"#\s*-\*-\s*noplot\s*-\*-")
+
+def generate_example_rst(app):
+ rootdir = os.path.join(app.builder.srcdir, 'mpl_examples')
+ exampledir = os.path.join(app.builder.srcdir, 'examples')
+ if not os.path.exists(exampledir):
+ os.makedirs(exampledir)
+
+ datad = {}
+ for root, subFolders, files in os.walk(rootdir):
+ for fname in files:
+ if ( fname.startswith('.') or fname.startswith('#') or fname.startswith('_') or
+ fname.find('.svn')>=0 or not fname.endswith('.py') ):
+ continue
+
+ fullpath = os.path.join(root,fname)
+ contents = file(fullpath).read()
+ # indent
+ relpath = os.path.split(root)[-1]
+ datad.setdefault(relpath, []).append((fullpath, fname, contents))
+
+ subdirs = datad.keys()
+ subdirs.sort()
+
+ fhindex = file(os.path.join(exampledir, 'index.rst'), 'w')
+ fhindex.write("""\
+.. _examples-index:
+
+####################
+Matplotlib Examples
+####################
+
+.. htmlonly::
+
+ :Release: |version|
+ :Date: |today|
+
+.. toctree::
+ :maxdepth: 2
+
+""")
+
+ for subdir in subdirs:
+ rstdir = os.path.join(exampledir, subdir)
+ if not os.path.exists(rstdir):
+ os.makedirs(rstdir)
+
+ outputdir = os.path.join(app.builder.outdir, 'examples')
+ if not os.path.exists(outputdir):
+ os.makedirs(outputdir)
+
+ outputdir = os.path.join(outputdir, subdir)
+ if not os.path.exists(outputdir):
+ os.makedirs(outputdir)
+
+ subdirIndexFile = os.path.join(rstdir, 'index.rst')
+ fhsubdirIndex = file(subdirIndexFile, 'w')
+ fhindex.write(' %s/index.rst\n\n'%subdir)
+
+ fhsubdirIndex.write("""\
+.. _%s-examples-index:
+
+##############################################
+%s Examples
+##############################################
+
+.. htmlonly::
+
+ :Release: |version|
+ :Date: |today|
+
+.. toctree::
+ :maxdepth: 1
+
+"""%(subdir, subdir))
+
+ print subdir
+
+ data = datad[subdir]
+ data.sort()
+
+ for fullpath, fname, contents in data:
+ basename, ext = os.path.splitext(fname)
+ outputfile = os.path.join(outputdir, fname)
+ #thumbfile = os.path.join(thumb_dir, '%s.png'%basename)
+ #print ' static_dir=%s, basename=%s, fullpath=%s, fname=%s, thumb_dir=%s, thumbfile=%s'%(static_dir, basename, fullpath, fname, thumb_dir, thumbfile)
+
+ rstfile = '%s.rst'%basename
+ outrstfile = os.path.join(rstdir, rstfile)
+
+ fhsubdirIndex.write(' %s\n'%rstfile)
+
+ if (not out_of_date(fullpath, outputfile) and
+ not out_of_date(fullpath, outrstfile)):
+ continue
+
+ print ' %s'%fname
+
+ fh = file(outrstfile, 'w')
+ fh.write('.. _%s-%s:\n\n'%(subdir, basename))
+ title = '%s example code: %s'%(subdir, fname)
+ #title = '<img src=%s> %s example code: %s'%(thumbfile, subdir, fname)
+
+
+ fh.write(title + '\n')
+ fh.write('='*len(title) + '\n\n')
+
+ do_plot = (subdir in ('api',
+ 'pylab_examples',
+ 'units') and
+ not noplot_regex.search(contents))
+
+ if do_plot:
+ fh.write("\n\n.. plot:: %s\n\n::\n\n" % fullpath)
+ else:
+ fh.write("[`source code <%s>`_]\n\n::\n\n" % fname)
+ fhstatic = file(outputfile, 'w')
+ fhstatic.write(contents)
+ fhstatic.close()
+
+ # indent the contents
+ contents = '\n'.join([' %s'%row.rstrip() for row in contents.split('\n')])
+ fh.write(contents)
+
+ fh.write('\n\nKeywords: python, matplotlib, pylab, example, codex (see :ref:`how-to-search-examples`)')
+ fh.close()
+
+ fhsubdirIndex.close()
+
+ fhindex.close()
+
+def setup(app):
+ app.connect('builder-inited', generate_example_rst)
Modified: trunk/matplotlib/doc/sphinxext/plot_directive.py
===================================================================
--- trunk/matplotlib/doc/sphinxext/plot_directive.py 2008-12-18 19:08:45 UTC (rev 6673)
+++ trunk/matplotlib/doc/sphinxext/plot_directive.py 2008-12-18 19:10:38 UTC (rev 6674)
@@ -34,6 +34,41 @@
import matplotlib.image as image
from matplotlib import _pylab_helpers
+if hasattr(os.path, 'relpath'):
+ relpath = os.path.relpath
+else:
+ def relpath(target, base=os.curdir):
+ """
+ Return a relative path to the target from either the current dir or an optional base dir.
+ Base can be a directory specified either as absolute or relative to current dir.
+ """
+
+ if not os.path.exists(target):
+ raise OSError, 'Target does not exist: '+target
+
+ if not os.path.isdir(base):
+ raise OSError, 'Base is not a directory or does not exist: '+base
+
+ base_list = (os.path.abspath(base)).split(os.sep)
+ target_list = (os.path.abspath(target)).split(os.sep)
+
+ # On the windows platform the target may be on a completely different drive from the base.
+ if os.name in ['nt','dos','os2'] and base_list[0] <> target_list[0]:
+ raise OSError, 'Target is on a different drive to base. Target: '+target_list[0].upper()+', base: '+base_list[0].upper()
+
+ # Starting from the filepath root, work out how much of the filepath is
+ # shared by base and target.
+ for i in range(min(len(base_list), len(target_list))):
+ if base_list[i] <> target_list[i]: break
+ else:
+ # If we broke out of the loop, i is pointing to the first differing path elements.
+ # If we didn't break out of the loop, i is pointing to identical path elements.
+ # Increment i so that in all cases it points to the first differing path elements.
+ i+=1
+
+ rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
+ return os.path.join(*rel_list)
+
def write_char(s):
sys.stdout.write(s)
sys.stdout.flush()
@@ -186,6 +221,7 @@
reference = directives.uri(arguments[0])
basedir, fname = os.path.split(reference)
basename, ext = os.path.splitext(fname)
+ basedir = relpath(basedir, setup.app.builder.srcdir)
# Get the directory of the rst file, and determine the relative
# path from the resulting html file to the plot_directive links
Modified: trunk/matplotlib/lib/matplotlib/pyplot.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/pyplot.py 2008-12-18 19:08:45 UTC (rev 6673)
+++ trunk/matplotlib/lib/matplotlib/pyplot.py 2008-12-18 19:10:38 UTC (rev 6674)
@@ -1148,10 +1148,9 @@
def plotting():
"""
Plotting commands
-
- ============ =================================================
+ =============== =========================================================
Command Description
- ========= =================================================
+ =============== =========================================================
axes Create a new axes
axis Set or return the current axis limits
bar make a bar chart
@@ -1204,7 +1203,7 @@
title add a title to the current axes
xlabel add an xlabel to the current axes
ylabel add a ylabel to the current axes
- ============ =================================================
+ =============== =========================================================
The following commands will set the default colormap accordingly:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-18 19:08:49
|
Revision: 6673
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6673&view=rev
Author: mdboom
Date: 2008-12-18 19:08:45 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
removing examples from svn
Removed Paths:
-------------
branches/v0_98_5_maint/doc/examples/
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-18 19:07:12
|
Revision: 6672
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6672&view=rev
Author: mdboom
Date: 2008-12-18 19:07:08 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Fix how example files are added to the build. Saves about 1MB in html output.
Modified Paths:
--------------
branches/v0_98_5_maint/doc/conf.py
branches/v0_98_5_maint/doc/make.py
branches/v0_98_5_maint/doc/sphinxext/plot_directive.py
branches/v0_98_5_maint/lib/matplotlib/pyplot.py
Added Paths:
-----------
branches/v0_98_5_maint/doc/sphinxext/gen_rst.py
Modified: branches/v0_98_5_maint/doc/conf.py
===================================================================
--- branches/v0_98_5_maint/doc/conf.py 2008-12-18 17:41:11 UTC (rev 6671)
+++ branches/v0_98_5_maint/doc/conf.py 2008-12-18 19:07:08 UTC (rev 6672)
@@ -29,7 +29,7 @@
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['mathmpl', 'math_symbol_table', 'sphinx.ext.autodoc',
'only_directives', 'plot_directive', 'inheritance_diagram',
- 'gen_gallery']
+ 'gen_gallery', 'gen_rst']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
Modified: branches/v0_98_5_maint/doc/make.py
===================================================================
--- branches/v0_98_5_maint/doc/make.py 2008-12-18 17:41:11 UTC (rev 6671)
+++ branches/v0_98_5_maint/doc/make.py 2008-12-18 19:07:08 UTC (rev 6672)
@@ -34,15 +34,12 @@
def html():
check_build()
- if not os.path.exists('examples/index.rst'):
- examples()
shutil.copy('../lib/matplotlib/mpl-data/matplotlibrc', '_static/matplotlibrc')
- #figs()
if small_docs:
options = "-D plot_formats=\"['png']\""
else:
options = ''
- if os.system('sphinx-build %s -b html -d build/doctrees . build/html' % options):
+ if os.system('sphinx-build %s -P -b html -d build/doctrees . build/html' % options):
raise SystemExit("Building HTML failed.")
figures_dest_path = 'build/html/pyplots'
Copied: branches/v0_98_5_maint/doc/sphinxext/gen_rst.py (from rev 6660, branches/v0_98_5_maint/doc/examples/gen_rst.py)
===================================================================
--- branches/v0_98_5_maint/doc/sphinxext/gen_rst.py (rev 0)
+++ branches/v0_98_5_maint/doc/sphinxext/gen_rst.py 2008-12-18 19:07:08 UTC (rev 6672)
@@ -0,0 +1,155 @@
+"""
+generate the rst files for the examples by iterating over the pylab examples
+"""
+import os, glob
+
+import os
+import re
+import sys
+fileList = []
+
+def out_of_date(original, derived):
+ """
+ Returns True if derivative is out-of-date wrt original,
+ both of which are full file paths.
+
+ TODO: this check isn't adequate in some cases. Eg, if we discover
+ a bug when building the examples, the original and derived will be
+ unchanged but we still want to force a rebuild.
+ """
+ return (not os.path.exists(derived) or
+ os.stat(derived).st_mtime < os.stat(original).st_mtime)
+
+noplot_regex = re.compile(r"#\s*-\*-\s*noplot\s*-\*-")
+
+def generate_example_rst(app):
+ rootdir = os.path.join(app.builder.srcdir, 'mpl_examples')
+ exampledir = os.path.join(app.builder.srcdir, 'examples')
+ if not os.path.exists(exampledir):
+ os.makedirs(exampledir)
+
+ datad = {}
+ for root, subFolders, files in os.walk(rootdir):
+ for fname in files:
+ if ( fname.startswith('.') or fname.startswith('#') or fname.startswith('_') or
+ fname.find('.svn')>=0 or not fname.endswith('.py') ):
+ continue
+
+ fullpath = os.path.join(root,fname)
+ contents = file(fullpath).read()
+ # indent
+ relpath = os.path.split(root)[-1]
+ datad.setdefault(relpath, []).append((fullpath, fname, contents))
+
+ subdirs = datad.keys()
+ subdirs.sort()
+
+ fhindex = file(os.path.join(exampledir, 'index.rst'), 'w')
+ fhindex.write("""\
+.. _examples-index:
+
+####################
+Matplotlib Examples
+####################
+
+.. htmlonly::
+
+ :Release: |version|
+ :Date: |today|
+
+.. toctree::
+ :maxdepth: 2
+
+""")
+
+ for subdir in subdirs:
+ rstdir = os.path.join(exampledir, subdir)
+ if not os.path.exists(rstdir):
+ os.makedirs(rstdir)
+
+ outputdir = os.path.join(app.builder.outdir, 'examples')
+ if not os.path.exists(outputdir):
+ os.makedirs(outputdir)
+
+ outputdir = os.path.join(outputdir, subdir)
+ if not os.path.exists(outputdir):
+ os.makedirs(outputdir)
+
+ subdirIndexFile = os.path.join(rstdir, 'index.rst')
+ fhsubdirIndex = file(subdirIndexFile, 'w')
+ fhindex.write(' %s/index.rst\n\n'%subdir)
+
+ fhsubdirIndex.write("""\
+.. _%s-examples-index:
+
+##############################################
+%s Examples
+##############################################
+
+.. htmlonly::
+
+ :Release: |version|
+ :Date: |today|
+
+.. toctree::
+ :maxdepth: 1
+
+"""%(subdir, subdir))
+
+ print subdir
+
+ data = datad[subdir]
+ data.sort()
+
+ for fullpath, fname, contents in data:
+ basename, ext = os.path.splitext(fname)
+ outputfile = os.path.join(outputdir, fname)
+ #thumbfile = os.path.join(thumb_dir, '%s.png'%basename)
+ #print ' static_dir=%s, basename=%s, fullpath=%s, fname=%s, thumb_dir=%s, thumbfile=%s'%(static_dir, basename, fullpath, fname, thumb_dir, thumbfile)
+
+ rstfile = '%s.rst'%basename
+ outrstfile = os.path.join(rstdir, rstfile)
+
+ fhsubdirIndex.write(' %s\n'%rstfile)
+
+ if (not out_of_date(fullpath, outputfile) and
+ not out_of_date(fullpath, outrstfile)):
+ continue
+
+ print ' %s'%fname
+
+ fh = file(outrstfile, 'w')
+ fh.write('.. _%s-%s:\n\n'%(subdir, basename))
+ title = '%s example code: %s'%(subdir, fname)
+ #title = '<img src=%s> %s example code: %s'%(thumbfile, subdir, fname)
+
+
+ fh.write(title + '\n')
+ fh.write('='*len(title) + '\n\n')
+
+ do_plot = (subdir in ('api',
+ 'pylab_examples',
+ 'units') and
+ not noplot_regex.search(contents))
+
+ if do_plot:
+ fh.write("\n\n.. plot:: %s\n\n::\n\n" % fullpath)
+ else:
+ fh.write("[`source code <%s>`_]\n\n::\n\n" % fname)
+ fhstatic = file(outputfile, 'w')
+ fhstatic.write(contents)
+ fhstatic.close()
+
+ # indent the contents
+ contents = '\n'.join([' %s'%row.rstrip() for row in contents.split('\n')])
+ fh.write(contents)
+
+ fh.write('\n\nKeywords: python, matplotlib, pylab, example, codex (see :ref:`how-to-search-examples`)')
+ fh.close()
+
+ fhsubdirIndex.close()
+
+ fhindex.close()
+
+def setup(app):
+ app.connect('builder-inited', generate_example_rst)
Property changes on: branches/v0_98_5_maint/doc/sphinxext/gen_rst.py
___________________________________________________________________
Added: svn:mergeinfo
+ /branches/v0_91_maint/doc/examples/gen_rst.py:5753-5771
Modified: branches/v0_98_5_maint/doc/sphinxext/plot_directive.py
===================================================================
--- branches/v0_98_5_maint/doc/sphinxext/plot_directive.py 2008-12-18 17:41:11 UTC (rev 6671)
+++ branches/v0_98_5_maint/doc/sphinxext/plot_directive.py 2008-12-18 19:07:08 UTC (rev 6672)
@@ -34,6 +34,41 @@
import matplotlib.image as image
from matplotlib import _pylab_helpers
+if hasattr(os.path, 'relpath'):
+ relpath = os.path.relpath
+else:
+ def relpath(target, base=os.curdir):
+ """
+ Return a relative path to the target from either the current dir or an optional base dir.
+ Base can be a directory specified either as absolute or relative to current dir.
+ """
+
+ if not os.path.exists(target):
+ raise OSError, 'Target does not exist: '+target
+
+ if not os.path.isdir(base):
+ raise OSError, 'Base is not a directory or does not exist: '+base
+
+ base_list = (os.path.abspath(base)).split(os.sep)
+ target_list = (os.path.abspath(target)).split(os.sep)
+
+ # On the windows platform the target may be on a completely different drive from the base.
+ if os.name in ['nt','dos','os2'] and base_list[0] <> target_list[0]:
+ raise OSError, 'Target is on a different drive to base. Target: '+target_list[0].upper()+', base: '+base_list[0].upper()
+
+ # Starting from the filepath root, work out how much of the filepath is
+ # shared by base and target.
+ for i in range(min(len(base_list), len(target_list))):
+ if base_list[i] <> target_list[i]: break
+ else:
+ # If we broke out of the loop, i is pointing to the first differing path elements.
+ # If we didn't break out of the loop, i is pointing to identical path elements.
+ # Increment i so that in all cases it points to the first differing path elements.
+ i+=1
+
+ rel_list = [os.pardir] * (len(base_list)-i) + target_list[i:]
+ return os.path.join(*rel_list)
+
def write_char(s):
sys.stdout.write(s)
sys.stdout.flush()
@@ -186,6 +221,7 @@
reference = directives.uri(arguments[0])
basedir, fname = os.path.split(reference)
basename, ext = os.path.splitext(fname)
+ basedir = relpath(basedir, setup.app.builder.srcdir)
# Get the directory of the rst file, and determine the relative
# path from the resulting html file to the plot_directive links
Modified: branches/v0_98_5_maint/lib/matplotlib/pyplot.py
===================================================================
--- branches/v0_98_5_maint/lib/matplotlib/pyplot.py 2008-12-18 17:41:11 UTC (rev 6671)
+++ branches/v0_98_5_maint/lib/matplotlib/pyplot.py 2008-12-18 19:07:08 UTC (rev 6672)
@@ -1138,9 +1138,9 @@
def plotting():
"""
Plotting commands
- ============ =================================================
+ =============== =========================================================
Command Description
- ========= =================================================
+ =============== =========================================================
axes Create a new axes
axis Set or return the current axis limits
bar make a bar chart
@@ -1193,7 +1193,7 @@
title add a title to the current axes
xlabel add an xlabel to the current axes
ylabel add a ylabel to the current axes
- ============ =================================================
+ =============== =========================================================
The following commands will set the default colormap accordingly:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 17:41:14
|
Revision: 6671
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6671&view=rev
Author: jdh2358
Date: 2008-12-18 17:41:11 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
removed references to configobj and traits from setup.cfg
Modified Paths:
--------------
trunk/matplotlib/release/osx/data/setup.cfg
Modified: trunk/matplotlib/release/osx/data/setup.cfg
===================================================================
--- trunk/matplotlib/release/osx/data/setup.cfg 2008-12-18 17:40:19 UTC (rev 6670)
+++ trunk/matplotlib/release/osx/data/setup.cfg 2008-12-18 17:41:11 UTC (rev 6671)
@@ -25,10 +25,6 @@
pytz = True
dateutil = True
-## Experimental config package support, this should only be enabled by
-## matplotlib developers, for matplotlib development
-enthought.traits = False
-configobj = False
[gui_support]
# Matplotlib supports multiple GUI toolkits, including Cocoa,
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 17:40:23
|
Revision: 6670
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6670&view=rev
Author: jdh2358
Date: 2008-12-18 17:40:19 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
updates to osx makefile
Modified Paths:
--------------
trunk/matplotlib/release/osx/Makefile
trunk/matplotlib/release/osx/data/setup.cfg
Modified: trunk/matplotlib/release/osx/Makefile
===================================================================
--- trunk/matplotlib/release/osx/Makefile 2008-12-18 17:32:22 UTC (rev 6669)
+++ trunk/matplotlib/release/osx/Makefile 2008-12-18 17:40:19 UTC (rev 6670)
@@ -2,7 +2,7 @@
ZLIBVERSION=1.2.3
PNGVERSION=1.2.33
FREETYPEVERSION=2.3.7
-MPLVERSION=0.98.5.1
+MPLVERSION=0.98.5.2
MPLSRC=matplotlib-${MPLVERSION}
MACOSX_DEPLOYMENT_TARGET=10.4
@@ -91,8 +91,16 @@
cd dist && \
zip -ro matplotlib-${MPLVERSION}-py2.5-macosx10.5.zip matplotlib-${MPLVERSION}-py2.5-macosx10.5.mpkg
+upload:
+ rm -rf upload &&\
+ mkdir upload &&\
+ cp matplotlib-${MPLVERSION}.tar.gz upload/ &&\
+ cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}_r0-py2.5-macosx-10.5-i386.egg upload/matplotlib-${MPLVERSION}-py2.5.egg &&\
+ cp matplotlib-${MPLVERSION}/dist/matplotlib-${MPLVERSION}-py2.5-macosx10.5.zip upload/matplotlib-${MPLVERSION}-py2.5-mpkg.zip&&\
+ scp upload/* jd...@fr...:uploads/
+
all:
- make clean fetch_deps dependencies installers
+ make clean fetch_deps dependencies installers upload
Modified: trunk/matplotlib/release/osx/data/setup.cfg
===================================================================
--- trunk/matplotlib/release/osx/data/setup.cfg 2008-12-18 17:32:22 UTC (rev 6669)
+++ trunk/matplotlib/release/osx/data/setup.cfg 2008-12-18 17:40:19 UTC (rev 6670)
@@ -25,6 +25,11 @@
pytz = True
dateutil = True
+## Experimental config package support, this should only be enabled by
+## matplotlib developers, for matplotlib development
+enthought.traits = False
+configobj = False
+
[gui_support]
# Matplotlib supports multiple GUI toolkits, including Cocoa,
# GTK, Fltk, MacOSX, Qt, Qt4, Tk, and WX. Support for many of
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 17:32:26
|
Revision: 6669
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6669&view=rev
Author: jdh2358
Date: 2008-12-18 17:32:22 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Merged revisions 6665-6668 via svnmerge from
https://matplotlib.svn.sourceforge.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6665 | jdh2358 | 2008-12-18 08:29:51 -0800 (Thu, 18 Dec 2008) | 1 line
removed some configobj and traits detritus
........
r6666 | jdh2358 | 2008-12-18 08:31:44 -0800 (Thu, 18 Dec 2008) | 1 line
tagging release 0.98.5.2
........
r6667 | jdh2358 | 2008-12-18 09:02:41 -0800 (Thu, 18 Dec 2008) | 1 line
removed mpl_data
........
r6668 | jdh2358 | 2008-12-18 09:03:47 -0800 (Thu, 18 Dec 2008) | 1 line
retagging for 98.5.2
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/api/api_changes.rst
trunk/matplotlib/setup.py
trunk/matplotlib/setupext.py
Removed Paths:
-------------
trunk/matplotlib/doc/mpl_data
Property Changed:
----------------
trunk/matplotlib/
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6662
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6668
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-18 17:03:47 UTC (rev 6668)
+++ trunk/matplotlib/CHANGELOG 2008-12-18 17:32:22 UTC (rev 6669)
@@ -1,5 +1,10 @@
2008-12-18 add new arrow style, a line + filled triangles. -JJL
+==================================================================
+2008-12-18 Released 0.98.5.2 from v0_98_5_maint at r6667
+
+2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
+
2008-12-18 Fix bug where a line with NULL data limits prevents
subsequent data limits from calculating correctly - MGD
Modified: trunk/matplotlib/doc/api/api_changes.rst
===================================================================
--- trunk/matplotlib/doc/api/api_changes.rst 2008-12-18 17:03:47 UTC (rev 6668)
+++ trunk/matplotlib/doc/api/api_changes.rst 2008-12-18 17:32:22 UTC (rev 6669)
@@ -15,6 +15,7 @@
Changes for 0.98.x
==================
+* Removed the configobj and experiemtnal traits rc support
* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`,
:func:`matplotlib.mlab.cohere`, and :func:`matplotlib.mlab.specgram`
Deleted: trunk/matplotlib/doc/mpl_data
===================================================================
--- trunk/matplotlib/doc/mpl_data 2008-12-18 17:03:47 UTC (rev 6668)
+++ trunk/matplotlib/doc/mpl_data 2008-12-18 17:32:22 UTC (rev 6669)
@@ -1 +0,0 @@
-link ../lib/matplotlib/mpl-data/
\ No newline at end of file
Modified: trunk/matplotlib/setup.py
===================================================================
--- trunk/matplotlib/setup.py 2008-12-18 17:03:47 UTC (rev 6668)
+++ trunk/matplotlib/setup.py 2008-12-18 17:32:22 UTC (rev 6669)
@@ -35,12 +35,12 @@
from distutils.core import setup
from setupext import build_agg, build_gtkagg, build_tkagg, build_wxagg,\
build_macosx, build_ft2font, build_image, build_windowing, build_path, \
- build_contour, build_delaunay, build_nxutils, build_traits, build_gdk, \
+ build_contour, build_delaunay, build_nxutils, build_gdk, \
build_ttconv, print_line, print_status, print_message, \
print_raw, check_for_freetype, check_for_libpng, check_for_gtk, \
check_for_tk, check_for_wx, check_for_macosx, check_for_numpy, \
- check_for_qt, check_for_qt4, check_for_cairo, check_for_traits, \
- check_provide_pytz, check_provide_dateutil, check_for_configobj, \
+ check_for_qt, check_for_qt4, check_for_cairo, \
+ check_provide_pytz, check_provide_dateutil,\
check_for_dvipng, check_for_ghostscript, check_for_latex, \
check_for_pdftops, check_for_datetime, options, build_png
#import distutils.sysconfig
@@ -217,15 +217,7 @@
check_for_latex()
check_for_pdftops()
-# TODO: comment out for mpl release:
print_raw("")
-print_raw("EXPERIMENTAL CONFIG PACKAGE DEPENDENCIES")
-has_configobj = check_for_configobj()
-has_traits = check_for_traits()
-if has_configobj and has_traits:
- packages.append('matplotlib.config')
-
-print_raw("")
print_raw("[Edit setup.cfg to suppress the above messages]")
print_line()
Modified: trunk/matplotlib/setupext.py
===================================================================
--- trunk/matplotlib/setupext.py 2008-12-18 17:03:47 UTC (rev 6668)
+++ trunk/matplotlib/setupext.py 2008-12-18 17:32:22 UTC (rev 6669)
@@ -83,7 +83,6 @@
BUILT_CONTOUR = False
BUILT_DELAUNAY = False
BUILT_NXUTILS = False
-BUILT_TRAITS = False
BUILT_CONTOUR = False
BUILT_GDK = False
BUILT_PATH = False
@@ -434,36 +433,6 @@
print_status("dateutil", "present, version unknown")
return False
-def check_for_configobj():
- try:
- import configobj
- except ImportError:
- print_status("configobj", "no")
- return False
- else:
- print_status("configobj", configobj.__version__)
- return True
-
-def check_for_traits():
- try:
- from enthought import traits
- try:
- from enthought.traits import version
- except:
- print_status("enthought.traits", "unknown and incompatible version: < 2.0")
- return False
- else:
- # traits 2 and 3 store their version strings in different places:
- try:
- version = version.version
- except AttributeError:
- version = version.__version__
- print_status("enthought.traits", version)
- return True
- except ImportError:
- print_status("enthought.traits", "no")
- return False
-
def check_for_dvipng():
try:
stdin, stdout = run_child_process('dvipng -version')
@@ -1316,24 +1285,7 @@
BUILT_IMAGE = True
-def build_traits(ext_modules, packages):
- global BUILT_TRAITS
- if BUILT_TRAITS:
- return # only build it if you you haven't already
- ctraits = Extension('enthought.traits.ctraits',
- ['lib/enthought/traits/ctraits.c'])
- ext_modules.append(ctraits)
- packages.extend(['enthought',
- 'enthought/etsconfig',
- 'enthought/traits',
- 'enthought/traits/ui',
- 'enthought/traits/ui/extras',
- 'enthought/traits/ui/null',
- 'enthought/traits/ui/tk',
- ])
- BUILT_TRAITS = True
-
def build_delaunay(ext_modules, packages):
global BUILT_DELAUNAY
if BUILT_DELAUNAY:
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 17:03:51
|
Revision: 6668
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6668&view=rev
Author: jdh2358
Date: 2008-12-18 17:03:47 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
retagging for 98.5.2
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-18 17:02:41 UTC (rev 6667)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-18 17:03:47 UTC (rev 6668)
@@ -1,7 +1,7 @@
=======================================================================
-Release 0.98.5.2 at r6665
+Release 0.98.5.3 at r6667
-2008-12-18 Removed configobj and experimental traits - JDH
+2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH
2008-12-18 Fix bug where a line with NULL data limits prevents
subsequent data limits from calculating correctly - MGD
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 17:02:45
|
Revision: 6667
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6667&view=rev
Author: jdh2358
Date: 2008-12-18 17:02:41 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
removed mpl_data
Removed Paths:
-------------
branches/v0_98_5_maint/doc/mpl_data
Deleted: branches/v0_98_5_maint/doc/mpl_data
===================================================================
--- branches/v0_98_5_maint/doc/mpl_data 2008-12-18 16:31:44 UTC (rev 6666)
+++ branches/v0_98_5_maint/doc/mpl_data 2008-12-18 17:02:41 UTC (rev 6667)
@@ -1 +0,0 @@
-link ../lib/matplotlib/mpl-data/
\ No newline at end of file
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 16:31:49
|
Revision: 6666
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6666&view=rev
Author: jdh2358
Date: 2008-12-18 16:31:44 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
tagging release 0.98.5.2
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
branches/v0_98_5_maint/doc/api/api_changes.rst
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-18 16:29:51 UTC (rev 6665)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-18 16:31:44 UTC (rev 6666)
@@ -1,4 +1,8 @@
+=======================================================================
+Release 0.98.5.2 at r6665
+2008-12-18 Removed configobj and experimental traits - JDH
+
2008-12-18 Fix bug where a line with NULL data limits prevents
subsequent data limits from calculating correctly - MGD
Modified: branches/v0_98_5_maint/doc/api/api_changes.rst
===================================================================
--- branches/v0_98_5_maint/doc/api/api_changes.rst 2008-12-18 16:29:51 UTC (rev 6665)
+++ branches/v0_98_5_maint/doc/api/api_changes.rst 2008-12-18 16:31:44 UTC (rev 6666)
@@ -8,6 +8,7 @@
Changes for 0.98.x
==================
+* Removed the configobj and experiemtnal traits rc support
* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`,
:func:`matplotlib.mlab.cohere`, and :func:`matplotlib.mlab.specgram`
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <jd...@us...> - 2008-12-18 16:29:54
|
Revision: 6665
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6665&view=rev
Author: jdh2358
Date: 2008-12-18 16:29:51 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
removed some configobj and traits detritus
Modified Paths:
--------------
branches/v0_98_5_maint/CHANGELOG
branches/v0_98_5_maint/setup.py
branches/v0_98_5_maint/setupext.py
Removed Paths:
-------------
branches/v0_98_5_maint/lib/configobj.py
branches/v0_98_5_maint/lib/enthought/
Modified: branches/v0_98_5_maint/CHANGELOG
===================================================================
--- branches/v0_98_5_maint/CHANGELOG 2008-12-18 15:38:33 UTC (rev 6664)
+++ branches/v0_98_5_maint/CHANGELOG 2008-12-18 16:29:51 UTC (rev 6665)
@@ -1,3 +1,4 @@
+
2008-12-18 Fix bug where a line with NULL data limits prevents
subsequent data limits from calculating correctly - MGD
Deleted: branches/v0_98_5_maint/lib/configobj.py
===================================================================
--- branches/v0_98_5_maint/lib/configobj.py 2008-12-18 15:38:33 UTC (rev 6664)
+++ branches/v0_98_5_maint/lib/configobj.py 2008-12-18 16:29:51 UTC (rev 6665)
@@ -1,2279 +0,0 @@
-# configobj.py
-# A config file reader/writer that supports nested sections in config files.
-# Copyright (C) 2005-2006 Michael Foord, Nicola Larosa
-# E-mail: fuzzyman AT voidspace DOT org DOT uk
-# nico AT tekNico DOT net
-
-# ConfigObj 4
-# http://www.voidspace.org.uk/python/configobj.html
-
-# Released subject to the BSD License
-# Please see http://www.voidspace.org.uk/python/license.shtml
-
-# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
-# For information about bugfixes, updates and support, please join the
-# ConfigObj mailing list:
-# http://lists.sourceforge.net/lists/listinfo/configobj-develop
-# Comments, suggestions and bug reports welcome.
-
-from __future__ import generators
-
-import sys
-INTP_VER = sys.version_info[:2]
-if INTP_VER < (2, 2):
- raise RuntimeError("Python v.2.2 or later needed")
-
-import os, re
-compiler = None
-try:
- import compiler
-except ImportError:
- # for IronPython
- pass
-from types import StringTypes
-from warnings import warn
-try:
- from codecs import BOM_UTF8, BOM_UTF16, BOM_UTF16_BE, BOM_UTF16_LE
-except ImportError:
- # Python 2.2 does not have these
- # UTF-8
- BOM_UTF8 = '\xef\xbb\xbf'
- # UTF-16, little endian
- BOM_UTF16_LE = '\xff\xfe'
- # UTF-16, big endian
- BOM_UTF16_BE = '\xfe\xff'
- if sys.byteorder == 'little':
- # UTF-16, native endianness
- BOM_UTF16 = BOM_UTF16_LE
- else:
- # UTF-16, native endianness
- BOM_UTF16 = BOM_UTF16_BE
-
-# A dictionary mapping BOM to
-# the encoding to decode with, and what to set the
-# encoding attribute to.
-BOMS = {
- BOM_UTF8: ('utf_8', None),
- BOM_UTF16_BE: ('utf16_be', 'utf_16'),
- BOM_UTF16_LE: ('utf16_le', 'utf_16'),
- BOM_UTF16: ('utf_16', 'utf_16'),
- }
-# All legal variants of the BOM codecs.
-# TODO: the list of aliases is not meant to be exhaustive, is there a
-# better way ?
-BOM_LIST = {
- 'utf_16': 'utf_16',
- 'u16': 'utf_16',
- 'utf16': 'utf_16',
- 'utf-16': 'utf_16',
- 'utf16_be': 'utf16_be',
- 'utf_16_be': 'utf16_be',
- 'utf-16be': 'utf16_be',
- 'utf16_le': 'utf16_le',
- 'utf_16_le': 'utf16_le',
- 'utf-16le': 'utf16_le',
- 'utf_8': 'utf_8',
- 'u8': 'utf_8',
- 'utf': 'utf_8',
- 'utf8': 'utf_8',
- 'utf-8': 'utf_8',
- }
-
-# Map of encodings to the BOM to write.
-BOM_SET = {
- 'utf_8': BOM_UTF8,
- 'utf_16': BOM_UTF16,
- 'utf16_be': BOM_UTF16_BE,
- 'utf16_le': BOM_UTF16_LE,
- None: BOM_UTF8
- }
-
-try:
- from validate import VdtMissingValue
-except ImportError:
- VdtMissingValue = None
-
-try:
- enumerate
-except NameError:
- def enumerate(obj):
- """enumerate for Python 2.2."""
- i = -1
- for item in obj:
- i += 1
- yield i, item
-
-try:
- True, False
-except NameError:
- True, False = 1, 0
-
-
-__version__ = '4.4.0-mpl'
-
-__revision__ = '$Id: configobj.py 156 2006-01-31 14:57:08Z fuzzyman $'
-
-__docformat__ = "restructuredtext en"
-
-__all__ = (
- '__version__',
- 'DEFAULT_INDENT_TYPE',
- 'DEFAULT_INTERPOLATION',
- 'ConfigObjError',
- 'NestingError',
- 'ParseError',
- 'DuplicateError',
- 'ConfigspecError',
- 'ConfigObj',
- 'SimpleVal',
- 'InterpolationError',
- 'InterpolationLoopError',
- 'MissingInterpolationOption',
- 'RepeatSectionError',
- 'UnreprError',
- 'UnknownType',
- '__docformat__',
- 'flatten_errors',
-)
-
-DEFAULT_INTERPOLATION = 'configparser'
-DEFAULT_INDENT_TYPE = ' '
-MAX_INTERPOL_DEPTH = 10
-
-OPTION_DEFAULTS = {
- 'interpolation': True,
- 'raise_errors': False,
- 'list_values': True,
- 'create_empty': False,
- 'file_error': False,
- 'configspec': None,
- 'stringify': True,
- # option may be set to one of ('', ' ', '\t')
- 'indent_type': None,
- 'encoding': None,
- 'default_encoding': None,
- 'unrepr': False,
- 'write_empty_values': False,
-}
-
-
-def getObj(s):
- s = "a=" + s
- if compiler is None:
- raise ImportError('compiler module not available')
- p = compiler.parse(s)
- return p.getChildren()[1].getChildren()[0].getChildren()[1]
-
-class UnknownType(Exception):
- pass
-
-class Builder:
-
- def build(self, o):
- m = getattr(self, 'build_' + o.__class__.__name__, None)
- if m is None:
- raise UnknownType(o.__class__.__name__)
- return m(o)
-
- def build_List(self, o):
- return map(self.build, o.getChildren())
-
- def build_Const(self, o):
- return o.value
-
- def build_Dict(self, o):
- d = {}
- i = iter(map(self.build, o.getChildren()))
- for el in i:
- d[el] = i.next()
- return d
-
- def build_Tuple(self, o):
- return tuple(self.build_List(o))
-
- def build_Name(self, o):
- if o.name == 'None':
- return None
- if o.name == 'True':
- return True
- if o.name == 'False':
- return False
-
- # An undefinted Name
- raise UnknownType('Undefined Name')
-
- def build_Add(self, o):
- real, imag = map(self.build_Const, o.getChildren())
- try:
- real = float(real)
- except TypeError:
- raise UnknownType('Add')
- if not isinstance(imag, complex) or imag.real != 0.0:
- raise UnknownType('Add')
- return real+imag
-
- def build_Getattr(self, o):
- parent = self.build(o.expr)
- return getattr(parent, o.attrname)
-
- def build_UnarySub(self, o):
- return -self.build_Const(o.getChildren()[0])
-
- def build_UnaryAdd(self, o):
- return self.build_Const(o.getChildren()[0])
-
-def unrepr(s):
- if not s:
- return s
- return Builder().build(getObj(s))
-
-def _splitlines(instring):
- """Split a string on lines, without losing line endings or truncating."""
-
-
-class ConfigObjError(SyntaxError):
- """
- This is the base class for all errors that ConfigObj raises.
- It is a subclass of SyntaxError.
- """
- def __init__(self, message='', line_number=None, line=''):
- self.line = line
- self.line_number = line_number
- self.message = message
- SyntaxError.__init__(self, message)
-
-class NestingError(ConfigObjError):
- """
- This error indicates a level of nesting that doesn't match.
- """
-
-class ParseError(ConfigObjError):
- """
- This error indicates that a line is badly written.
- It is neither a valid ``key = value`` line,
- nor a valid section marker line.
- """
-
-class DuplicateError(ConfigObjError):
- """
- The keyword or section specified already exists.
- """
-
-class ConfigspecError(ConfigObjError):
- """
- An error occured whilst parsing a configspec.
- """
-
-class InterpolationError(ConfigObjError):
- """Base class for the two interpolation errors."""
-
-class InterpolationLoopError(InterpolationError):
- """Maximum interpolation depth exceeded in string interpolation."""
-
- def __init__(self, option):
- InterpolationError.__init__(
- self,
- 'interpolation loop detected in value "%s".' % option)
-
-class RepeatSectionError(ConfigObjError):
- """
- This error indicates additional sections in a section with a
- ``__many__`` (repeated) section.
- """
-
-class MissingInterpolationOption(InterpolationError):
- """A value specified for interpolation was missing."""
-
- def __init__(self, option):
- InterpolationError.__init__(
- self,
- 'missing option "%s" in interpolation.' % option)
-
-class UnreprError(ConfigObjError):
- """An error parsing in unrepr mode."""
-
-
-class InterpolationEngine(object):
- """
- A helper class to help perform string interpolation.
-
- This class is an abstract base class; its descendants perform
- the actual work.
- """
-
- # compiled regexp to use in self.interpolate()
- _KEYCRE = re.compile(r"%\(([^)]*)\)s")
-
- def __init__(self, section):
- # the Section instance that "owns" this engine
- self.section = section
-
- def interpolate(self, key, value):
- def recursive_interpolate(key, value, section, backtrail):
- """The function that does the actual work.
-
- ``value``: the string we're trying to interpolate.
- ``section``: the section in which that string was found
- ``backtrail``: a dict to keep track of where we've been,
- to detect and prevent infinite recursion loops
-
- This is similar to a depth-first-search algorithm.
- """
- # Have we been here already?
- if backtrail.has_key((key, section.name)):
- # Yes - infinite loop detected
- raise InterpolationLoopError(key)
- # Place a marker on our backtrail so we won't come back here again
- backtrail[(key, section.name)] = 1
-
- # Now start the actual work
- match = self._KEYCRE.search(value)
- while match:
- # The actual parsing of the match is implementation-dependent,
- # so delegate to our helper function
- k, v, s = self._parse_match(match)
- if k is None:
- # That's the signal that no further interpolation is needed
- replacement = v
- else:
- # Further interpolation may be needed to obtain final value
- replacement = recursive_interpolate(k, v, s, backtrail)
- # Replace the matched string with its final value
- start, end = match.span()
- value = ''.join((value[:start], replacement, value[end:]))
- new_search_start = start + len(replacement)
- # Pick up the next interpolation key, if any, for next time
- # through the while loop
- match = self._KEYCRE.search(value, new_search_start)
-
- # Now safe to come back here again; remove marker from backtrail
- del backtrail[(key, section.name)]
-
- return value
-
- # Back in interpolate(), all we have to do is kick off the recursive
- # function with appropriate starting values
- value = recursive_interpolate(key, value, self.section, {})
- return value
-
- def _fetch(self, key):
- """Helper function to fetch values from owning section.
-
- Returns a 2-tuple: the value, and the section where it was found.
- """
- # switch off interpolation before we try and fetch anything !
- save_interp = self.section.main.interpolation
- self.section.main.interpolation = False
-
- # Start at section that "owns" this InterpolationEngine
- current_section = self.section
- while True:
- # try the current section first
- val = current_section.get(key)
- if val is not None:
- break
- # try "DEFAULT" next
- val = current_section.get('DEFAULT', {}).get(key)
- if val is not None:
- break
- # move up to parent and try again
- # top-level's parent is itself
- if current_section.parent is current_section:
- # reached top level, time to give up
- break
- current_section = current_section.parent
-
- # restore interpolation to previous value before returning
- self.section.main.interpolation = save_interp
- if val is None:
- raise MissingInterpolationOption(key)
- return val, current_section
-
- def _parse_match(self, match):
- """Implementation-dependent helper function.
-
- Will be passed a match object corresponding to the interpolation
- key we just found (e.g., "%(foo)s" or "$foo"). Should look up that
- key in the appropriate config file section (using the ``_fetch()``
- helper function) and return a 3-tuple: (key, value, section)
-
- ``key`` is the name of the key we're looking for
- ``value`` is the value found for that key
- ``section`` is a reference to the section where it was found
-
- ``key`` and ``section`` should be None if no further
- interpolation should be performed on the resulting value
- (e.g., if we interpolated "$$" and returned "$").
- """
- raise NotImplementedError
-
-
-class ConfigParserInterpolation(InterpolationEngine):
- """Behaves like ConfigParser."""
- _KEYCRE = re.compile(r"%\(([^)]*)\)s")
-
- def _parse_match(self, match):
- key = match.group(1)
- value, section = self._fetch(key)
- return key, value, section
-
-
-class TemplateInterpolation(InterpolationEngine):
- """Behaves like string.Template."""
- _delimiter = '$'
- _KEYCRE = re.compile(r"""
- \$(?:
- (?P<escaped>\$) | # Two $ signs
- (?P<named>[_a-z][_a-z0-9]*) | # $name format
- {(?P<braced>[^}]*)} # ${name} format
- )
- """, re.IGNORECASE | re.VERBOSE)
-
- def _parse_match(self, match):
- # Valid name (in or out of braces): fetch value from section
- key = match.group('named') or match.group('braced')
- if key is not None:
- value, section = self._fetch(key)
- return key, value, section
- # Escaped delimiter (e.g., $$): return single delimiter
- if match.group('escaped') is not None:
- # Return None for key and section to indicate it's time to stop
- return None, self._delimiter, None
- # Anything else: ignore completely, just return it unchanged
- return None, match.group(), None
-
-interpolation_engines = {
- 'configparser': ConfigParserInterpolation,
- 'template': TemplateInterpolation,
-}
-
-class Section(dict):
- """
- A dictionary-like object that represents a section in a config file.
-
- It does string interpolation if the 'interpolation' attribute
- of the 'main' object is set to True.
-
- Interpolation is tried first from this object, then from the 'DEFAULT'
- section of this object, next from the parent and its 'DEFAULT' section,
- and so on until the main object is reached.
-
- A Section will behave like an ordered dictionary - following the
- order of the ``scalars`` and ``sections`` attributes.
- You can use this to change the order of members.
-
- Iteration follows the order: scalars, then sections.
- """
-
- def __init__(self, parent, depth, main, indict=None, name=None):
- """
- * parent is the section above
- * depth is the depth level of this section
- * main is the main ConfigObj
- * indict is a dictionary to initialise the section with
- """
- if indict is None:
- indict = {}
- dict.__init__(self)
- # used for nesting level *and* interpolation
- self.parent = parent
- # used for the interpolation attribute
- self.main = main
- # level of nesting depth of this Section
- self.depth = depth
- # the sequence of scalar values in this Section
- self.scalars = []
- # the sequence of sections in this Section
- self.sections = []
- # purely for information
- self.name = name
- # for comments :-)
- self.comments = {}
- self.inline_comments = {}
- # for the configspec
- self.configspec = {}
- self._order = []
- self._configspec_comments = {}
- self._configspec_inline_comments = {}
- self._cs_section_comments = {}
- self._cs_section_inline_comments = {}
- # for defaults
- self.defaults = []
- #
- # we do this explicitly so that __setitem__ is used properly
- # (rather than just passing to ``dict.__init__``)
- for entry in indict:
- self[entry] = indict[entry]
-
- def _interpolate(self, key, value):
- try:
- # do we already have an interpolation engine?
- engine = self._interpolation_engine
- except AttributeError:
- # not yet: first time running _interpolate(), so pick the engine
- name = self.main.interpolation
- if name == True: # note that "if name:" would be incorrect here
- # backwards-compatibility: interpolation=True means use default
- name = DEFAULT_INTERPOLATION
- name = name.lower() # so that "Template", "template", etc. all work
- class_ = interpolation_engines.get(name, None)
- if class_ is None:
- # invalid value for self.main.interpolation
- self.main.interpolation = False
- return value
- else:
- # save reference to engine so we don't have to do this again
- engine = self._interpolation_engine = class_(self)
- # let the engine do the actual work
- return engine.interpolate(key, value)
-
- def __getitem__(self, key):
- """Fetch the item and do string interpolation."""
- val = dict.__getitem__(self, key)
- if self.main.interpolation and isinstance(val, StringTypes):
- return self._interpolate(key, val)
- return val
-
- def __setitem__(self, key, value, unrepr=False):
- """
- Correctly set a value.
-
- Making dictionary values Section instances.
- (We have to special case 'Section' instances - which are also dicts)
-
- Keys must be strings.
- Values need only be strings (or lists of strings) if
- ``main.stringify`` is set.
-
- `unrepr`` must be set when setting a value to a dictionary, without
- creating a new sub-section.
- """
- if not isinstance(key, StringTypes):
- raise ValueError, 'The key "%s" is not a string.' % key
- # add the comment
- if not self.comments.has_key(key):
- self.comments[key] = []
- self.inline_comments[key] = ''
- # remove the entry from defaults
- if key in self.defaults:
- self.defaults.remove(key)
- #
- if isinstance(value, Section):
- if not self.has_key(key):
- self.sections.append(key)
- dict.__setitem__(self, key, value)
- elif isinstance(value, dict) and not unrepr:
- # First create the new depth level,
- # then create the section
- if not self.has_key(key):
- self.sections.append(key)
- new_depth = self.depth + 1
- dict.__setitem__(
- self,
- key,
- Section(
- self,
- new_depth,
- self.main,
- indict=value,
- name=key))
- else:
- if not self.has_key(key):
- self.scalars.append(key)
- if not self.main.stringify:
- if isinstance(value, StringTypes):
- pass
- elif isinstance(value, (list, tuple)):
- for entry in value:
- if not isinstance(entry, StringTypes):
- raise TypeError, (
- 'Value is not a string "%s".' % entry)
- else:
- raise TypeError, 'Value is not a string "%s".' % value
- dict.__setitem__(self, key, value)
-
- def __delitem__(self, key):
- """Remove items from the sequence when deleting."""
- dict. __delitem__(self, key)
- if key in self.scalars:
- self.scalars.remove(key)
- else:
- self.sections.remove(key)
- del self.comments[key]
- del self.inline_comments[key]
-
- def get(self, key, default=None):
- """A version of ``get`` that doesn't bypass string interpolation."""
- try:
- return self[key]
- except KeyError:
- return default
-
- def update(self, indict):
- """
- A version of update that uses our ``__setitem__``.
- """
- for entry in indict:
- self[entry] = indict[entry]
-
- def pop(self, key, *args):
- """ """
- val = dict.pop(self, key, *args)
- if key in self.scalars:
- del self.comments[key]
- del self.inline_comments[key]
- self.scalars.remove(key)
- elif key in self.sections:
- del self.comments[key]
- del self.inline_comments[key]
- self.sections.remove(key)
- if self.main.interpolation and isinstance(val, StringTypes):
- return self._interpolate(key, val)
- return val
-
- def popitem(self):
- """Pops the first (key,val)"""
- sequence = (self.scalars + self.sections)
- if not sequence:
- raise KeyError, ": 'popitem(): dictionary is empty'"
- key = sequence[0]
- val = self[key]
- del self[key]
- return key, val
-
- def clear(self):
- """
- A version of clear that also affects scalars/sections
- Also clears comments and configspec.
-
- Leaves other attributes alone :
- depth/main/parent are not affected
- """
- dict.clear(self)
- self.scalars = []
- self.sections = []
- self.comments = {}
- self.inline_comments = {}
- self.configspec = {}
-
- def setdefault(self, key, default=None):
- """A version of setdefault that sets sequence if appropriate."""
- try:
- return self[key]
- except KeyError:
- self[key] = default
- return self[key]
-
- def items(self):
- """ """
- return zip((self.scalars + self.sections), self.values())
-
- def keys(self):
- """ """
- return (self.scalars + self.sections)
-
- def values(self):
- """ """
- return [self[key] for key in (self.scalars + self.sections)]
-
- def iteritems(self):
- """ """
- return iter(self.items())
-
- def iterkeys(self):
- """ """
- return iter((self.scalars + self.sections))
-
- __iter__ = iterkeys
-
- def itervalues(self):
- """ """
- return iter(self.values())
-
- def __repr__(self):
- return '{%s}' % ', '.join([('%s: %s' % (repr(key), repr(self[key])))
- for key in (self.scalars + self.sections)])
-
- __str__ = __repr__
-
- # Extra methods - not in a normal dictionary
-
- def dict(self):
- """
- Return a deepcopy of self as a dictionary.
-
- All members that are ``Section`` instances are recursively turned to
- ordinary dictionaries - by calling their ``dict`` method.
-
- >>> n = a.dict()
- >>> n == a
- 1
- >>> n is a
- 0
- """
- newdict = {}
- for entry in self:
- this_entry = self[entry]
- if isinstance(this_entry, Section):
- this_entry = this_entry.dict()
- elif isinstance(this_entry, list):
- # create a copy rather than a reference
- this_entry = list(this_entry)
- elif isinstance(this_entry, tuple):
- # create a copy rather than a reference
- this_entry = tuple(this_entry)
- newdict[entry] = this_entry
- return newdict
-
- def merge(self, indict):
- """
- A recursive update - useful for merging config files.
-
- >>> a = '''[section1]
- ... option1 = True
- ... [[subsection]]
- ... more_options = False
- ... # end of file'''.splitlines()
- >>> b = '''# File is user.ini
- ... [section1]
- ... option1 = False
- ... # end of file'''.splitlines()
- >>> c1 = ConfigObj(b)
- >>> c2 = ConfigObj(a)
- >>> c2.merge(c1)
- >>> c2
- {'section1': {'option1': 'False', 'subsection': {'more_options': 'False'}}}
- """
- for key, val in indict.items():
- if (key in self and isinstance(self[key], dict) and
- isinstance(val, dict)):
- self[key].merge(val)
- else:
- self[key] = val
-
- def rename(self, oldkey, newkey):
- """
- Change a keyname to another, without changing position in sequence.
-
- Implemented so that transformations can be made on keys,
- as well as on values. (used by encode and decode)
-
- Also renames comments.
- """
- if oldkey in self.scalars:
- the_list = self.scalars
- elif oldkey in self.sections:
- the_list = self.sections
- else:
- raise KeyError, 'Key "%s" not found.' % oldkey
- pos = the_list.index(oldkey)
- #
- val = self[oldkey]
- dict.__delitem__(self, oldkey)
- dict.__setitem__(self, newkey, val)
- the_list.remove(oldkey)
- the_list.insert(pos, newkey)
- comm = self.comments[oldkey]
- inline_comment = self.inline_comments[oldkey]
- del self.comments[oldkey]
- del self.inline_comments[oldkey]
- self.comments[newkey] = comm
- self.inline_comments[newkey] = inline_comment
-
- def walk(self, function, raise_errors=True,
- call_on_sections=False, **keywargs):
- """
- Walk every member and call a function on the keyword and value.
-
- Return a dictionary of the return values
-
- If the function raises an exception, raise the errror
- unless ``raise_errors=False``, in which case set the return value to
- ``False``.
-
- Any unrecognised keyword arguments you pass to walk, will be pased on
- to the function you pass in.
-
- Note: if ``call_on_sections`` is ``True`` then - on encountering a
- subsection, *first* the function is called for the *whole* subsection,
- and then recurses into it's members. This means your function must be
- able to handle strings, dictionaries and lists. This allows you
- to change the key of subsections as well as for ordinary members. The
- return value when called on the whole subsection has to be discarded.
-
- See the encode and decode methods for examples, including functions.
-
- .. caution::
-
- You can use ``walk`` to transform the names of members of a section
- but you mustn't add or delete members.
-
- >>> config = '''[XXXXsection]
- ... XXXXkey = XXXXvalue'''.splitlines()
- >>> cfg = ConfigObj(config)
- >>> cfg
- {'XXXXsection': {'XXXXkey': 'XXXXvalue'}}
- >>> def transform(section, key):
- ... val = section[key]
- ... newkey = key.replace('XXXX', 'CLIENT1')
- ... section.rename(key, newkey)
- ... if isinstance(val, (tuple, list, dict)):
- ... pass
- ... else:
- ... val = val.replace('XXXX', 'CLIENT1')
- ... section[newkey] = val
- >>> cfg.walk(transform, call_on_sections=True)
- {'CLIENT1section': {'CLIENT1key': None}}
- >>> cfg
- {'CLIENT1section': {'CLIENT1key': 'CLIENT1value'}}
- """
- out = {}
- # scalars first
- for i in range(len(self.scalars)):
- entry = self.scalars[i]
- try:
- val = function(self, entry, **keywargs)
- # bound again in case name has changed
- entry = self.scalars[i]
- out[entry] = val
- except Exception:
- if raise_errors:
- raise
- else:
- entry = self.scalars[i]
- out[entry] = False
- # then sections
- for i in range(len(self.sections)):
- entry = self.sections[i]
- if call_on_sections:
- try:
- function(self, entry, **keywargs)
- except Exception:
- if raise_errors:
- raise
- else:
- entry = self.sections[i]
- out[entry] = False
- # bound again in case name has changed
- entry = self.sections[i]
- # previous result is discarded
- out[entry] = self[entry].walk(
- function,
- raise_errors=raise_errors,
- call_on_sections=call_on_sections,
- **keywargs)
- return out
-
- def decode(self, encoding):
- """
- Decode all strings and values to unicode, using the specified encoding.
-
- Works with subsections and list values.
-
- Uses the ``walk`` method.
-
- Testing ``encode`` and ``decode``.
- >>> m = ConfigObj(a)
- >>> m.decode('ascii')
- >>> def testuni(val):
- ... for entry in val:
- ... if not isinstance(entry, unicode):
- ... print >> sys.stderr, type(entry)
- ... raise AssertionError, 'decode failed.'
- ... if isinstance(val[entry], dict):
- ... testuni(val[entry])
- ... elif not isinstance(val[entry], unicode):
- ... raise AssertionError, 'decode failed.'
- >>> testuni(m)
- >>> m.encode('ascii')
- >>> a == m
- 1
- """
- warn('use of ``decode`` is deprecated.', DeprecationWarning)
- def decode(section, key, encoding=encoding, warn=True):
- """ """
- val = section[key]
- if isinstance(val, (list, tuple)):
- newval = []
- for entry in val:
- newval.append(entry.decode(encoding))
- elif isinstance(val, dict):
- newval = val
- else:
- newval = val.decode(encoding)
- newkey = key.decode(encoding)
- section.rename(key, newkey)
- section[newkey] = newval
- # using ``call_on_sections`` allows us to modify section names
- self.walk(decode, call_on_sections=True)
-
- def encode(self, encoding):
- """
- Encode all strings and values from unicode,
- using the specified encoding.
-
- Works with subsections and list values.
- Uses the ``walk`` method.
- """
- warn('use of ``encode`` is deprecated.', DeprecationWarning)
- def encode(section, key, encoding=encoding):
- """ """
- val = section[key]
- if isinstance(val, (list, tuple)):
- newval = []
- for entry in val:
- newval.append(entry.encode(encoding))
- elif isinstance(val, dict):
- newval = val
- else:
- newval = val.encode(encoding)
- newkey = key.encode(encoding)
- section.rename(key, newkey)
- section[newkey] = newval
- self.walk(encode, call_on_sections=True)
-
- def istrue(self, key):
- """A deprecated version of ``as_bool``."""
- warn('use of ``istrue`` is deprecated. Use ``as_bool`` method '
- 'instead.', DeprecationWarning)
- return self.as_bool(key)
-
- def as_bool(self, key):
- """
- Accepts a key as input. The corresponding value must be a string or
- the objects (``True`` or 1) or (``False`` or 0). We allow 0 and 1 to
- retain compatibility with Python 2.2.
-
- If the string is one of ``True``, ``On``, ``Yes``, or ``1`` it returns
- ``True``.
-
- If the string is one of ``False``, ``Off``, ``No``, or ``0`` it returns
- ``False``.
-
- ``as_bool`` is not case sensitive.
-
- Any other input will raise a ``ValueError``.
-
- >>> a = ConfigObj()
- >>> a['a'] = 'fish'
- >>> a.as_bool('a')
- Traceback (most recent call last):
- ValueError: Value "fish" is neither True nor False
- >>> a['b'] = 'True'
- >>> a.as_bool('b')
- 1
- >>> a['b'] = 'off'
- >>> a.as_bool('b')
- 0
- """
- val = self[key]
- if val == True:
- return True
- elif val == False:
- return False
- else:
- try:
- if not isinstance(val, StringTypes):
- raise KeyError
- else:
- return self.main._bools[val.lower()]
- except KeyError:
- raise ValueError('Value "%s" is neither True nor False' % val)
-
- def as_int(self, key):
- """
- A convenience method which coerces the specified value to an integer.
-
- If the value is an invalid literal for ``int``, a ``ValueError`` will
- be raised.
-
- >>> a = ConfigObj()
- >>> a['a'] = 'fish'
- >>> a.as_int('a')
- Traceback (most recent call last):
- ValueError: invalid literal for int(): fish
- >>> a['b'] = '1'
- >>> a.as_int('b')
- 1
- >>> a['b'] = '3.2'
- >>> a.as_int('b')
- Traceback (most recent call last):
- ValueError: invalid literal for int(): 3.2
- """
- return int(self[key])
-
- def as_float(self, key):
- """
- A convenience method which coerces the specified value to a float.
-
- If the value is an invalid literal for ``float``, a ``ValueError`` will
- be raised.
-
- >>> a = ConfigObj()
- >>> a['a'] = 'fish'
- >>> a.as_float('a')
- Traceback (most recent call last):
- ValueError: invalid literal for float(): fish
- >>> a['b'] = '1'
- >>> a.as_float('b')
- 1.0
- >>> a['b'] = '3.2'
- >>> a.as_float('b')
- 3.2000000000000002
- """
- return float(self[key])
-
-
-class ConfigObj(Section):
- """An object to read, create, and write config files."""
-
- _keyword = re.compile(r'''^ # line start
- (\s*) # indentation
- ( # keyword
- (?:".*?")| # double quotes
- (?:'.*?')| # single quotes
- (?:[^'"=].*?) # no quotes
- )
- \s*=\s* # divider
- (.*) # value (including list values and comments)
- $ # line end
- ''',
- re.VERBOSE)
-
- _sectionmarker = re.compile(r'''^
- (\s*) # 1: indentation
- ((?:\[\s*)+) # 2: section marker open
- ( # 3: section name open
- (?:"\s*\S.*?\s*")| # at least one non-space with double quotes
- (?:'\s*\S.*?\s*')| # at least one non-space with single quotes
- (?:[^'"\s].*?) # at least one non-space unquoted
- ) # section name close
- ((?:\s*\])+) # 4: section marker close
- \s*(\#.*)? # 5: optional comment
- $''',
- re.VERBOSE)
-
- # this regexp pulls list values out as a single string
- # or single values and comments
- # FIXME: this regex adds a '' to the end of comma terminated lists
- # workaround in ``_handle_value``
- _valueexp = re.compile(r'''^
- (?:
- (?:
- (
- (?:
- (?:
- (?:".*?")| # double quotes
- (?:'.*?')| # single quotes
- (?:[^'",\#][^,\#]*?) # unquoted
- )
- \s*,\s* # comma
- )* # match all list items ending in a comma (if any)
- )
- (
- (?:".*?")| # double quotes
- (?:'.*?')| # single quotes
- (?:[^'",\#\s][^,]*?)| # unquoted
- (?:(?<!,)) # Empty value
- )? # last item in a list - or string value
- )|
- (,) # alternatively a single comma - empty list
- )
- \s*(\#.*)? # optional comment
- $''',
- re.VERBOSE)
-
- # use findall to get the members of a list value
- _listvalueexp = re.compile(r'''
- (
- (?:".*?")| # double quotes
- (?:'.*?')| # single quotes
- (?:[^'",\#].*?) # unquoted
- )
- \s*,\s* # comma
- ''',
- re.VERBOSE)
-
- # this regexp is used for the value
- # when lists are switched off
- _nolistvalue = re.compile(r'''^
- (
- (?:".*?")| # double quotes
- (?:'.*?')| # single quotes
- (?:[^'"\#].*?)| # unquoted
- (?:) # Empty value
- )
- \s*(\#.*)? # optional comment
- $''',
- re.VERBOSE)
-
- # regexes for finding triple quoted values on one line
- _single_line_single = re.compile(r"^'''(.*?)'''\s*(#.*)?$")
- _single_line_double = re.compile(r'^"""(.*?)"""\s*(#.*)?$')
- _multi_line_single = re.compile(r"^(.*?)'''\s*(#.*)?$")
- _multi_line_double = re.compile(r'^(.*?)"""\s*(#.*)?$')
-
- _triple_quote = {
- "'''": (_single_line_single, _multi_line_single),
- '"""': (_single_line_double, _multi_line_double),
- }
-
- # Used by the ``istrue`` Section method
- _bools = {
- 'yes': True, 'no': False,
- 'on': True, 'off': False,
- '1': True, '0': False,
- 'true': True, 'false': False,
- }
-
- def __init__(self, infile=None, options=None, **kwargs):
- """
- Parse or create a config file object.
-
- ``ConfigObj(infile=None, options=None, **kwargs)``
- """
- if infile is None:
- infile = []
- if options is None:
- options = {}
- else:
- options = dict(options)
- # keyword arguments take precedence over an options dictionary
- options.update(kwargs)
- # init the superclass
- Section.__init__(self, self, 0, self)
- #
- defaults = OPTION_DEFAULTS.copy()
- for entry in options.keys():
- if entry not in defaults.keys():
- raise TypeError, 'Unrecognised option "%s".' % entry
- # TODO: check the values too.
- #
- # Add any explicit options to the defaults
- defaults.update(options)
- #
- # initialise a few variables
- self.filename = None
- self._errors = []
- self.raise_errors = defaults['raise_errors']
- self.interpolation = defaults['interpolation']
- self.list_values = defaults['list_values']
- self.create_empty = defaults['create_empty']
- self.file_error = defaults['file_error']
- self.stringify = defaults['stringify']
- self.indent_type = defaults['indent_type']
- self.encoding = defaults['encoding']
- self.default_encoding = defaults['default_encoding']
- self.BOM = False
- self.newlines = None
- self.write_empty_values = defaults['write_empty_values']
- self.unrepr = defaults['unrepr']
- #
- self.initial_comment = []
- self.final_comment = []
- #
- self._terminated = False
- #
- if isinstance(infile, StringTypes):
- self.filename = infile
- if os.path.isfile(infile):
- infile = open(infile).read() or []
- elif self.file_error:
- # raise an error if the file doesn't exist
- raise IOError, 'Config file not found: "%s".' % self.filename
- else:
- # file doesn't already exist
- if self.create_empty:
- # this is a good test that the filename specified
- # isn't impossible - like on a non existent device
- h = open(infile, 'w')
- h.write('')
- h.close()
- infile = []
- elif isinstance(infile, (list, tuple)):
- infile = list(infile)
- elif isinstance(infile, dict):
- # initialise self
- # the Section class handles creating subsections
- if isinstance(infile, ConfigObj):
- # get a copy of our ConfigObj
- infile = infile.dict()
- for entry in infile:
- self[entry] = infile[entry]
- del self._errors
- if defaults['configspec'] is not None:
- self._handle_configspec(defaults['configspec'])
- else:
- self.configspec = None
- return
- elif hasattr(infile, 'read'):
- # This supports file like objects
- infile = infile.read() or []
- # needs splitting into lines - but needs doing *after* decoding
- # in case it's not an 8 bit encoding
- else:
- raise TypeError, ('infile must be a filename,'
- ' file like object, or list of lines.')
- #
- if infile:
- # don't do it for the empty ConfigObj
- infile = self._handle_bom(infile)
- # infile is now *always* a list
- #
- # Set the newlines attribute (first line ending it finds)
- # and strip trailing '\n' or '\r' from lines
- for line in infile:
- if (not line) or (line[-1] not in ('\r', '\n', '\r\n')):
- continue
- for end in ('\r\n', '\n', '\r'):
- if line.endswith(end):
- self.newlines = end
- break
- break
- if infile[-1] and infile[-1] in ('\r', '\n', '\r\n'):
- self._terminated = True
- infile = [line.rstrip('\r\n') for line in infile]
- #
- self._parse(infile)
- # if we had any errors, now is the time to raise them
- if self._errors:
- info = "at line %s." % self._errors[0].line_number
- if len(self._errors) > 1:
- msg = ("Parsing failed with several errors.\nFirst error %s" %
- info)
- error = ConfigObjError(msg)
- else:
- error = self._errors[0]
- # set the errors attribute; it's a list of tuples:
- # (error_type, message, line_number)
- error.errors = self._errors
- # set the config attribute
- error.config = self
- raise error
- # delete private attributes
- del self._errors
- #
- if defaults['configspec'] is None:
- self.configspec = None
- else:
- self._handle_configspec(defaults['configspec'])
-
- def __repr__(self):
- return 'ConfigObj({%s})' % ', '.join(
- [('%s: %s' % (repr(key), repr(self[key]))) for key in
- (self.scalars + self.sections)])
-
- def _handle_bom(self, infile):
- """
- Handle any BOM, and decode if necessary.
-
- If an encoding is specified, that *must* be used - but the BOM should
- still be removed (and the BOM attribute set).
-
- (If the encoding is wrongly specified, then a BOM for an alternative
- encoding won't be discovered or removed.)
-
- If an encoding is not specified, UTF8 or UTF16 BOM will be detected and
- removed. The BOM attribute will be set. UTF16 will be decoded to
- unicode.
-
- NOTE: This method must not be called with an empty ``infile``.
-
- Specifying the *wrong* encoding is likely to cause a
- ``UnicodeDecodeError``.
-
- ``infile`` must always be returned as a list of lines, but may be
- passed in as a single string.
- """
- if ((self.encoding is not None) and
- (self.encoding.lower() not in BOM_LIST)):
- # No need to check for a BOM
- # the encoding specified doesn't have one
- # just decode
- return self._decode(infile, self.encoding)
- #
- if isinstance(infile, (list, tuple)):
- line = infile[0]
- else:
- line = infile
- if self.encoding is not None:
- # encoding explicitly supplied
- # And it could have an associated BOM
- # TODO: if encoding is just UTF16 - we ought to check for both
- # TODO: big endian and little endian versions.
- enc = BOM_LIST[self.encoding.lower()]
- if enc == 'utf_16':
- # For UTF16 we try big endian and little endian
- for BOM, (encoding, final_encoding) in BOMS.items():
- if not final_encoding:
- # skip UTF8
- continue
- if infile.startswith(BOM):
- ### BOM discovered
- ##self.BOM = True
- # Don't need to remove BOM
- return self._decode(infile, encoding)
- #
- # If we get this far, will *probably* raise a DecodeError
- # As it doesn't appear to start with a BOM
- return self._decode(infile, self.encoding)
- #
- # Must be UTF8
- BOM = BOM_SET[enc]
- if not line.startswith(BOM):
- return self._decode(infile, self.encoding)
- #
- newline = line[len(BOM):]
- #
- # BOM removed
- if isinstance(infile, (list, tuple)):
- infile[0] = newline
- else:
- infile = newline
- self.BOM = True
- return self._decode(infile, self.encoding)
- #
- # No encoding specified - so we need to check for UTF8/UTF16
- for BOM, (encoding, final_encoding) in BOMS.items():
- if not line.startswith(BOM):
- continue
- else:
- # BOM discovered
- self.encoding = final_encoding
- if not final_encoding:
- self.BOM = True
- # UTF8
- # remove BOM
- newline = line[len(BOM):]
- if isinstance(infile, (list, tuple)):
- infile[0] = newline
- else:
- infile = newline
- # UTF8 - don't decode
- if isinstance(infile, StringTypes):
- return infile.splitlines(True)
- else:
- return infile
- # UTF16 - have to decode
- return self._decode(infile, encoding)
- #
- # No BOM discovered and no encoding specified, just return
- if isinstance(infile, StringTypes):
- # infile read from a file will be a single string
- return infile.splitlines(True)
- else:
- return infile
-
- def _a_to_u(self, aString):
- """Decode ASCII strings to unicode if a self.encoding is specified."""
- if self.encoding:
- return aString.decode('ascii')
- else:
- return aString
-
- def _decode(self, infile, encoding):
- """
- Decode infile to unicode. Using the specified encoding.
-
- if is a string, it also needs converting to a list.
- """
- if isinstance(infile, StringTypes):
- # can't be unicode
- # NOTE: Could raise a ``UnicodeDecodeError``
- return infile.decode(encoding).splitlines(True)
- for i, line in enumerate(infile):
- if not isinstance(line, unicode):
- # NOTE: The isinstance test here handles mixed lists of unicode/string
- # NOTE: But the decode will break on any non-string values
- # NOTE: Or could raise a ``UnicodeDecodeError``
- infile[i] = line.decode(encoding)
- return infile
-
- def _decode_element(self, line):
- """Decode element to unicode if necessary."""
- if not self.encoding:
- return line
- if isinstance(line, str) and self.default_encoding:
- return line.decode(self.default_encoding)
- return line
-
- def _str(self, value):
- """
- Used by ``stringify`` within validate, to turn non-string values
- into strings.
- """
- if not isinstance(value, StringTypes):
- return str(value)
- else:
- return value
-
- def _parse(self, infile):
- """Actually parse the config file."""
- temp_list_values = self.list_values
- if self.unrepr:
- self.list_values = False
- comment_list = []
- done_start = False
- this_section = self
- maxline = len(infile) - 1
- cur_index = -1
- reset_comment = False
- while cur_index < maxline:
- if reset_comment:
- comment_list = []
- cur_index += 1
- line = infile[cur_index]
- sline = line.strip()
- # do we have anything on the line ?
- if not sline or sline.startswith('#'):
- reset_comment = False
- comment_list.append(line)
- continue
- if not done_start:
- # preserve initial comment
- self.initial_comment = comment_list
- comment_list = []
- done_start = True
- reset_comment = True
- # first we check if it's a section marker
- mat = self._sectionmarker.match(line)
- if mat is not None:
- # is a section line
- (indent, sect_open, sect_name, sect_close, comment) = (
- mat.groups())
- if indent and (self.indent_type is None):
- self.indent_type = indent
- cur_depth = sect_open.count('[')
- if cur_depth != sect_close.count(']'):
- self._handle_error(
- "Cannot compute the section depth at line %s.",
- NestingError, infile, cur_index)
- continue
- #
- if cur_depth < this_section.depth:
- # the new section is dropping back to a previous level
- try:
- parent = self._match_depth(
- this_section,
- cur_depth).parent
- except SyntaxError:
- self._handle_error(
- "Cannot compute nesting level at line %s.",
- NestingError, infile, cur_index)
- continue
- elif cur_depth == this_section.depth:
- # the new section is a sibling of the current section
- parent = this_section.parent
- elif cur_depth == this_section.depth + 1:
- # the new section is a child the current section
- parent = this_section
- else:
- self._handle_error(
- "Section too nested at line %s.",
- NestingError, infile, cur_index)
- #
- sect_name = self._unquote(sect_name)
- if parent.has_key(sect_name):
- self._handle_error(
- 'Duplicate section name at line %s.',
- DuplicateError, infile, cur_index)
- continue
- # create the new section
- this_section = Section(
- parent,
- cur_depth,
- self,
- name=sect_name)
- parent[sect_name] = this_section
- parent.inline_comments[sect_name] = comment
- parent.comments[sect_name] = comment_list
- continue
- #
- # it's not a section marker,
- # so it should be a valid ``key = value`` line
- mat = self._keyword.match(line)
- if mat is None:
- # it neither matched as a keyword
- # or a section marker
- self._handle_error(
- 'Invalid line at line "%s".',
- ParseError, infile, cur_index)
- else:
- # is a keyword value
- # value will include any inline comment
- (indent, key, value) = mat.groups()
- if indent and (self.indent_type is None):
- self.indent_type = indent
- # check for a multiline value
- if value[:3] in ['"""', "'''"]:
- try:
- (value, comment, cur_index) = self._multiline(
- value, infile, cur_index, maxline)
- except SyntaxError:
- self._handle_error(
- 'Parse error in value at line %s.',
- ParseError, infile, cur_index)
- continue
- else:
- if self.unrepr:
- comment = ''
- try:
- value = unrepr(value)
- except Exception, e:
- if type(e) == UnknownType:
- msg = 'Unknown name or type in value at line %s.'
- else:
- msg = 'Parse error in value at line %s.'
- self._handle_error(msg, UnreprError, infile,
- cur_index)
- continue
- else:
- if self.unrepr:
- comment = ''
- try:
- value = unrepr(value)
- except Exception, e:
- if isinstance(e, UnknownType):
- msg = 'Unknown name or type in value at line %s.'
- else:
- msg = 'Parse error in value at line %s.'
- self._handle_error(msg, UnreprError, infile,
- cur_index)
- continue
- else:
- # extract comment and lists
- try:
- (value, comment) = self._handle_value(value)
- except SyntaxError:
- self._handle_error(
- 'Parse error in value at line %s.',
- ParseError, infile, cur_index)
- continue
- #
- key = self._unquote(key)
- if this_section.has_key(key):
- self._handle_error(
- 'Duplicate keyword name at line %s.',
- DuplicateError, infile, cur_index)
- continue
- # add the key.
- # we set unrepr because if we have got this far we will never
- # be creating a new section
- this_section.__setitem__(key, value, unrepr=True)
- this_section.inline_comments[key] = comment
- this_section.comments[key] = comment_list
- continue
- #
- if self.indent_type is None:
- # no indentation used, set the type accordingly
- self.indent_type = ''
- #
- if self._terminated:
- comment_list.append('')
- # preserve the final comment
- if not self and not self.initial_comment:
- self.initial_comment = comment_list
- elif not reset_comment:
- self.final_comment = comment_list
- self.list_values = temp_list_values
-
- def _match_depth(self, sect, depth):
- """
- Given a section and a depth level, walk back through the sections
- parents to see if the depth level matches a previous section.
-
- Return a reference to the right section,
- or raise a SyntaxError.
- """
- while depth < sect.depth:
- if sect is sect.parent:
- # we've reached the top level already
- raise SyntaxError
- sect = sect.parent
- if sect.depth == depth:
- return sect
- # shouldn't get here
- raise SyntaxError
-
- def _handle_error(self, text, ErrorClass, infile, cur_index):
- """
- Handle an error according to the error settings.
-
- Either raise the error or store it.
- The error will have occured at ``cur_index``
- """
- line = infile[cur_index]
- cur_index += 1
- message = text % cur_index
- error = ErrorClass(message, cur_index, line)
- if self.raise_errors:
- # raise the error - parsing stops here
- raise error
- # store the error
- # reraise when parsing has finished
- self._errors.append(error)
-
- def _unquote(self, value):
- """Return an unquoted version of a value"""
- if (value[0] == value[-1]) and (value[0] in ('"', "'")):
- value = value[1:-1]
- return value
-
- def _quote(self, value, multiline=True):
- """
- Return a safely quoted version of a value.
-
- Raise a ConfigObjError if the value cannot be safely quoted.
- If multiline is ``True`` (default) then use triple quotes
- if necessary.
-
- Don't quote values that don't need it.
- Recursively quote members of a list and return a comma joined list.
- Multiline is ``False`` for lists.
- Obey list syntax for empty and single member lists.
-
- If ``list_values=False`` then the value is only quoted if it contains
- a ...
[truncated message content] |
|
From: <lee...@us...> - 2008-12-18 15:38:43
|
Revision: 6664
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6664&view=rev
Author: leejjoon
Date: 2008-12-18 15:38:33 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
add new arrow style (a line + filled triangles)
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py
trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py
trunk/matplotlib/lib/matplotlib/bezier.py
trunk/matplotlib/lib/matplotlib/patches.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-18 13:47:19 UTC (rev 6663)
+++ trunk/matplotlib/CHANGELOG 2008-12-18 15:38:33 UTC (rev 6664)
@@ -1,3 +1,5 @@
+2008-12-18 add new arrow style, a line + filled triangles. -JJL
+
2008-12-18 Fix bug where a line with NULL data limits prevents
subsequent data limits from calculating correctly - MGD
Modified: trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008-12-18 13:47:19 UTC (rev 6663)
+++ trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008-12-18 15:38:33 UTC (rev 6664)
@@ -3,23 +3,26 @@
styles = mpatches.ArrowStyle.get_styles()
-figheight = (len(styles)+.5)
-fig1 = plt.figure(1, (4, figheight))
-fontsize = 0.3 * fig1.dpi
+ncol=2
+nrow = len(styles) // ncol + 1
+figheight = (nrow+0.5)
+fig1 = plt.figure(1, (4.*ncol/1.5, figheight/1.5))
+fontsize = 0.2 * 70
ax = fig1.add_axes([0, 0, 1, 1], frameon=False, aspect=1.)
-ax.set_xlim(0, 4)
+ax.set_xlim(0, 4*ncol)
ax.set_ylim(0, figheight)
for i, (stylename, styleclass) in enumerate(sorted(styles.items())):
- y = (float(len(styles)) -0.25 - i) # /figheight
- p = mpatches.Circle((3.2, y), 0.2, fc="w")
+ x = 3.2 + (i//nrow)*4
+ y = (figheight - 0.7 - i%nrow) # /figheight
+ p = mpatches.Circle((x, y), 0.2, fc="w")
ax.add_patch(p)
- ax.annotate(stylename, (3.2, y),
- (2., y),
+ ax.annotate(stylename, (x, y),
+ (x-1.2, y),
#xycoords="figure fraction", textcoords="figure fraction",
ha="right", va="center",
size=fontsize,
Modified: trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py
===================================================================
--- trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py 2008-12-18 13:47:19 UTC (rev 6663)
+++ trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py 2008-12-18 15:38:33 UTC (rev 6664)
@@ -4,8 +4,8 @@
styles = mpatch.BoxStyle.get_styles()
figheight = (len(styles)+.5)
-fig1 = plt.figure(1, (4, figheight))
-fontsize = 0.4 * fig1.dpi
+fig1 = plt.figure(1, (4/1.5, figheight/1.5))
+fontsize = 0.3 * 72
for i, (stylename, styleclass) in enumerate(styles.items()):
fig1.text(0.5, (float(len(styles)) - 0.5 - i)/figheight, stylename,
@@ -15,3 +15,4 @@
bbox=dict(boxstyle=stylename, fc="w", ec="k"))
plt.draw()
plt.show()
+
Modified: trunk/matplotlib/lib/matplotlib/bezier.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/bezier.py 2008-12-18 13:47:19 UTC (rev 6663)
+++ trunk/matplotlib/lib/matplotlib/bezier.py 2008-12-18 15:38:33 UTC (rev 6664)
@@ -468,6 +468,38 @@
+def make_path_regular(p):
+ """
+ fill in the codes if None.
+ """
+ c = p.codes
+ if c is None:
+ c = np.empty(p.vertices.shape, "i")
+ c.fill(Path.LINETO)
+ c[0] = Path.MOVETO
+
+ return Path(p.vertices, c)
+ else:
+ return p
+
+def concatenate_paths(paths):
+ """
+ concatenate list of paths into a single path.
+ """
+
+ vertices = []
+ codes = []
+ for p in paths:
+ p = make_path_regular(p)
+ vertices.append(p.vertices)
+ codes.append(p.codes)
+
+ _path = Path(np.concatenate(vertices),
+ np.concatenate(codes))
+ return _path
+
+
+
if 0:
path = Path([(0, 0), (1, 0), (2, 2)],
[Path.MOVETO, Path.CURVE3, Path.CURVE3])
@@ -476,3 +508,4 @@
ax = gca()
+
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py 2008-12-18 13:47:19 UTC (rev 6663)
+++ trunk/matplotlib/lib/matplotlib/patches.py 2008-12-18 15:38:33 UTC (rev 6664)
@@ -2176,6 +2176,7 @@
from matplotlib.bezier import get_intersection, inside_circle, get_parallels
from matplotlib.bezier import make_wedged_bezier2
from matplotlib.bezier import split_path_inout, get_cos_sin
+from matplotlib.bezier import make_path_regular, concatenate_paths
class ConnectionStyle(_Style):
@@ -2627,12 +2628,15 @@
def transmute(self, path, mutation_size, linewidth):
"""
The transmute method is a very core of the ArrowStyle
- class and must be overriden in the subclasses. It receives the
- path object along which the arrow will be drawn, and the
- mutation_size, with which the amount arrow head and etc. will
- be scaled. It returns a Path instance. The linewidth may be
- used to adjust the the path so that it does not pass beyond
- the given points.
+ class and must be overriden in the subclasses. It receives
+ the path object along which the arrow will be drawn, and
+ the mutation_size, with which the amount arrow head and
+ etc. will be scaled. The linewidth may be used to adjust
+ the the path so that it does not pass beyond the given
+ points. It returns a tuple of a Path instance and a
+ boolean. The boolean value indicate whether the path can
+ be filled or not. The return value can also be a list of paths
+ and list of booleans of a same length.
"""
raise NotImplementedError('Derived must override')
@@ -2646,6 +2650,8 @@
and take care of the aspect ratio.
"""
+ path = make_path_regular(path)
+
if aspect_ratio is not None:
# Squeeze the given height by the aspect_ratio
@@ -2654,12 +2660,19 @@
vertices[:,1] = vertices[:,1] / aspect_ratio
path_shrinked = Path(vertices, codes)
# call transmute method with squeezed height.
- path_mutated, closed = self.transmute(path_shrinked, linewidth,
- mutation_size)
- vertices, codes = path_mutated.vertices, path_mutated.codes
- # Restore the height
- vertices[:,1] = vertices[:,1] * aspect_ratio
- return Path(vertices, codes), closed
+ path_mutated, fillable = self.transmute(path_shrinked,
+ linewidth,
+ mutation_size)
+ if cbook.iterable(fillable):
+ path_list = []
+ for p in zip(path_mutated):
+ v, c = p.vertices, p.codes
+ # Restore the height
+ v[:,1] = v[:,1] * aspect_ratio
+ path_list.append(Path(v, c))
+ return path_list, fillable
+ else:
+ return path_mutated, fillable
else:
return self.transmute(path, mutation_size, linewidth)
@@ -2669,21 +2682,24 @@
"""
A simple arrow which will work with any path instance. The
returned path is simply concatenation of the original path + at
- most two paths representing the arrow at the begin point and the
- at the end point. The returned path is not closed and only meant
- to be stroked.
+ most two paths representing the arrow head at the begin point and the
+ at the end point. The arrow heads can be either open or closed.
"""
def __init__(self, beginarrow=None, endarrow=None,
+ fillbegin=False, fillend=False,
head_length=.2, head_width=.1):
"""
The arrows are drawn if *beginarrow* and/or *endarrow* are
- true. *head_length* and *head_width* determines the size of
- the arrow relative to the *mutation scale*.
+ true. *head_length* and *head_width* determines the size
+ of the arrow relative to the *mutation scale*. The
+ arrowhead at the begin (or end) is closed if fillbegin (or
+ fillend) is True.
"""
self.beginarrow, self.endarrow = beginarrow, endarrow
self.head_length, self.head_width = \
head_length, head_width
+ self.fillbegin, self.fillend = fillbegin, fillend
super(ArrowStyle._Curve, self).__init__()
@@ -2783,18 +2799,35 @@
# this simple code will not work if ddx, ddy is greater than
# separation bettern vertices.
- vertices = np.concatenate([verticesA + [(x0+ddxA, y0+ddyA)],
- path.vertices[1:-1],
- [(x3+ddxB, y3+ddyB)] + verticesB])
- codes = np.concatenate([codesA,
- path.codes,
- codesB])
+ _path = [Path(np.concatenate([[(x0+ddxA, y0+ddyA)],
+ path.vertices[1:-1],
+ [(x3+ddxB, y3+ddyB)]]),
+ path.codes)]
+ _fillable = [False]
+
+ if self.beginarrow:
+ if self.fillbegin:
+ p = np.concatenate([verticesA, [verticesA[0], verticesA[0]], ])
+ c = np.concatenate([codesA, [Path.LINETO, Path.CLOSEPOLY]])
+ _path.append(Path(p, c))
+ _fillable.append(True)
+ else:
+ _path.append(Path(verticesA, codesA))
+ _fillable.append(False)
+
+ if self.endarrow:
+ if self.fillend:
+ _fillable.append(True)
+ p = np.concatenate([verticesB, [verticesB[0], verticesB[0]], ])
+ c = np.concatenate([codesB, [Path.LINETO, Path.CLOSEPOLY]])
+ _path.append(Path(p, c))
+ else:
+ _fillable.append(False)
+ _path.append(Path(verticesB, codesB))
+
+ return _path, _fillable
- p = Path(vertices, codes)
- return p, False
-
-
class Curve(_Curve):
"""
A simple curve without any arrow head.
@@ -2872,6 +2905,73 @@
_style_list["<->"] = CurveAB
+
+ class CurveFilledA(_Curve):
+ """
+ An arrow with filled triangle head at the begin.
+ """
+
+ def __init__(self, head_length=.4, head_width=.2):
+ """
+ *head_length*
+ length of the arrow head
+
+ *head_width*
+ width of the arrow head
+ """
+
+ super(ArrowStyle.CurveFilledA, self).__init__( \
+ beginarrow=True, endarrow=False,
+ fillbegin=True, fillend=False,
+ head_length=head_length, head_width=head_width )
+
+ _style_list["<|-"] = CurveFilledA
+
+
+ class CurveFilledB(_Curve):
+ """
+ An arrow with filled triangle head at the end.
+ """
+
+ def __init__(self, head_length=.4, head_width=.2):
+ """
+ *head_length*
+ length of the arrow head
+
+ *head_width*
+ width of the arrow head
+ """
+
+ super(ArrowStyle.CurveFilledB, self).__init__( \
+ beginarrow=False, endarrow=True,
+ fillbegin=False, fillend=True,
+ head_length=head_length, head_width=head_width )
+
+ _style_list["-|>"] = CurveFilledB
+
+
+ class CurveFilledAB(_Curve):
+ """
+ An arrow with filled triangle heads both at the begin and the end point.
+ """
+
+ def __init__(self, head_length=.4, head_width=.2):
+ """
+ *head_length*
+ length of the arrow head
+
+ *head_width*
+ width of the arrow head
+ """
+
+ super(ArrowStyle.CurveFilledAB, self).__init__( \
+ beginarrow=True, endarrow=True,
+ fillbegin=True, fillend=True,
+ head_length=head_length, head_width=head_width )
+
+ _style_list["<|-|>"] = CurveFilledAB
+
+
class _Bracket(_Base):
def __init__(self, bracketA=None, bracketB=None,
@@ -3201,6 +3301,7 @@
+
class FancyArrowPatch(Patch):
"""
A fancy arrow patch. It draws an arrow using the :class:ArrowStyle.
@@ -3423,9 +3524,14 @@
get_path_in_displaycoord() medthod to retrieve the arrow path
in the disaply coord.
"""
- _path = self.get_path_in_displaycoord()
+ _path, fillable = self.get_path_in_displaycoord()
+
+ if cbook.iterable(fillable):
+ _path = concatenate_paths(_path)
+
return self.get_transform().inverted().transform_path(_path)
+
def get_path_in_displaycoord(self):
"""
Return the mutated path of the arrow in the display coord
@@ -3445,16 +3551,16 @@
- _path, closed = self.get_arrowstyle()(_path,
- self.get_mutation_scale(),
- self.get_linewidth(),
- self.get_mutation_aspect()
- )
+ _path, fillable = self.get_arrowstyle()(_path,
+ self.get_mutation_scale(),
+ self.get_linewidth(),
+ self.get_mutation_aspect()
+ )
- if not closed:
- self.fill = False
+ #if not fillable:
+ # self.fill = False
- return _path
+ return _path, fillable
@@ -3463,12 +3569,7 @@
#renderer.open_group('patch')
gc = renderer.new_gc()
- fill_orig = self.fill
- path = self.get_path_in_displaycoord()
- affine = transforms.IdentityTransform()
-
-
if cbook.is_string_like(self._edgecolor) and self._edgecolor.lower()=='none':
gc.set_linewidth(0)
else:
@@ -3494,8 +3595,22 @@
gc.set_hatch(self._hatch )
- renderer.draw_path(gc, path, affine, rgbFace)
+ path, fillable = self.get_path_in_displaycoord()
- self.fill = fill_orig
+ if not cbook.iterable(fillable):
+ path = [path]
+ fillable = [fillable]
+
- #renderer.close_group('patch')
+ affine = transforms.IdentityTransform()
+
+ renderer.open_group('patch', self.get_gid())
+
+ for p, f in zip(path, fillable):
+ if f:
+ renderer.draw_path(gc, p, affine, rgbFace)
+ else:
+ renderer.draw_path(gc, p, affine, None)
+
+
+ renderer.close_group('patch')
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|
|
From: <md...@us...> - 2008-12-18 13:47:23
|
Revision: 6663
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6663&view=rev
Author: mdboom
Date: 2008-12-18 13:47:19 +0000 (Thu, 18 Dec 2008)
Log Message:
-----------
Merged revisions 6660-6662 via svnmerge from
https://matplotlib.svn.sf.net/svnroot/matplotlib/branches/v0_98_5_maint
........
r6660 | jdh2358 | 2008-12-18 07:10:51 -0500 (Thu, 18 Dec 2008) | 1 line
applied maxosx backend update
........
r6661 | mdboom | 2008-12-18 08:41:35 -0500 (Thu, 18 Dec 2008) | 2 lines
Fix bug where a line with NULL data limits prevents subsequent data limits from calculating correctly
........
r6662 | mdboom | 2008-12-18 08:42:13 -0500 (Thu, 18 Dec 2008) | 2 lines
Fix docstring typo.
........
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/doc/_templates/index.html
trunk/matplotlib/doc/api/font_manager_api.rst
trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
trunk/matplotlib/src/_macosx.m
trunk/matplotlib/src/_path.cpp
Property Changed:
----------------
trunk/matplotlib/
trunk/matplotlib/doc/pyplots/README
trunk/matplotlib/doc/sphinxext/gen_gallery.py
Property changes on: trunk/matplotlib
___________________________________________________________________
Modified: svnmerge-integrated
- /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6658
+ /branches/v0_91_maint:1-6428 /branches/v0_98_5_maint:1-6662
Modified: svn:mergeinfo
- /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652
+ /branches/v0_91_maint:5753-5771
/branches/v0_98_5_maint:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-12-18 13:42:13 UTC (rev 6662)
+++ trunk/matplotlib/CHANGELOG 2008-12-18 13:47:19 UTC (rev 6663)
@@ -1,3 +1,11 @@
+2008-12-18 Fix bug where a line with NULL data limits prevents
+ subsequent data limits from calculating correctly - MGD
+
+2008-12-17 Major documentation generator changes - MGD
+
+2008-12-17 Applied macosx backend patch with support for path
+ collections, quadmesh, etc... - JDH
+
2008-12-17 fix dpi-dependent behavior of text bbox and arrow in annotate
-JJL
Modified: trunk/matplotlib/doc/_templates/index.html
===================================================================
--- trunk/matplotlib/doc/_templates/index.html 2008-12-18 13:42:13 UTC (rev 6662)
+++ trunk/matplotlib/doc/_templates/index.html 2008-12-18 13:47:19 UTC (rev 6663)
@@ -1,5 +1,5 @@
{% extends "layout.html" %}
-{% set title = 'Overview' %}
+{% set title = 'matplotlib: python plotting' %}
{% block body %}
Modified: trunk/matplotlib/doc/api/font_manager_api.rst
===================================================================
--- trunk/matplotlib/doc/api/font_manager_api.rst 2008-12-18 13:42:13 UTC (rev 6662)
+++ trunk/matplotlib/doc/api/font_manager_api.rst 2008-12-18 13:47:19 UTC (rev 6663)
@@ -11,7 +11,7 @@
:show-inheritance:
:mod:`matplotlib.fontconfig_pattern`
-========================================
+====================================
.. automodule:: matplotlib.fontconfig_pattern
:members:
Property changes on: trunk/matplotlib/doc/pyplots/README
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652
+ /branches/v0_98_5_maint/doc/pyplots/README:6581,6585,6587,6589-6609,6614,6616,6625,6652,6660-6662
Property changes on: trunk/matplotlib/doc/sphinxext/gen_gallery.py
___________________________________________________________________
Modified: svn:mergeinfo
- /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
+ /branches/v0_91_maint/doc/_templates/gen_gallery.py:5753-5771
/branches/v0_98_5_maint/doc/sphinxext/gen_gallery.py:6660-6662
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2008-12-18 13:42:13 UTC (rev 6662)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_macosx.py 2008-12-18 13:47:19 UTC (rev 6663)
@@ -10,6 +10,7 @@
from matplotlib.figure import Figure
from matplotlib.path import Path
from matplotlib.mathtext import MathTextParser
+from matplotlib.colors import colorConverter
@@ -48,34 +49,47 @@
self.width, self.height = width, height
def draw_path(self, gc, path, transform, rgbFace=None):
- path = transform.transform_path(path)
- for points, code in path.iter_segments():
- if code == Path.MOVETO:
- gc.moveto(points)
- elif code == Path.LINETO:
- gc.lineto(points)
- elif code == Path.CURVE3:
- gc.curve3(points)
- elif code == Path.CURVE4:
- gc.curve4(points)
- elif code == Path.CLOSEPOLY:
- gc.closepoly()
if rgbFace is not None:
rgbFace = tuple(rgbFace)
- gc.stroke(rgbFace)
+ if gc!=self.gc:
+ n = self.gc.level() - gc.level()
+ for i in range(n): self.gc.restore()
+ self.gc = gc
+ gc.draw_path(path, transform, rgbFace)
+ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
+ if rgbFace is not None:
+ rgbFace = tuple(rgbFace)
+ if gc!=self.gc:
+ n = self.gc.level() - gc.level()
+ for i in range(n): self.gc.restore()
+ self.gc = gc
+ gc.draw_markers(marker_path, marker_trans, path, trans, rgbFace)
+
+ def draw_path_collection(self, *args):
+ gc = self.gc
+ args = args[:13]
+ gc.draw_path_collection(*args)
+
+ def draw_quad_mesh(self, *args):
+ gc = self.gc
+ gc.draw_quad_mesh(*args)
+
def new_gc(self):
self.gc.reset()
return self.gc
def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
- self.gc.set_clip_rectangle(bbox)
im.flipud_out()
nrows, ncols, data = im.as_rgba_str()
- self.gc.draw_image(x, y, nrows, ncols, data)
+ self.gc.draw_image(x, y, nrows, ncols, data, bbox, clippath, clippath_trans)
im.flipud_out()
def draw_tex(self, gc, x, y, s, prop, angle):
+ if gc!=self.gc:
+ n = self.gc.level() - gc.level()
+ for i in range(n): self.gc.restore()
+ self.gc = gc
# todo, handle props, angle, origins
size = prop.get_size_in_points()
texmanager = self.get_texmanager()
@@ -88,12 +102,20 @@
gc.draw_mathtext(x, y, angle, Z)
def _draw_mathtext(self, gc, x, y, s, prop, angle):
+ if gc!=self.gc:
+ n = self.gc.level() - gc.level()
+ for i in range(n): self.gc.restore()
+ self.gc = gc
size = prop.get_size_in_points()
ox, oy, width, height, descent, image, used_characters = \
self.mathtext_parser.parse(s, self.dpi, prop)
gc.draw_mathtext(x, y, angle, 255 - image.as_array())
def draw_text(self, gc, x, y, s, prop, angle, ismath=False):
+ if gc!=self.gc:
+ n = self.gc.level() - gc.level()
+ for i in range(n): self.gc.restore()
+ self.gc = gc
if ismath:
self._draw_mathtext(gc, x, y, s, prop, angle)
else:
@@ -143,6 +165,11 @@
GraphicsContextBase.__init__(self)
_macosx.GraphicsContext.__init__(self)
+ def set_foreground(self, fg, isRGB=False):
+ if not isRGB:
+ fg = colorConverter.to_rgb(fg)
+ _macosx.GraphicsContext.set_foreground(self, fg)
+
def set_clip_rectangle(self, box):
GraphicsContextBase.set_clip_rectangle(self, box)
if not box: return
@@ -152,20 +179,8 @@
GraphicsContextBase.set_clip_path(self, path)
if not path: return
path = path.get_fully_transformed_path()
- for points, code in path.iter_segments():
- if code == Path.MOVETO:
- self.moveto(points)
- elif code == Path.LINETO:
- self.lineto(points)
- elif code == Path.CURVE3:
- self.curve3(points)
- elif code == Path.CURVE4:
- self.curve4(points)
- elif code == Path.CLOSEPOLY:
- self.closepoly()
- self.clip_path()
+ _macosx.GraphicsContext.set_clip_path(self, path)
-
########################################################################
#
# The following functions and classes are for pylab and implement
Modified: trunk/matplotlib/src/_macosx.m
===================================================================
--- trunk/matplotlib/src/_macosx.m 2008-12-18 13:42:13 UTC (rev 6662)
+++ trunk/matplotlib/src/_macosx.m 2008-12-18 13:47:19 UTC (rev 6663)
@@ -4,15 +4,33 @@
#include <Python.h>
#include "numpy/arrayobject.h"
-static int nwin = 0;
+static int nwin = 0; /* The number of open windows */
+static int ngc = 0; /* The number of graphics contexts in use */
-/* Varius NSApplicationDefined event subtypes */
+/* For drawing Unicode strings with ATSUI */
+static ATSUStyle style = NULL;
+static ATSUTextLayout layout = NULL;
+
+/* CGFloat was defined in Mac OS X 10.5 */
+#ifndef CGFloat
+#define CGFloat float
+#endif
+
+
+/* Various NSApplicationDefined event subtypes */
#define STDIN_READY 0
#define SIGINT_CALLED 1
#define STOP_EVENT_LOOP 2
#define WINDOW_CLOSING 3
+/* Path definitions */
+#define STOP 0
+#define MOVETO 1
+#define LINETO 2
+#define CURVE3 3
+#define CURVE4 4
+#define CLOSEPOLY 5
/* -------------------------- Helper function ---------------------------- */
static void stdin_ready(CFReadStreamRef readStream, CFStreamEventType eventType, void* context)
@@ -147,8 +165,44 @@
return 1;
}
-static char show__doc__[] = "Show all the figures and enter the main loop.\nThis function does not return until all Matplotlib windows are closed,\nand is normally not needed in interactive sessions.";
+static int _init_atsui(void)
+{
+ OSStatus status;
+ status = ATSUCreateStyle(&style);
+ if (status!=noErr)
+ {
+ PyErr_SetString(PyExc_RuntimeError, "ATSUCreateStyle failed");
+ return 0;
+ }
+
+ status = ATSUCreateTextLayout(&layout);
+ if (status!=noErr)
+ {
+ status = ATSUDisposeStyle(style);
+ if (status!=noErr)
+ PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeStyle failed", 1);
+ PyErr_SetString(PyExc_RuntimeError, "ATSUCreateTextLayout failed");
+ return 0;
+ }
+
+
+ return 1;
+}
+
+static void _dealloc_atsui(void)
+{
+ OSStatus status;
+
+ status = ATSUDisposeStyle(style);
+ if (status!=noErr)
+ PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeStyle failed", 1);
+
+ status = ATSUDisposeTextLayout(layout);
+ if (status!=noErr)
+ PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeTextLayout failed", 1);
+}
+
/* ---------------------------- Cocoa classes ---------------------------- */
@@ -220,76 +274,38 @@
typedef struct {
PyObject_HEAD
CGContextRef cr;
- PyObject* converter; /* Convert color specifications to r,g,b triples */
CGPatternRef pattern; /* For drawing hatches */
- ATSUStyle style; /* For drawing Unicode strings with ATSUI */
- ATSUTextLayout layout; /* For drawing Unicode strings with ATSUI */
} GraphicsContext;
static PyObject*
GraphicsContext_new(PyTypeObject* type, PyObject *args, PyObject *kwds)
{
- OSStatus status;
-
GraphicsContext* self = (GraphicsContext*)type->tp_alloc(type, 0);
if (!self) return NULL;
self->cr = NULL;
- PyObject* module = PyImport_AddModule("matplotlib.colors");
- if (!module) return NULL;
- PyObject* dict = PyObject_GetAttrString(module, "__dict__");
- if (!dict) return NULL;
- PyObject* colorConverter = PyDict_GetItemString(dict, "colorConverter");
- Py_DECREF(dict);
- if (!colorConverter)
- {
- PyErr_SetString(PyExc_KeyError,
- "failed to find colorConverter in matplotlib.colors");
- return NULL;
- }
- self->converter = PyObject_GetAttrString(colorConverter, "to_rgb");
- if (!self->converter) return NULL;
-
self->pattern = NULL;
- status = ATSUCreateStyle(&self->style);
- if (status!=noErr)
+ if (ngc==0)
{
- Py_DECREF(self->converter);
- PyErr_SetString(PyExc_RuntimeError, "ATSUCreateStyle failed");
- return NULL;
+ int ok = _init_atsui();
+ if (!ok)
+ {
+ return NULL;
+ }
}
+ ngc++;
- status = ATSUCreateTextLayout(&self->layout);
- if (status!=noErr)
- {
- Py_DECREF(self->converter);
- status = ATSUDisposeStyle(self->style);
- if (status!=noErr)
- PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeStyle failed", 1);
- PyErr_SetString(PyExc_RuntimeError, "ATSUCreateTextLayout failed");
- return NULL;
- }
-
return (PyObject*) self;
}
static void
GraphicsContext_dealloc(GraphicsContext *self)
{
- Py_DECREF(self->converter);
+ CGPatternRelease(self->pattern);
- if (self->pattern) CGPatternRelease(self->pattern);
+ ngc--;
+ if (ngc==0) _dealloc_atsui();
- OSStatus status;
-
- status = ATSUDisposeStyle(self->style);
- if (status!=noErr)
- PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeStyle failed", 1);
-
- status = ATSUDisposeTextLayout(self->layout);
- if (status!=noErr)
- PyErr_WarnEx(PyExc_RuntimeWarning, "ATSUDisposeTextLayout failed", 1);
-
self->ob_type->tp_free((PyObject*)self);
}
@@ -308,6 +324,13 @@
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
+
+ if (self->pattern)
+ {
+ CGPatternRelease(self->pattern);
+ self->pattern = NULL;
+ }
+
CGContextRestoreGState(cr);
CGContextSaveGState(cr);
Py_INCREF(Py_None);
@@ -400,7 +423,7 @@
}
static PyObject*
-GraphicsContext_clip_path (GraphicsContext* self)
+GraphicsContext_set_clip_path (GraphicsContext* self, PyObject* args)
{
CGContextRef cr = self->cr;
if (!cr)
@@ -408,29 +431,216 @@
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
- CGContextRestoreGState(cr);
- CGContextSaveGState(cr);
- CGContextClip(cr);
- Py_INCREF(Py_None);
- return Py_None;
-}
+#ifdef BUH
+ CGContextRestoreGState(cr); /* FIXME */
+ CGContextSaveGState(cr); /* FIXME */
+#endif
-static PyObject*
-GraphicsContext_set_dashes (GraphicsContext* self, PyObject* args)
-{
- float phase = 0.0;
- PyObject* offset;
- PyObject* dashes;
+ PyObject* path;
- if (!PyArg_ParseTuple(args, "OO", &offset, &dashes)) return NULL;
+ if(!PyArg_ParseTuple(args, "O", &path)) return NULL;
- CGContextRef cr = self->cr;
- if (!cr)
+ PyObject* vertices = PyObject_GetAttrString(path, "vertices");
+ if (vertices==NULL)
{
- PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
+ PyErr_SetString(PyExc_AttributeError, "path has no vertices");
return NULL;
}
+ Py_DECREF(vertices); /* Don't keep a reference here */
+ PyObject* codes = PyObject_GetAttrString(path, "codes");
+ if (codes==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "path has no codes");
+ return NULL;
+ }
+ Py_DECREF(codes); /* Don't keep a reference here */
+
+ PyArrayObject* coordinates;
+ coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
+ NPY_DOUBLE, 2, 2);
+ if (!coordinates)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to convert vertices array");
+ return NULL;
+ }
+
+ if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid vertices array");
+ return NULL;
+ }
+
+ npy_intp n = PyArray_DIM(coordinates, 0);
+
+ if (n==0) /* Nothing to do here */
+ {
+ Py_DECREF(coordinates);
+ return NULL;
+ }
+
+ PyArrayObject* codelist = NULL;
+ if (codes != Py_None)
+ {
+ codelist = (PyArrayObject*)PyArray_FromObject(codes,
+ NPY_UINT8, 1, 1);
+ if (!codelist)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid codes array");
+ return NULL;
+ }
+ }
+
+ CGFloat x, y;
+
+ if (codelist==NULL)
+ {
+ npy_intp i;
+ npy_uint8 code = MOVETO;
+ for (i = 0; i < n; i++)
+ {
+ x = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ if (isnan(x) || isnan(y))
+ {
+ code = MOVETO;
+ }
+ else
+ {
+ switch (code)
+ {
+ case MOVETO:
+ CGContextMoveToPoint(cr, x, y);
+ break;
+ case LINETO:
+ CGContextAddLineToPoint(cr, x, y);
+ break;
+ }
+ code = LINETO;
+ }
+ }
+ }
+ else
+ {
+ npy_intp i = 0;
+ BOOL was_nan = false;
+ npy_uint8 code;
+ CGFloat x1, y1, x2, y2, x3, y3;
+ while (i < n)
+ {
+ code = *(npy_uint8*)PyArray_GETPTR1(codelist, i);
+ if (code == CLOSEPOLY)
+ {
+ CGContextClosePath(cr);
+ i++;
+ }
+ else if (code == STOP)
+ {
+ break;
+ }
+ else if (was_nan)
+ {
+ if (code==CURVE3) i++;
+ else if (code==CURVE4) i+=2;
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ CGContextMoveToPoint(cr, x1, y1);
+ was_nan = false;
+ }
+ }
+ else if (code==MOVETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ CGContextMoveToPoint(cr, x1, y1);
+ was_nan = false;
+ }
+ }
+ else if (code==LINETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ CGContextAddLineToPoint(cr, x1, y1);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE3)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE4)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3);
+ was_nan = false;
+ }
+ }
+ }
+ Py_DECREF(codelist);
+ }
+
+ Py_DECREF(coordinates);
+
+ CGContextClip(cr);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static BOOL
+_set_dashes(CGContextRef cr, PyObject* offset, PyObject* dashes)
+{
+ float phase = 0.0;
if (offset!=Py_None)
{
if (PyFloat_Check(offset)) phase = PyFloat_AsDouble(offset);
@@ -439,7 +649,7 @@
{
PyErr_SetString(PyExc_TypeError,
"offset should be a floating point value");
- return NULL;
+ return false;
}
}
@@ -451,7 +661,7 @@
{
PyErr_SetString(PyExc_TypeError,
"dashes should be a tuple or a list");
- return NULL;
+ return false;
}
int n = PyTuple_GET_SIZE(dashes);
int i;
@@ -460,7 +670,7 @@
{
PyErr_SetString(PyExc_MemoryError, "Failed to store dashes");
Py_DECREF(dashes);
- return NULL;
+ return false;
}
for (i = 0; i < n; i++)
{
@@ -476,7 +686,7 @@
{
free(lengths);
PyErr_SetString(PyExc_TypeError, "Failed to read dashes");
- return NULL;
+ return false;
}
CGContextSetLineDash(cr, phase, lengths, n);
free(lengths);
@@ -484,29 +694,40 @@
else
CGContextSetLineDash(cr, phase, NULL, 0);
- Py_INCREF(Py_None);
- return Py_None;
+ return true;
}
static PyObject*
-GraphicsContext_set_foreground(GraphicsContext* self, PyObject* args, PyObject* keywords)
-{ float r, g, b;
- PyObject* fg;
- int isRGB = 0;
- static char* kwlist[] = {"fg", "isRGB", NULL};
- if(!PyArg_ParseTupleAndKeywords(args, keywords, "O|i", kwlist,
- &fg, &isRGB)) return NULL;
- if (isRGB)
+GraphicsContext_set_dashes (GraphicsContext* self, PyObject* args)
+{
+ PyObject* offset;
+ PyObject* dashes;
+
+ if (!PyArg_ParseTuple(args, "OO", &offset, &dashes)) return NULL;
+
+ CGContextRef cr = self->cr;
+ if (!cr)
{
- if(!PyArg_ParseTuple(fg, "fff", &r, &g, &b)) return NULL;
+ PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
+ return NULL;
}
+
+ BOOL ok = _set_dashes(cr, offset, dashes);
+ if (ok)
+ {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
else
- { fg = PyObject_CallFunctionObjArgs(self->converter, fg, NULL);
- if(!fg) return NULL;
- if(!PyArg_ParseTuple(fg, "fff", &r, &g, &b)) return NULL;
- Py_DECREF(fg);
- }
+ return NULL;
+}
+static PyObject*
+GraphicsContext_set_foreground(GraphicsContext* self, PyObject* args)
+{
+ float r, g, b;
+ if(!PyArg_ParseTuple(args, "(fff)", &r, &g, &b)) return NULL;
+
CGContextRef cr = self->cr;
if (!cr)
{
@@ -538,7 +759,7 @@
return Py_None;
}
-static void drawHatch (void *info, CGContextRef cr)
+static void _draw_hatch (void *info, CGContextRef cr)
{
int i;
@@ -603,12 +824,20 @@
Py_DECREF(string);
}
+static void _release_hatch(void* info)
+{
+ PyObject* hatches = info;
+ Py_DECREF(hatches);
+}
+
static PyObject*
GraphicsContext_set_hatch(GraphicsContext* self, PyObject* args)
{ PyObject* hatches;
const float size = 12.0;
- static const CGPatternCallbacks callbacks = {0, &drawHatch, NULL};
+ static const CGPatternCallbacks callbacks = {0,
+ &_draw_hatch,
+ &_release_hatch};
CGContextRef cr = self->cr;
if (!cr)
@@ -687,122 +916,828 @@
return Py_None;
}
-static PyObject*
-GraphicsContext_moveto(GraphicsContext* self, PyObject* args)
-{
- float x;
- float y;
-
- if(!PyArg_ParseTuple(args, "(ff)", &x, &y)) return NULL;
-
- CGContextRef cr = self->cr;
- if (!cr)
+static int
+_convert_affine_transform(PyObject* object, CGAffineTransform* transform)
+/* Reads a Numpy affine transformation matrix and returns
+ * a CGAffineTransform.
+ */
+{
+ PyArrayObject* matrix = NULL;
+ if (object==Py_None)
{
- PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
- return NULL;
+ PyErr_SetString(PyExc_ValueError,
+ "Found affine transformation matrix equal to None");
+ return 0;
}
- CGContextMoveToPoint(cr, x, y);
+ matrix = (PyArrayObject*) PyArray_FromObject(object, NPY_DOUBLE, 2, 2);
+ if (!matrix)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Invalid affine transformation matrix");
+ return 0;
+ }
+ if (PyArray_NDIM(matrix) != 2 || PyArray_DIM(matrix, 0) != 3 || PyArray_DIM(matrix, 1) != 3)
+ {
+ Py_DECREF(matrix);
+ PyErr_SetString(PyExc_ValueError,
+ "Affine transformation matrix has invalid dimensions");
+ return 0;
+ }
- Py_INCREF(Py_None);
- return Py_None;
+ size_t stride0 = (size_t)PyArray_STRIDE(matrix, 0);
+ size_t stride1 = (size_t)PyArray_STRIDE(matrix, 1);
+ char* row0 = PyArray_BYTES(matrix);
+ char* row1 = row0 + stride0;
+
+ double a = *(double*)(row0);
+ row0 += stride1;
+ double c = *(double*)(row0);
+ row0 += stride1;
+ double e = *(double*)(row0);
+ double b = *(double*)(row1);
+ row1 += stride1;
+ double d = *(double*)(row1);
+ row1 += stride1;
+ double f = *(double*)(row1);
+ *transform = CGAffineTransformMake(a, b, c, d, e, f);
+
+ Py_DECREF(matrix);
+ return 1;
}
-static PyObject*
-GraphicsContext_lineto(GraphicsContext* self, PyObject* args)
+static int
+_draw_path(CGContextRef cr, PyObject* path, CGAffineTransform affine)
{
- float x;
- float y;
+ CGPoint point;
- if(!PyArg_ParseTuple(args, "(ff)", &x, &y)) return NULL;
+ PyObject* vertices = PyObject_GetAttrString(path, "vertices");
+ if (vertices==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "path has no vertices");
+ return -1;
+ }
+ Py_DECREF(vertices); /* Don't keep a reference here */
- CGContextRef cr = self->cr;
- if (!cr)
+ PyObject* codes = PyObject_GetAttrString(path, "codes");
+ if (codes==NULL)
{
- PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
- return NULL;
+ PyErr_SetString(PyExc_AttributeError, "path has no codes");
+ return -1;
}
- CGContextAddLineToPoint(cr, x, y);
+ Py_DECREF(codes); /* Don't keep a reference here */
- Py_INCREF(Py_None);
- return Py_None;
+ PyArrayObject* coordinates;
+ coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
+ NPY_DOUBLE, 2, 2);
+ if (!coordinates)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to convert vertices array");
+ return -1;
+ }
+
+ if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid vertices array");
+ return -1;
+ }
+
+ npy_intp n = PyArray_DIM(coordinates, 0);
+
+ if (n==0) /* Nothing to do here */
+ {
+ Py_DECREF(coordinates);
+ return 0;
+ }
+
+ PyArrayObject* codelist = NULL;
+ if (codes != Py_None)
+ {
+ codelist = (PyArrayObject*)PyArray_FromObject(codes,
+ NPY_UINT8, 1, 1);
+ if (!codelist)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid codes array");
+ return -1;
+ }
+ }
+
+ if (codelist==NULL)
+ {
+ npy_intp i;
+ npy_uint8 code = MOVETO;
+ for (i = 0; i < n; i++)
+ {
+ point.x = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ point.y = (CGFloat)(*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ if (isnan(point.x) || isnan(point.y))
+ {
+ code = MOVETO;
+ }
+ else
+ {
+ point = CGPointApplyAffineTransform(point, affine);
+ switch (code)
+ {
+ case MOVETO:
+ CGContextMoveToPoint(cr, point.x, point.y);
+ break;
+ case LINETO:
+ CGContextAddLineToPoint(cr, point.x, point.y);
+ break;
+ }
+ code = LINETO;
+ }
+ }
+ }
+ else
+ {
+ npy_intp i = 0;
+ BOOL was_nan = false;
+ npy_uint8 code;
+ CGFloat x1, y1, x2, y2, x3, y3;
+ while (i < n)
+ {
+ code = *(npy_uint8*)PyArray_GETPTR1(codelist, i);
+ if (code == CLOSEPOLY)
+ {
+ CGContextClosePath(cr);
+ i++;
+ }
+ else if (code == STOP)
+ {
+ break;
+ }
+ else if (was_nan)
+ {
+ if (code==CURVE3) i++;
+ else if (code==CURVE4) i+=2;
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextMoveToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==MOVETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextMoveToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==LINETO)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ CGContextAddLineToPoint(cr, point.x, point.y);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE3)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ x1 = point.x;
+ y1 = point.y;
+ point.x = x2;
+ point.y = y2;
+ point = CGPointApplyAffineTransform(point, affine);
+ x2 = point.x;
+ y2 = point.y;
+ CGContextAddQuadCurveToPoint(cr, x1, y1, x2, y2);
+ was_nan = false;
+ }
+ }
+ else if (code==CURVE4)
+ {
+ x1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y1 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y2 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ x3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ y3 = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ i++;
+ if (isnan(x1) || isnan(y1) || isnan(x2) || isnan(y2) || isnan(x3) || isnan(y3))
+ {
+ was_nan = true;
+ }
+ else
+ {
+ point.x = x1;
+ point.y = y1;
+ point = CGPointApplyAffineTransform(point, affine);
+ x1 = point.x;
+ y1 = point.y;
+ point.x = x2;
+ point.y = y2;
+ point = CGPointApplyAffineTransform(point, affine);
+ x2 = point.x;
+ y2 = point.y;
+ point.x = x3;
+ point.y = y3;
+ point = CGPointApplyAffineTransform(point, affine);
+ x3 = point.x;
+ y3 = point.y;
+ CGContextAddCurveToPoint(cr, x1, y1, x2, y2, x3, y3);
+ was_nan = false;
+ }
+ }
+ }
+ }
+
+ Py_DECREF(coordinates);
+ Py_XDECREF(codelist);
+ return n;
}
static PyObject*
-GraphicsContext_curve3(GraphicsContext* self, PyObject* args)
-{
- float cpx;
- float cpy;
- float x;
- float y;
+GraphicsContext_draw_path (GraphicsContext* self, PyObject* args)
+{
+ PyObject* path;
+ PyObject* transform;
+ PyObject* rgbFace;
+ int ok;
+
CGContextRef cr = self->cr;
+
if (!cr)
{
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
- if(!PyArg_ParseTuple(args, "(ffff)", &cpx,
- &cpy,
- &x,
- &y)) return NULL;
+ if(!PyArg_ParseTuple(args, "OO|O",
+ &path,
+ &transform,
+ &rgbFace)) return NULL;
- CGContextAddQuadCurveToPoint(cr, cpx, cpy, x, y);
+ if(rgbFace==Py_None) rgbFace = NULL;
+ CGAffineTransform affine;
+ ok = _convert_affine_transform(transform, &affine);
+ if (!ok) return NULL;
+
+ int n = _draw_path(cr, path, affine);
+ if (n==-1) return NULL;
+
+ if (n > 0)
+ {
+ if(rgbFace)
+ {
+ float r, g, b;
+ ok = PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b);
+ if (!ok)
+ {
+ return NULL;
+ }
+ CGContextSaveGState(cr);
+ if(self->pattern)
+ {
+ float components[4];
+ components[0] = r;
+ components[1] = g;
+ components[2] = b;
+ components[3] = 1.0;
+ CGContextSetFillPattern(cr, self->pattern, components);
+ CGPatternRelease(self->pattern);
+ self->pattern = nil;
+ }
+ else CGContextSetRGBFillColor(cr, r, g, b, 1.0);
+ CGContextDrawPath(cr, kCGPathFillStroke);
+ CGContextRestoreGState(cr);
+ }
+ else CGContextStrokePath(cr);
+ }
+
Py_INCREF(Py_None);
return Py_None;
}
static PyObject*
-GraphicsContext_curve4 (GraphicsContext* self, PyObject* args)
+GraphicsContext_draw_markers (GraphicsContext* self, PyObject* args)
{
- float cp1x;
- float cp1y;
- float cp2x;
- float cp2y;
- float x;
- float y;
+ PyObject* marker_path;
+ PyObject* marker_transform;
+ PyObject* path;
+ PyObject* transform;
+ PyObject* rgbFace;
+ int ok;
+ float r, g, b;
+
CGContextRef cr = self->cr;
+
if (!cr)
{
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
- if(!PyArg_ParseTuple(args, "(ffffff)", &cp1x,
- &cp1y,
- &cp2x,
- &cp2y,
- &x,
- &y)) return NULL;
+ if(!PyArg_ParseTuple(args, "OOOO|O",
+ &marker_path,
+ &marker_transform,
+ &path,
+ &transform,
+ &rgbFace)) return NULL;
- CGContextAddCurveToPoint(cr, cp1x, cp1y, cp2x, cp2y, x, y);
+ if(rgbFace==Py_None) rgbFace = NULL;
+ if (rgbFace)
+ {
+ ok = PyArg_ParseTuple(rgbFace, "fff", &r, &g, &b);
+ if (!ok)
+ {
+ return NULL;
+ }
+ if(self->pattern)
+ {
+ float components[4];
+ components[0] = r;
+ components[1] = g;
+ components[2] = b;
+ components[3] = 1.0;
+ CGContextSetFillPattern(cr, self->pattern, components);
+ CGPatternRelease(self->pattern);
+ self->pattern = nil;
+ }
+ else CGContextSetRGBFillColor(cr, r, g, b, 1.0);
+ }
+
+ CGAffineTransform affine;
+ ok = _convert_affine_transform(transform, &affine);
+ if (!ok) return NULL;
+
+ CGAffineTransform marker_affine;
+ ok = _convert_affine_transform(marker_transform, &marker_affine);
+ if (!ok) return NULL;
+
+ PyObject* vertices = PyObject_GetAttrString(path, "vertices");
+ if (vertices==NULL)
+ {
+ PyErr_SetString(PyExc_AttributeError, "path has no vertices");
+ return NULL;
+ }
+ Py_DECREF(vertices); /* Don't keep a reference here */
+
+ PyArrayObject* coordinates;
+ coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
+ NPY_DOUBLE, 2, 2);
+ if (!coordinates)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to convert vertices array");
+ return NULL;
+ }
+
+ if (PyArray_NDIM(coordinates) != 2 || PyArray_DIM(coordinates, 1) != 2)
+ {
+ Py_DECREF(coordinates);
+ PyErr_SetString(PyExc_ValueError, "invalid vertices array");
+ return NULL;
+ }
+
+ npy_intp i;
+ npy_intp n = PyArray_DIM(coordinates, 0);
+ CGPoint point;
+ CGAffineTransform t;
+ int m = 0;
+ for (i = 0; i < n; i++)
+ {
+ point.x = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 0));
+ point.y = (CGFloat) (*(double*)PyArray_GETPTR2(coordinates, i, 1));
+ point = CGPointApplyAffineTransform(point, affine);
+ t = marker_affine;
+ t.tx += point.x;
+ t.ty += point.y;
+ m = _draw_path(cr, marker_path, t);
+
+ if (m > 0)
+ {
+ if(rgbFace) CGContextDrawPath(cr, kCGPathFillStroke);
+ else CGContextStrokePath(cr);
+ }
+ }
+
+ Py_DECREF(coordinates);
+
Py_INCREF(Py_None);
return Py_None;
}
+static BOOL _clip(CGContextRef cr, PyObject* object)
+{
+ if (object == Py_None) return true;
+
+ PyArrayObject* array = NULL;
+ array = (PyArrayObject*) PyArray_FromObject(object, PyArray_DOUBLE, 2, 2);
+ if (!array)
+ {
+ PyErr_SetString(PyExc_ValueError, "failed to read clipping bounding box");
+ return false;
+ }
+
+ if (PyArray_NDIM(array)!=2 || PyArray_DIM(array, 0)!=2 || PyArray_DIM(array, 1)!=2)
+ {
+ Py_DECREF(array);
+ PyErr_SetString(PyExc_ValueError, "clipping bounding box should be a 2x2 array");
+ return false;
+ }
+
+ const double l = *(double*)PyArray_GETPTR2(array, 0, 0);
+ const double b = *(double*)PyArray_GETPTR2(array, 0, 1);
+ const double r = *(double*)PyArray_GETPTR2(array, 1, 0);
+ const double t = *(double*)PyArray_GETPTR2(array, 1, 1);
+
+ Py_DECREF(array);
+
+ CGRect rect;
+ rect.origin.x = (CGFloat) l;
+ rect.origin.y = (CGFloat) b;
+ rect.size.width = (CGFloat) (r-l);
+ rect.size.height = (CGFloat) (t-b);
+
+ CGContextClipToRect(cr, rect);
+
+ return true;
+}
+
+
static PyObject*
-GraphicsContext_closepoly (GraphicsContext* self)
+GraphicsContext_draw_path_collection (GraphicsContext* self, PyObject* args)
{
+ PyObject* master_transform_obj;
+ PyObject* cliprect;
+ PyObject* clippath;
+ PyObject* clippath_transform;
+ PyObject* paths;
+ PyObject* transforms_obj;
+ PyObject* offsets_obj;
+ PyObject* offset_transform_obj;
+ PyObject* facecolors_obj;
+ PyObject* edgecolors_obj;
+ PyObject* linewidths;
+ PyObject* linestyles;
+ PyObject* antialiaseds;
+
CGContextRef cr = self->cr;
+
if (!cr)
{
PyErr_SetString(PyExc_RuntimeError, "CGContextRef is NULL");
return NULL;
}
- CGContextClosePath(cr);
+ if(!PyArg_ParseTuple(args, "OOOOOOOOOOOOO", &master_transform_obj,
+ &cliprect,
+ &clippath,
+ &clippath_transform,
+ &paths,
+ &transforms_obj,
+ &offsets_obj,
+ &offset_transform_obj,
+ &facecolors_obj,
+ &edgecolors_obj,
+ &linewidths,
+ &linestyles,
+ &antialiaseds))
+ return NULL;
+ CGContextSaveGState(cr);
+
+ CGAffineTransform transform;
+ CGAffineTransform master_transform;
+ CGAffineTransform offset_transform;
+ CGAffineTransform* transforms = NULL;
+
+ if (!_convert_affine_transform(master_transform_obj, &master_transform)) return NULL;
+ if (!_convert_affine_transform(offset_transform_obj, &offset_transform)) return NULL;
+
+ if (!_clip(cr, cliprect)) return NULL;
+ if (clippath!=Py_None)
+ {
+ if (!_convert_affine_transform(clippath_transform, &transform)) return NULL;
+ int n = _draw_path(cr, clippath, transform);
+ if (n==-1) return NULL;
+ else if (n > 0) CGContextClip(cr);
+ }
+
+ PyArrayObject* offsets = NULL;
+ PyArrayObject* facecolors = NULL;
+ PyArrayObject* edgecolors = NULL;
+
+ /* ------------------- Check offsets array ---------------------------- */
+
+ offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj, NPY_DOUBLE, 0, 2);
+ if (!offsets ||
+ (PyArray_NDIM(offsets)==2 && PyArray_DIM(offsets, 1)!=2) ||
+ (PyArray_NDIM(offsets)==1 && PyArray_DIM(offsets, 0)!=0))
+ {
+ PyErr_SetString(PyExc_ValueError, "Offsets array must be Nx2");
+ goto error;
+ }
+
+ /* ------------------- Check facecolors array ------------------------- */
+
+ facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj,
+ NPY_DOUBLE, 1, 2);
+ if (!facecolors ||
+ (PyArray_NDIM(facecolors)==1 && PyArray_DIM(facecolors, 0)!=0) ||
+ (PyArray_NDIM(facecolors)==2 && PyArray_DIM(facecolors, 1)!=4))
+ {
+ PyErr_SetString(PyExc_ValueError, "Facecolors must by a Nx4 numpy array or empty");
+ goto error;
+ }
+
+ /* ------------------- Check edgecolors array ------------------------- */
+
+ edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj,
+ NPY_DOUBLE, 1, 2);
+ if (!edgecolors ||
+ (PyArray_NDIM(edgecolors)==1 && PyArray_DIM(edgecolors, 0)!=0) ||
+ (PyArray_NDIM(edgecolors)==2 && PyArray_DIM(edgecolors, 1)!=4))
+ {
+ PyErr_SetString(PyExc_ValueError, "Edgecolors must by a Nx4 numpy array or empty");
+ goto error;
+ }
+
+ /* ------------------- Check the other arguments ---------------------- */
+
+ if (!PySequence_Check(paths))
+ {
+ PyErr_SetString(PyExc_ValueError, "paths must be a sequence object");
+ goto error;
+ }
+ if (!PySequence_Check(transforms_obj))
+ {
+ PyErr_SetString(PyExc_ValueError, "transforms must be a sequence object");
+ goto error;
+ }
+ if (!PySequence_Check(linewidths))
+ {
+ PyErr_SetString(PyExc_ValueError, "linewidths must be a sequence object");
+ goto error;
+ }
+ if (!PySequence_Check(linestyles))
+ {
+ PyErr_SetString(PyExc_ValueError, "linestyles must be a sequence object");
+ goto error;
+ }
+ if (!PySequence_Check(antialiaseds))
+ {
+ PyErr_SetString(PyExc_ValueError, "antialiaseds must be a sequence object");
+ goto error;
+ }
+
+ size_t Npaths = (size_t) PySequence_Size(paths);
+ size_t Noffsets = (size_t) PyArray_DIM(offsets, 0);
+ size_t N = Npaths > Noffsets ? Npaths : Noffsets;
+ size_t Ntransforms = (size_t) PySequence_Size(transforms_obj);
+ size_t Nfacecolors = (size_t) PyArray_DIM(facecolors, 0);
+ size_t Nedgecolors = (size_t) PyArray_DIM(edgecolors, 0);
+ size_t Nlinewidths = (size_t) PySequence_Size(linewidths);
+ size_t Nlinestyles = (size_t) PySequence_Size(linestyles);
+ size_t Naa = (size_t) PySequence_Size(antialiaseds);
+ if (N < Ntransforms) Ntransforms = N;
+ if (N < Nlinestyles) Nlinestyles = N;
+ if ((Nfacecolors == 0 && Nedgecolors == 0) || Npaths == 0)
+ {
+ goto success;
+ }
+
+ size_t i = 0;
+
+ /* Convert all of the transforms up front */
+ if (Ntransforms > 0)
+ {
+ transforms = malloc(Ntransforms*sizeof(CGAffineTransform));
+ if (!transforms) goto error;
+ for (i = 0; i < Ntransforms; i++)
+ {
+ PyObject* transform_obj = PySequence_ITEM(transforms_obj, i);
+ if(!_convert_affine_transform(transform_obj, &transforms[i])) goto error;
+ transforms[i] = CGAffineTransformConcat(transforms[i], master_transform);
+ }
+ }
+
+ CGPoint offset;
+ PyObject* path;
+
+ /* Preset graphics context properties if possible */
+ if (Naa==1)
+ {
+ switch(PyObject_IsTrue(PySequence_ITEM(antialiaseds, 0)))
+ {
+ case 1: CGContextSetShouldAntialias(cr, true); break;
+ case 0: CGContextSetShouldAntialias(cr, false); break;
+ case -1:
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Failed to read antialiaseds array");
+ goto error;
+ }
+ }
+ }
+
+ if (Nlinewidths==1)
+ {
+ double linewidth = PyFloat_AsDouble(PySequence_ITEM(linewidths, 0));
+ CGContextSetLineWidth(cr, (CGFloat)linewidth);
+ }
+ else if (Nlinewidths==0)
+ CGContextSetLineWidth(cr, 0.0);
+
+ if (Nlinestyles==1)
+ {
+ PyObject* offset;
+ PyObject* dashes;
+ PyObject* linestyle = PySequence_ITEM(linestyles, 0);
+ if (!PyArg_ParseTuple(linestyle, "OO", &offset, &dashes)) goto error;
+ if (!_set_dashes(cr, offset, dashes)) goto error;
+ }
+
+ if (Nedgecolors==1)
+ {
+ const double r = *(double*)PyArray_GETPTR2(edgecolors, 0, 0);
+ const double g = *(double*)PyArray_GETPTR2(edgecolors, 0, 1);
+ const double b = *(double*)PyArray_GETPTR2(edgecolors, 0, 2);
+ const double a = *(double*)PyArray_GETPTR2(edgecolors, 0, 3);
+ CGContextSetRGBStrokeColor(cr, r, g, b, a);
+ }
+
+ if (Nfacecolors==1)
+ {
+ const double r = *(double*)PyArray_GETPTR2(facecolors, 0, 0);
+ const double g = *(double*)PyArray_GETPTR2(facecolors, 0, 1);
+ const double b = *(double*)PyArray_GETPTR2(facecolors, 0, 2);
+ const double a = *(double*)PyArray_GETPTR2(facecolors, 0, 3);
+ CGContextSetRGBFillColor(cr, r, g, b, a);
+ }
+
+ for (i = 0; i < N; i++)
+ {
+
+ if (Ntransforms)
+ {
+ transform = transforms[i % Ntransforms];
+ }
+ else
+ {
+ transform = master_transform;
+ }
+
+ if (Noffsets)
+ {
+ offset.x = (CGFloat) (*(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0));
+ offset.y = (CGFloat) (*(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1));
+ offset = CGPointApplyAffineTransform(offset, offset_transform);
+ transform.tx += offset.x;
+ transform.ty += offset.y;
+ }
+
+ if (Naa > 1)
+ {
+ switch(PyObject_IsTrue(PySequence_ITEM(antialiaseds, i % Naa)))
+ {
+ case 1: CGContextSetShouldAntialias(cr, true); break;
+ case 0: CGContextSetShouldAntialias(cr, false); break;
+ case -1:
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "Failed to read antialiaseds array");
+ goto error;
+ }
+ }
+ }
+
+ path = PySequence_ITEM(paths, i % Npaths);
+ int n = _draw_path(cr, path, transform);
+ if (n==-1) goto error;
+ else if (n==0) continue;
+
+ if (Nlinewidths > 1)
+ {
+ double linewidth = PyFloat_AsDouble(PySequence_ITEM(linewidths, i % Nlinewidths));
+ CGContextSetLineWidth(cr, (CGFloat)linewidth);
+ }
+
+ if (Nlinestyles > 1)
+ {
+ PyObject* offset;
+ PyObject* dashes;
+ PyObject* linestyle = PySequence_ITEM(linestyles, i % Nlinestyles);
+ if (!PyArg_ParseTuple(linestyle, "OO", &offset, &dashes)) goto error;
+ if (!_set_dashes(cr, offset, dashes)) goto error;
+ }
+
+ if (Nedgecolors > 1)
+ {
+ npy_intp fi = i % Nedgecolors;
+ const double r = *(double*)PyArray_GETPTR2(edgecolors, fi, 0);
+ const double g = *(double*)PyArray_GETPTR2(edgecolors, fi, 1);
+ const double b = *(double*)PyArray_GETPTR2(edgecolors, fi, 2);
+ const double a = *(double*)PyArray_GETPTR2(edgecolors, fi, 3);
+ CGContextSetRGBStrokeColor(cr, r, g, b, a);
+ }
+
+ if (Nfacecolors > 1)
+ {
+ npy_intp fi = i % Nfacecolors;
+ const double r = *(double*)PyArray_GETPTR2(facecolors, fi, 0);
+ const double g = *(double*)PyArray_GETPTR2(facecolors, fi, 1);
+ const double b = *(double*)PyArray_GETPTR2(facecolors, fi, 2);
+ const double a = *(double*)PyArray_GETPTR2(facecolors, fi, 3);
+ CGContextSetRGBFillColor(cr, r, g, b, a);
+ CGContextDrawPath(cr, kCGPathFillStroke);
+ }
+ else if (Nfacecolors==1)
+ CGContextDrawPath(cr, kCGPathFillStroke);
+ else
+ CGContextStrokePath(cr);
+ }
+
+success:
+ CGContextRestoreGState(cr);
+ if (transforms) free(transforms);
+ Py_DECREF(offsets);
+ Py_DECREF(facecolors);
+ Py_DECREF(edgecolors);
+
Py_INCREF(Py_None);
return Py_None;
+
+error:
+ CGContextRestoreGState(cr);
+ if (transforms) free(transforms);
+ Py_XDECREF(offsets);
+ Py_XDECREF(facecolors);
+ Py_XDECREF(edgecolors);
+
+ return NULL;
}
static PyObject*
-GraphicsContext_stroke (GraphicsContext* self, PyObject* args)
+GraphicsContext_draw_quad_mesh (GraphicsContext* self, PyObject* args)
{
- PyObject* color;
+ PyObject* master_transform_obj;
+ PyObject* cliprect;
+ PyObject* clippath;
+ PyObject* clippath_transform;
+ int meshWidth;
+ int meshHeight;
+ PyObject* vertices;
+ PyObject* offsets_obj;
+ PyObject* offset_transform_obj;
+ PyObject* facecolors_obj;
+ int antialiased;
+ int showedges;
+
CGContextRef cr = self->cr;
if (!cr)
@@ -811,35 +1746,219 @@
return NULL;
}
- if(!PyArg_ParseTuple(args, "O", &color)) return NULL;
+ if(!PyArg_ParseTuple(args, "OOOOiiOOOOii",
+ &master_transform_obj,
+ &cliprect,
+ &clippath,
+ &clippath_transform,
+ &meshWidth,
+ &meshHeight,
+ &vertices,
+ &offsets_obj,
+ &offset_transform_obj,
+ &facecolors_obj,
+ &antialiased,
+ &showedges)) return NULL;
- if(color!=Py_None)
+ PyArrayObject* offsets = NULL;
+ PyArrayObject* facecolors = NULL;
+
+ CGAffineTransform transform;
+ CGAffineTransform master_transform;
+ CGAffineTransform offset_transform;
+
+ if (!_convert_affine_transform(master_transform_obj, &master_transform))
+ return NULL;
+ if (!_convert_affine_transform(offset_transform_obj, &offset_transform))
+ return NULL;
+
+ /* clipping */
+
+ if (!_clip(cr, cliprect)) return NULL;
+ if (clippath!=Py_None)
{
- float r, g, b;
- if(!PyArg_ParseTuple(color, "fff", &r, &g, &b)) return NULL;
- if(self->pattern)
+ if (!_convert_affine_transform(clippath_transform, &transform))
+ return NULL;
+ int n = _draw_path(cr, clippath, transform);
+ if (n==-1) return NULL;
+ else if (n > 0) CGContextClip(cr);
+ }
+
+ PyArrayObject* coordinates;
+ coordinates = (PyArrayObject*)PyArray_FromObject(vertices,
+ NPY_DOUBLE, 3, 3);
+ if (!coordinates ||
+ PyArray_NDIM(coordinates) != 3 || PyArray_DIM(coordinates, 2) != 2)
+ {
+ PyErr_SetString(PyExc_ValueError, "Invalid coordinates array");
+ goto error;
+ }
+
+ /* ------------------- Check offsets array ---------------------------- */
+
+ offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj, NPY_DOUBLE, 0, 2);
+ if (!offsets ||
+ (PyArray_NDIM(offsets)==2 && PyArray_DIM(offsets, 1)!=2) ||
+ (PyArray_NDIM(offsets)==1 && PyArray_DIM(offsets, 0)!=0))
+ {
+ PyErr_SetString(PyExc_ValueError, "Offsets array must be Nx2");
+ goto error;
+ }
+
+ /* ------------------- Check facecolors array ------------------------- */
+
+ facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj,
+ NPY_DOUBLE, 1, 2);
+ if (!facecolors ||
+ (PyArray_NDIM(facecolors)==1 && PyArray_DIM(facecolors, 0)!=0) ||
+ (PyArray_NDIM(facecolors)==2 && PyArray_DIM(facecolors, 1)!=4))
+ {
+ PyErr_SetString(PyExc_ValueError, "Facecolors must by a Nx4 numpy array or empty");
+ goto error;
+ }
+
+ /* ------------------- Check the other arguments ---------------------- */
+
+ size_t Noffsets = (size_t) PyArray_DIM(offsets, 0);
+ size_t Npaths = meshWidth * meshHeight;
+ size_t Nfacecolors = (size_t) PyArray_DIM(facecolors, 0);
+ if ((Nfacecolors == 0 && !showedges) || Npaths == 0)
+ {
+ /* Nothing to do here */
+ goto success;
+ }
+
+ size_t i = 0;
+ size_t iw = 0;
+ size_t ih = 0;
+
+ CGPoint offset;
+
+ /* Preset graphics context properties if possible */
+ if (antialiased) CGContextSetShouldAntialias(cr, true);
+ else CGContextSetShouldAntialias(cr, false);
+
+ CGContextSetLineWidth(cr, 0.0);
+
+ if (Nfacecolors==1)
+ {
+ const double r = *(double*)PyArray_GETPTR2(facecolors, 0, 0);
+ const double g = *(double*)PyArray_GETPTR2(facecolors, 0, 1);
+ const double b = *(double*)PyArray_GETPTR2(facecolors, 0, 2);
+ const double a = *(double*)PyArray_GETPTR2(facecolors, 0, 3);
+ CGContextSetRGBFillColor(cr, r, g, b, a);
+ if (antialiased && !showedges)
{
- float components[4];
- components[0] = r;
- components[1] = g;
- components[2] = b;
- components[3] = 1.0;
- CGContextSetFillPattern(cr, self->pattern, components);
- CGPatternRelease (self->pattern);
- self->pattern = nil;
+ CGContextSetRGBStrokeColor(cr, r, g, b, a);
}
- else CGContextSetRGBFillColor(cr, r, g, b, 1.0);
- CGContextDrawPath(cr, kCGPathFillStroke);
}
- else CGContextStrokePath(cr);
+ if (showedges)
+ {
+ CGContextSetRGBStrokeColor(cr, 0, 0, 0, 1);
+ }
+
+ for (ih = 0; ih < meshHeight; ih++)
+ {
+ for (iw = 0; iw < meshWidth; iw++, i++)
+ {
+
+ transform = master_transform;
+
+ if (Noffsets)
+ {
+ offset.x = (CGFloat) (*(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0));
+ offset.y = (CGFloat) (*(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1));
+ offset = CGPointApplyAffineTransform(offset, offset_transform);
+ transform.tx += offset.x;
+ transform.ty += offset.y;
+ }
+
+ CGPoint p;
+ CGPoint points[4];
+
+ p.x = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih, iw, 0));
+ p.y = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih, iw, 1));
+ if (isnan(p.x) || isnan(p.y)) continue;
+ points[0] = CGPointApplyAffineTransform(p, transform);
+
+ p.x = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih, iw+1, 0));
+ p.y = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih, iw+1, 1));
+ if (isnan(p.x) || isnan(p.y)) continue;
+ points[1] = CGPointApplyAffineTransform(p, transform);
+
+ p.x = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih+1, iw+1, 0));
+ p.y = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih+1, iw+1, 1));
+ if (isnan(p.x) || isnan(p.y)) continue;
+ points[2] = CGPointApplyAffineTransform(p, transform);
+
+ p.x = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih+1, iw, 0));
+ p.y = (CGFloat)(*(double*)PyArray_GETPTR3(coordinates, ih+1, iw, 1));
+ if (isnan(p.x) || isnan(p.y)) continue;
+ points[3] = CGPointApplyAffineTransform(p, transf...
[truncated message content] |