SourceForge logo
SourceForge logo
Menu

matplotlib-checkins — Commit notification. DO NOT POST to this list, just subscribe to it.

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

Showing results of 5455

<< < 1 .. 204 205 206 207 208 .. 219 > >> (Page 206 of 219)
Revision: 3861
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3861&view=rev
Author: mdboom
Date: 2007年09月20日 05:31:26 -0700 (2007年9月20日)
Log Message:
-----------
Fix font.size from being saved in the fontManager.cache
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/font_manager.py
Modified: trunk/matplotlib/lib/matplotlib/font_manager.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/font_manager.py	2007年09月19日 19:48:17 UTC (rev 3860)
+++ trunk/matplotlib/lib/matplotlib/font_manager.py	2007年09月20日 12:31:26 UTC (rev 3861)
@@ -773,6 +773,7 @@
 else:
 if is_string_like(size):
 parent_size = fontManager.get_default_size()
+ print "parent_size", parent_size, size
 scaling = font_scalings.get(size)
 if scaling is not None:
 size = parent_size * scaling
@@ -843,10 +844,9 @@
 """
 
 def __init__(self, size=None, weight='normal'):
- if not size : size = rcParams['font.size']
- self.__default_size = size
 self.__default_weight = weight
-
+ self.default_size = size
+ 
 paths = [os.path.join(rcParams['datapath'],'fonts','ttf'),
 os.path.join(rcParams['datapath'],'fonts','afm')]
 
@@ -899,7 +899,9 @@
 
 def get_default_size(self):
 "Return the default font size."
- return self.__default_size
+ if self.default_size is None:
+ return rcParams['font.size']
+ return self.default_size
 
 def set_default_weight(self, weight):
 "Set the default font weight. The initial value is 'normal'."
@@ -1085,6 +1087,7 @@
 
 try:
 fontManager = pickle_load(_fmcache)
+ fontManager.default_size = None
 verbose.report("Using fontManager instance from %s" % _fmcache)
 except:
 _rebuild()
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月19日 19:48:22
Revision: 3860
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3860&view=rev
Author: mdboom
Date: 2007年09月19日 12:48:17 -0700 (2007年9月19日)
Log Message:
-----------
Use iterator rather than caching approach for paths
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月19日 19:46:34 UTC (rev 3859)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月19日 19:48:17 UTC (rev 3860)
@@ -112,8 +112,7 @@
 self.dpi = dpi
 self.width = width
 self.height = height
- if __debug__: verbose.report('RendererAgg.__init__ width=%s, \
- height=%s'%(width, height), 'debug-annoying')
+ if __debug__: verbose.report('RendererAgg.__init__ width=%s, height=%s'%(width, height), 'debug-annoying')
 self._renderer = _RendererAgg(int(width), int(height), dpi,
 				 debug=False)
 if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done',
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月19日 19:46:34 UTC (rev 3859)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月19日 19:48:17 UTC (rev 3860)
@@ -87,15 +87,17 @@
 inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, 
 			 double& x, double& y,
 			 size_t next_vertex_stride, 
-			 size_t next_axis_stride) {
+			 size_t next_axis_stride,
+			 const char* & code_i, size_t code_stride) {
 if (vertex_i + next_axis_stride >= vertex_end)
 throw Py::ValueError("Error parsing path. Read past end of vertices");
 x = *(double*)vertex_i;
 y = *(double*)(vertex_i + next_axis_stride);
 vertex_i += next_vertex_stride;
+ code_i += code_stride;
 }
 
-#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
+#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride, code_i, code_stride)
 
 Py::Object BufferRegion::to_string(const Py::Tuple &args) {
 
@@ -103,7 +105,71 @@
 return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true);
 }
 
+class PathIterator {
+ PyArrayObject* vertices;
+ PyArrayObject* codes;
+ size_t m_iterator;
+ size_t m_total_vertices;
 
+public:
+ PathIterator(const Py::Object& path_obj) :
+ vertices(NULL), codes(NULL), m_iterator(0) {
+ Py::Object vertices_obj = path_obj.getAttr("vertices");
+ Py::Object codes_obj = path_obj.getAttr("codes");
+ 
+ vertices = (PyArrayObject*)PyArray_ContiguousFromObject
+ (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2);
+ if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2)
+ throw Py::ValueError("Invalid vertices array.");
+ codes = (PyArrayObject*)PyArray_ContiguousFromObject
+ (codes_obj.ptr(), PyArray_UINT8, 1, 1);
+ if (!codes) 
+ throw Py::ValueError("Invalid codes array.");
+ 
+ if (codes->dimensions[0] != vertices->dimensions[0])
+ throw Py::ValueError("Vertices and codes array are not the same length.");
+
+ m_total_vertices = codes->dimensions[0];
+ }
+
+ ~PathIterator() {
+ Py_XDECREF(vertices);
+ Py_XDECREF(codes);
+ }
+
+ static const char code_map[];
+
+ inline unsigned vertex(unsigned idx, double* x, double* y) {
+ if (idx > m_total_vertices)
+ throw Py::RuntimeError("Requested vertex past end");
+ double* pv = (double*)(vertices->data + (idx * vertices->strides[0]));
+ *x = *pv++;
+ *y = *pv;
+ // MGDTODO: Range check
+ return code_map[(unsigned int)*(codes->data + (idx * codes->strides[0]))];
+ }
+
+ inline unsigned vertex(double* x, double* y) {
+ if(m_iterator >= m_total_vertices) return agg::path_cmd_stop;
+ return vertex(m_iterator++, x, y);
+ }
+
+ inline void rewind(unsigned path_id) {
+ m_iterator = path_id;
+ }
+
+ inline unsigned total_vertices() {
+ return m_total_vertices;
+ }
+};
+
+const char PathIterator::code_map[] = {0, 
+				 agg::path_cmd_move_to, 
+				 agg::path_cmd_line_to, 
+				 agg::path_cmd_curve3,
+				 agg::path_cmd_curve4,
+				 agg::path_cmd_end_poly | agg::path_flags_close};
+
 GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) :
 dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0),
 cliprect(NULL), clippath(NULL), 
@@ -634,7 +700,7 @@
 if (num_vertices) {
 	for (size_t j=0; j<num_vertices; ++j)
 	 GET_NEXT_VERTEX(x, y);
-	if (code_i == IGNORE)
+	if (*code_i == STOP || *code_i == CLOSEPOLY)
 	 continue;
 
 	trans.transform(&x, &y);
@@ -863,9 +929,10 @@
 
 for (size_t i = 0; i < N; ++i) {
 switch (*(unsigned char*)(code_i)) {
- case IGNORE:
+ case STOP:
 	GET_NEXT_VERTEX(x0, y0);
-	_VERBOSE("IGNORE");
+	_VERBOSE("STOP");
+	// MGDTODO: If this isn't the end, we should raise an error
 	break;
 case MOVETO:
 	GET_NEXT_VERTEX(x0, y0);
@@ -894,10 +961,10 @@
 	break;
 case CLOSEPOLY:
 	close_polygon();
+	GET_NEXT_VERTEX(x0, y0);
 	_VERBOSE("CLOSEPOLY");
 	break;
 }
- code_i += code_stride;
 }
 } catch(...) {
 Py_XDECREF(vertices);
@@ -911,7 +978,7 @@
 
 Py::Object
 RendererAgg::draw_path(const Py::Tuple& args) {
- typedef agg::conv_transform<agg::path_storage> transformed_path_t;
+ typedef agg::conv_transform<PathIterator> transformed_path_t;
 typedef agg::conv_curve<transformed_path_t> curve_t;
 typedef agg::conv_stroke<curve_t> stroke_t;
 typedef agg::conv_dash<curve_t> dash_t;
@@ -928,9 +995,11 @@
 
 GCAgg gc = GCAgg(args[0], dpi);
 Py::Object path_obj = args[1];
- if (!PathAgg::check(path_obj))
- throw Py::TypeError("Native path object is not of correct type");
- PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
+// if (!PathAgg::check(path_obj))
+// throw Py::TypeError("Native path object is not of correct type");
+ // PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
+ PathIterator path(path_obj);
+
 agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]);
 facepair_t face = _get_rgba_face(args[3], gc.alpha);
 
@@ -943,34 +1012,34 @@
 bool has_clippath = (gc.clippath != NULL);
 
 if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) {
- rendererBaseAlphaMask->clear(agg::gray8(0, 0));
- gc.clippath->rewind(0);
- transformed_path_t transformed_clippath(*(gc.clippath), trans);
- theRasterizer->add_path(transformed_clippath);
- rendererAlphaMask->color(agg::gray8(255, 255));
- agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
- lastclippath = gc.clippath;
- lastclippath_transform = trans;
+// rendererBaseAlphaMask->clear(agg::gray8(0, 0));
+// gc.clippath->rewind(0);
+// transformed_path_t transformed_clippath(*(gc.clippath), trans);
+// theRasterizer->add_path(transformed_clippath);
+// rendererAlphaMask->color(agg::gray8(255, 255));
+// agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
+// lastclippath = gc.clippath;
+// lastclippath_transform = trans;
 }
 
 try {
 // If this is a straight horizontal or vertical line, quantize to nearest 
 // pixels
- if (path->total_vertices() == 2) {
- double x0, y0, x1, y1;
- path->vertex(0, &x0, &y0);
- trans.transform(&x0, &y0);
- path->vertex(1, &x1, &y1);
- trans.transform(&x1, &y1);
- if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) {
-	new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5);
-	new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5);
-	tpath = new transformed_path_t(new_path, agg::trans_affine());
- }
- }
+// if (path.total_vertices() == 2) {
+// double x0, y0, x1, y1;
+// path.vertex(0, &x0, &y0);
+// trans.transform(&x0, &y0);
+// path.vertex(1, &x1, &y1);
+// trans.transform(&x1, &y1);
+// if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) {
+// 	new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5);
+// 	new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5);
+// 	tpath = new transformed_path_t(new_path, agg::trans_affine());
+// }
+// }
 
 if (!tpath) {
- tpath = new transformed_path_t(*path, trans);
+ tpath = new transformed_path_t(path, trans);
 }
 
 // Benchmarking shows that there is no noticable slowdown to always
Modified: branches/transforms/src/_backend_agg.h
===================================================================
--- branches/transforms/src/_backend_agg.h	2007年09月19日 19:46:34 UTC (rev 3859)
+++ branches/transforms/src/_backend_agg.h	2007年09月19日 19:48:17 UTC (rev 3860)
@@ -40,14 +40,14 @@
 #include "agg_vcgen_markers_term.h"
 
 // These are copied directly from path.py, and must be kept in sync
-#define IGNORE 0
+#define STOP 0
 #define MOVETO 1
 #define LINETO 2
 #define CURVE3 3
 #define CURVE4 4
 #define CLOSEPOLY 5
 
-const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 0 };
+const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 1 };
 
 typedef agg::pixfmt_rgba32 pixfmt;
 typedef agg::renderer_base<pixfmt> renderer_base;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月19日 19:46:41
Revision: 3859
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3859&view=rev
Author: mdboom
Date: 2007年09月19日 12:46:34 -0700 (2007年9月19日)
Log Message:
-----------
Lots of minor fixes
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/pbox.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -252,12 +252,9 @@
 if not is_numlike(self.pickradius):
 raise ValueError,"pick radius should be a distance"
 
- if self._newstyle:
- # transform in backend
- x = self._x
- y = self._y
- else:
- x, y = self._get_plottable()
+ # transform in backend
+ x = self._x
+ y = self._y
 if len(x)==0: return False,{}
 
 xt, yt = self.get_transform().numerix_x_y(x, y)
@@ -337,7 +334,6 @@
 
 ACCEPTS: (npy.array xdata, npy.array ydata)
 """
-
 if len(args)==1:
 x, y = args[0]
 else:
@@ -347,8 +343,9 @@
 self._yorig = y
 self.recache()
 
+ # MGDTODO: Masked data arrays are broken
 _masked_array_to_path_code_mapping = npy.array(
- [Path.LINETO, Path.IGNORE, Path.MOVETO], Path.code_type)
+ [Path.LINETO, Path.MOVETO, Path.MOVETO], Path.code_type)
 def recache(self):
 #if self.axes is None: print 'recache no axes'
 #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
@@ -387,18 +384,18 @@
 # MGDTODO: If _draw_steps is removed, remove the following line also
 self._step_path = None
 
-
 def _is_sorted(self, x):
 "return true if x is sorted"
 if len(x)<2: return 1
 return npy.alltrue(x[1:]-x[0:-1]>=0)
 
+ # MGDTODO: Remove me (seems to be used for old-style interface only)
 def _get_plottable(self):
 # If log scale is set, only pos data will be returned
 
 x, y = self._x, self._y
 
-	# MGDTODO: Deal with the log scale here
+	# MGDTODO: (log-scaling)
 	
 # try: logx = self.get_transform().get_funcx().get_type()==LOG10
 # except RuntimeError: logx = False # non-separable
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -319,8 +319,6 @@
 return str(self.__class__).split('.')[-1] \
 + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height)
 
- # MGDTODO: Perhaps pass in a Bbox here instead, then the updates will
- # happen automatically (without needing to call set_x etc.
 def __init__(self, xy, width, height, **kwargs):
 """
 xy is an x,y tuple lower, left
@@ -459,17 +457,14 @@
 
 def __init__(self, xy, **kwargs):
 """
- xy is a sequence of (x,y) 2 tuples
+ xy is a numpy array with shape Nx2
 
 Valid kwargs are:
 %(Patch)s
 See Patch documentation for additional kwargs
 """
-	# MGDTODO: This should encourage the use of numpy arrays of shape Nx2
 Patch.__init__(self, **kwargs)
- if not isinstance(xy, list):
- xy = list(xy)
-	self._path = Path(xy, closed=False)
+	self._path = Path(xy, closed=True)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
 def get_verts(self):
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -1,15 +1,13 @@
 import numpy as npy
 
-DEBUG = True
-
 class Path(object):
 # Path codes
- IGNORE = 0 # 1 vertex
+ STOP = 0 # 1 vertex
 MOVETO = 1 # 1 vertex
 LINETO = 2 # 1 vertex
 CURVE3 = 3 # 2 vertices
 CURVE4 = 4 # 3 vertices
- CLOSEPOLY = 5
+ CLOSEPOLY = 5 # 1 vertex
 ###
 # MGDTODO: I'm not sure these are supported by PS/PDF/SVG,
 # so if they don't, we probably shouldn't
@@ -18,38 +16,36 @@
 UBSPLINE = 8
 ####
 
- NUM_VERTICES = [1, 1, 1, 2, 3, 0]
+ NUM_VERTICES = [1, 1, 1, 2, 3, 1]
 
 code_type = npy.uint8
 
 def __init__(self, vertices, codes=None, closed=True):
-	self._vertices = npy.asarray(vertices, npy.float_)
-	assert self._vertices.ndim == 2
-	assert self._vertices.shape[1] == 2
-
+ vertices = npy.asarray(vertices, npy.float_)
+	assert vertices.ndim == 2
+	assert vertices.shape[1] == 2
+ 
 	if codes is None:
 	 if closed:
 		codes = self.LINETO * npy.ones(
-		 self._vertices.shape[0] + 1, self.code_type)
+		 vertices.shape[0] + 1, self.code_type)
 		codes[0] = self.MOVETO
-		codes[-1] = self.CLOSEPOLY
+ codes[-1] = self.CLOSEPOLY
+ vertices = npy.concatenate((vertices, [[0.0, 0.0]]))
 	 else:
 		codes = self.LINETO * npy.ones(
-		 self._vertices.shape[0], self.code_type)
+		 vertices.shape[0], self.code_type)
 		codes[0] = self.MOVETO
 else:
 	 codes = npy.asarray(codes, self.code_type)
-	self._codes = codes
-	 
+ assert codes.ndim == 1
+ assert len(codes) == len(vertices)
+
+ self._codes = codes
+	self._vertices = vertices
+ 
 	assert self._codes.ndim == 1
 
-	if DEBUG:
-	 i = 0
-	 NUM_VERTICES = self.NUM_VERTICES
-	 for code in codes:
-		i += NUM_VERTICES[code]
-	 assert i == len(self.vertices)
-
 def __repr__(self):
 	return "Path(%s, %s)" % (self.vertices, self.codes)
 	 
@@ -66,11 +62,13 @@
 	NUM_VERTICES = self.NUM_VERTICES
 	vertices = self.vertices
 	for code in self.codes:
-	 num_vertices = NUM_VERTICES[code]
-	 if num_vertices >= 1:
-		i += num_vertices - 1
-		yield vertices[i]
-		i += 1
+ if code == self.CLOSEPOLY:
+ i += 1
+ else:
+ num_vertices = NUM_VERTICES[code]
+ i += num_vertices - 1
+ yield vertices[i]
+ i += 1
 
 _unit_rectangle = None
 #@classmethod
@@ -118,16 +116,18 @@
 		 
 		 [-offset, -1.0],
 		 [-1.0, -offset],
-		 [-1.0, 0.0]],
-		npy.float_)
-	 codes = npy.array(
-		[cls.MOVETO,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CURVE4,
-		 cls.CLOSEPOLY],
-		cls.code_type)
+		 [-1.0, 0.0],
+
+ [-1.0, 0.0]],
+ npy.float_)
+
+ codes = cls.CURVE4 + npy.ones((len(vertices)))
+	 codes[0] = cls.MOVETO
+ codes[-1] = cls.CLOSEPOLY
+
 	 cls._unit_circle = Path(vertices, codes)
 	return cls._unit_circle
 unit_circle = classmethod(unit_circle)
+
+# MGDTODO: Add a transformed path that would automatically invalidate
+# itself when its transform changes
Modified: branches/transforms/lib/matplotlib/pbox.py
===================================================================
--- branches/transforms/lib/matplotlib/pbox.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/pbox.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -1,5 +1,3 @@
-# MGDTODO: Just included verbatim for now
-
 class PBox(list):
 '''
 A left-bottom-width-height (lbwh) specification of a bounding box,
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -231,7 +231,7 @@
 
 # now rotate the bbox
 
- cornersRotated = M(cornersHoriz)
+ cornersRotated = M.transform(cornersHoriz)
 
 txs = cornersRotated[:, 0]
 tys = cornersRotated[:, 1]
@@ -269,7 +269,7 @@
 	
 
 # now rotate the positions around the first x,y position
- xys = M(offsetLayout)
+ xys = M.transform(offsetLayout)
 	tx = xys[:, 0]
 	ty = xys[:, 1]
 	tx += offsetx
@@ -277,7 +277,7 @@
 
 # now inverse transform back to data coords
 	inverse_transform = self.get_transform().inverted()
- xys = inverse_transform(xys)
+ xys = inverse_transform.transform(xys)
 
 xs, ys = zip(*xys)
 
@@ -407,7 +407,7 @@
 return (x, y, self._text, self._color,
 self._verticalalignment, self._horizontalalignment,
 hash(self._fontproperties), self._rotation,
- self.get_transform().to_values(),
+ self.get_transform(),
 )
 
 def get_text(self):
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 16:18:51 UTC (rev 3858)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 19:46:34 UTC (rev 3859)
@@ -32,7 +32,8 @@
 for child in children:
 getattr(self, child)._parents.add(self)
 self._children = children
- 
+
+ 
 class BboxBase(TransformNode):
 '''
 This is the read-only part of a bounding-box
@@ -293,6 +294,7 @@
 return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
 union = staticmethod(union)
 
+ 
 class TransformedBbox(BboxBase):
 def __init__(self, bbox, transform):
 assert isinstance(bbox, Bbox)
@@ -313,16 +315,20 @@
 
 def get_points(self):
 if self._points is None:
- self._points = self.transform(self.bbox.get_points())
+ self._points = self.transform.transform(self.bbox.get_points())
 return self._points
+
 
 class Transform(TransformNode):
 def __init__(self):
 TransformNode.__init__(self)
 
- def __call__(self, points):
+ def transform(self, points):
 raise NotImplementedError()
 
+ def transform_without_affine(self, points):
+ return self.transform(points), IDENTITY
+ 
 def __add__(self, other):
 if isinstance(other, Transform):
 return composite_transform_factory(self, other)
@@ -336,7 +342,7 @@
 "Can not add Transform to object of type '%s'" % type(other))
 
 def transform_point(self, point):
- return self.__call__(npy.asarray([point]))[0]
+ return self.transform(npy.asarray([point]))[0]
 
 def has_inverse(self):
 raise NotImplementedError()
@@ -350,6 +356,7 @@
 def is_affine(self):
 return False
 
+ 
 class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
@@ -390,7 +397,7 @@
 def get_matrix(self):
 raise NotImplementedError()
 
- def __call__(self, points):
+ def transform(self, points):
 """
 Applies the transformation to an array of 2D points and
 returns the result.
@@ -414,6 +421,11 @@
 points = npy.dot(mtx[0:2, 0:2], points)
 points = points + mtx[0:2, 2:]
 return points.transpose()
+
+ def transform_without_affine(self, points):
+ # MGDTODO: Should we copy the points here? I'd like to avoid it,
+ # if possible
+ return points, self
 
 def inverted(self):
 if self._inverted is None:
@@ -430,9 +442,6 @@
 
 
 class Affine2D(Affine2DBase):
- input_dims = 2
- output_dims = 2
- 
 def __init__(self, matrix = None):
 """
 Initialize an Affine transform from a 3x3 numpy float array.
@@ -535,40 +544,82 @@
 
 def is_affine(self):
 return True
+
+IDENTITY = Affine2D()
 
 class BlendedGenericTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
 def __init__(self, x_transform, y_transform):
 	# Here we ask: "Does it blend?"
 assert x_transform.is_separable()
 assert y_transform.is_separable()
-
+ assert x_transform.input_dims == x_transform.output_dims == 2
+ assert y_transform.input_dims == y_transform.output_dims == 2
+ 
 Transform.__init__(self)
 self._x = x_transform
 self._y = y_transform
 self.set_children(['_x', '_y'])
 
- def __call__(self, points):
- if self._x == self._y:
+ def transform(self, points):
+ # MGDTODO: Optimize the case where one of these is
+ # an affine
+ x = self._x
+ y = self._y
+ if x == y and x.input_dims == 2:
 return self._x(points)
- 
- x_points = self._x(points)
- y_points = self._y(points)
- # This works because we already know the transforms are
- # separable
- return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
 
-# def set_x_transform(self, x_transform):
-# self.replace_child(0, x_transform)
+ if x.input_dims == 2:
+ x_points = x.transform(points)[:, 0]
+ else:
+ x_points = x.transform(points[:, 0])
 
-# def set_y_transform(self, y_transform):
-# self.replace_child(1, y_transform)
+ if y.input_dims == 2:
+ y_points = y.transform(points)[:, 1]
+ else:
+ y_points = y.transform(points[:, 1])
 
+ return npy.vstack((x_points, y_points)).transpose()
+
+ def inverted(self):
+ return BlendedGenericTransform(self._x.inverted(), self._y.inverted())
 
-class BlendedAffine2D(Affine2DBase, BlendedGenericTransform):
+ def is_separable(self):
+ return True
+ 
+ 
+class BlendedSeparableTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+
 def __init__(self, x_transform, y_transform):
+	# Here we ask: "Does it blend?"
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
+ assert x_transform.input_dims == x.transform.output_dims == 1
+ assert y_transform.input_dims == y.transform.output_dims == 1
+ 
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
+
+ def transform(self, points):
+ x_points = self._x(points[:, 0])
+ y_points = self._y(points[:, 1])
+ return npy.vstack((x_points[:, 0:1], y_points[:, 1:2])).transpose()
+ 
+ 
+class BlendedAffine2D(Affine2DBase, Transform):
+ def __init__(self, x_transform, y_transform):
 assert x_transform.is_affine()
 assert y_transform.is_affine()
- BlendedGenericTransform.__init__(self, x_transform, y_transform)
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
 
 Affine2DBase.__init__(self)
 self._mtx = None
@@ -597,12 +648,14 @@
 # c to zero.
 self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 return self._mtx
- 
+
+ 
 def blended_transform_factory(x_transform, y_transform):
 if x_transform.is_affine() and y_transform.is_affine():
 return BlendedAffine2D(x_transform, y_transform)
 return BlendedGenericTransform(x_transform, y_transform)
 
+
 class CompositeGenericTransform(Transform):
 def __init__(self, a, b):
 assert a.output_dims == b.input_dims
@@ -614,9 +667,17 @@
 self._b = b
 self.set_children(['_a', '_b'])
 
- def __call__(self, points):
- return self._b(self._a(points))
+ def transform(self, points):
+ return self._b.transform(self._a.transform(points))
+
+ def inverted(self):
+ return CompositeGenericTransform(self._b.inverted(), self._a.inverted())
 
+ def is_separable(self):
+ return True
+ return self._a.is_separable() and self._b.is_separable()
+
+ 
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
 assert a.is_affine()
@@ -643,11 +704,32 @@
 self._b.get_matrix())
 return self._mtx
 
+ 
 def composite_transform_factory(a, b):
 if a.is_affine() and b.is_affine():
 return CompositeAffine2D(a, b)
 return CompositeGenericTransform(a, b)
+
+
+class LogTransform(Transform):
+ input_dims = 1
+ output_dims = 1
 
+ def transform(self, a):
+ m = npy.ma.masked_where(a < 0, a)
+ return npy.log10(m)
+
+
+class TestLogTransform(Transform):
+ input_dims = 2
+ output_dims = 2
+ def transform(self, xy):
+ return xy * 2
+
+ def inverted(self):
+ return self
+
+ 
 class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
 assert isinstance(boxin, BboxBase)
@@ -688,6 +770,7 @@
 self._mtx = affine._mtx
 return self._mtx
 
+ 
 def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
 '''
 Ensure the endpoints of a range are not too close together.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月19日 16:18:56
Revision: 3858
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3858&view=rev
Author: mdboom
Date: 2007年09月19日 09:18:51 -0700 (2007年9月19日)
Log Message:
-----------
Got steps_demo.py working
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/transforms.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -40,7 +40,7 @@
 def _get_cached_native_path(self, path):
 	native_path = self._native_paths.get(path)
 	if native_path is None:
-	 # print "CACHE MISS", path
+	 print "CACHE MISS", path
 	 native_path = self.convert_to_native_path(path)
 	 self._native_paths[path] = native_path
 	return native_path
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -25,53 +25,6 @@
 (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN,
 CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8)
 
-def unmasked_index_ranges(mask, compressed = True):
- '''
- Calculate the good data ranges in a masked 1-D npy.array, based on mask.
-
- Returns Nx2 npy.array with each row the start and stop indices
- for slices of the compressed npy.array corresponding to each of N
- uninterrupted runs of unmasked values.
- If optional argument compressed is False, it returns the
- start and stop indices into the original npy.array, not the
- compressed npy.array.
- Returns None if there are no unmasked values.
-
- Example:
-
- y = ma.array(npy.arange(5), mask = [0,0,1,0,0])
- #ii = unmasked_index_ranges(y.mask())
- ii = unmasked_index_ranges(ma.getmask(y))
- # returns [[0,2,] [2,4,]]
-
- y.compressed().filled()[ii[1,0]:ii[1,1]]
- # returns npy.array [3,4,]
- # (The 'filled()' method converts the masked npy.array to a numerix npy.array.)
-
- #i0, i1 = unmasked_index_ranges(y.mask(), compressed=False)
- i0, i1 = unmasked_index_ranges(ma.getmask(y), compressed=False)
- # returns [[0,3,] [2,5,]]
-
- y.filled()[ii[1,0]:ii[1,1]]
- # returns npy.array [3,4,]
-
- '''
- m = npy.concatenate(((1,), mask, (1,)))
- indices = npy.arange(len(mask) + 1)
- mdif = m[1:] - m[:-1]
- i0 = npy.compress(mdif == -1, indices)
- i1 = npy.compress(mdif == 1, indices)
- assert len(i0) == len(i1)
- if len(i1) == 0:
- return None
- if not compressed:
- return npy.concatenate((i0[:, npy.newaxis], i1[:, npy.newaxis]), axis=1)
- seglengths = i1 - i0
- breakpoints = npy.cumsum(seglengths)
- ic0 = npy.concatenate(((0,), breakpoints[:-1]))
- ic1 = breakpoints
- return npy.concatenate((ic0[:, npy.newaxis], ic1[:, npy.newaxis]), axis=1)
-
 def segment_hits(cx,cy,x,y,radius):
 """Determine if any line segments are within radius of a point. Returns
 the list of line segments that are within that radius.
@@ -117,7 +70,7 @@
 '--' : '_draw_dashed',
 '-.' : '_draw_dash_dot',
 ':' : '_draw_dotted',
- 'steps': '_draw_solid',
+ 'steps': '_draw_steps',
 'None' : '_draw_nothing',
 ' ' : '_draw_nothing',
 '' : '_draw_nothing',
@@ -394,6 +347,8 @@
 self._yorig = y
 self.recache()
 
+ _masked_array_to_path_code_mapping = npy.array(
+ [Path.LINETO, Path.IGNORE, Path.MOVETO], Path.code_type)
 def recache(self):
 #if self.axes is None: print 'recache no axes'
 #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
@@ -411,36 +366,28 @@
 if len(x) != len(y):
 raise RuntimeError('xdata and ydata must be the same length')
 
-	# MGDTODO: Deal with segments
+	self._xy = npy.vstack((npy.asarray(x, npy.float_),
+			 npy.asarray(y, npy.float_))).transpose()
+	self._x = self._xy[:, 0] # just a view
+	self._y = self._xy[:, 1] # just a view
+ self._logcache = None
+
 mx = ma.getmask(x)
 my = ma.getmask(y)
 mask = ma.mask_or(mx, my)
+ codes = None
 if mask is not ma.nomask:
- x = ma.masked_array(x, mask=mask).compressed()
- y = ma.masked_array(y, mask=mask).compressed()
- self._segments = unmasked_index_ranges(mask)
- else:
- self._segments = None
-
-	self._xy = npy.vstack((npy.asarray(x, npy.float_),
-			 npy.asarray(y, npy.float_))).transpose()
-	self._x = self._xy[:, 0]
-	self._y = self._xy[:, 1]
- self._logcache = None
+ m = npy.concatenate(((1,), mask, (1,)))
+ mdif = m[1:] - m[:-1]
+ mdif = npy.maximum((mdif[:-1] * -2), mask)
+ codes = npy.take(
+ self._masked_array_to_path_code_mapping,
+ mdif)
+ self._path = Path(self._xy, codes, closed=False)
+ # MGDTODO: If _draw_steps is removed, remove the following line also
+ self._step_path = None
 
- if self._linestyle == 'steps':
- siz=len(xt)
- if siz<2: return
- xt, yt = self._x, self._y
- xt2=npy.ones((2*siz,), xt.dtype)
- xt2[0:-1:2], xt2[1:-1:2], xt2[-1] = xt, xt[1:], xt[-1]
- yt2=npy.ones((2*siz,), yt.dtype)
- yt2[0:-1:2], yt2[1::2] = yt, yt
- self._path = Path(npy.vstack((xt2, yt2)).transpose(), closed=False)
- else:
- self._path = Path(self._xy, closed=False)
 
-
 def _is_sorted(self, x):
 "return true if x is sorted"
 if len(x)<2: return 1
@@ -507,14 +454,7 @@
 
 funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
 lineFunc = getattr(self, funcname)
-
-	# MGDTODO: Deal with self._segments
- if self._segments is not None:
- for ii in self._segments:
- lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]])
-
- else:
- lineFunc(renderer, gc, self._path)
+ lineFunc(renderer, gc, self._path)
 	 
 	# MGDTODO: Deal with markers
 if self._marker is not None:
@@ -709,7 +649,29 @@
 def _draw_nothing(self, renderer, gc, path):
 pass
 
- 
+
+ def _draw_steps(self, renderer, gc, path):
+ # We generate the step function path on-the-fly, and then cache it.
+ # The cache may be later invalidated when the data changes
+ # (in self.recache())
+
+ # MGDTODO: Untested -- using pylab.step doesn't actually trigger
+ # this code -- the path is "stepped" before even getting to this
+ # class. Perhaps this should be removed here, since it is not as
+ # powerful as what is in axes.step() anyway.
+ if self._step_path is None:
+ vertices = self._path.vertices
+ codes = self._path.codes
+ siz = len(vertices)
+ if siz<2: return
+ new_vertices = npy.zeros((2*siz, 2), vertices.dtype)
+ new_vertices[0:-1:2, 0], new_vertices[1:-1:2, 0], newvertices[-1, 0] = vertices[:, 0], vertices[1:, 0], vertices[-1, 0]
+ new_vertices[0:-1:2, 1], new_vertices[1::2, 1] = vertices[:, 1], vertices[:, 1]
+ self._step_path = Path(new_vertices, closed=False)
+ gc.set_linestyle('solid')
+	renderer.draw_path(gc, self._step_path, self.get_transform())
+
+ 
 def _draw_solid(self, renderer, gc, path):
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, self.get_transform())
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -1,10 +1,10 @@
 import numpy as npy
 
-VALIDATE_PATHS = True
+DEBUG = True
 
 class Path(object):
 # Path codes
- STOP = 0
+ IGNORE = 0 # 1 vertex
 MOVETO = 1 # 1 vertex
 LINETO = 2 # 1 vertex
 CURVE3 = 3 # 2 vertices
@@ -18,7 +18,7 @@
 UBSPLINE = 8
 ####
 
- NUM_VERTICES = [0, 1, 1, 2, 3, 0]
+ NUM_VERTICES = [1, 1, 1, 2, 3, 0]
 
 code_type = npy.uint8
 
@@ -43,7 +43,7 @@
 	 
 	assert self._codes.ndim == 1
 
-	if VALIDATE_PATHS:
+	if DEBUG:
 	 i = 0
 	 NUM_VERTICES = self.NUM_VERTICES
 	 for code in codes:
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -32,18 +32,6 @@
 for child in children:
 getattr(self, child)._parents.add(self)
 self._children = children
-
- # MGDTODO: decide whether we need this in-place updating and
- # remove if not
-# def replace_child(self, index, child):
-# children = self._children
-# getattr(self, children[index])._parents.remove(self)
-# setattr(self, children[index], child)
-# # We have to reset children in case two or more
-# # of the children are the same
-# for child in children:
-# getattr(self, child)._parents.add(self)
-# self.invalidate()
 
 class BboxBase(TransformNode):
 '''
@@ -327,53 +315,7 @@
 if self._points is None:
 self._points = self.transform(self.bbox.get_points())
 return self._points
-
-# MGDTODO: This code probably works, but I don't think it's a good idea
-# (from a code clarity perspective)
-# class BlendedBbox(BboxBase):
-# def __init__(self, bbox_x, bbox_y):
-# assert isinstance(bbox_x, BboxBase)
-# assert isinstance(bbox_y, BboxBase)
-
-# BboxBase.__init__(self)
-# self._x = bbox_x
-# self._y = bbox_y
-# self.set_children(['_x', '_y'])
-# self._points = None
-
-# def __repr__(self):
-# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
-# __str__ = __repr__
 
-# def _do_invalidation(self):
-# self._points = None
-
-# def get_points(self):
-# if self._points is None:
-# # MGDTODO: Optimize
-# if self._x == self._y:
-# self._points = self._x.get_points()
-# else:
-# x_points = self._x.get_points()
-# y_points = self._y.get_points()
-# self._points = npy.array(
-# [[x_points[0,0], y_points[0,1]],
-# [x_points[1,0], y_points[1,1]]],
-# npy.float_)
-# return self._points
-
-# def _set_intervalx(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
-# self.replace_child(0, bbox)
-# intervalx = property(BboxBase._get_intervalx, _set_intervalx)
-
-# def _set_intervaly(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
-# self.replace_child(1, bbox)
-# intervaly = property(BboxBase._get_intervaly, _set_intervaly)
- 
 class Transform(TransformNode):
 def __init__(self):
 TransformNode.__init__(self)
@@ -746,7 +688,6 @@
 self._mtx = affine._mtx
 return self._mtx
 
-# MGDTODO: There's probably a better place for this
 def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
 '''
 Ensure the endpoints of a range are not too close together.
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -634,6 +634,9 @@
 if (num_vertices) {
 	for (size_t j=0; j<num_vertices; ++j)
 	 GET_NEXT_VERTEX(x, y);
+	if (code_i == IGNORE)
+	 continue;
+
 	trans.transform(&x, &y);
 	
 	if (face.first) {
@@ -860,6 +863,10 @@
 
 for (size_t i = 0; i < N; ++i) {
 switch (*(unsigned char*)(code_i)) {
+ case IGNORE:
+	GET_NEXT_VERTEX(x0, y0);
+	_VERBOSE("IGNORE");
+	break;
 case MOVETO:
 	GET_NEXT_VERTEX(x0, y0);
 	move_to(x0, y0);
Modified: branches/transforms/src/_backend_agg.h
===================================================================
--- branches/transforms/src/_backend_agg.h	2007年09月19日 13:28:11 UTC (rev 3857)
+++ branches/transforms/src/_backend_agg.h	2007年09月19日 16:18:51 UTC (rev 3858)
@@ -40,14 +40,14 @@
 #include "agg_vcgen_markers_term.h"
 
 // These are copied directly from path.py, and must be kept in sync
-#define STOP 0
+#define IGNORE 0
 #define MOVETO 1
 #define LINETO 2
 #define CURVE3 3
 #define CURVE4 4
 #define CLOSEPOLY 5
 
-const size_t NUM_VERTICES[] = { 0, 1, 1, 2, 3, 0 };
+const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 0 };
 
 typedef agg::pixfmt_rgba32 pixfmt;
 typedef agg::renderer_base<pixfmt> renderer_base;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月19日 13:28:21
Revision: 3857
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3857&view=rev
Author: mdboom
Date: 2007年09月19日 06:28:11 -0700 (2007年9月19日)
Log Message:
-----------
Got legend working with new transforms
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/transforms.py
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -632,6 +632,7 @@
 	
 self.transAxes = mtransforms.BboxTransform(
 mtransforms.Bbox.unit(), self.bbox)
+ # self.set_transform(self.transAxes)
 self.transData = mtransforms.BboxTransform(
 self.viewLim, self.bbox)
 	 
@@ -724,6 +725,7 @@
 self.axesPatch.set_figure(self.figure)
 self.axesPatch.set_transform(self.transAxes)
 self.axesPatch.set_linewidth(rcParams['axes.linewidth'])
+ # MGDTODO: What is axesFrame for? We already have axesPatch
 self.axesFrame = mlines.Line2D((0,1,1,0,0), (0,0,1,1,0),
 linewidth=rcParams['axes.linewidth'],
 color=rcParams['axes.edgecolor'],
@@ -5201,7 +5203,7 @@
 Subplot(211) # 2 rows, 1 column, first (upper) plot
 """
 def __str__(self):
- return "Subplot(%g,%g)"%(self.bottom.get(),self.left.get())
+ return "Subplot(%f,%f,%f,%f)" % (self.bbox.bounds)
 
 def __init__(self, fig, *args, **kwargs):
 """
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -164,7 +164,7 @@
 else:
 raise TypeError("Legend needs either Axes or Figure as parent")
 self.parent = parent
- self.set_transform( BboxTransform( Bbox.unit(), parent.bbox) )
+ self.set_transform( BboxTransform(Bbox.unit(), parent.bbox) )
 
 if loc is None:
 loc = rcParams["legend.loc"]
@@ -223,7 +223,7 @@
 a.set_transform(self.get_transform())
 
 def _approx_text_height(self):
- return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height()
+ return self.fontsize/72.0*self.figure.dpi/self.parent.bbox.height
 
 
 def draw(self, renderer):
@@ -531,7 +531,7 @@
 def get_tbounds(text): #get text bounds in axes coords
 bbox = text.get_window_extent(renderer)
 bboxa = bbox.inverse_transformed(self.get_transform())
- return bboxa.get_bounds()
+ return bboxa.bounds
 
 hpos = []
 for t, tabove in zip(self.texts[1:], self.texts[:-1]):
@@ -560,10 +560,10 @@
 # Set the data for the legend patch
 bbox = copy.copy(self._get_handle_text_bbox(renderer))
 
- bbox = bbox.scaled(1 + self.pad, 1 + self.pad)
- l,b,w,h = bbox.get_bounds()
- self.legendPatch.set_bounds(l,b,w,h)
-
+ bbox = bbox.expanded(1 + self.pad, 1 + self.pad)
+ l, b, w, h = bbox.bounds
+ self.legendPatch.set_bounds(l, b, w, h)
+ 
 ox, oy = 0, 0 # center
 
 if iterable(self._loc) and len(self._loc)==2:
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -117,7 +117,7 @@
 '--' : '_draw_dashed',
 '-.' : '_draw_dash_dot',
 ':' : '_draw_dotted',
- 'steps': '_draw_steps',
+ 'steps': '_draw_solid',
 'None' : '_draw_nothing',
 ' ' : '_draw_nothing',
 '' : '_draw_nothing',
@@ -352,10 +352,10 @@
 self._picker = p
 
 def get_window_extent(self, renderer):
- xys = self.get_transform()(self._xys)
+ xy = self.get_transform()(self._xy)
 
-	x = xys[:, 0]
-	y = xys[:, 1]
+	x = xy[:, 0]
+	y = xy[:, 1]
 left = x.min()
 bottom = y.min()
 width = x.max() - left
@@ -426,9 +426,19 @@
 			 npy.asarray(y, npy.float_))).transpose()
 	self._x = self._xy[:, 0]
 	self._y = self._xy[:, 1]
-	self._path = Path(self._xy, closed=False)
-	
 self._logcache = None
+ 
+ if self._linestyle == 'steps':
+ siz=len(xt)
+ if siz<2: return
+ xt, yt = self._x, self._y
+ xt2=npy.ones((2*siz,), xt.dtype)
+ xt2[0:-1:2], xt2[1:-1:2], xt2[-1] = xt, xt[1:], xt[-1]
+ yt2=npy.ones((2*siz,), yt.dtype)
+ yt2[0:-1:2], yt2[1::2] = yt, yt
+ self._path = Path(npy.vstack((xt2, yt2)).transpose(), closed=False)
+ else:
+ self._path = Path(self._xy, closed=False)
 
 
 def _is_sorted(self, x):
@@ -700,24 +710,6 @@
 pass
 
 
- def _draw_steps(self, renderer, gc, xt, yt):
-	# MGDTODO: This is a quirky one. The step-plotting part
-	# should probably be moved to where the path is generated
-	# in recache, and then just drawn with _draw_solid
- siz=len(xt)
- if siz<2: return
- xt2=npy.ones((2*siz,), xt.dtype)
- xt2[0:-1:2], xt2[1:-1:2], xt2[-1]=xt, xt[1:], xt[-1]
- yt2=npy.ones((2*siz,), yt.dtype)
- yt2[0:-1:2], yt2[1::2]=yt, yt
- gc.set_linestyle('solid')
-
- if self._newstyle:
- renderer.draw_lines(gc, xt2, yt2, self.get_transform())
- else:
- renderer.draw_lines(gc, xt2, yt2)
-
-	 
 def _draw_solid(self, renderer, gc, path):
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, self.get_transform())
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -212,8 +212,8 @@
 gc.set_hatch(self._hatch )
 
 path = self.get_path()
- transform = self.get_transform()
-
+ transform = self.get_patch_transform() + self.get_transform()
+ 
 renderer.draw_path(gc, path, transform, rgbFace)
 
 #renderer.close_group('patch')
@@ -284,7 +284,7 @@
 self.patch = patch
 self.props = props
 	self.ox, self.oy = ox, oy
-	self._shadow_transform = transforms.Affine2D.translate(self.ox, self.oy)
+	self._shadow_transform = transforms.Affine2D().translate(self.ox, self.oy)
 self._update()
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
@@ -305,8 +305,8 @@
 def get_path(self):
 return self.patch.get_path()
 
- def get_transform(self):
-	return self._transform + self._shadow_transform
+ def get_patch_transform(self):
+	return self._shadow_transform
 
 class Rectangle(Patch):
 """
@@ -315,8 +315,6 @@
 
 """
 
- _path = Path.unit_rectangle()
- 
 def __str__(self):
 return str(self.__class__).split('.')[-1] \
 + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height)
@@ -346,16 +344,14 @@
 """
 Return the vertices of the rectangle
 """
-	# This is a "class-static" variable, so all rectangles in the plot
-	# will be shared (and merely have different transforms)
-	return self._path
+	return Path.unit_rectangle()
 
 # MGDTODO: Convert units
 # left, right = self.convert_xunits((x, x + self.width))
 # bottom, top = self.convert_yunits((y, y + self.height))
 
- def get_transform(self):
-	return self._rect_transform + self._transform
+ def get_patch_transform(self):
+	return self._rect_transform
 
 def get_x(self):
 "Return the left coord of the rectangle"
@@ -379,7 +375,8 @@
 
 ACCEPTS: float
 """
- self._bbox.xmin = x
+ w = self._bbox.width
+ self._bbox.intervalx = (x, x + w)
 
 def set_y(self, y):
 """
@@ -387,7 +384,8 @@
 
 ACCEPTS: float
 """
- self._bbox.ymin = y
+ h = self._bbox.height
+ self._bbox.intervaly = (y, y + h)
 
 def set_width(self, w):
 """
@@ -395,7 +393,7 @@
 
 ACCEPTS: float
 """
- self._bbox.width = w
+ self._bbox.xmax = self._bbox.xmin + w
 
 def set_height(self, h):
 """
@@ -403,7 +401,7 @@
 
 ACCEPTS: float
 """
- self._bbox.height = h
+ self._bbox.ymax = self._bbox.ymin + h
 
 def set_bounds(self, *args):
 """
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月18日 19:29:21 UTC (rev 3856)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月19日 13:28:11 UTC (rev 3857)
@@ -8,6 +8,8 @@
 from numpy.linalg import inv
 from sets import Set
 
+DEBUG = True
+
 # MGDTODO: This creates a ton of cyclical references. We may want to
 # consider using weak references
 
@@ -53,6 +55,13 @@
 
 def __array__(self):
 return self.get_points()
+
+ if DEBUG:
+ def invalidate(self):
+ points = self.get_points()
+ assert points[0, 0] <= points[1, 0]
+ assert points[0, 1] <= points[1, 1]
+ TransformNode.invalidate(self)
 
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月18日 19:29:24
Revision: 3856
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3856&view=rev
Author: mdboom
Date: 2007年09月18日 12:29:21 -0700 (2007年9月18日)
Log Message:
-----------
Optimize shared axes (to prevent calling set_xlim/set_ylim more than
once per axes per update).
Save figure at correct dpi.
General cleanup and optimizations.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/backends/backend_gtkagg.py
 branches/transforms/lib/matplotlib/backends/backend_tkagg.py
 branches/transforms/lib/matplotlib/cbook.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/transforms.py
 branches/transforms/src/_backend_agg.cpp
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -435,6 +435,9 @@
 1 : 'log',
 }
 
+ _shared_x_axes = cbook.Grouper()
+ _shared_y_axes = cbook.Grouper()
+ 
 def __str__(self):
 return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds)
 def __init__(self, fig, rect,
@@ -491,6 +494,10 @@
 # must be set before set_figure
 self._sharex = sharex
 self._sharey = sharey
+	if sharex is not None:
+	 self._shared_x_axes.join(self, sharex)
+	if sharey is not None:
+	 self._shared_y_axes.join(self, sharey)
 # Flag: True if some other Axes instance is sharing our x or y axis
 self._masterx = False
 self._mastery = False
@@ -502,7 +509,6 @@
 # this call may differ for non-sep axes, eg polar
 self._init_axis()
 
-
 if axisbg is None: axisbg = rcParams['axes.facecolor']
 self._axisbg = axisbg
 self._frameon = frameon
@@ -616,55 +622,28 @@
 #these will be updated later as data is added
 self._set_lim_and_transforms()
 
- def _shared_xlim_callback(self, ax):
-	xmin, xmax = ax.get_xlim()
-	self.set_xlim(xmin, xmax, emit=False)
-	self.figure.canvas.draw_idle()
-
- def _shared_ylim_callback(self, ax):
-	ymin, ymax = ax.get_ylim()
-	self.set_ylim(ymin, ymax, emit=False)
-	self.figure.canvas.draw_idle()
-	
 def _set_lim_and_transforms(self):
 """
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
-	Bbox = mtransforms.Bbox
-	self.viewLim = Bbox.unit()
+	self.viewLim = mtransforms.Bbox.unit()
+	self.dataLim = mtransforms.Bbox.unit()
 	
- if self._sharex is not None:
-	 # MGDTODO: This may be doing at least one too many updates
-	 # than necessary
-	 self._sharex.callbacks.connect(
- 		'xlim_changed', self._shared_xlim_callback)
-	 self.viewLim.intervalx = self._sharex.viewLim.intervalx
- if self._sharey is not None:
- 	 self._sharey.callbacks.connect(
- 		'ylim_changed', self._shared_ylim_callback)
-	 self.viewLim.intervaly = self._sharex.viewLim.intervaly
-
-	self.dataLim = Bbox.unit()
-	
 self.transAxes = mtransforms.BboxTransform(
- Bbox.unit(), self.bbox)
-
+ mtransforms.Bbox.unit(), self.bbox)
 self.transData = mtransforms.BboxTransform(
 self.viewLim, self.bbox)
 	 
 	 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
-	# MGDTODO: This changed from returning a list to returning a Bbox
-	# If you get any errors with the result of this function, please
-	# update the calling code
 if original:
- return copy.copy(self._originalPosition)
+ return self._originalPosition
 else:
- return copy.copy(self._position)
-	 # return [val.get() for val in self._position]
+ return self._position
 
+	
 def set_position(self, pos, which='both'):
 """
 Set the axes position with pos = [left, bottom, width, height]
@@ -699,8 +678,7 @@
 self.xaxis.cla()
 self.yaxis.cla()
 
-	# MGDTODO
- # self.dataLim.ignore(1)
+	self.ignore_existing_data_limits = True
 self.callbacks = cbook.CallbackRegistry(('xlim_changed', 'ylim_changed'))
 
 if self._sharex is not None:
@@ -886,7 +864,7 @@
 return
 
 
- l,b,w,h = self.get_position(original=True)
+ l,b,w,h = self.get_position(original=True).bounds
 box_aspect = fig_aspect * (h/w)
 data_ratio = box_aspect / A
 
@@ -1152,7 +1130,7 @@
 # Otherwise, it will compute the bounds of it's current data
 # and the data in xydata
 xys = npy.asarray(xys)
- self.dataLim.update_numerix_xy(xys, -1)
+ self.update_datalim_numerix(xys[:, 0], xys[:, 1])
 
 
 def update_datalim_numerix(self, x, y):
@@ -1161,10 +1139,9 @@
 # limits and set the bound to be the bounds of the xydata.
 # Otherwise, it will compute the bounds of it's current data
 # and the data in xydata
- #print type(x), type(y)
-	# MGDTODO
 ## self.dataLim.update_numerix(x, y, -1)
-	self.dataLim.update_from_data(x, y)
+	self.dataLim.update_from_data(x, y, self.ignore_existing_data_limits)
+	self.ignore_existing_data_limits = False
 
 def _get_verts_in_data_coords(self, trans, xys):
 if trans == self.transData:
@@ -1264,9 +1241,7 @@
 if not self.get_visible(): return
 renderer.open_group('axes')
 self.apply_aspect()
-	# MGDTODO -- this is where we can finalize all of the transforms
- # self.transData.freeze() # eval the lazy objects
- # self.transAxes.freeze()
+
 if self.axison and self._frameon: self.axesPatch.draw(renderer)
 artists = []
 
@@ -1314,17 +1289,13 @@
 if self.axison and self._frameon:
 artists.append(self.axesFrame)
 
- # keep track of i to guarantee stable sort for python 2.2
- dsu = [ (a.zorder, i, a) for i, a in enumerate(artists)
- if not a.get_animated()]
+	dsu = [ (a.zorder, a) for a in artists
+		if not a.get_animated() ]
 dsu.sort()
 
- for zorder, i, a in dsu:
+ for zorder, a in dsu:
 a.draw(renderer)
 
-	# MGDTODO
-	# self.transData.thaw() # release the lazy objects
- # self.transAxes.thaw() # release the lazy objects
 renderer.close_group('axes')
 self._cachedRenderer = renderer
 
@@ -1509,7 +1480,6 @@
 
 ACCEPTS: len(2) sequence of floats
 """
-
 if xmax is None and iterable(xmin):
 xmin,xmax = xmin
 
@@ -1534,11 +1504,10 @@
 	self.viewLim.intervalx = (xmin, xmax)
 if emit:
 	 self.callbacks.process('xlim_changed', self)
-	 # MGDTODO: It would be nice to do this is in the above callback list,
-	 # but it's difficult to tell how to initialize this at the
-	 # right time
-	 if self._sharex:
-		self._sharex.set_xlim(*self.viewLim.intervalx)
+	 # Call all of the other x-axes that are shared with this one
+	 for other in self._shared_x_axes.get_siblings(self):
+		if other is not self:
+		 other.set_xlim(self.viewLim.xmin, self.viewLim.xmax, emit=False)
 	 
 return xmin, xmax
 
@@ -1665,11 +1634,10 @@
 	self.viewLim.intervaly = (ymin, ymax)
 if emit:
 	 self.callbacks.process('ylim_changed', self)
-	 # MGDTODO: It would be nice to do this is in the above callback list,
-	 # but it's difficult to tell how to initialize this at the
-	 # right time
-	 if self._sharey:
-		self._sharey.set_ylim(*self.viewLim.intervaly)
+	 # Call all of the other y-axes that are shared with this one
+	 for other in self._shared_y_axes.get_siblings(self):
+		if other is not self:
+		 other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False)
 	 
 return ymin, ymax
 
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -1033,8 +1033,7 @@
 bbox = Bbox.union(bboxes)
 bottom = bbox.ymin
 
- self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi/72.0))
-# self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) MGDTODO
+ self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi / 72.0))
 
 else:
 if not len(bboxes2):
@@ -1057,7 +1056,6 @@
 bbox = Bbox.union(bboxes)
 bottom = bbox.ymin
 self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0))
-# self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO
 	
 def set_ticks_position(self, position):
 """
@@ -1225,7 +1223,6 @@
 left = bbox.xmin
 
 self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y))
-	 # self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) MGDTODO
 	 
 else:
 if not len(bboxes2):
@@ -1245,7 +1242,6 @@
 x,y = self.offsetText.get_position()
 top = self.axes.bbox.ymax
 self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0))
-# self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO
 	
 def set_offset_position(self, position):
 assert position == 'left' or position == 'right'
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -18,8 +18,9 @@
 """An abstract base class to handle drawing/rendering operations
 """
 # This will cache paths across rendering instances
- # Each subclass of RenderBase should define this -->
- # _paths = weakref.WeakKeyDictionary()
+ # Each subclass of RenderBase should define this a weak-keyed
+ # dictionary to hold native paths
+ # _native_paths = weakref.WeakKeyDictionary()
 
 def __init__(self):
 self._texmanager = None
@@ -44,7 +45,7 @@
 	 self._native_paths[path] = native_path
 	return native_path
 
- def draw_path(self, gc, path, transform, rgbFace = None):
+ def draw_path(self, gc, path, transform, rgbFace=None):
 	"""
 	Handles the caching of the native path associated with the
 	given path and calls the underlying backend's _draw_path to
@@ -67,17 +68,31 @@
 	passed to them in draw_path.
 	"""
 	return path
+
+ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
+	native_marker_path = self._get_cached_native_path(marker_path)
+	self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace)
 	
- def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
- rotation):
+ def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
 """
- Draw an arc using GraphicsContext instance gcEdge, centered at x,y,
- with width and height and angles from 0.0 to 360.0
- 0 degrees is at 3-o'clock
- positive angles are anti-clockwise
- draw rotated 'rotation' degrees anti-clockwise about x,y
+ This method is currently underscore hidden because the
+ draw_markers method is being used as a sentinel for newstyle
+ backend drawing
 
- If the color rgbFace is not None, fill the arc with it.
+ path - a matplotlib.agg.path_storage instance
+
+ Draw the marker specified in path with graphics context gc at
+ each of the locations in arrays x and y. trans is a
+ matplotlib.transforms.Transformation instance used to
+ transform x and y to display coords. It consists of an
+ optional nonlinear component and an affine. You can access
+ these two components as
+
+ if transform.need_nonlinear():
+ x,y = transform.nonlinear_only_numerix(x, y)
+ # the a,b,c,d,tx,ty affine which transforms x and y
+ vec6 = transform.as_vec6_val()
+ ...backend dependent affine...
 """
 raise NotImplementedError
 
@@ -109,30 +124,21 @@
 """
 return False
 
- def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
-	native_marker_path = self._get_cached_native_path(marker_path)
-	self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace)
-	
- def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
+ ######################################################################
+ ## OLD API IS BELOW
+ ## These functions no longer need to be implemented in the backends --
+ ## they now perform all of their functions in terms of the new API.
+ 
+ def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
+ rotation):
 """
- This method is currently underscore hidden because the
- draw_markers method is being used as a sentinel for newstyle
- backend drawing
+ Draw an arc using GraphicsContext instance gcEdge, centered at x,y,
+ with width and height and angles from 0.0 to 360.0
+ 0 degrees is at 3-o'clock
+ positive angles are anti-clockwise
+ draw rotated 'rotation' degrees anti-clockwise about x,y
 
- path - a matplotlib.agg.path_storage instance
-
- Draw the marker specified in path with graphics context gc at
- each of the locations in arrays x and y. trans is a
- matplotlib.transforms.Transformation instance used to
- transform x and y to display coords. It consists of an
- optional nonlinear component and an affine. You can access
- these two components as
-
- if transform.need_nonlinear():
- x,y = transform.nonlinear_only_numerix(x, y)
- # the a,b,c,d,tx,ty affine which transforms x and y
- vec6 = transform.as_vec6_val()
- ...backend dependent affine...
+ If the color rgbFace is not None, fill the arc with it.
 """
 raise NotImplementedError
 
@@ -346,8 +352,10 @@
 
 If rgbFace is not None, fill the rectangle with it.
 """
- raise NotImplementedError
-
+	warnings.warn("draw_rectangle called", warnings.PendingDeprecationWarning)
+	transform = transforms.Affine2D().scale(width, height).translate(x, y)
+	self.draw_path(gcEdge, Path.unit_rectangle(), transform, rgbFace)
+	
 def draw_regpoly_collection(
 self, clipbox, offsets, transOffset, verts, sizes,
 facecolors, edgecolors, linewidths, antialiaseds):
@@ -1221,8 +1229,6 @@
 origfacecolor = self.figure.get_facecolor()
 origedgecolor = self.figure.get_edgecolor()
 
-	# MGDTODO
- # self.figure.dpi.set(dpi)
 self.figure.dpi = dpi
 self.figure.set_facecolor(facecolor)
 self.figure.set_edgecolor(edgecolor)
@@ -1236,12 +1242,12 @@
 orientation=orientation,
 **kwargs)
 finally:
-	 # MGDTODO
- # self.figure.dpi.set(origDPI)
 self.figure.dpi = origDPI
 self.figure.set_facecolor(origfacecolor)
 self.figure.set_edgecolor(origedgecolor)
 self.figure.set_canvas(self)
+
+ self.draw()
 
 return result
 
@@ -1623,8 +1629,8 @@
 lims.append( (xmin, xmax, ymin, ymax) )
 # Store both the original and modified positions
 pos.append( (
-		 a.get_position(True),
- a.get_position() ) )
+		 copy.copy(a.get_position(True)),
+ copy.copy(a.get_position() )) )
 self._views.push(lims)
 self._positions.push(pos)
 self.set_history_buttons()
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -114,9 +114,6 @@
 self.height = height
 if __debug__: verbose.report('RendererAgg.__init__ width=%s, \
 height=%s'%(width, height), 'debug-annoying')
-	# MGDTODO
-# self._renderer = _RendererAgg(int(width), int(height), dpi.get(),
-# 				 debug=False)
 self._renderer = _RendererAgg(int(width), int(height), dpi,
 				 debug=False)
 if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done',
@@ -136,35 +133,6 @@
 def _draw_native_path(self, gc, path, transform, rgbFace):
 	return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace)
 
- def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation):
- """
- Draw an arc centered at x,y with width and height and angles
- from 0.0 to 360.0
-
- If rgbFace is not None, fill the rectangle with that color. gcEdge
- is a GraphicsContext instance
-
- Currently, I'm only supporting ellipses, ie angle args are
- ignored
- """
- if __debug__: verbose.report('RendererAgg.draw_arc', 'debug-annoying')
- self._renderer.draw_ellipse(
- gcEdge, rgbFace, x, y, width/2, height/2, rotation) # ellipse takes radius
-
-
- def draw_line(self, gc, x1, y1, x2, y2):
- """
- x and y are equal length arrays, draw lines connecting each
- point in x, y
- """
- if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying')
- x = npy.array([x1,x2], float)
- y = npy.array([y1,y2], float)
- self._renderer.draw_lines(gc, x, y)
-
- def draw_lines(self, gc, x, y, transform):
-	return self._renderer.draw_lines(gc, x, y, transform.to_values())
-
 def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
 	return self._renderer.draw_markers(
 	 gc,
@@ -172,18 +140,6 @@
 	 path.vertices, path.codes, trans.get_matrix(),
 	 rgbFace)
 
- def draw_polygon(self, *args):
-	return self._renderer.draw_polygon(*args)
- 
- def draw_point(self, gc, x, y):
- """
- Draw a single point at x,y
- """
- if __debug__: verbose.report('RendererAgg.draw_point', 'debug-annoying')
- rgbFace = gc.get_rgb()
- self._renderer.draw_ellipse(
- gc, rgbFace, x, y, 0.5, 0.5, 0.0)
-
 def draw_mathtext(self, gc, x, y, s, prop, angle):
 """
 Draw the math text using matplotlib.mathtext
@@ -192,8 +148,6 @@
 'debug-annoying')
 ox, oy, width, height, descent, font_image, used_characters = \
 self.mathtext_parser.parse(s, self.dpi, prop)
-# ox, oy, width, height, descent, font_image, used_characters = \
-# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO
 
 x = int(x) + ox
 y = int(y) - oy
@@ -227,7 +181,6 @@
 # (in vector space) in the above call to font.set_text.
 self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc)
 
-
 def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)):
 """
 get the width and height in display coords of the string s
@@ -241,7 +194,7 @@
 # todo: handle props
 size = prop.get_size_in_points()
 texmanager = self.get_texmanager()
- Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb)
+ Z = texmanager.get_rgba(s, size, self.dpi, rgb)
 m,n,tmp = Z.shape
 # TODO: descent of TeX text (I am imitating backend_ps here -JKS)
 return n, m, 0
@@ -249,8 +202,6 @@
 if ismath:
 ox, oy, width, height, descent, fonts, used_characters = \
 self.mathtext_parser.parse(s, self.dpi, prop)
-# ox, oy, width, height, descent, fonts, used_characters = \
-# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO
 return width, height, descent
 font = self._get_agg_font(prop)
 font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string
@@ -265,7 +216,7 @@
 # todo, handle props, angle, origins
 rgb = gc.get_rgb()
 size = prop.get_size_in_points()
- dpi = self.dpi.get()
+ dpi = self.dpi
 
 flip = angle==90
 w,h,d = self.get_text_width_height_descent(s, prop, 'TeX', rgb)
@@ -306,7 +257,6 @@
 'return the canvas width and height in display coords'
 return self.width, self.height
 
-
 def _get_agg_font(self, prop):
 """
 Get the font for text instance t, cacheing for efficiency
@@ -325,11 +275,9 @@
 font.clear()
 size = prop.get_size_in_points()
 font.set_size(size, self.dpi)
- # font.set_size(size, self.dpi.get()) MGDTODO
 
 return font
 
-
 def points_to_pixels(self, points):
 """
 convert point measures to pixes using dpi and the pixels per
@@ -337,8 +285,6 @@
 """
 if __debug__: verbose.report('RendererAgg.points_to_pixels',
 'debug-annoying')
-	# MGDTODO
- # return points*self.dpi.get()/72.0
 return points*self.dpi/72.0
 
 def tostring_rgb(self):
@@ -404,9 +350,7 @@
 self.figure.draw(self.renderer)
 
 def get_renderer(self):
- l,b,w,h = self.figure.bbox.bounds
-	# MGDTODO
- # key = w, h, self.figure.dpi.get()
+ l, b, w, h = self.figure.bbox.bounds
 key = w, h, self.figure.dpi
 try: self._lastKey, self.renderer
 except AttributeError: need_new_renderer = True
Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -60,7 +60,6 @@
 w,h = widget.window.get_size()
 if w==1 or h==1: return # empty fig
 
-	# dpival = self.figure.dpi.get() MGDTODO
 # compute desired figure size in inches
 dpival = self.figure.dpi
 winch = w/dpival
Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -175,7 +175,6 @@
 self._resize_callback(event)
 
 # compute desired figure size in inches
-	# dpival = self.figure.dpi.get() MGDTODO
 	dpival = self.figure.dpi
 winch = width/dpival
 hinch = height/dpival
Modified: branches/transforms/lib/matplotlib/cbook.py
===================================================================
--- branches/transforms/lib/matplotlib/cbook.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/cbook.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -955,6 +955,84 @@
 outstream.write("Examining: %r\n" % (obj,))
 recurse(obj, obj, { }, [])
 
+class Grouper(object):
+ """
+ This class provides a lightweight way to group arbitrary objects
+ together into disjoint sets when a full-blown graph data structure
+ would be overkill.
+
+ Objects can be joined using .join(), tested for connectedness
+ using .joined(), and all disjoint sets can be retreived using
+ .get().
+
+ The objects being joined must be hashable.
+ 
+ For example:
+ 
+ >>> g = grouper.Grouper()
+ >>> g.join('a', 'b')
+ >>> g.join('b', 'c')
+ >>> g.join('d', 'e')
+ >>> list(g.get())
+ [['a', 'b', 'c'], ['d', 'e']]
+ >>> g.joined('a', 'b')
+ True
+ >>> g.joined('a', 'c')
+ True
+ >>> g.joined('a', 'd')
+ False""" 
+ def __init__(self, init=[]):
+	mapping = self._mapping = {}
+	for x in init:
+	 mapping[x] = [x]
+ 
+ def join(self, a, *args):
+	"""
+	Join given arguments into the same set.
+	Accepts one or more arguments.
+	"""
+	mapping = self._mapping
+	set_a = mapping.setdefault(a, [a])
+
+	for arg in args:
+	 set_b = mapping.get(arg)
+	 if set_b is None:
+		set_a.append(arg)
+		mapping[arg] = set_a
+	 elif set_b is not set_a:
+		if len(set_b) > len(set_a):
+		 set_a, set_b = set_b, set_a
+		set_a.extend(set_b)
+		for elem in set_b:
+		 mapping[elem] = set_a
+
+ def joined(self, a, b):
+	"""
+	Returns True if a and b are members of the same set.
+	"""
+	mapping = self._mapping
+	try:
+	 return mapping[a] is mapping[b]
+	except KeyError:
+	 return False
+
+ def __iter__(self):
+	"""
+	Returns an iterator returning each of the disjoint sets as a list.
+	"""
+	seen = set()
+	for elem, group in self._mapping.iteritems():
+	 if elem not in seen:
+		yield group
+		seen.update(group)
+
+ def get_siblings(self, a):
+	"""
+	Returns all of the items joined with the given item, including
+	itself.
+	"""
+	return self._mapping.get(a, [a])
+		
 if __name__=='__main__':
 assert( allequal([1,1,1]) )
 assert(not allequal([1,1,0]) )
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -161,10 +161,8 @@
 def _get_dpi(self):
 	return self._dpi
 def _set_dpi(self, dpi):
-	print "setting dpi"
 	self._dpi = dpi
 	self._dpi_scale_trans.clear().scale(dpi, dpi)
-	print self._dpi_scale_trans
 dpi = property(_get_dpi, _set_dpi)
 	
 def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'):
@@ -178,10 +176,7 @@
 bottom : the bottom of the subplots for subplots_adjust
 rotation: the rotation of the xtick labels
 ha : the horizontal alignment of the xticklabels
-
-
 """
-
 for ax in self.get_axes():
 if not hasattr(ax, 'is_last_row'):
 raise RuntimeError('Axes must be subplot instances; found %s'%type(ax))
@@ -333,11 +328,8 @@
 
 	dpival = self.dpi
 	self.bbox_inches.max = w, h
- # self.figwidth.set(w) MGDTODO
- # self.figheight.set(h)
 	
 if forward:
- # dpival = self.dpi.get()
 dpival = self.dpi
 canvasw = w*dpival
 canvash = h*dpival
@@ -347,7 +339,6 @@
 
 def get_size_inches(self):
 return self.bbox_inches.max
- # return self.figwidth.get(), self.figheight.get() MGDTODO
 
 def get_edgecolor(self):
 'Get the edge color of the Figure rectangle'
@@ -360,7 +351,6 @@
 def get_figwidth(self):
 'Return the figwidth as a float'
 	return self.bbox_inches.xmax
- # return self.figwidth.get() MGDTODO
 
 def get_figheight(self):
 'Return the figheight as a float'
@@ -369,7 +359,6 @@
 def get_dpi(self):
 'Return the dpi as a float'
 return self.dpi
- # return self.dpi.get() MGDTODO
 
 def get_frameon(self):
 'get the boolean indicating frameon'
@@ -397,7 +386,6 @@
 
 ACCEPTS: float
 """
- # self.dpi.set(val) MGDTODO
 	self.dpi = val
 
 def set_figwidth(self, val):
@@ -406,7 +394,6 @@
 
 ACCEPTS: float
 """
- # self.figwidth.set(val) MGDTODO
 	self.bbox_inches.xmax = val
 	
 def set_figheight(self, val):
@@ -415,7 +402,6 @@
 
 ACCEPTS: float
 """
-	# MGDTODO (set())
 	self.bbox_inches.ymax = val
 
 def set_frameon(self, b):
@@ -598,8 +584,6 @@
 #print 'figure draw'
 if not self.get_visible(): return
 renderer.open_group('figure')
-	# MGDTODO
- # self.transFigure.freeze() # eval the lazy objects
 
 if self.frameon: self.figurePatch.draw(renderer)
 
@@ -633,8 +617,6 @@
 for legend in self.legends:
 legend.draw(renderer)
 
-	# MGDTODO
-	# self.transFigure.thaw() # release the lazy objects
 renderer.close_group('figure')
 
 self._cachedRenderer = renderer
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -21,7 +21,7 @@
 up the legend
 """
 from __future__ import division
-import sys, warnings
+import copy, sys, warnings
 
 import numpy as npy
 
@@ -558,9 +558,7 @@
 handle.set_height(h/2)
 
 # Set the data for the legend patch
-	# MGDTODO: This copy may no longer be needed now that Bboxes are
-	# essentially immutable
- bbox = self._get_handle_text_bbox(renderer).copy()
+ bbox = copy.copy(self._get_handle_text_bbox(renderer))
 
 bbox = bbox.scaled(1 + self.pad, 1 + self.pad)
 l,b,w,h = bbox.get_bounds()
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -352,32 +352,18 @@
 self._picker = p
 
 def get_window_extent(self, renderer):
- self._newstyle = hasattr(renderer, 'draw_markers')
- if self._newstyle:
- x = self._x
- y = self._y
- else:
- x, y = self._get_plottable()
+ xys = self.get_transform()(self._xys)
 
-	# MGDTODO: Put this in a single Nx2 array, rather than these
-	# separate ones
-	#### Conversion code
-	a = npy.vstack((x, y)).swapaxes(0, 1)
-	####
- x, y = self.get_transform()(a)
-	print "get_window_extent", self.get_transform()
-	
- #x, y = self.get_transform().seq_x_y(x, y)
+	x = xys[:, 0]
+	y = xys[:, 1]
+ left = x.min()
+ bottom = y.min()
+ width = x.max() - left
+ height = y.max() - bottom
 
- left = min(x)
- bottom = min(y)
- width = max(x) - left
- height = max(y) - bottom
-
 # correct for marker size, if any
 if self._marker is not None:
- ms = self._markersize/72.0*self.figure.dpi
- # ms = self._markersize/72.0*self.figure.dpi.get() MGDTODO
+ ms = self._markersize / 72.0 * self.figure.dpi
 left -= ms/2
 bottom -= ms/2
 width += ms
@@ -411,6 +397,7 @@
 def recache(self):
 #if self.axes is None: print 'recache no axes'
 #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
+	# MGDTODO: Deal with units
 x = ma.asarray(self.convert_xunits(self._xorig), float)
 y = ma.asarray(self.convert_yunits(self._yorig), float)
 
@@ -435,15 +422,15 @@
 else:
 self._segments = None
 
- self._x = npy.asarray(x, float)
- self._y = npy.asarray(y, float)
-	self._path = Path(npy.vstack((self._x, self._y)).transpose(),
-			 closed=False)
+	self._xy = npy.vstack((npy.asarray(x, npy.float_),
+			 npy.asarray(y, npy.float_))).transpose()
+	self._x = self._xy[:, 0]
+	self._y = self._xy[:, 1]
+	self._path = Path(self._xy, closed=False)
 	
 self._logcache = None
 
 
-
 def _is_sorted(self, x):
 "return true if x is sorted"
 if len(x)<2: return 1
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -19,9 +19,9 @@
 self._parents = Set()
 
 def invalidate(self):
- if not self._do_invalidation():
- for parent in self._parents:
- parent.invalidate()
+ self._do_invalidation()
+ for parent in self._parents:
+ parent.invalidate()
 
 def _do_invalidation(self):
 return False
@@ -187,14 +187,16 @@
 return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
- # JDH: the update method will update the box limits from the
- # existing limits and the new data; it appears here you are just
- # using the new data. We use an "ignore" flag to specify whether
- # you want to include the existing data or not in the update
 def update_from_data(self, x, y, ignore=True):
- self._points = npy.array(
- [[x.min(), y.min()], [x.max(), y.max()]],
- npy.float_)
+	if ignore:
+	 self._points = npy.array(
+		[[x.min(), y.min()], [x.max(), y.max()]],
+		npy.float_)
+	else:
+	 self._points = npy.array(
+		[[min(x.min(), self.xmin), min(y.min(), self.ymin)],
+		 [max(x.max(), self.xmax), max(y.max(), self.ymax)]],
+		 npy.float_)
 self.invalidate()
 
 # MGDTODO: Probably a more efficient ways to do this...
@@ -409,9 +411,7 @@
 	return self.get_matrix()
 	
 def _do_invalidation(self):
- result = self._inverted is None
 self._inverted = None
- return result
 
 #@staticmethod
 def _concat(a, b):
@@ -494,6 +494,7 @@
 if matrix is None:
 matrix = npy.identity(3)
 else:
+	 matrix = npy.asarray(matrix, npy.float_)
 assert matrix.shape == (3, 3)
 self._mtx = matrix
 self._inverted = None
@@ -629,8 +630,6 @@
 if self._mtx is not None:
 self._mtx = None
 Affine2DBase._do_invalidation(self)
- return False
- return True
 
 def is_separable(self):
 return True
@@ -684,7 +683,7 @@
 
 def _do_invalidation(self):
 self._mtx = None
- Affine2DBase._do_invalidation(self)
+ return Affine2DBase._do_invalidation(self)
 
 def get_matrix(self):
 if self._mtx is None:
@@ -718,8 +717,6 @@
 if self._mtx is not None:
 self._mtx = None
 Affine2DBase._do_invalidation(self)
- return False
- return True
 
 def is_separable(self):
 return True
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月18日 16:21:37 UTC (rev 3855)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月18日 19:29:21 UTC (rev 3856)
@@ -456,7 +456,7 @@
 //return the agg::rect for bbox, flipping y
 PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2);
 
- if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
+ if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
 throw Py::TypeError
 ("Expected a Bbox object.");
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月18日 16:21:40
Revision: 3855
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3855&view=rev
Author: mdboom
Date: 2007年09月18日 09:21:37 -0700 (2007年9月18日)
Log Message:
-----------
More code using new transformation framework. Lots of dead code
removed from backend_agg.cpp/h
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/lib/matplotlib/transforms.py
 branches/transforms/lib/matplotlib/type1font.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -39,8 +39,7 @@
 def _get_cached_native_path(self, path):
 	native_path = self._native_paths.get(path)
 	if native_path is None:
-	 import matplotlib.patches
-	 print "CACHE MISS", path
+	 # print "CACHE MISS", path
 	 native_path = self.convert_to_native_path(path)
 	 self._native_paths[path] = native_path
 	return native_path
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -121,13 +121,9 @@
 				 debug=False)
 if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done',
 'debug-annoying')
- # self.draw_polygon = self._renderer.draw_polygon
- self.draw_rectangle = self._renderer.draw_rectangle
-	# MGDTODO -- remove these lines
- # self.draw_lines = self._renderer.draw_lines
- # self.draw_markers = self._renderer.draw_markers
- self.draw_image = self._renderer.draw_image
 
+	self.convert_to_native_path = self._renderer.convert_to_native_path
+ self.draw_image = self._renderer.draw_image
 self.copy_from_bbox = self._renderer.copy_from_bbox
 self.restore_region = self._renderer.restore_region
 self.mathtext_parser = MathTextParser('Agg')
@@ -137,12 +133,9 @@
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
- def convert_to_native_path(self, path):
-	return self._renderer.convert_to_native_path(path.vertices, path.codes)
-
- def _draw_native_path(self, gc, native_path, transform, rgbFace):
-	return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace)
-	
+ def _draw_native_path(self, gc, path, transform, rgbFace):
+	return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace)
+ 
 def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation):
 """
 Draw an arc centered at x,y with width and height and angles
@@ -175,8 +168,8 @@
 def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
 	return self._renderer.draw_markers(
 	 gc,
-	 native_marker_path, marker_trans.to_values(),
-	 path.vertices, path.codes, trans.to_values(),
+	 native_marker_path, marker_trans.get_matrix(),
+	 path.vertices, path.codes, trans.get_matrix(),
 	 rgbFace)
 
 def draw_polygon(self, *args):
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -712,6 +712,7 @@
 def _draw_nothing(self, renderer, gc, path):
 pass
 
+ 
 def _draw_steps(self, renderer, gc, xt, yt):
 	# MGDTODO: This is a quirky one. The step-plotting part
 	# should probably be moved to where the path is generated
@@ -729,6 +730,7 @@
 else:
 renderer.draw_lines(gc, xt2, yt2)
 
+	 
 def _draw_solid(self, renderer, gc, path):
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, self.get_transform())
@@ -753,8 +755,15 @@
 
 	
 def _draw_point(self, renderer, gc, path):
-	self._draw_circle(renderer, gc, path, point = True)
+ w = renderer.points_to_pixels(self._markersize) * \
+	 self._point_size_reduction * 0.5
+ rgbFace = self._get_rgb_face()
+	transform = Affine2D().scale(w)
+	renderer.draw_markers(
+	 gc, Path.unit_circle(), transform, path, self.get_transform(),
+	 rgbFace)
 
+	
 def _draw_pixel(self, renderer, gc, path):
 	rgbFace = self._get_rgb_face()
 	transform = Affine2D().translate(-0.5, -0.5)
@@ -762,12 +771,8 @@
 			 path, self.get_transform(), rgbFace)
 	
 	
- def _draw_circle(self, renderer, gc, path, point=False):
- w = renderer.points_to_pixels(self._markersize)
- if point:
- w *= self._point_size_reduction
-	w *= 0.5
-
+ def _draw_circle(self, renderer, gc, path):
+ w = renderer.points_to_pixels(self._markersize) * 0.5
 rgbFace = self._get_rgb_face()
 	transform = Affine2D().scale(w, w)
 	renderer.draw_markers(
@@ -826,7 +831,8 @@
 	
 def _draw_thin_diamond(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
-	transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(offset * 0.8, offset)
+	transform = Affine2D().translate(0.5, 0.5) \
+	 .rotate_deg(45).scale(offset * 0.8, offset)
 rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
 			 path, self.get_transform(), rgbFace)
@@ -840,7 +846,7 @@
 			 path, self.get_transform(), rgbFace)
 
 	
- def _draw_hexagon1(self, renderer, gc, path, point=False):
+ def _draw_hexagon1(self, renderer, gc, path):
 offset = 0.5 * renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset)
 	rgbFace = self._get_rgb_face()
@@ -848,50 +854,44 @@
 			 path, self.get_transform(), rgbFace)
 
 	
- def _draw_hexagon2(self, renderer, gc, xt, yt):
+ def _draw_hexagon2(self, renderer, gc, path):
 offset = 0.5 * renderer.points_to_pixels(self._markersize)
 	transform = Affine2D().scale(offset).rotate_deg(30)
 	rgbFace = self._get_rgb_face()
 	renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
 			 path, self.get_transform(), rgbFace)
 
-	
- def _draw_vline(self, renderer, gc, xt, yt):
+
+ _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]], closed=False)
+ def _draw_vline(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, -offset)
- path.line_to(0, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y-offset, x, y+offset)
+	transform = Affine2D().scale(offset)
+	renderer.draw_markers(gc, self._line_marker_path, transform,
+			 path, self.get_transform())
 
 		
- def _draw_hline(self, renderer, gc, xt, yt):
+ def _draw_hline(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, 0)
- path.line_to(offset, 0)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y, x+offset, y)
+	transform = Affine2D().scale(offset).rotate_deg(90)
+	renderer.draw_markers(gc, self._line_marker_path, transform,
+			 path, self.get_transform())
 
+		
 _tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]])
 def _draw_tickleft(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
-	marker_transform = Affine2D().scale(offset, 1.0)
+	marker_transform = Affine2D().scale(-offset, 1.0)
 	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
 			 path, self.get_transform())
 
+	
 def _draw_tickright(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
-	marker_transform = Affine2D().scale(-offset, 1.0)
+	marker_transform = Affine2D().scale(offset, 1.0)
 	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
 			 path, self.get_transform())
 
+	
 _tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]])
 def _draw_tickup(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
@@ -899,174 +899,99 @@
 	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
 			 path, self.get_transform())
 
+	
 def _draw_tickdown(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(1.0, -offset)
 	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
 			 path, self.get_transform())
 
- def _draw_plus(self, renderer, gc, xt, yt):
+
+ _plus_path = Path([[-1.0, 0.0], [1.0, 0.0],
+		 [0.0, -1.0], [0.0, 1.0]],
+		 [Path.MOVETO, Path.LINETO,
+		 Path.MOVETO, Path.LINETO])
+ def _draw_plus(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- if self._newstyle:
+	transform = Affine2D().scale(offset)
+	renderer.draw_markers(gc, self._plus_path, transform,
+			 path, self.get_transform())
 
- path = agg.path_storage()
- path.move_to(-offset, 0)
- path.line_to( offset, 0)
- path.move_to( 0, -offset)
- path.line_to( 0, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y, x+offset, y)
- renderer.draw_line(gc, x, y-offset, x, y+offset)
 
- def _draw_tri_down(self, renderer, gc, xt, yt):
+ _tri_path = Path([[0.0, 0.0], [0.0, -1.0],
+		 [0.0, 0.0], [0.8, 0.5],
+		 [0.0, 0.0], [-0.8, 0.5]],
+		 [Path.MOVETO, Path.LINETO,
+		 Path.MOVETO, Path.LINETO,
+		 Path.MOVETO, Path.LINETO])
+ def _draw_tri_down(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(0, -offset)
- path.move_to(0, 0)
- path.line_to(offset1, offset2)
- path.move_to(0, 0)
- path.line_to(-offset1, offset2)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x, y-offset)
- renderer.draw_line(gc, x, y, x+offset1, y+offset2)
- renderer.draw_line(gc, x, y, x-offset1, y+offset2)
+	transform = Affine2D().scale(offset)
+	renderer.draw_markers(gc, self._tri_path, transform,
+			 path, self.get_transform())
 
- def _draw_tri_up(self, renderer, gc, xt, yt):
+	
+ def _draw_tri_up(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(0, offset)
- path.move_to(0, 0)
- path.line_to(offset1, -offset2)
- path.move_to(0, 0)
- path.line_to(-offset1, -offset2)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x, y+offset)
- renderer.draw_line(gc, x, y, x+offset1, y-offset2)
- renderer.draw_line(gc, x, y, x-offset1, y-offset2)
+	transform = Affine2D().scale(offset).rotate_deg(180)
+	renderer.draw_markers(gc, self._tri_path, transform,
+			 path, self.get_transform())
 
- def _draw_tri_left(self, renderer, gc, xt, yt):
- offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(-offset, 0)
- path.move_to(0, 0)
- path.line_to(offset2, offset1)
- path.move_to(0, 0)
- path.line_to(offset2, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x-offset, y)
- renderer.draw_line(gc, x, y, x+offset2, y+offset1)
- renderer.draw_line(gc, x, y, x+offset2, y-offset1)
+	
+ def _draw_tri_left(self, renderer, gc, path):
+	offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset).rotate_deg(90)
+	renderer.draw_markers(gc, self._tri_path, transform,
+			 path, self.get_transform())
 
- def _draw_tri_right(self, renderer, gc, xt, yt):
- offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = offset*0.8
- offset2 = offset*0.5
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0)
- path.line_to(offset, 0)
- path.move_to(0, 0)
- path.line_to(-offset2, offset1)
- path.move_to(0, 0)
- path.line_to(-offset2, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x+offset, y)
- renderer.draw_line(gc, x, y, x-offset2, y+offset1)
- renderer.draw_line(gc, x, y, x-offset2, y-offset1)
+	
+ def _draw_tri_right(self, renderer, gc, path):
+	offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset).rotate_deg(270)
+	renderer.draw_markers(gc, self._tri_path, transform,
+			 path, self.get_transform())
 
- def _draw_caretdown(self, renderer, gc, xt, yt):
+
+ _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]], closed=False)
+ def _draw_caretdown(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, offset1)
- path.line_to(0, 0)
- path.line_to(+offset, offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y+offset1, x, y)
- renderer.draw_line(gc, x, y, x+offset, y+offset1)
+	transform = Affine2D().scale(offset)
+	renderer.draw_markers(gc, self._caret_path, transform,
+			 path, self.get_transform())
 
- def _draw_caretup(self, renderer, gc, xt, yt):
+	
+ def _draw_caretup(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, -offset1)
- path.line_to(0, 0)
- path.line_to(+offset, -offset1)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y-offset1, x, y)
- renderer.draw_line(gc, x, y, x+offset, y-offset1)
+	transform = Affine2D().scale(offset).rotate_deg(180)
+	renderer.draw_markers(gc, self._caret_path, transform,
+			 path, self.get_transform())
 
- def _draw_caretleft(self, renderer, gc, xt, yt):
+	
+ def _draw_caretleft(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(offset1, -offset)
- path.line_to(0, 0)
- path.line_to(offset1, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x+offset1, y-offset, x, y)
- renderer.draw_line(gc, x, y, x+offset1, y+offset)
+	transform = Affine2D().scale(offset).rotate_deg(90)
+	renderer.draw_markers(gc, self._caret_path, transform,
+			 path, self.get_transform())
 
- def _draw_caretright(self, renderer, gc, xt, yt):
+	
+ def _draw_caretright(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
- offset1 = 1.5*offset
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset1, -offset)
- path.line_to(0, 0)
- path.line_to(-offset1, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset1, y-offset, x, y)
- renderer.draw_line(gc, x, y, x-offset1, y+offset)
+	transform = Affine2D().scale(offset).rotate_deg(270)
+	renderer.draw_markers(gc, self._caret_path, transform,
+			 path, self.get_transform())
 
+
+ _x_path = Path([[-1.0, -1.0], [1.0, 1.0],
+		 [-1.0, 1.0], [1.0, -1.0]],
+		 [Path.MOVETO, Path.LINETO,
+		 Path.MOVETO, Path.LINETO])
 def _draw_x(self, renderer, gc, xt, yt):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset)
+	renderer.draw_markers(gc, self._x_path, transform,
+			 path, self.get_transform())
 
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, -offset)
- path.line_to(offset, offset)
- path.move_to(-offset, offset)
- path.line_to(offset, -offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y-offset, x+offset, y+offset)
- renderer.draw_line(gc, x-offset, y+offset, x+offset, y-offset)
-
+	
 def update_from(self, other):
 'copy properties from other to self'
 Artist.update_from(self, other)
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -50,6 +50,9 @@
 		i += NUM_VERTICES[code]
 	 assert i == len(self.vertices)
 
+ def __repr__(self):
+	return "Path(%s, %s)" % (self.vertices, self.codes)
+	 
 def _get_codes(self):
 	return self._codes
 codes = property(_get_codes)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -88,11 +88,13 @@
 intervaly = property(_get_intervaly)
 
 def _get_width(self):
- return self.xmax - self.xmin
+	points = self.get_points()
+	return points[1, 0] - points[0, 0]
 width = property(_get_width)
 
 def _get_height(self):
- return self.ymax - self.ymin
+	points = self.get_points()
+	return points[1, 1] - points[0, 1]
 height = property(_get_height)
 
 def _get_bounds(self):
Modified: branches/transforms/lib/matplotlib/type1font.py
===================================================================
--- branches/transforms/lib/matplotlib/type1font.py	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/lib/matplotlib/type1font.py	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -1,15 +1,15 @@
 """
 A class representing a Type 1 font.
 
-This version merely allows reading in pfa and pfb files, stores the
-data in pfa format, and allows reading the parts of the data in a
-format suitable for embedding in pdf files. A more complete class
-might support subsetting.
+This version merely reads pfa and pfb files and splits them for
+embedding in pdf files. There is no support yet for subsetting or
+anything like that.
 
-Usage: font = Type1Font(filename)
- somefile.write(font.data) # writes out font in pfa format
- len1, len2, len3 = font.lengths() # needed for pdf embedding
+Usage (subject to change):
 
+ font = Type1Font(filename)
+ clear_part, encrypted_part, finale = font.parts
+
 Source: Adobe Technical Note #5040, Supporting Downloadable PostScript
 Language Fonts.
 
@@ -32,8 +32,7 @@
 def _read(self, file):
 rawdata = file.read()
 if not rawdata.startswith(chr(128)):
- self.data = rawdata
- return
+ return rawdata
 
 data = ''
 while len(rawdata) > 0:
@@ -101,4 +100,6 @@
 if __name__ == '__main__':
 import sys
 font = Type1Font(sys.argv[1])
- sys.stdout.write(font.data)
+ parts = font.parts
+ print len(parts[0]), len(parts[1]), len(parts[2])
+
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月17日 13:41:38 UTC (rev 3854)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月18日 16:21:37 UTC (rev 3855)
@@ -10,7 +10,6 @@
 #include <time.h>
 #include <algorithm>
 
-
 #include "agg_conv_transform.h"
 #include "agg_conv_curve.h"
 #include "agg_scanline_storage_aa.h"
@@ -43,28 +42,48 @@
 #define M_PI_2 1.57079632679489661923
 #endif
 
-agg::trans_affine py_sequence_to_agg_transformation_matrix(const Py::Object& obj) {
- Py::SeqBase<Py::Float> seq;
+/** A helper function to convert from a Numpy affine transformation matrix
+ * to an agg::trans_affine.
+ */
+agg::trans_affine py_to_agg_transformation_matrix(const Py::Object& obj) {
+ PyArrayObject* matrix = NULL;
+ 
+ double a = 1.0, b = 0.0, c = 0.0, d = 1.0, e = 0.0, f = 0.0;
+
 try {
- seq = obj;
- } catch(...) {
- throw Py::ValueError("Transformation matrix must be given as a 6-element list.");
- }
+ matrix = (PyArrayObject*) PyArray_ContiguousFromObject(obj.ptr(), PyArray_DOUBLE, 2, 2);
+ if (!matrix || matrix->nd != 2 || matrix->dimensions[0] != 3 || matrix->dimensions[1] != 3) {
+ throw Py::ValueError("Invalid affine transformation matrix.");
+ }
 
- if (seq.size() != 6) {
- throw Py::ValueError("Transformation matrix must be given as a 6-element list.");
+ size_t stride0 = matrix->strides[0];
+ size_t stride1 = matrix->strides[1];
+ char* row0 = matrix->data;
+ char* row1 = row0 + stride0;
+
+ a = *(double*)(row0);
+ row0 += stride1;
+ c = *(double*)(row0);
+ row0 += stride1;
+ e = *(double*)(row0);
+ 
+ b = *(double*)(row1);
+ row1 += stride1;
+ d = *(double*)(row1);
+ row1 += stride1;
+ f = *(double*)(row1);
+ } catch (...) {
+ Py_XDECREF(matrix);
 }
 
- return agg::trans_affine
- (Py::Float(seq[0]), 
- Py::Float(seq[1]), 
- Py::Float(seq[2]), 
- Py::Float(seq[3]), 
- Py::Float(seq[4]), 
- Py::Float(seq[5]));
+ Py_XDECREF(matrix);
+
+ return agg::trans_affine(a, b, c, d, e, f);
 }
 
-// MGDTODO: Implement this as a nice iterator
+/** Helper function to get the next vertex in a Numpy array of vertices.
+ * Will generally be used through the GET_NEXT_VERTEX macro.
+ */
 inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, 
 			 double& x, double& y,
 			 size_t next_vertex_stride, 
@@ -78,12 +97,18 @@
 
 #define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
 
+Py::Object BufferRegion::to_string(const Py::Tuple &args) {
+ 
+ // owned=true to prevent memory leak
+ return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true);
+}
+
+
 GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) :
 dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0),
 cliprect(NULL), clippath(NULL), 
 Ndash(0), dashOffset(0.0), dasha(NULL)
 {
- 
 _VERBOSE("GCAgg::GCAgg");
 linewidth = points_to_pixels ( gc.getAttr("_linewidth") ) ;
 alpha = Py::Float( gc.getAttr("_alpha") );
@@ -100,7 +125,6 @@
 GCAgg::_set_antialiased(const Py::Object& gc) {
 _VERBOSE("GCAgg::antialiased");
 isaa = Py::Int( gc.getAttr( "_antialiased") );
- 
 }
 
 agg::rgba
@@ -123,13 +147,12 @@
 return p * dpi/72.0;
 }
 
-
 void
 GCAgg::_set_linecap(const Py::Object& gc) {
 _VERBOSE("GCAgg::_set_linecap");
 
 std::string capstyle = Py::String( gc.getAttr( "_capstyle" ) );
- 
+
 if (capstyle=="butt")
 cap = agg::butt_cap;
 else if (capstyle=="round")
@@ -138,7 +161,6 @@
 cap = agg::square_cap;
 else
 throw Py::ValueError(Printf("GC _capstyle attribute must be one of butt, round, projecting; found %s", capstyle.c_str()).str());
- 
 }
 
 void
@@ -155,7 +177,6 @@
 join = agg::bevel_join;
 else
 throw Py::ValueError(Printf("GC _joinstyle attribute must be one of butt, round, projecting; found %s", joinstyle.c_str()).str());
- 
 }
 
 void
@@ -193,7 +214,7 @@
 }
 }
 
-
+// MGDTODO: Convert directly from Bbox object (numpy)
 void
 GCAgg::_set_clip_rectangle( const Py::Object& gc) {
 //set the clip rectangle from the gc
@@ -204,7 +225,7 @@
 cliprect = NULL;
 
 Py::Object o ( gc.getAttr( "_cliprect" ) );
- if (o.ptr()==Py_None) {
+ if (o.ptr() == Py_None) {
 return;
 }
 
@@ -229,38 +250,18 @@
 
 _VERBOSE("GCAgg::_set_clip_path");
 
- delete clippath;
+ Py_XINCREF(clippath);
 clippath = NULL;
 
- Py::Object o = gc.getAttr( "_clippath" );
+ Py::Object o = gc.getAttr("_clippath");
 if (o.ptr()==Py_None) {
 return;
 }
 
- agg::path_storage *tmppath;
- swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *");
- assert(descr);
- if (SWIG_ConvertPtr(o.ptr(),(void **)(&tmppath), descr, 0) == -1) {
- throw Py::TypeError("Could not convert gc path_storage");
- }
- 
- tmppath->rewind(0);
- clippath = new agg::path_storage();
- clippath->copy_from(*tmppath);
- clippath->rewind(0);
- tmppath->rewind(0);
+ clippath = new PathAgg(o);
 }
 
 
-Py::Object BufferRegion::to_string(const Py::Tuple &args) {
- 
- // owned=true to prevent memory leak
- return Py::String(PyString_FromStringAndSize((const char*)aggbuf.data,aggbuf.height*aggbuf.stride), true);
-}
-
-
-
-
 const size_t
 RendererAgg::PIXELS_PER_INCH(96);
 
@@ -311,19 +312,14 @@
 
 
 void
-RendererAgg::set_clipbox_rasterizer( double *cliprect) {
+RendererAgg::set_clipbox_rasterizer(double *cliprect) {
 //set the clip rectangle from the gc
 
 _VERBOSE("RendererAgg::set_clipbox_rasterizer");
- 
 
 theRasterizer->reset_clipping();
 rendererBase->reset_clipping(true);
 
- //if (cliprect==NULL) {
- // theRasterizer->reset_clipping();
- // rendererBase->reset_clipping(true);
- //}
 if (cliprect!=NULL) {
 
 double l = cliprect[0] ;
@@ -355,273 +351,10 @@
 
 }
 
-// MGDTODO: Remove this method (it has been conglomerated into draw_path
-template <class VS>
-void
-RendererAgg::_fill_and_stroke(VS& path,
-			 const GCAgg& gc,
-			 const facepair_t& face,
-			 bool curvy) {
- typedef agg::conv_curve<VS> curve_t;
- 
- //bool isclippath(gc.clippath!=NULL);
- //if (isclippath) _process_alpha_mask(gc); 
-
- if (face.first) {
- rendererAA->color(face.second);
- if (curvy) {
- curve_t curve(path);
- theRasterizer->add_path(curve);
- }
- else
- theRasterizer->add_path(path);
- 
- /*
- if (isclippath) {
-	typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
-	typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
-	pixfmt_amask_type pfa(*pixFmt, *alphaMask);
-	amask_ren_type r(pfa);
-	typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
-	renderer_type ren(r);
-	ren.color(gc.color);
-	//std::cout << "render clippath" << std::endl;
-	
-	agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
-	rendererAA->color(gc.color);
-	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- */
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- 
- //now stroke the edge
- if (gc.linewidth) {
- if (curvy) {
- curve_t curve(path);
- agg::conv_stroke<curve_t> stroke(curve);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
- else {
- agg::conv_stroke<VS> stroke(path);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
- 
- 
- /*
- if ( gc.isaa ) {
- if (isclippath) {
-	typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
-	typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
-	pixfmt_amask_type pfa(*pixFmt, *alphaMask);
-	amask_ren_type r(pfa);
-	typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
-	renderer_type ren(r);
-	ren.color(gc.color);
-	//std::cout << "render clippath" << std::endl;
-	
-	agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
-	rendererAA->color(gc.color);
-	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- }
- else {
- if (isclippath) {
-	typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
-	typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
-	pixfmt_amask_type pfa(*pixFmt, *alphaMask);
-	amask_ren_type r(pfa);
-	typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type;
-	renderer_type ren(r);
-	ren.color(gc.color);
-	agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else{
-	rendererBin->color(gc.color);
-	agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
-
- */
- 
- if ( gc.isaa ) {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- else {
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
- 
-
-}
-
-Py::Object
-RendererAgg::draw_rectangle(const Py::Tuple & args) {
- _VERBOSE("RendererAgg::draw_rectangle");
- args.verify_length(6);
- 
- 
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
- 
- 
- double l = Py::Float( args[2] );
- double b = Py::Float( args[3] );
- double w = Py::Float( args[4] );
- double h = Py::Float( args[5] );
- 
- b = height - (b+h);
- double r = l + w;
- double t = b + h;
- 
- //snapto pixel centers
- l = (int)l + 0.5;
- b = (int)b + 0.5;
- r = (int)r + 0.5;
- t = (int)t + 0.5;
- 
- 
- set_clipbox_rasterizer(gc.cliprect);
- 
- agg::path_storage path;
- 
- 
- path.move_to(l, t);
- path.line_to(r, t);
- path.line_to(r, b);
- path.line_to(l, b);
- path.close_polygon();
- 
- _fill_and_stroke(path, gc, face, false);
- 
- return Py::Object();
- 
-}
-
-Py::Object
-RendererAgg::draw_ellipse(const Py::Tuple& args) {
- _VERBOSE("RendererAgg::draw_ellipse");
- args.verify_length(7);
- 
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
- 
- double x = Py::Float( args[2] );
- double y = Py::Float( args[3] );
- double w = Py::Float( args[4] );
- double h = Py::Float( args[5] );
- double rot = Py::Float( args[6] );
- 
- double r; // rot in radians
- 
- set_clipbox_rasterizer(gc.cliprect);
- 
- // Approximate the ellipse with 4 bezier paths
- agg::path_storage path;
- if (rot == 0.0) // simple case
- {
- path.move_to(x, height-(y+h));
- path.arc_to(w, h, 0.0, false, true, x+w, height-y);
- path.arc_to(w, h, 0.0, false, true, x, height-(y-h));
- path.arc_to(w, h, 0.0, false, true, x-w, height-y);
- path.arc_to(w, h, 0.0, false, true, x, height-(y+h));
- path.close_polygon();
- }
- else // rotate by hand :(
- {
- // deg to rad
- r = rot * (M_PI/180.0);
- path.move_to( x+(cos(r)*w), height-(y+(sin(r)*w)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2*3)*h), height-(y+(sin(r+M_PI_2*3)*h)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI)*w), height-(y+(sin(r+M_PI)*w)));
- path.arc_to(w, h, -r, false, true, x+(cos(r+M_PI_2)*h), height-(y+(sin(r+M_PI_2)*h)));
- path.arc_to(w, h, -r, false, true, x+(cos(r)*w), height-(y+(sin(r)*w)));
- path.close_polygon();
- }
- 
- _fill_and_stroke(path, gc, face);
- return Py::Object();
- 
-}
-
-Py::Object
-RendererAgg::draw_polygon(const Py::Tuple& args) {
- _VERBOSE("RendererAgg::draw_polygon");
- 
- args.verify_length(3);
- 
- GCAgg gc = GCAgg(args[0], dpi);
- facepair_t face = _get_rgba_face(args[1], gc.alpha);
- 
- Py::SeqBase<Py::Object> points( args[2] );
- 
- set_clipbox_rasterizer(gc.cliprect);
- 
- size_t Npoints = points.length();
- if (Npoints<=0)
- return Py::Object();
- 
- 
- // dump the x.y vertices into a double array for faster look ahead
- // and behind access
- double *xs = new double[Npoints];
- double *ys = new double[Npoints];
- 
- for (size_t i=0; i<Npoints; i++) {
- Py::SeqBase<Py::Object> xy(points[i]);
- xy = Py::Tuple(points[i]);
- xs[i] = Py::Float(xy[0]);
- ys[i] = Py::Float(xy[1]);
- ys[i] = height - ys[i];
- }
- 
- 
- 
- agg::path_storage path;
- for (size_t j=0; j<Npoints; j++) {
- 
- double x = xs[j];
- double y = ys[j];
- 
- //snapto pixel centers
- x = (int)x + 0.5;
- y = (int)y + 0.5;
- 
- if (j==0) path.move_to(x,y);
- else path.line_to(x,y);
- }
- path.close_polygon();
- 
- _fill_and_stroke(path, gc, face, false);
- 
- delete [] xs;
- delete [] ys;
- 
- _VERBOSE("RendererAgg::draw_polygon DONE");
- return Py::Object();
- 
-}
-
-
-
 SnapData
 SafeSnap::snap (const float& x, const float& y) {
 xsnap = (int)x + 0.5;
 ysnap = (int)y + 0.5;
-
-
 
 if ( first || ( (xsnap!=lastxsnap) || (ysnap!=lastysnap) ) ) {
 lastxsnap = xsnap;
@@ -690,9 +423,6 @@
 rb.copy_from(*renderingBuffer, &r, -r.x1, -r.y1);
 BufferRegion* reg = new BufferRegion(buf, r, true);
 return Py::asObject(reg);
- 
- 
- 
 }
 
 Py::Object
@@ -715,25 +445,20 @@
 rendererBase->copy_from(rbuf, 0, region->rect.x1, region->rect.y1);
 
 return Py::Object();
- 
- 
- 
 }
 
-
+/**
+ * Helper function to convert a Python Bbox object to an agg rectangle
+ */
 template<class T>
 agg::rect_base<T>
 RendererAgg::bbox_to_rect(const Py::Object& o) {
 //return the agg::rect for bbox, flipping y
 PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2);
 
- if (!bbox)
+ if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
 throw Py::TypeError
 ("Expected a Bbox object.");
- 
- if (bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2)
- throw Py::TypeError
- ("Expected a Bbox object.");
 
 double l = bbox->data[0];
 double b = bbox->data[1];
@@ -805,469 +530,8 @@
 return numIntersect;
 }
 
-void RendererAgg::DrawQuadMesh(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[])
-{
- /* draw each quadrilateral */
- //	agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase);
- int i = 0;
- int j = 0;
- int k = 0;
- double xs[4];
- double ys[4];
- int col[4];
- int numCol;
- double ymin;
- int firstRow;
- double ymax;
- int lastRow;
- for(i=0; i < meshHeight; i++)
- {
- for(j=0; j < meshWidth; j++)
-	{
-	 //currTime = clock();
-	 xs[0] = xCoords[(i * (meshWidth + 1)) + j];
-	 ys[0] = yCoords[(i * (meshWidth + 1)) + j];
-	 xs[1] = xCoords[(i * (meshWidth + 1)) + j+1];
-	 ys[1] = yCoords[(i * (meshWidth + 1)) + j+1];
-	 xs[3] = xCoords[((i+1) * (meshWidth + 1)) + j];
-	 ys[3] = yCoords[((i+1) * (meshWidth + 1)) + j];
-	 xs[2] = xCoords[((i+1) * (meshWidth + 1)) + j+1];
-	 ys[2] = yCoords[((i+1) * (meshWidth + 1)) + j+1];
-	 ymin = std::min(std::min(std::min(ys[0], ys[1]), ys[2]), ys[3]);
-	 ymax = std::max(std::max(std::max(ys[0], ys[1]), ys[2]), ys[3]);
-	 firstRow = (int)(ymin);
-	 lastRow = (int)(ymax);
-	 //timer1 += (clock() - currTime);
-	 //currTime = clock();
-	 //timer2 += (clock() - currTime);
-	 //currTime = clock();
-	 for(k = firstRow; k <= lastRow; k++)
-	 {
-	 numCol = inPolygon(k, xs, ys, col);
-	 if (numCol >= 2) rendererBase->copy_hline(col[0], k, col[1] - 1, colorArray[(i * meshWidth) + j]);
-	 if (numCol == 4) rendererBase->copy_hline(col[2], k, col[3] - 1, colorArray[(i * meshWidth) + j]);
-	 }
-	}
- }
- return;
-}
 
-void RendererAgg::DrawQuadMeshEdges(int meshWidth, int meshHeight, const agg::rgba8 colorArray[], const double xCoords[], const double yCoords[])
-{
- int i, j;
- agg::renderer_primitives<agg::renderer_base<agg::pixfmt_rgba32> > lineRen(*rendererBase);
- agg::rgba8 lc(0, 0, 0, 32);
- lineRen.line_color(lc);
- /* show the vertical edges */
- for(i=0; i <= meshWidth; i++)
- {
- lineRen.move_to((int)(256.0 * (xCoords[i])), (int)(256.0 * (yCoords[i])));
- for(j=1; j <= meshHeight; j++)
-	lineRen.line_to((int)(256.0 *(xCoords[(j * (meshWidth + 1))+i])), (int)(256.0 * (yCoords[(j * (meshWidth + 1))+i])));
- }
- /* show the horizontal edges */
- for(i=0; i <= meshHeight; i++)
- {
- lineRen.move_to((int)(256.0 * (xCoords[i * (meshWidth + 1)])), (int)(256.0 * (yCoords[i * (meshWidth + 1)])));
- for(j=1; j <= meshWidth; j++)
-	lineRen.line_to((int)(256.0 * (xCoords[(i * (meshWidth + 1))+j])), (int)(256.0 * (yCoords[(i * (meshWidth + 1))+j])));
- }
-}
-
-
-
 Py::Object
-RendererAgg::draw_lines(const Py::Tuple& args) {
- 
- _VERBOSE("RendererAgg::draw_lines");
- args.verify_length(4);
-
- Py::Object xo = args[1];
- Py::Object yo = args[2];
-
- PyArrayObject *xa = (PyArrayObject *) PyArray_ContiguousFromObject(xo.ptr(), PyArray_DOUBLE, 1, 1);
-
- if (xa==NULL)
- throw Py::TypeError("RendererAgg::draw_lines expected numerix array");
-
-
- PyArrayObject *ya = (PyArrayObject *) PyArray_ContiguousFromObject(yo.ptr(), PyArray_DOUBLE, 1, 1);
-
- if (ya==NULL)
- throw Py::TypeError("RendererAgg::draw_lines expected numerix array");
-
-
- size_t Nx = xa->dimensions[0];
- size_t Ny = ya->dimensions[0];
-
- if (Nx!=Ny)
- throw Py::ValueError(Printf("x and y must be equal length arrays; found %d and %d", Nx, Ny).str());
-
- // call gc with snapto==True if line len is 2 to fix grid line
- // problem
- bool snapto = false;
- if (Nx==2) {
- // disable subpiel rendering for len(2) horizontal or vertical
- // lines
- double x0 = *(double *)(xa->data + 0*xa->strides[0]);
- double x1 = *(double *)(xa->data + 1*xa->strides[0]);
- double y0 = *(double *)(ya->data + 0*ya->strides[0]);
- double y1 = *(double *)(ya->data + 1*ya->strides[0]);
- snapto = (x0==x1) || (y0==y1);
-
- }
- GCAgg gc = GCAgg(args[0], dpi, snapto);
-
- set_clipbox_rasterizer(gc.cliprect);
- //path_t transpath(path, xytrans);
- _process_alpha_mask(gc);
-
- agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[3]);
-
- agg::path_storage path;
-
- // MGDTODO
- bool needNonlinear = false;
- // mpltransform->need_nonlinear_api();
-
- double thisx(0.0), thisy(0.0);
- double origdx(0.0), origdy(0.0), origdNorm2(0);
- bool moveto = true;
- double heightd = height;
-
- double lastx(0), lasty(0);
- double lastWrittenx(0), lastWritteny(0);
- bool clipped = false;
- 
- bool haveMin = false, lastMax = true;
- double dnorm2Min(0), dnorm2Max(0);
- double maxX(0), maxY(0), minX(0), minY(0);
- 
- double totdx, totdy, totdot;
- double paradx, parady, paradNorm2;
- double perpdx, perpdy, perpdNorm2;
- 
- int counter = 0;
- //idea: we can skip drawing many lines: lines < 1 pixel in length, lines 
- //outside of the drawing area, and we can combine sequential parallel lines
- //into a single line instead of redrawing lines over the same points.
- //The loop below works a bit like a state machine, where what it does depends 
- //on what it did in the last looping. To test whether sequential lines
- //are close to parallel, I calculate the distance moved perpendicular to the
- //last line. Once it gets too big, the lines cannot be combined.
- for (size_t i=0; i<Nx; i++) {
-
- thisx = *(double *)(xa->data + i*xa->strides[0]);
- thisy = *(double *)(ya->data + i*ya->strides[0]);
-
- if (needNonlinear)
- try {
-	// MGDTODO
- // mpltransform->nonlinear_only_api(&thisx, &thisy);
- }
- catch (...) {
- moveto = true;
- continue;
- }
- if (MPL_isnan64(thisx) || MPL_isnan64(thisy)) {
- moveto = true;
- continue;
- }
- 
- //use agg's transformer?
- xytrans.transform(&thisx, &thisy);
- thisy = heightd - thisy; //flipy
- 
- if (snapto) {
- //disable subpixel rendering for horizontal or vertical lines of len=2
- //because it causes irregular line widths for grids and ticks
- thisx = (int)thisx + 0.5;
- thisy = (int)thisy + 0.5;
- }
- 
- //if we are starting a new path segment, move to the first point + init
- if(moveto){
- path.move_to(thisx, thisy);
- lastx = thisx;
- lasty = thisy;
- origdNorm2 = 0; //resets the orig-vector variables (see if-statement below)
- moveto = false;
- continue;
- }
-
- //don't render line segments less that on pixel long!
- if (fabs(thisx-lastx) < 1.0 && fabs(thisy-lasty) < 1.0 ){
- continue; //don't update lastx this time!
- }
- 
- //skip any lines that are outside the drawing area. Note: More lines
- //could be clipped, but a more involved calculation would be needed
- if( (thisx < 0 && lastx < 0 ) ||
- (thisx > width && lastx > width ) ||
- (thisy < 0 && lasty < 0 ) ||
- (thisy > height && lasty > height) ){
- lastx = thisx;
- lasty = thisy;
- clipped = true; 
- continue;
- }
- 
- //if we have no orig vector, set it to this vector and continue.
- //this orig vector is the reference vector we will build up the line to
- if(origdNorm2 == 0){
- //if we clipped after the moveto but before we got here, redo the moveto
- if(clipped){
- path.move_to(lastx, lasty);
- clipped = false;
- }
- 
- origdx = thisx - lastx;
- origdy = thisy - lasty;
- origdNorm2 = origdx*origdx + origdy*origdy;
- 
- //set all the variables to reflect this new orig vecor
- dnorm2Max = origdNorm2;
- dnorm2Min = 0;
- haveMin = false;
- lastMax = true;
- maxX = thisx;
- maxY = thisy;
- minX = lastx; 
- minY = lasty; 
- 
- lastWrittenx = lastx;
- lastWritteny = lasty; 
- 
- //set the last point seen
- lastx = thisx;
- lasty = thisy; 
- continue;
- }
- 
- //if got to here, then we have an orig vector and we just got 
- //a vector in the sequence.
- 
- //check that the perpendicular distance we have moved from the
- //last written point compared to the line we are building is not too 
- //much. If o is the orig vector (we are building on), and v is the vector 
- //from the last written point to the current point, then the perpendicular 
- //vector is p = v - (o.v)o, and we normalize o (by dividing the 
- //second term by o.o). 
- 
- //get the v vector
- totdx = thisx - lastWrittenx;
- totdy = thisy - lastWritteny;
- totdot = origdx*totdx + origdy*totdy;
- 
- //get the para vector ( = (o.v)o/(o.o) )
- paradx = totdot*origdx/origdNorm2;
- parady = totdot*origdy/origdNorm2;
- paradNorm2 = paradx*paradx + parady*parady;
- 
- //get the perp vector ( = v - para )
- perpdx = totdx - paradx;
- perpdy = totdy - parady; 
- perpdNorm2 = perpdx*perpdx + perpdy*perpdy; 
- 
- //if the perp vector is less than some number of (squared) pixels in size,
- //then merge the current vector
- if(perpdNorm2 < 0.25 ){
- //check if the current vector is parallel or
- //anti-parallel to the orig vector. If it is parallel, test
- //if it is the longest of the vectors we are merging in that direction. 
- //If anti-p, test if it is the longest in the opposite direction (the 
- //min of our final line)
- 
- lastMax = false;
- if(totdot >= 0){
- if(paradNorm2 > dnorm2Max){
- lastMax = true;
- dnorm2Max = paradNorm2;
- maxX = lastWrittenx + paradx;
- maxY = lastWritteny + parady;
- }
- }
- else{
- 
- haveMin = true;
- if(paradNorm2 > dnorm2Min){
- dnorm2Min = paradNorm2;
- minX = lastWrittenx + paradx;
- minY = lastWritteny + parady;
- }
- }
- 
- lastx = thisx;
- lasty = thisy;
- continue;
- }
- 
- //if we get here, then this vector was not similar enough to the line
- //we are building, so we need to draw that line and start the next one.
- 
- //if the line needs to extend in the opposite direction from the direction
- //we are drawing in, move back to we start drawing from back there.
- if(haveMin){
- path.line_to(minX, minY); //would be move_to if not for artifacts
- }
- 
- path.line_to(maxX, maxY);
- 
- //if we clipped some segments between this line and the next line
- //we are starting, we also need to move to the last point.
- if(clipped){
- path.move_to(lastx, lasty);
- }
- else if(!lastMax){
- 	//if the last line was not the longest line, then move back to the end 
- //point of the last line in the sequence. Only do this if not clipped,
- //since in that case lastx,lasty is not part of the line just drawn.
- path.line_to(lastx, lasty); //would be move_to if not for artifacts
- } 
-
- //std::cout << "draw lines (" << lastx << ", " << lasty << ")" << std::endl;
-
- //now reset all the variables to get ready for the next line
- 
- origdx = thisx - lastx;
- origdy = thisy - lasty;
- origdNorm2 = origdx*origdx + origdy*origdy;
- 
- dnorm2Max = origdNorm2;
- dnorm2Min = 0;
- haveMin = false;
- lastMax = true;
- maxX = thisx;
- maxY = thisy;
- minX = lastx; 
- minY = lasty;
- 
- lastWrittenx = lastx;
- lastWritteny = lasty; 
- 
- clipped = false;
- 
- lastx = thisx;
- lasty = thisy;
- 
- counter++;
- }
-
- //draw the last line, which is usually not drawn in the loop
- if(origdNorm2 != 0){
- if(haveMin){
- path.line_to(minX, minY); //would be move_to if not for artifacts
- } 
- 
- path.line_to(maxX, maxY);
- }
- 
- //std::cout << "drew " << counter+1 << " lines" << std::endl;
-
- Py_XDECREF(xa);
- Py_XDECREF(ya);
-
- //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t;
- //path_t transpath(path, xytrans);
- _VERBOSE("RendererAgg::draw_lines rendering lines path");
- _render_lines_path(path, gc);
-
- _VERBOSE("RendererAgg::draw_lines DONE");
- return Py::Object();
-
-}
-
-bool 
-RendererAgg::_process_alpha_mask(const GCAgg& gc)
- //if gc has a clippath set, process the alpha mask and return True,
- //else return False
-{
- if (gc.clippath==NULL) {
- return false;
- }
- if (0 &(gc.clippath==lastclippath)) {
- //std::cout << "seen it" << std::endl;
- return true;
- }
- rendererBaseAlphaMask->clear(agg::gray8(0, 0));
- gc.clippath->rewind(0);
- theRasterizer->add_path(*(gc.clippath));
- rendererAlphaMask->color(agg::gray8(255,255));
- agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
- lastclippath = gc.clippath;
- return true;
-}
-
-template<class PathSource>
-void
-RendererAgg::_render_lines_path(PathSource &path, const GCAgg& gc) {
- _VERBOSE("RendererAgg::_render_lines_path");
- typedef PathSource path_t;
- //typedef agg::conv_transform<agg::path_storage, agg::trans_affine> path_t;
- typedef agg::conv_stroke<path_t> stroke_t;
- typedef agg::conv_dash<path_t> dash_t;
- 
- bool isclippath(gc.clippath!=NULL);
- 
- if (gc.dasha==NULL ) { //no dashes
- stroke_t stroke(path);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- }
- else {
- dash_t dash(path);
- 
- //todo: dash.dash_start(gc.dashOffset);
- for (size_t i=0; i<gc.Ndash/2; i+=1)
- dash.add_dash(gc.dasha[2*i], gc.dasha[2*i+1]);
- 
- agg::conv_stroke<dash_t> stroke(dash);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.width(gc.linewidth);
- theRasterizer->add_path(stroke); //boyle freeze is herre
- }
- 
- 
- if ( gc.isaa ) {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_aa_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- //std::cout << "render clippath" << std::endl;
- 
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
- }
- }
- else {
- if (isclippath) {
- typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
- typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
- pixfmt_amask_type pfa(*pixFmt, *alphaMask);
- amask_ren_type r(pfa);
- typedef agg::renderer_scanline_bin_solid<amask_ren_type> renderer_type;
- renderer_type ren(r);
- ren.color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, ren);
- }
- else{
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
- }
- }
-}
-
-Py::Object
 RendererAgg::draw_markers(const Py::Tuple& args) {
 typedef agg::conv_transform<agg::path_storage> transformed_path_t;
 typedef agg::conv_curve<transformed_path_t> curve_t;
@@ -1284,10 +548,10 @@
 if (!PathAgg::check(marker_path_obj))
 throw Py::TypeError("Native path object is not of correct type");
 PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr());
- agg::trans_affine marker_trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ agg::trans_affine marker_trans = py_to_agg_transformation_matrix(args[2]);
 Py::Object vertices_obj = args[3];
 Py::Object codes_obj = args[4];
- agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[5]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[5]);
 facepair_t face = _get_rgba_face(args[6], gc.alpha);
 
 // Deal with the difference in y-axis direction
@@ -1337,7 +601,8 @@
 unsigned strokeSize = scanlines.byte_size();
 strokeCache = new agg::int8u[strokeSize]; // or any container
 scanlines.serialize(strokeCache);
- 
+
+ // MGDTODO: Clean this up and support clippaths as well
 theRasterizer->reset_clipping();
 if (gc.cliprect==NULL) {
 rendererBase->reset_clipping(true);
@@ -1557,14 +822,20 @@
 Py::Object
 RendererAgg::convert_to_native_path(const Py::Tuple& args) {
 _VERBOSE("RendererAgg::draw_image");
- args.verify_length(2);
+ args.verify_length(1);
 
- Py::Object vertices_obj = args[0];
- Py::Object codes_obj = args[1];
+ Py::Object path = args[0];
+
+ return Py::asObject(new PathAgg(path));
+}
+
 
+PathAgg::PathAgg(const Py::Object& path_obj) : curvy(false) {
+ Py::Object vertices_obj = path_obj.getAttr("vertices");
+ Py::Object codes_obj = path_obj.getAttr("codes");
+ 
 PyArrayObject* vertices = NULL;
 PyArrayObject* codes = NULL;
- PathAgg* path = NULL; 
 
 try {
 vertices = (PyArrayObject*)PyArray_ContiguousFromObject
@@ -1576,8 +847,6 @@
 if (!codes) 
 throw Py::ValueError("Invalid codes array.");
 
- path = new PathAgg();
-
 size_t next_vertex_stride = vertices->strides[0];
 size_t next_axis_stride = vertices->strides[1];
 size_t code_stride = codes->strides[0];
@@ -1593,31 +862,31 @@
 switch (*(unsigned char*)(code_i)) {
 case MOVETO:
 	GET_NEXT_VERTEX(x0, y0);
-	path->move_to(x0, y0);
+	move_to(x0, y0);
 	_VERBOSE("MOVETO");
 	break;
 case LINETO:
 	GET_NEXT_VERTEX(x0, y0);
-	path->line_to(x0, y0);
+	line_to(x0, y0);
 	_VERBOSE("LINETO");
 	break;
 case CURVE3:
 	GET_NEXT_VERTEX(x0, y0);
 	GET_NEXT_VERTEX(x1, y1);
-	path->curve3(x0, y0, x1, y1);
-	path->curvy = true;
+	curve3(x0, y0, x1, y1);
+	curvy = true;
 	_VERBOSE("CURVE3");
 	break;
 case CURVE4:
 	GET_NEXT_VERTEX(x0, y0);
 	GET_NEXT_VERTEX(x1, y1);
 	GET_NEXT_VERTEX(x2, y2);
-	path->curve4(x0, y0, x1, y1, x2, y2);
-	path->curvy = true;
+	curve4(x0, y0, x1, y1, x2, y2);
+	curvy = true;
 	_VERBOSE("CURVE4");
 	break;
 case CLOSEPOLY:
-	path->close_polygon();
+	close_polygon();
 	_VERBOSE("CLOSEPOLY");
 	break;
 }
@@ -1626,14 +895,11 @@
 } catch(...) {
 Py_XDECREF(vertices);
 Py_XDECREF(codes);
- delete path;
 throw;
 }
 
 Py_XDECREF(vertices);
 Py_XDECREF(codes);
- 
- return Py::asObject(path);
 }
 
 Py::Object
@@ -1643,7 +909,11 @@
 typedef agg::conv_stroke<curve_t> stroke_t;
 typedef agg::conv_dash<curve_t> dash_t;
 typedef agg::conv_stroke<dash_t> stroke_dash_t;
- //draw_path(gc, rgbFace, path, transform)
+ typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type;
+ typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type;
+ typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type;
+ typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type;
+
 theRasterizer->reset_clipping();
 
 _VERBOSE("RendererAgg::draw_path");
@@ -1654,52 +924,118 @@
 if (!PathAgg::check(path_obj))
 throw Py::TypeError("Native path object is not of correct type");
 PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
- agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[2]);
 facepair_t face = _get_rgba_face(args[3], gc.alpha);
 
 trans *= agg::trans_affine_scaling(1.0, -1.0);
 trans *= agg::trans_affine_translation(0.0, (double)height);
 
- transformed_path_t tpath(*path, trans);
- // MGDTODO: See if there is any advantage to only curving if necessary
- curve_t curve(tpath);
+ transformed_path_t* tpath = NULL;
+ agg::path_storage new_path;
 
- set_clipbox_rasterizer(gc.cliprect);
- 
- if (face.first) {
- rendererAA->color(face.second);
- theRasterizer->add_path(curve);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ bool has_clippath = (gc.clippath != NULL);
+
+ if (has_clippath && (gc.clippath != lastclippath || trans != lastclippath_transform)) {
+ rendererBaseAlphaMask->clear(agg::gray8(0, 0));
+ gc.clippath->rewind(0);
+ transformed_path_t transformed_clippath(*(gc.clippath), trans);
+ theRasterizer->add_path(transformed_clippath);
+ rendererAlphaMask->color(agg::gray8(255, 255));
+ agg::render_scanlines(*theRasterizer, *scanlineAlphaMask, *rendererAlphaMask);
+ lastclippath = gc.clippath;
+ lastclippath_transform = trans;
 }
 
- if (gc.linewidth) {
- if (gc.dasha == NULL) {
- stroke_t stroke(curve);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->add_path(stroke);
- } else {
- dash_t dash(curve);
- for (size_t i = 0; i < (gc.Ndash / 2); ++i)
-	dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]);
- stroke_dash_t stroke(dash);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- stroke.width(gc.linewidth);
- theRasterizer->add_path(stroke); //boyle freeze is herre
+ try {
+ // If this is a straight horizontal or vertical line, quantize to nearest 
+ // pixels
+ if (path->total_vertices() == 2) {
+ double x0, y0, x1, y1;
+ path->vertex(0, &x0, &y0);
+ trans.transform(&x0, &y0);
+ path->vertex(1, &x1, &y1);
+ trans.transform(&x1, &y1);
+ if (((int)x0 == (int)x1) || ((int)y0 == (int)y1)) {
+	new_path.move_to((int)x0 + 0.5, (int)y0 + 0.5);
+	new_path.line_to((int)x1 + 0.5, (int)y1 + 0.5);
+	tpath = new transformed_path_t(new_path, agg::trans_affine());
+ }
 }
+
+ if (!tpath) {
+ tpath = new transformed_path_t(*path, trans);
+ }
+
+ // Benchmarking shows that there is no noticable slowdown to always
+ // treating paths as having curved segments. Doing so greatly 
+ // simplifies the code
+ curve_t curve(*tpath);
 
- if ( gc.isaa ) {
- rendererAA->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ set_clipbox_rasterizer(gc.cliprect);
+ 
+ if (face.first) {
+ if (has_clippath) {
+	pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+	amask_ren_type r(pfa);
+	amask_aa_renderer_type ren(r);
+	ren.color(gc.color);
+	agg::render_scanlines(*theRasterizer, *slineP8, ren);
+ } else{
+	rendererAA->color(face.second);
+	theRasterizer->add_path(curve);
+	agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ }
 }
- else {
- rendererBin->color(gc.color);
- agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
+ 
+ if (gc.linewidth) {
+ if (gc.dasha == NULL) {
+	stroke_t stroke(curve);
+	stroke.width(gc.linewidth);
+	stroke.line_cap(gc.cap);
+	stroke.line_join(gc.join);
+	theRasterizer->add_path(stroke);
+ } else {
+ 	dash_t dash(curve);
+	for (size_t i = 0; i < (gc.Ndash / 2); ++i)
+	dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]);
+	stroke_dash_t stroke(dash);
+	stroke.line_cap(gc.cap);
+	stroke.line_join(gc.join);
+	stroke.width(gc.linewidth);
+	theRasterizer->add_path(stroke);
+ }
+ 
+ if (gc.isaa) {
+	if (has_clippath) {
+	 pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+	 amask_ren_type r(pfa);
+	 amask_aa_renderer_type ren(r);
+	 ren.color(gc.color);
+	 agg::render_scanlines(*theRasterizer, *slineP8, ren);
+	} else {
+	 rendererAA->color(gc.color);
+	 agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+	}
+ } else {
+	if (has_clippath) {
+	 pixfmt_amask_type pfa(*pixFmt, *alphaMask);
+	 amask_ren_type r(pfa);
+	 amask_bin_renderer_type ren(r);
+	 ren.color(gc.color);
+	 agg::render_scanlines(*theRasterizer, *slineP8, ren);
+	} else {
+	 rendererBin->color(gc.color);
+	 agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
+	}
+ }
 }
+ } catch (...) {
+ delete tpath;
+ throw;
 }
 
+ delete tpath;
+
 return Py::Object();
 }
 
@@ -2033,18 +1369,10 @@
 behaviors().name("RendererAgg");
 behaviors().doc("The agg backend extension module");
 
- add_varargs_method("draw_rectangle", &RendererAgg::draw_rectangle,
-		 "draw_rectangle(gc, rgbFace, l, b, w, h)\n");
- add_varargs_method("draw_ellipse", &RendererAgg::draw_ellipse,
-		 "draw_ellipse(gc, rgbFace, x, y, w, h)\n");
- add_varargs_method("draw_polygon", &RendererAgg::draw_polygon,
-		 "draw_polygon(gc, rgbFace, points)\n");
 add_varargs_method("draw_path",...
 
[truncated message content]
From: <md...@us...> - 2007年09月17日 13:41:58
Revision: 3854
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3854&view=rev
Author: mdboom
Date: 2007年09月17日 06:41:38 -0700 (2007年9月17日)
Log Message:
-----------
Transferring work-in-progress
Modified Paths:
--------------
 branches/transforms/examples/shared_axis_demo.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/path.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
Modified: branches/transforms/examples/shared_axis_demo.py
===================================================================
--- branches/transforms/examples/shared_axis_demo.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/examples/shared_axis_demo.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -36,12 +36,12 @@
 s2 = exp(-t)
 s3 = sin(4*pi*t)
 ax1 = subplot(311)
-plot(t,s1)
+plot(t,s1, "bH")
 setp( ax1.get_xticklabels(), fontsize=6)
 
 ## share x only
 ax2 = subplot(312, sharex=ax1)
-plot(t, s2)
+plot(t, s2, "b<")
 # make these tick labels invisible
 setp( ax2.get_xticklabels(), visible=False)
 
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -36,21 +36,25 @@
 """
 pass
 
+ def _get_cached_native_path(self, path):
+	native_path = self._native_paths.get(path)
+	if native_path is None:
+	 import matplotlib.patches
+	 print "CACHE MISS", path
+	 native_path = self.convert_to_native_path(path)
+	 self._native_paths[path] = native_path
+	return native_path
+ 
 def draw_path(self, gc, path, transform, rgbFace = None):
 	"""
 	Handles the caching of the native path associated with the
 	given path and calls the underlying backend's _draw_path to
 	actually do the drawing.
 	"""
-	native_path = self._native_paths.get(path)
-	if native_path is None:
-	 import matplotlib.patches
-	 print "CACHE MISS", path
-	 native_path = self.convert_to_native_path(path)
-	 self._native_paths[path] = native_path
-	self._draw_path(gc, native_path, transform, rgbFace)
+	native_path = self._get_cached_native_path(path)
+	self._draw_native_path(gc, native_path, transform, rgbFace)
 
- def _draw_path(self, gc, native_path, transform, rgbFace):
+ def _draw_native_path(self, gc, native_path, transform, rgbFace):
 	"""
 	Draw the native path object with the given GraphicsContext and
 	transform. The transform passed in will always be affine.
@@ -107,9 +111,10 @@
 return False
 
 def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
-	pass
- 
- def _draw_markers(self, bgc, path, rgbFace, x, y, trans):
+	native_marker_path = self._get_cached_native_path(marker_path)
+	self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace)
+	
+ def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
 """
 This method is currently underscore hidden because the
 draw_markers method is being used as a sentinel for newstyle
@@ -130,7 +135,7 @@
 vec6 = transform.as_vec6_val()
 ...backend dependent affine...
 """
- pass
+ raise NotImplementedError
 
 def draw_line_collection(self, segments, transform, clipbox,
 colors, linewidths, linestyle, antialiaseds,
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -140,7 +140,7 @@
 def convert_to_native_path(self, path):
 	return self._renderer.convert_to_native_path(path.vertices, path.codes)
 
- def _draw_path(self, gc, native_path, transform, rgbFace):
+ def _draw_native_path(self, gc, native_path, transform, rgbFace):
 	return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace)
 	
 def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation):
@@ -172,8 +172,12 @@
 def draw_lines(self, gc, x, y, transform):
 	return self._renderer.draw_lines(gc, x, y, transform.to_values())
 
- def draw_markers(self, gc, path, color, x, y, transform):
-	return self._renderer.draw_markers(gc, path, color, x, y, transform.to_values())
+ def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None):
+	return self._renderer.draw_markers(
+	 gc,
+	 native_marker_path, marker_trans.to_values(),
+	 path.vertices, path.codes, trans.to_values(),
+	 rgbFace)
 
 def draw_polygon(self, *args):
 	return self._renderer.draw_polygon(*args)
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -520,7 +520,7 @@
 lineFunc(renderer, gc, self._path)
 	 
 	# MGDTODO: Deal with markers
- if self._marker is not None and False:
+ if self._marker is not None:
 gc = renderer.new_gc()
 self._set_gc_clip(gc)
 gc.set_foreground(self.get_markeredgecolor())
@@ -713,6 +713,9 @@
 pass
 
 def _draw_steps(self, renderer, gc, xt, yt):
+	# MGDTODO: This is a quirky one. The step-plotting part
+	# should probably be moved to where the path is generated
+	# in recache, and then just drawn with _draw_solid
 siz=len(xt)
 if siz<2: return
 xt2=npy.ones((2*siz,), xt.dtype)
@@ -727,323 +730,132 @@
 renderer.draw_lines(gc, xt2, yt2)
 
 def _draw_solid(self, renderer, gc, path):
- # if len(xt)<2: return
 gc.set_linestyle('solid')
 	renderer.draw_path(gc, path, self.get_transform())
 
 
- def _draw_dashed(self, renderer, gc, xt, yt):
- if len(xt)<2: return
+ def _draw_dashed(self, renderer, gc, path):
 gc.set_linestyle('dashed')
 if self._dashSeq is not None:
 gc.set_dashes(0, self._dashSeq)
 
- if self._newstyle:
- renderer.draw_lines(gc, xt, yt, self.get_transform())
- else:
- renderer.draw_lines(gc, xt, yt)
+	renderer.draw_path(gc, path, self.get_transform())
 
 
- def _draw_dash_dot(self, renderer, gc, xt, yt):
- if len(xt)<2: return
+ def _draw_dash_dot(self, renderer, gc, path):
 gc.set_linestyle('dashdot')
- if self._newstyle:
- renderer.draw_lines(gc, xt, yt, self.get_transform())
- else:
- renderer.draw_lines(gc, xt, yt)
+	renderer.draw_path(gc, path, self.get_transform())
 
- def _draw_dotted(self, renderer, gc, xt, yt):
-
- if len(xt)<2: return
+	 
+ def _draw_dotted(self, renderer, gc, path):
 gc.set_linestyle('dotted')
- if self._newstyle:
- renderer.draw_lines(gc, xt, yt, self.get_transform())
- else:
- renderer.draw_lines(gc, xt, yt)
+	renderer.draw_path(gc, path, self.get_transform())
 
- def _draw_point(self, renderer, gc, xt, yt):
+	
+ def _draw_point(self, renderer, gc, path):
+	self._draw_circle(renderer, gc, path, point = True)
 
- r = 0.5 * renderer.points_to_pixels(self._markersize)
- r *= self._point_size_reduction
- gc.set_linewidth(0)
- if r <= 0.5:
- self._draw_pixel(renderer, gc, xt, yt)
- elif r <= 2:
- self._draw_hexagon1(renderer, gc, xt, yt, point=True)
- else:
- self._draw_circle(renderer, gc, xt, yt, point=True)
-
- def _draw_pixel(self, renderer, gc, xt, yt):
- if self._newstyle:
- rgbFace = self._get_rgb_face()
- path = agg.path_storage()
- path.move_to(-0.5, -0.5)
- path.line_to(-0.5, 0.5)
- path.line_to(0.5, 0.5)
- path.line_to(0.5, -0.5)
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_point(gc, x, y)
-
-
- def _draw_circle(self, renderer, gc, xt, yt, point=False):
-
+ def _draw_pixel(self, renderer, gc, path):
+	rgbFace = self._get_rgb_face()
+	transform = Affine2D().translate(-0.5, -0.5)
+	renderer.draw_markers(gc, Path.unit_rectangle, transform,
+			 path, self.get_transform(), rgbFace)
+	
+	
+ def _draw_circle(self, renderer, gc, path, point=False):
 w = renderer.points_to_pixels(self._markersize)
 if point:
 w *= self._point_size_reduction
+	w *= 0.5
 
-
 rgbFace = self._get_rgb_face()
+	transform = Affine2D().scale(w, w)
+	renderer.draw_markers(
+	 gc, Path.unit_circle(), transform, path, self.get_transform(),
+	 rgbFace)
 
- if self._newstyle:
- N = 50.0
- r = w/2.
- rads = (2*math.pi/N)*npy.arange(N)
- xs = r*npy.cos(rads)
- ys = r*npy.sin(rads)
- # todo: use curve3!
- path = agg.path_storage()
- path.move_to(xs[0], ys[0])
- for x, y in zip(xs[1:], ys[1:]):
- path.line_to(x, y)
 
- path.end_poly()
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt,yt):
- renderer.draw_arc(gc, rgbFace,
- x, y, w, w, 0.0, 360.0, 0.0)
-
-
-
- def _draw_triangle_up(self, renderer, gc, xt, yt):
-
-
+ _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0]])
+ def _draw_triangle_up(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset, offset)
 rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, self._triangle_path, transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, offset)
- path.line_to(-offset, -offset)
- path.line_to(offset, -offset)
- path.end_poly()
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x, y+offset),
- (x-offset, y-offset),
- (x+offset, y-offset) )
- renderer.draw_polygon(gc, rgbFace, verts)
 
-
- def _draw_triangle_down(self, renderer, gc, xt, yt):
+ def _draw_triangle_down(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset, -offset)
 rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, self._triangle_path, transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
-
- path = agg.path_storage()
- path.move_to(-offset, offset)
- path.line_to(offset, offset)
- path.line_to(0, -offset)
- path.end_poly()
-
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x-offset, y+offset),
- (x+offset, y+offset),
- (x, y-offset))
- renderer.draw_polygon(gc, rgbFace, verts)
-
- def _draw_triangle_left(self, renderer, gc, xt, yt):
+	
+ def _draw_triangle_left(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset, offset).rotate_deg(90)
 rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, self._triangle_path, transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
 
- path = agg.path_storage()
- path.move_to(-offset, 0)
- path.line_to(offset, -offset)
- path.line_to(offset, offset)
- path.end_poly()
-
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x-offset, y),
- (x+offset, y-offset),
- (x+offset, y+offset))
- renderer.draw_polygon(gc, rgbFace, verts)
-
-
- def _draw_triangle_right(self, renderer, gc, xt, yt):
+ def _draw_triangle_right(self, renderer, gc, path):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset, offset).rotate_deg(-90)
 rgbFace = self._get_rgb_face()
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(offset, 0)
- path.line_to(-offset, -offset)
- path.line_to(-offset, offset)
- path.end_poly()
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x+offset, y),
- (x-offset, y-offset),
- (x-offset, y+offset))
- renderer.draw_polygon(gc, rgbFace, verts)
+	renderer.draw_markers(gc, self._triangle_path, transform,
+			 path, self.get_transform(), rgbFace)
 
 
-
- def _draw_square(self, renderer, gc, xt, yt):
+ def _draw_square(self, renderer, gc, path):
 side = renderer.points_to_pixels(self._markersize)
- offset = side*0.5
+	transform = Affine2D().translate(-0.5, -0.5).scale(side)
 rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
-
- path = agg.path_storage()
- path.move_to(-offset, -offset)
- path.line_to(-offset, offset)
- path.line_to(offset, offset)
- path.line_to(offset, -offset)
- path.end_poly()
-
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
-
- for (x,y) in zip(xt, yt):
- renderer.draw_rectangle(
- gc, rgbFace,
- x-offset, y-offset, side, side)
-
- def _draw_diamond(self, renderer, gc, xt, yt):
- offset = 0.6*renderer.points_to_pixels(self._markersize)
+	
+ def _draw_diamond(self, renderer, gc, path):
+ side = renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(side)
 rgbFace = self._get_rgb_face()
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(offset, 0)
- path.line_to(0, -offset)
- path.line_to(-offset, 0)
- path.line_to(0, offset)
- path.end_poly()
+	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
+			 path, self.get_transform(), rgbFace)
 
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
-
-
- for (x,y) in zip(xt, yt):
- verts = ( (x+offset, y),
- (x, y-offset),
- (x-offset, y),
- (x, y+offset))
- renderer.draw_polygon(gc, rgbFace, verts)
-
- def _draw_thin_diamond(self, renderer, gc, xt, yt):
- offset = 0.7*renderer.points_to_pixels(self._markersize)
- xoffset = 0.6*offset
+	
+ def _draw_thin_diamond(self, renderer, gc, path):
+ offset = renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(offset * 0.8, offset)
 rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, Path.unit_rectangle(), transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(xoffset, 0)
- path.line_to(0, -offset)
- path.line_to(-xoffset, 0)
- path.line_to(0, offset)
- path.end_poly()
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x+xoffset, y),
- (x, y-offset),
- (x-xoffset, y),
- (x, y+offset))
- renderer.draw_polygon(gc, rgbFace, verts)
+	
+ def _draw_pentagon(self, renderer, gc, path):
+ offset = 0.5 * renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset)
+	rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform,
+			 path, self.get_transform(), rgbFace)
 
- def _draw_pentagon(self, renderer, gc, xt, yt):
- offset = 0.6*renderer.points_to_pixels(self._markersize)
- offsetX1 = offset*0.95
- offsetY1 = offset*0.31
- offsetX2 = offset*0.59
- offsetY2 = offset*0.81
- rgbFace = self._get_rgb_face()
+	
+ def _draw_hexagon1(self, renderer, gc, path, point=False):
+ offset = 0.5 * renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset)
+	rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
+			 path, self.get_transform(), rgbFace)
 
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, offset)
- path.line_to(-offsetX1, offsetY1)
- path.line_to(-offsetX2, -offsetY2)
- path.line_to(+offsetX2, -offsetY2)
- path.line_to(+offsetX1, offsetY1)
- path.end_poly()
-
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x, y+offset),
- (x-offsetX1, y+offsetY1),
- (x-offsetX2, y-offsetY2),
- (x+offsetX2, y-offsetY2),
- (x+offsetX1, y+offsetY1))
- renderer.draw_polygon(gc, rgbFace, verts)
-
- def _draw_hexagon1(self, renderer, gc, xt, yt, point=False):
- offset = 0.6*renderer.points_to_pixels(self._markersize)
- if point:
- offset *= self._point_size_reduction
- offsetX1 = offset*0.87
- offsetY1 = offset*0.5
- rgbFace = self._get_rgb_face()
-
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, offset)
- path.line_to(-offsetX1, offsetY1)
- path.line_to(-offsetX1, -offsetY1)
- path.line_to(0, -offset)
- path.line_to(offsetX1, -offsetY1)
- path.line_to(offsetX1, offsetY1)
- path.end_poly()
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x, y+offset),
- (x-offsetX1, y+offsetY1),
- (x-offsetX1, y-offsetY1),
- (x, y-offset),
- (x+offsetX1, y-offsetY1),
- (x+offsetX1, y+offsetY1))
- renderer.draw_polygon(gc, rgbFace, verts)
-
+	
 def _draw_hexagon2(self, renderer, gc, xt, yt):
- offset = 0.6*renderer.points_to_pixels(self._markersize)
- offsetX1 = offset*0.5
- offsetY1 = offset*0.87
- rgbFace = self._get_rgb_face()
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(offset, 0)
- path.line_to(offsetX1, offsetY1)
- path.line_to(-offsetX1, offsetY1)
- path.line_to(-offset, 0)
- path.line_to(-offsetX1, -offsetY1)
- path.line_to(offsetX1, -offsetY1)
- path.end_poly()
+ offset = 0.5 * renderer.points_to_pixels(self._markersize)
+	transform = Affine2D().scale(offset).rotate_deg(30)
+	rgbFace = self._get_rgb_face()
+	renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform,
+			 path, self.get_transform(), rgbFace)
 
- renderer.draw_markers(gc, path, rgbFace, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- verts = ( (x+offset, y),
- (x+offsetX1, y+offsetY1),
- (x-offsetX1, y+offsetY1),
- (x-offset, y),
- (x-offsetX1, y-offsetY1),
- (x+offsetX1, y-offsetY1))
- renderer.draw_polygon(gc, rgbFace, verts)
-
+	
 def _draw_vline(self, renderer, gc, xt, yt):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 if self._newstyle:
@@ -1055,6 +867,7 @@
 for (x,y) in zip(xt, yt):
 renderer.draw_line(gc, x, y-offset, x, y+offset)
 
+		
 def _draw_hline(self, renderer, gc, xt, yt):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
 if self._newstyle:
@@ -1066,46 +879,31 @@
 for (x,y) in zip(xt, yt):
 renderer.draw_line(gc, x-offset, y, x+offset, y)
 
- def _draw_tickleft(self, renderer, gc, xt, yt):
+ _tickhoriz_path = Path([[0.0, 0.5], [1.0, 0.5]])
+ def _draw_tickleft(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-offset, 0.5)
- path.line_to(0, 0.5)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x-offset, y, x, y)
+	marker_transform = Affine2D().scale(offset, 1.0)
+	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
+			 path, self.get_transform())
 
- def _draw_tickright(self, renderer, gc, xt, yt):
-
+ def _draw_tickright(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(0, 0.5)
- path.line_to(offset, 0.5)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x+offset, y)
+	marker_transform = Affine2D().scale(-offset, 1.0)
+	renderer.draw_markers(gc, self._tickhoriz_path, marker_transform,
+			 path, self.get_transform())
 
- _tickup_path = Path([[-0.5, 0.0], [-0.5, 1.0]])
- def _draw_tickup(self, renderer, gc, xt, yt):
+ _tickvert_path = Path([[-0.5, 0.0], [-0.5, 1.0]])
+ def _draw_tickup(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
 	marker_transform = Affine2D().scale(1.0, offset)
-	renderer.draw_markers(gc, self._tickup_path, marker_transform,
-			 self._path, self.get_transform())
+	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
+			 path, self.get_transform())
 
- def _draw_tickdown(self, renderer, gc, xt, yt):
+ def _draw_tickdown(self, renderer, gc, path):
 offset = renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-0.5, -offset)
- path.line_to(-0.5, 0)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y-offset, x, y)
+	marker_transform = Affine2D().scale(1.0, -offset)
+	renderer.draw_markers(gc, self._tickvert_path, marker_transform,
+			 path, self.get_transform())
 
 def _draw_plus(self, renderer, gc, xt, yt):
 offset = 0.5*renderer.points_to_pixels(self._markersize)
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -288,7 +288,6 @@
 self._update()
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
-
 def _update(self):
 self.update_from(self.patch)
 if self.props is not None:
@@ -316,8 +315,7 @@
 
 """
 
- _path = Path(
-	[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]])
+ _path = Path.unit_rectangle()
 
 def __str__(self):
 return str(self.__class__).split('.')[-1] \
@@ -424,8 +422,6 @@
 """
 A regular polygon patch.
 """
- _polygon_cache = {}
- 
 def __str__(self):
 return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1])
 
@@ -442,14 +438,7 @@
 """
 Patch.__init__(self, **kwargs)
 
-	path = self._polygon_cache[numVertices]
-	if path is None:
-	 theta = 2*npy.pi/numVertices * npy.arange(numVertices)
-	 verts = npy.hstack((npy.cos(theta), npy.sin(theta)))
-	 path = Path(verts)
-	 self._polygon_cache[numVertices] = path
-
-	self._path = path
+	self._path = Path.unit_regular_polygon(numVertices)
 	self._poly_transform = transforms.Affine2D() \
 	 .scale(radius) \
 	 .rotate(orientation) \
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -1,21 +1,25 @@
 import numpy as npy
 
-class Path:
+VALIDATE_PATHS = True
+
+class Path(object):
 # Path codes
 STOP = 0
 MOVETO = 1 # 1 vertex
 LINETO = 2 # 1 vertex
 CURVE3 = 3 # 2 vertices
 CURVE4 = 4 # 3 vertices
+ CLOSEPOLY = 5
 ###
 # MGDTODO: I'm not sure these are supported by PS/PDF/SVG,
 # so if they don't, we probably shouldn't
- CURVEN = 5
- CATROM = 6
- UBSPLINE = 7
+ CURVEN = 6
+ CATROM = 7
+ UBSPLINE = 8
 ####
- CLOSEPOLY = 0x0F # 0 vertices
 
+ NUM_VERTICES = [0, 1, 1, 2, 3, 0]
+ 
 code_type = npy.uint8
 
 def __init__(self, vertices, codes=None, closed=True):
@@ -38,9 +42,14 @@
 	self._codes = codes
 	 
 	assert self._codes.ndim == 1
-	# MGDTODO: Maybe we should add some quick-and-dirty check that
-	# the number of vertices is correct for the code array
 
+	if VALIDATE_PATHS:
+	 i = 0
+	 NUM_VERTICES = self.NUM_VERTICES
+	 for code in codes:
+		i += NUM_VERTICES[code]
+	 assert i == len(self.vertices)
+
 def _get_codes(self):
 	return self._codes
 codes = property(_get_codes)
@@ -48,3 +57,74 @@
 def _get_vertices(self):
 	return self._vertices
 vertices = property(_get_vertices)
+
+ def iter_endpoints(self):
+	i = 0
+	NUM_VERTICES = self.NUM_VERTICES
+	vertices = self.vertices
+	for code in self.codes:
+	 num_vertices = NUM_VERTICES[code]
+	 if num_vertices >= 1:
+		i += num_vertices - 1
+		yield vertices[i]
+		i += 1
+
+ _unit_rectangle = None
+ #@classmethod
+ def unit_rectangle(cls):
+	if cls._unit_rectangle is None:
+	 cls._unit_rectangle = \
+		Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]])
+	return cls._unit_rectangle
+ unit_rectangle = classmethod(unit_rectangle)
+
+ _unit_regular_polygons = {}
+ #@classmethod
+ def unit_regular_polygon(cls, numVertices):
+	path = cls._unit_regular_polygons.get(numVertices)
+	if path is None:
+	 theta = 2*npy.pi/numVertices * npy.arange(numVertices)
+	 # This is to make sure the polygon always "points-up"
+	 theta += npy.pi / 2.0
+	 verts = npy.vstack((npy.cos(theta), npy.sin(theta))).transpose()
+	 path = Path(verts)
+	 cls._unit_regular_polygons[numVertices] = path
+	return path
+ unit_regular_polygon = classmethod(unit_regular_polygon)
+
+ _unit_circle = None
+ #@classmethod
+ def unit_circle(cls):
+	# MGDTODO: Optimize?
+	if cls._unit_circle is None:
+	 offset = 4.0 * (npy.sqrt(2) - 1) / 3.0
+	 vertices = npy.array(
+		[[-1.0, 0.0],
+		 
+		 [-1.0, offset],
+		 [-offset, 1.0],
+		 [0.0, 1.0],
+		 
+		 [offset, 1.0],
+		 [1.0, offset],
+		 [1.0, 0.0],
+		 
+		 [1.0, -offset],
+		 [offset, -1.0],
+		 [0.0, -1.0],
+		 
+		 [-offset, -1.0],
+		 [-1.0, -offset],
+		 [-1.0, 0.0]],
+		npy.float_)
+	 codes = npy.array(
+		[cls.MOVETO,
+		 cls.CURVE4,
+		 cls.CURVE4,
+		 cls.CURVE4,
+		 cls.CURVE4,
+		 cls.CLOSEPOLY],
+		cls.code_type)
+	 cls._unit_circle = Path(vertices, codes)
+	return cls._unit_circle
+ unit_circle = classmethod(unit_circle)
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -64,6 +64,20 @@
 Py::Float(seq[5]));
 }
 
+// MGDTODO: Implement this as a nice iterator
+inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, 
+			 double& x, double& y,
+			 size_t next_vertex_stride, 
+			 size_t next_axis_stride) {
+ if (vertex_i + next_axis_stride >= vertex_end)
+ throw Py::ValueError("Error parsing path. Read past end of vertices");
+ x = *(double*)vertex_i;
+ y = *(double*)(vertex_i + next_axis_stride);
+ vertex_i += next_vertex_stride;
+}
+
+#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
+
 GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) :
 dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0),
 cliprect(NULL), clippath(NULL), 
@@ -1255,146 +1269,134 @@
 
 Py::Object
 RendererAgg::draw_markers(const Py::Tuple& args) {
+ typedef agg::conv_transform<agg::path_storage> transformed_path_t;
+ typedef agg::conv_curve<transformed_path_t> curve_t;
+ typedef agg::conv_stroke<curve_t> stroke_t;
+ typedef agg::conv_dash<curve_t> dash_t;
+ typedef agg::conv_stroke<dash_t> stroke_dash_t;
+
 theRasterizer->reset_clipping();
 
- _VERBOSE("RendererAgg::_draw_markers_cache");
- args.verify_length(6);
+ args.verify_length(7);
 
- _VERBOSE("RendererAgg::_draw_markers_cache setting gc");
 GCAgg gc = GCAgg(args[0], dpi);
+ Py::Object marker_path_obj = args[1];
+ if (!PathAgg::check(marker_path_obj))
+ throw Py::TypeError("Native path object is not of correct type");
+ PathAgg* marker_path = static_cast<PathAgg*>(marker_path_obj.ptr());
+ agg::trans_affine marker_trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ Py::Object vertices_obj = args[3];
+ Py::Object codes_obj = args[4];
+ agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[5]);
+ facepair_t face = _get_rgba_face(args[6], gc.alpha);
+
+ // Deal with the difference in y-axis direction
+ marker_trans *= agg::trans_affine_scaling(1.0, -1.0);
+ trans *= agg::trans_affine_scaling(1.0, -1.0);
+ trans *= agg::trans_affine_translation(0.0, (double)height);
 
+ marker_path->rewind(0);
+ transformed_path_t marker_path_transformed(*marker_path, marker_trans);
+ curve_t marker_path_curve(marker_path_transformed);
 
- agg::path_storage *ppath;
- 
- swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *");
- assert(descr);
- if (SWIG_ConvertPtr(args[1].ptr(),(void **)(&ppath), descr, 0) == -1) {
- throw Py::TypeError("Could not convert path_storage");
- }
- facepair_t face = _get_rgba_face(args[2], gc.alpha);
- 
- Py::Object xo = args[3];
- Py::Object yo = args[4];
- 
- PyArrayObject *xa = (PyArrayObject *) PyArray_ContiguousFromObject(xo.ptr(), PyArray_DOUBLE, 1, 1);
- 
- if (xa==NULL)
- throw Py::TypeError("RendererAgg::_draw_markers_cache expected numerix array");
- 
- 
- PyArrayObject *ya = (PyArrayObject *) PyArray_ContiguousFromObject(yo.ptr(), PyArray_DOUBLE, 1, 1);
- 
- if (ya==NULL)
- throw Py::TypeError("RendererAgg::_draw_markers_cache expected numerix array");
- 
- agg::trans_affine xytrans = py_sequence_to_agg_transformation_matrix(args[5]);
- 
- size_t Nx = xa->dimensions[0];
- size_t Ny = ya->dimensions[0];
- 
- if (Nx!=Ny)
- throw Py::ValueError(Printf("x and y must be equal length arrays; found %d and %d", Nx, Ny).str());
- 
- 
- double heightd = double(height);
- 
- 
- ppath->rewind(0);
- ppath->flip_y(0,0);
- typedef agg::conv_curve<agg::path_storage> curve_t;
- curve_t curve(*ppath);
- 
 //maxim's suggestions for cached scanlines
 agg::scanline_storage_aa8 scanlines;
 theRasterizer->reset();
 
 agg::int8u* fillCache = NULL;
- unsigned fillSize = 0;
- if (face.first) {
- theRasterizer->add_path(curve);
+ agg::int8u* strokeCache = NULL;
+ PyArrayObject* vertices = NULL;
+ PyArrayObject* codes = NULL;
+
+ try {
+ vertices = (PyArrayObject*)PyArray_ContiguousFromObject
+ (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2);
+ if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2)
+ throw Py::ValueError("Invalid vertices array.");
+ codes = (PyArrayObject*)PyArray_ContiguousFromObject
+ (codes_obj.ptr(), PyArray_UINT8, 1, 1);
+ if (!codes) 
+ throw Py::ValueError("Invalid codes array.");
+
+ unsigned fillSize = 0;
+ if (face.first) {
+ theRasterizer->add_path(marker_path_curve);
+ agg::render_scanlines(*theRasterizer, *slineP8, scanlines);
+ fillSize = scanlines.byte_size();
+ fillCache = new agg::int8u[fillSize]; // or any container
+ scanlines.serialize(fillCache);
+ }
+ 
+ stroke_t stroke(marker_path_curve);
+ stroke.width(gc.linewidth);
+ stroke.line_cap(gc.cap);
+ stroke.line_join(gc.join);
+ theRasterizer->reset();
+ theRasterizer->add_path(stroke);
 agg::render_scanlines(*theRasterizer, *slineP8, scanlines);
- fillSize = scanlines.byte_size();
- fillCache = new agg::int8u[fillSize]; // or any container
- scanlines.serialize(fillCache);
- }
+ unsigned strokeSize = scanlines.byte_size();
+ strokeCache = new agg::int8u[strokeSize]; // or any container
+ scanlines.serialize(strokeCache);
 
- agg::conv_stroke<curve_t> stroke(curve);
- stroke.width(gc.linewidth);
- stroke.line_cap(gc.cap);
- stroke.line_join(gc.join);
- theRasterizer->reset();
- theRasterizer->add_path(stroke);
- agg::render_scanlines(*theRasterizer, *slineP8, scanlines);
- unsigned strokeSize = scanlines.byte_size();
- agg::int8u* strokeCache = new agg::int8u[strokeSize]; // or any container
- scanlines.serialize(strokeCache);
- 
- theRasterizer->reset_clipping();
- 
- 
- if (gc.cliprect==NULL) {
- rendererBase->reset_clipping(true);
- }
- else {
- int l = (int)(gc.cliprect[0]) ;
- int b = (int)(gc.cliprect[1]) ;
- int w = (int)(gc.cliprect[2]) ;
- int h = (int)(gc.cliprect[3]) ;
- rendererBase->clip_box(l, height-(b+h),l+w, height-b);
- }
- 
- 
- double thisx, thisy;
- for (size_t i=0; i<Nx; i++) {
- thisx = *(double *)(xa->data + i*xa->strides[0]);
- thisy = *(double *)(ya->data + i*ya->strides[0]);
-
- // MGDTODO
-// if (mpltransform->need_nonlinear_api())
-// try {
-// 	mpltransform->nonlinear_only_api(&thisx, &thisy);
-// }
-// catch(...) {
-// 	continue;
-// }
+ theRasterizer->reset_clipping();
+ if (gc.cliprect==NULL) {
+ rendererBase->reset_clipping(true);
+ }
+ else {
+ int l = (int)(gc.cliprect[0]) ;
+ int b = (int)(gc.cliprect[1]) ;
+ int w = (int)(gc.cliprect[2]) ;
+ int h = (int)(gc.cliprect[3]) ;
+ rendererBase->clip_box(l, height-(b+h),l+w, height-b);
+ }
 
- xytrans.transform(&thisx, &thisy);
- 
- thisy = heightd - thisy; //flipy
- 
- thisx = (int)thisx + 0.5;
- thisy = (int)thisy + 0.5;
- if (thisx<0) continue;
- if (thisy<0) continue;
- if (thisx>width) continue;
- if (thisy>height) continue;
- 
+ size_t next_vertex_stride = vertices->strides[0];
+ size_t next_axis_stride = vertices->strides[1];
+ size_t code_stride = codes->strides[0];
+
+ const char* vertex_i = vertices->data;
+ const char* code_i = codes->data;
+ const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]);
+
+ size_t N = codes->dimensions[0];
+ double x, y;
+
 agg::serialized_scanlines_adaptor_aa8 sa;
 agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl;
- 
- if (face.first) {
- //render the fill
- sa.init(fillCache, fillSize, thisx, thisy);
- rendererAA->color(face.second);
- agg::render_scanlines(sa, sl, *rendererAA);
+
+ for (size_t i=0; i < N; i++) {
+ size_t num_vertices = NUM_VERTICES[(int)(*code_i)];
+ if (num_vertices) {
+	for (size_t j=0; j<num_vertices; ++j)
+	 GET_NEXT_VERTEX(x, y);
+	trans.transform(&x, &y);
+	
+	if (face.first) {
+	 //render the fill
+	 sa.init(fillCache, fillSize, x, y);
+	 rendererAA->color(face.second);
+	 agg::render_scanlines(sa, sl, *rendererAA);
+	}
+
+	//render the stroke
+	sa.init(strokeCache, strokeSize, x, y);
+	rendererAA->color(gc.color);
+	agg::render_scanlines(sa, sl, *rendererAA);
+ }
+ code_i += code_stride;
 }
- 
- //render the stroke
- sa.init(strokeCache, strokeSize, thisx, thisy);
- rendererAA->color(gc.color);
- agg::render_scanlines(sa, sl, *rendererAA);
- 
- } //for each marker
+ } catch(...) {
+ Py_XDECREF(vertices);
+ Py_XDECREF(codes);
+ delete[] fillCache;
+ delete[] strokeCache;
+ }
 
- Py_XDECREF(xa);
- Py_XDECREF(ya);
- 
- if (face.first)
- delete [] fillCache;
+ Py_XDECREF(vertices);
+ Py_XDECREF(codes);
+ delete [] fillCache;
 delete [] strokeCache;
 
- //jdh
- _VERBOSE("RendererAgg::_draw_markers_cache done");
 return Py::Object();
 
 }
@@ -1552,21 +1554,6 @@
 
 }
 
-inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, 
-			 double& x, double& y,
-			 size_t next_vertex_stride, 
-			 size_t next_axis_stride) {
- if (vertex_i + next_axis_stride >= vertex_end)
- throw Py::ValueError("Error parsing path. Read past end of vertices");
- x = *(double*)vertex_i;
- y = *(double*)(vertex_i + next_axis_stride);
- vertex_i += next_vertex_stride;
-}
-
-#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
-
-
-
 Py::Object
 RendererAgg::convert_to_native_path(const Py::Tuple& args) {
 _VERBOSE("RendererAgg::draw_image");
@@ -2059,7 +2046,7 @@
 add_varargs_method("draw_lines", &RendererAgg::draw_lines,
 		 "draw_lines(gc, x, y,)\n");
 add_varargs_method("draw_markers", &RendererAgg::draw_markers,
-		 "draw_markers(gc, path, x, y)\n");
+		 "draw_markers(gc, marker_path, marker_trans, vertices, codes, rgbFace)\n");
 add_varargs_method("draw_text_image", &RendererAgg::draw_text_image,
 		 "draw_text_image(font_image, x, y, r, g, b, a)\n");
 add_varargs_method("draw_image", &RendererAgg::draw_image,
Modified: branches/transforms/src/_backend_agg.h
===================================================================
--- branches/transforms/src/_backend_agg.h	2007年09月15日 04:01:56 UTC (rev 3853)
+++ branches/transforms/src/_backend_agg.h	2007年09月17日 13:41:38 UTC (rev 3854)
@@ -45,8 +45,10 @@
 #define LINETO 2
 #define CURVE3 3
 #define CURVE4 4
-#define CLOSEPOLY 0x0F
+#define CLOSEPOLY 5
 
+const size_t NUM_VERTICES[] = { 0, 1, 1, 2, 3, 0 };
+
 typedef agg::pixfmt_rgba32 pixfmt;
 typedef agg::renderer_base<pixfmt> renderer_base;
 typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jo...@us...> - 2007年09月15日 04:01:58
Revision: 3853
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3853&view=rev
Author: jouni
Date: 2007年09月14日 21:01:56 -0700 (2007年9月14日)
Log Message:
-----------
Bugfix and doc fixes in type1font.py
Modified Paths:
--------------
 trunk/matplotlib/lib/matplotlib/type1font.py
Modified: trunk/matplotlib/lib/matplotlib/type1font.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/type1font.py	2007年09月14日 17:57:52 UTC (rev 3852)
+++ trunk/matplotlib/lib/matplotlib/type1font.py	2007年09月15日 04:01:56 UTC (rev 3853)
@@ -1,15 +1,15 @@
 """
 A class representing a Type 1 font.
 
-This version merely allows reading in pfa and pfb files, stores the
-data in pfa format, and allows reading the parts of the data in a
-format suitable for embedding in pdf files. A more complete class
-might support subsetting.
+This version merely reads pfa and pfb files and splits them for
+embedding in pdf files. There is no support yet for subsetting or
+anything like that.
 
-Usage: font = Type1Font(filename)
- somefile.write(font.data) # writes out font in pfa format
- len1, len2, len3 = font.lengths() # needed for pdf embedding
+Usage (subject to change):
 
+ font = Type1Font(filename)
+ clear_part, encrypted_part, finale = font.parts
+
 Source: Adobe Technical Note #5040, Supporting Downloadable PostScript
 Language Fonts.
 
@@ -32,8 +32,7 @@
 def _read(self, file):
 rawdata = file.read()
 if not rawdata.startswith(chr(128)):
- self.data = rawdata
- return
+ return rawdata
 
 data = ''
 while len(rawdata) > 0:
@@ -101,4 +100,6 @@
 if __name__ == '__main__':
 import sys
 font = Type1Font(sys.argv[1])
- sys.stdout.write(font.data)
+ parts = font.parts
+ print len(parts[0]), len(parts[1]), len(parts[2])
+
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月14日 18:01:00
Revision: 3852
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3852&view=rev
Author: mdboom
Date: 2007年09月14日 10:57:52 -0700 (2007年9月14日)
Log Message:
-----------
Sends paths to backend only once, and after that uses the "native" path by
reference with a changing transform. Started recongfiguring
patches.py to use only Paths under the hood (to take advantage of this
caching). Removed many methods from backend_agg that should
eventually be replaced by draw_path, at least in theory.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/transforms.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
Added Paths:
-----------
 branches/transforms/lib/matplotlib/path.py
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -4,7 +4,7 @@
 """
 
 from __future__ import division
-import os, sys, warnings, copy
+import os, sys, warnings, copy, weakref
 
 import numpy as npy
 import matplotlib.numerix.npyma as ma
@@ -17,7 +17,10 @@
 class RendererBase:
 """An abstract base class to handle drawing/rendering operations
 """
-
+ # This will cache paths across rendering instances
+ # Each subclass of RenderBase should define this -->
+ # _paths = weakref.WeakKeyDictionary()
+ 
 def __init__(self):
 self._texmanager = None
 
@@ -33,7 +36,35 @@
 """
 pass
 
+ def draw_path(self, gc, path, transform, rgbFace = None):
+	"""
+	Handles the caching of the native path associated with the
+	given path and calls the underlying backend's _draw_path to
+	actually do the drawing.
+	"""
+	native_path = self._native_paths.get(path)
+	if native_path is None:
+	 import matplotlib.patches
+	 print "CACHE MISS", path
+	 native_path = self.convert_to_native_path(path)
+	 self._native_paths[path] = native_path
+	self._draw_path(gc, native_path, transform, rgbFace)
 
+ def _draw_path(self, gc, native_path, transform, rgbFace):
+	"""
+	Draw the native path object with the given GraphicsContext and
+	transform. The transform passed in will always be affine.
+	"""
+	raise NotImplementedError
+	
+ def convert_to_native_path(self, path):
+	"""
+	Backends will normally will override this, but if they don't need any
+	special optimizations, they can just have the generic path data
+	passed to them in draw_path.
+	"""
+	return path
+	
 def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
 rotation):
 """
@@ -75,6 +106,9 @@
 """
 return False
 
+ def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
+	pass
+ 
 def _draw_markers(self, bgc, path, rgbFace, x, y, trans):
 """
 This method is currently underscore hidden because the
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -69,7 +69,7 @@
 
 """
 from __future__ import division
-import os, sys
+import os, sys, weakref
 
 import numpy as npy
 
@@ -95,7 +95,15 @@
 The renderer handles all the drawing primitives using a graphics
 context instance that controls the colors/styles
 """
-
+ # MGDTODO: Renderers seem to get created and destroyed fairly
+ # often so the paths are cached at the class (not instance) level.
+ # However, this dictionary is only directly used by RendererBase,
+ # so it seems funny to define it here. However, if we didn't, the
+ # native paths would be shared across renderers, which is
+ # obviously bad. Seems like a good use of metaclasses, but that
+ # also seems like a heavy solution for a minor problem.
+ _native_paths = weakref.WeakKeyDictionary()
+ 
 debug=1
 texd = {} # a cache of tex image rasters
 def __init__(self, width, height, dpi):
@@ -129,6 +137,12 @@
 if __debug__: verbose.report('RendererAgg.__init__ done',
 'debug-annoying')
 
+ def convert_to_native_path(self, path):
+	return self._renderer.convert_to_native_path(path.vertices, path.codes)
+
+ def _draw_path(self, gc, native_path, transform, rgbFace):
+	return self._renderer.draw_path(gc, native_path, transform.to_values(), rgbFace)
+	
 def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation):
 """
 Draw an arc centered at x,y with width and height and angles
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -10,14 +10,14 @@
 
 import numpy as npy
 
-import agg
 import numerix.ma as ma
 from matplotlib import verbose
 import artist
 from artist import Artist, setp
 from cbook import iterable, is_string_like, is_numlike
 from colors import colorConverter
-from transforms import Bbox
+from path import Path
+from transforms import Affine2D, Bbox
 
 from matplotlib import rcParams
 
@@ -284,9 +284,6 @@
 self.set_data(xdata, ydata)
 self._logcache = None
 
- # TODO: do we really need 'newstyle'
- self._newstyle = False
-
 def contains(self, mouseevent):
 """Test whether the mouse event occurred on the line. The pick radius determines
 the precision of the location test (usually within five points of the value). Use
@@ -427,6 +424,7 @@
 if len(x) != len(y):
 raise RuntimeError('xdata and ydata must be the same length')
 
+	# MGDTODO: Deal with segments
 mx = ma.getmask(x)
 my = ma.getmask(y)
 mask = ma.mask_or(mx, my)
@@ -439,7 +437,9 @@
 
 self._x = npy.asarray(x, float)
 self._y = npy.asarray(y, float)
-
+	self._path = Path(npy.vstack((self._x, self._y)).transpose(),
+			 closed=False)
+	
 self._logcache = None
 
 
@@ -508,30 +508,19 @@
 gc.set_joinstyle(join)
 gc.set_capstyle(cap)
 
- if self._newstyle:
- # transform in backend
- xt = self._x
- yt = self._y
- else:
- x, y = self._get_plottable()
- if len(x)==0: return
- xt, yt = self.get_transform().numerix_x_y(x, y)
-
-
-
 funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
 lineFunc = getattr(self, funcname)
 
+	# MGDTODO: Deal with self._segments
 if self._segments is not None:
 for ii in self._segments:
 lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]])
 
 else:
- lineFunc(renderer, gc, xt, yt)
-
-
- if self._marker is not None:
-
+ lineFunc(renderer, gc, self._path)
+	 
+	# MGDTODO: Deal with markers
+ if self._marker is not None and False:
 gc = renderer.new_gc()
 self._set_gc_clip(gc)
 gc.set_foreground(self.get_markeredgecolor())
@@ -539,7 +528,7 @@
 gc.set_alpha(self._alpha)
 funcname = self._markers.get(self._marker, '_draw_nothing')
 markerFunc = getattr(self, funcname)
- markerFunc(renderer, gc, xt, yt)
+ markerFunc(renderer, gc, self._path)
 
 #renderer.close_group('line2d')
 
@@ -720,7 +709,7 @@
 self.set_linestyle('--')
 self._dashSeq = seq # TODO: offset ignored for now
 
- def _draw_nothing(self, renderer, gc, xt, yt):
+ def _draw_nothing(self, renderer, gc, path):
 pass
 
 def _draw_steps(self, renderer, gc, xt, yt):
@@ -737,13 +726,10 @@
 else:
 renderer.draw_lines(gc, xt2, yt2)
 
- def _draw_solid(self, renderer, gc, xt, yt):
- if len(xt)<2: return
+ def _draw_solid(self, renderer, gc, path):
+ # if len(xt)<2: return
 gc.set_linestyle('solid')
- if self._newstyle:
- renderer.draw_lines(gc, xt, yt, self.get_transform())
- else:
- renderer.draw_lines(gc, xt, yt)
+	renderer.draw_path(gc, path, self.get_transform())
 
 
 def _draw_dashed(self, renderer, gc, xt, yt):
@@ -1103,16 +1089,12 @@
 for (x,y) in zip(xt, yt):
 renderer.draw_line(gc, x, y, x+offset, y)
 
+ _tickup_path = Path([[-0.5, 0.0], [-0.5, 1.0]])
 def _draw_tickup(self, renderer, gc, xt, yt):
 offset = renderer.points_to_pixels(self._markersize)
- if self._newstyle:
- path = agg.path_storage()
- path.move_to(-0.5, 0)
- path.line_to(-0.5, offset)
- renderer.draw_markers(gc, path, None, xt, yt, self.get_transform())
- else:
- for (x,y) in zip(xt, yt):
- renderer.draw_line(gc, x, y, x, y+offset)
+	marker_transform = Affine2D().scale(1.0, offset)
+	renderer.draw_markers(gc, self._tickup_path, marker_transform,
+			 self._path, self.get_transform())
 
 def _draw_tickdown(self, renderer, gc, xt, yt):
 offset = renderer.points_to_pixels(self._markersize)
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -11,8 +11,8 @@
 import matplotlib.nxutils as nxutils
 import matplotlib.mlab as mlab
 import matplotlib.artist as artist
+from matplotlib.path import Path
 
-
 # these are not available for the object inspector until after the
 # class is build so we define an initial set here for the init
 # function and they will be overridden after object defn
@@ -73,7 +73,7 @@
 self._antialiased = antialiased
 self._hatch = hatch
 self.fill = fill
-
+	
 if len(kwargs): artist.setp(self, **kwargs)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
@@ -84,8 +84,10 @@
 
 Returns T/F, {}
 """
- if callable(self._contains): return self._contains(self,mouseevent)
+	# MGDTODO: This will probably need to be implemented in C++
 
+	if callable(self._contains): return self._contains(self,mouseevent)
+
 try:
 # TODO: make this consistent with patch collection algorithm
 x, y = self.get_transform().inverse_xy_tup((mouseevent.x, mouseevent.y))
@@ -107,7 +109,6 @@
 self.set_figure(other.get_figure())
 self.set_alpha(other.get_alpha())
 
-
 def get_antialiased(self):
 return self._antialiased
 
@@ -210,22 +211,16 @@
 if self._hatch:
 gc.set_hatch(self._hatch )
 
- verts = self.get_verts()
- tverts = self.get_transform()(verts)
+ path = self.get_path()
+ transform = self.get_transform()
 
-	# MGDTODO: This result is an Nx2 numpy array, which could be passed
-	# directly to renderer.draw_polygon since it currently expects
-	# a list of tuples so we're converting it to that now.
-	tverts = [tuple(x) for x in tverts]
-	
- renderer.draw_polygon(gc, rgbFace, tverts)
+ renderer.draw_path(gc, path, transform, rgbFace)
 
-
 #renderer.close_group('patch')
 
- def get_verts(self):
+ def get_path(self):
 """
- Return the vertices of the patch
+ Return the path of this patch
 """
 raise NotImplementedError('Derived must override')
 
@@ -286,9 +281,10 @@
 %(Patch)s
 """
 Patch.__init__(self)
- self.ox, self.oy = ox, oy
 self.patch = patch
 self.props = props
+	self.ox, self.oy = ox, oy
+	self._shadow_transform = transforms.Affine2D.translate(self.ox, self.oy)
 self._update()
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
@@ -306,18 +302,13 @@
 
 self.set_facecolor((r,g,b))
 self.set_edgecolor((r,g,b))
+	 
+ def get_path(self):
+ return self.patch.get_path()
 
- def get_verts(self):
- verts = self.patch.get_verts()
- xs = self.convert_xunits([x+self.ox for x,y in verts])
- ys = self.convert_yunits([y+self.oy for x,y in verts])
- return zip(xs, ys)
-
- def _draw(self, renderer):
- 'draw the shadow'
- self._update()
- Patch.draw(self, renderer)
-
+ def get_transform(self):
+	return self._transform + self._shadow_transform
+ 
 class Rectangle(Patch):
 """
 Draw a rectangle with lower left at xy=(x,y) with specified
@@ -325,12 +316,16 @@
 
 """
 
+ _path = Path(
+	[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]])
+ 
 def __str__(self):
 return str(self.__class__).split('.')[-1] \
 + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height)
 
- def __init__(self, xy, width, height,
- **kwargs):
+ # MGDTODO: Perhaps pass in a Bbox here instead, then the updates will
+ # happen automatically (without needing to call set_x etc.
+ def __init__(self, xy, width, height, **kwargs):
 """
 xy is an x,y tuple lower, left
 
@@ -344,38 +339,41 @@
 
 Patch.__init__(self, **kwargs)
 
- self.xy = list(xy)
- self.width, self.height = width, height
+	self._bbox = transforms.Bbox.from_lbwh(xy[0], xy[1], width, height)
+	self._rect_transform = transforms.BboxTransform(
+	 transforms.Bbox.unit(), self._bbox)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
-
- def get_verts(self):
+ def get_path(self):
 """
 Return the vertices of the rectangle
 """
- x, y = self.xy
- left, right = self.convert_xunits((x, x + self.width))
- bottom, top = self.convert_yunits((y, y + self.height))
+	# This is a "class-static" variable, so all rectangles in the plot
+	# will be shared (and merely have different transforms)
+	return self._path
 
- return npy.array([[left, bottom], [left, top],
-			 [right, top], [right, bottom]],
-			 npy.float_)
+ # MGDTODO: Convert units
+# left, right = self.convert_xunits((x, x + self.width))
+# bottom, top = self.convert_yunits((y, y + self.height))
 
+ def get_transform(self):
+	return self._rect_transform + self._transform
+ 
 def get_x(self):
 "Return the left coord of the rectangle"
- return self.xy[0]
+ return self._bbox.xmin
 
 def get_y(self):
 "Return the bottom coord of the rectangle"
- return self.xy[1]
+ return self._bbox.ymin
 
 def get_width(self):
 "Return the width of the rectangle"
- return self.width
+ return self._bbox.width
 
 def get_height(self):
 "Return the height of the rectangle"
- return self.height
+ return self._bbox.height
 
 def set_x(self, x):
 """
@@ -383,7 +381,7 @@
 
 ACCEPTS: float
 """
- self.xy[0] = x
+ self._bbox.xmin = x
 
 def set_y(self, y):
 """
@@ -391,7 +389,7 @@
 
 ACCEPTS: float
 """
- self.xy[1] = y
+ self._bbox.ymin = y
 
 def set_width(self, w):
 """
@@ -399,7 +397,7 @@
 
 ACCEPTS: float
 """
- self.width = w
+ self._bbox.width = w
 
 def set_height(self, h):
 """
@@ -407,7 +405,7 @@
 
 ACCEPTS: float
 """
- self.height = h
+ self._bbox.height = h
 
 def set_bounds(self, *args):
 """
@@ -419,15 +417,15 @@
 l,b,w,h = args[0]
 else:
 l,b,w,h = args
- self.xy = [l,b]
- self.width = w
- self.height = h
+	self._bbox.bounds = l,b,w,h
 
 
 class RegularPolygon(Patch):
 """
 A regular polygon patch.
 """
+ _polygon_cache = {}
+ 
 def __str__(self):
 return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1])
 
@@ -444,32 +442,27 @@
 """
 Patch.__init__(self, **kwargs)
 
- self.xy = list(xy)
- self.numVertices = numVertices
- self.radius = radius
- self.orientation = orientation
+	path = self._polygon_cache[numVertices]
+	if path is None:
+	 theta = 2*npy.pi/numVertices * npy.arange(numVertices)
+	 verts = npy.hstack((npy.cos(theta), npy.sin(theta)))
+	 path = Path(verts)
+	 self._polygon_cache[numVertices] = path
 
+	self._path = path
+	self._poly_transform = transforms.Affine2D() \
+	 .scale(radius) \
+	 .rotate(orientation) \
+	 .translate(*xy)
+
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
+ def get_path(self):
+	return self._path
 
-
- def get_verts(self):
- theta = 2*npy.pi/self.numVertices*npy.arange(self.numVertices) + \
- self.orientation
- r = float(self.radius)
- x, y = map(float, self.xy)
-
- xs = x + r*npy.cos(theta)
- ys = y + r*npy.sin(theta)
-
- #xs = self.convert_xunits(xs)
- #ys = self.convert_yunits(ys)
-
-
- self.verts = zip(xs, ys)
-
- return self.verts
-
+ def get_transform(self):
+	return self._poly_transform + self._transform
+	
 class Polygon(Patch):
 """
 A general polygon patch.
@@ -485,22 +478,20 @@
 %(Patch)s
 See Patch documentation for additional kwargs
 """
-
+	# MGDTODO: This should encourage the use of numpy arrays of shape Nx2
 Patch.__init__(self, **kwargs)
 if not isinstance(xy, list):
 xy = list(xy)
- self.xy = xy
+	self._path = Path(xy, closed=False)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
-
-
 def get_verts(self):
- xs, ys = zip(*self.xy)[:2]
+	return self._path
+
+ # MGDTODO: Convert units
 xs = self.convert_xunits(xs)
 ys = self.convert_yunits(ys)
- return zip(xs, ys)
 
-
 class Wedge(Polygon):
 def __str__(self):
 return "Wedge(%g,%g)"%self.xy[0]
@@ -516,6 +507,7 @@
 %(Patch)s
 
 """
+	# MGDTODO: Implement me
 xc, yc = center
 rads = (math.pi/180.)*npy.arange(theta1, theta2+0.1*dtheta, dtheta)
 xs = r*npy.cos(rads)+xc
@@ -543,6 +535,7 @@
 Valid kwargs are:
 %(Patch)s
 """
+	# MGDTODO: Implement me
 arrow = npy.array( [
 [ 0.0, 0.1 ], [ 0.0, -0.1],
 [ 0.8, -0.1 ], [ 0.8, -0.3],
@@ -586,6 +579,7 @@
 %(Patch)s
 
 """
+	# MGDTODO: Implement me
 if head_width is None:
 head_width = 3 * width
 if head_length is None:
@@ -659,6 +653,7 @@
 %(Patch)s
 
 """
+	# MGDTODO: Implement me
 self.dpi = dpi
 self.xytip = xytip
 self.xybase = xybase
@@ -731,6 +726,7 @@
 %(Patch)s
 
 """
+	# MGDTODO: Implement me
 self.center = xy
 self.radius = radius
 RegularPolygon.__init__(self, xy,
@@ -767,6 +763,7 @@
 Valid kwargs are:
 %(Patch)s
 """
+	# MGDTODO: Implement me
 Patch.__init__(self, **kwargs)
 
 # self.center = npy.array(xy, npy.float)
@@ -833,6 +830,7 @@
 %(Patch)s
 
 """
+	# MGDTODO: Implement me
 if kwargs.has_key('resolution'):
 import warnings
 warnings.warn('Circle is now scale free. Use CirclePolygon instead!', DeprecationWarning)
Added: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/path.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -0,0 +1,50 @@
+import numpy as npy
+
+class Path:
+ # Path codes
+ STOP = 0
+ MOVETO = 1 # 1 vertex
+ LINETO = 2 # 1 vertex
+ CURVE3 = 3 # 2 vertices
+ CURVE4 = 4 # 3 vertices
+ ###
+ # MGDTODO: I'm not sure these are supported by PS/PDF/SVG,
+ # so if they don't, we probably shouldn't
+ CURVEN = 5
+ CATROM = 6
+ UBSPLINE = 7
+ ####
+ CLOSEPOLY = 0x0F # 0 vertices
+
+ code_type = npy.uint8
+ 
+ def __init__(self, vertices, codes=None, closed=True):
+	self._vertices = npy.asarray(vertices, npy.float_)
+	assert self._vertices.ndim == 2
+	assert self._vertices.shape[1] == 2
+
+	if codes is None:
+	 if closed:
+		codes = self.LINETO * npy.ones(
+		 self._vertices.shape[0] + 1, self.code_type)
+		codes[0] = self.MOVETO
+		codes[-1] = self.CLOSEPOLY
+	 else:
+		codes = self.LINETO * npy.ones(
+		 self._vertices.shape[0], self.code_type)
+		codes[0] = self.MOVETO
+ else:
+	 codes = npy.asarray(codes, self.code_type)
+	self._codes = codes
+	 
+	assert self._codes.ndim == 1
+	# MGDTODO: Maybe we should add some quick-and-dirty check that
+	# the number of vertices is correct for the code array
+
+ def _get_codes(self):
+	return self._codes
+ codes = property(_get_codes)
+
+ def _get_vertices(self):
+	return self._vertices
+ vertices = property(_get_vertices)
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -403,6 +403,9 @@
 Transform.__init__(self)
 self._inverted = None
 
+ def __array__(self):
+	return self.get_matrix()
+	
 def _do_invalidation(self):
 result = self._inverted is None
 self._inverted = None
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/src/_backend_agg.cpp	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -341,6 +341,7 @@
 
 }
 
+// MGDTODO: Remove this method (it has been conglomerated into draw_path
 template <class VS>
 void
 RendererAgg::_fill_and_stroke(VS& path,
@@ -1399,68 +1400,6 @@
 }
 
 
-
-
-// Py::Object
-// RendererAgg::draw_path(const Py::Tuple& args) {
-// //draw_path(gc, rgbFace, path, transform)
-// theRasterizer->reset_clipping();
- 
-// _VERBOSE("RendererAgg::draw_path");
-// args.verify_length(4);
- 
-// GCAgg gc = GCAgg(args[0], dpi);
-// facepair_t face = _get_rgba_face(args[1], gc.alpha);
- 
-// agg::path_storage *path;
-// swig_type_info * descr = SWIG_TypeQuery("agg::path_storage *");
-// assert(descr);
-// if (SWIG_ConvertPtr(args[2].ptr(),(void **)(&path), descr, 0) == -1)
-// throw Py::TypeError("Could not convert path_storage");
- 
- 
-// Transformation* mpltransform = static_cast<Transformation*>(args[3].ptr());
- 
-// double a, b, c, d, tx, ty;
-// try {
-// mpltransform->affine_params_api(&a, &b, &c, &d, &tx, &ty);
-// }
-// catch(...) {
-// throw Py::ValueError("Domain error on affine_params_api in RendererAgg::draw_path");
-// }
- 
-// agg::trans_affine xytrans = agg::trans_affine(a,b,c,d,tx,ty);
- 
-// double heightd = double(height);
-// agg::path_storage tpath; // the mpl transformed path
-// bool needNonlinear = mpltransform->need_nonlinear_api();
-// size_t Nx = path->total_vertices();
-// double x, y;
-// unsigned cmd;
-// bool curvy = false;
-// for (size_t i=0; i<Nx; i++) {
-// cmd = path->vertex(i, &x, &y);
-// if (cmd==agg::path_cmd_curve3 || cmd==agg::path_cmd_curve4) curvy=true;
-// if (needNonlinear)
-// try {
-// 	mpltransform->nonlinear_only_api(&x, &y);
-// }
-// catch (...) {
-// 	throw Py::ValueError("Domain error on nonlinear_only_api in RendererAgg::draw_path");
-	
-// }
- 
-// //use agg's transformer?
-// xytrans.transform(&x, &y);
-// y = heightd - y; //flipy
-// tpath.add_vertex(x,y,cmd);
-// }
- 
-// _fill_and_stroke(tpath, gc, face, curvy);
-// return Py::Object();
- 
-// }
-
 /**
 * This is a custom span generator that converts spans in the 
 * 8-bit inverted greyscale font buffer to rgba that agg can use.
@@ -1613,8 +1552,172 @@
 
 }
 
+inline void get_next_vertex(const char* & vertex_i, const char* vertex_end, 
+			 double& x, double& y,
+			 size_t next_vertex_stride, 
+			 size_t next_axis_stride) {
+ if (vertex_i + next_axis_stride >= vertex_end)
+ throw Py::ValueError("Error parsing path. Read past end of vertices");
+ x = *(double*)vertex_i;
+ y = *(double*)(vertex_i + next_axis_stride);
+ vertex_i += next_vertex_stride;
+}
 
+#define GET_NEXT_VERTEX(x, y) get_next_vertex(vertex_i, vertex_end, x, y, next_vertex_stride, next_axis_stride)
+
+
+
 Py::Object
+RendererAgg::convert_to_native_path(const Py::Tuple& args) {
+ _VERBOSE("RendererAgg::draw_image");
+ args.verify_length(2);
+ 
+ Py::Object vertices_obj = args[0];
+ Py::Object codes_obj = args[1];
+ 
+ PyArrayObject* vertices = NULL;
+ PyArrayObject* codes = NULL;
+ PathAgg* path = NULL; 
+
+ try {
+ vertices = (PyArrayObject*)PyArray_ContiguousFromObject
+ (vertices_obj.ptr(), PyArray_DOUBLE, 2, 2);
+ if (!vertices || vertices->nd != 2 || vertices->dimensions[1] != 2)
+ throw Py::ValueError("Invalid vertices array.");
+ codes = (PyArrayObject*)PyArray_ContiguousFromObject
+ (codes_obj.ptr(), PyArray_UINT8, 1, 1);
+ if (!codes) 
+ throw Py::ValueError("Invalid codes array.");
+
+ path = new PathAgg();
+
+ size_t next_vertex_stride = vertices->strides[0];
+ size_t next_axis_stride = vertices->strides[1];
+ size_t code_stride = codes->strides[0];
+
+ const char* vertex_i = vertices->data;
+ const char* code_i = codes->data;
+ const char* vertex_end = vertex_i + (vertices->dimensions[0] * vertices->strides[0]);
+
+ size_t N = codes->dimensions[0];
+ double x0, y0, x1, y1, x2, y2;
+
+ for (size_t i = 0; i < N; ++i) {
+ switch (*(unsigned char*)(code_i)) {
+ case MOVETO:
+	GET_NEXT_VERTEX(x0, y0);
+	path->move_to(x0, y0);
+	_VERBOSE("MOVETO");
+	break;
+ case LINETO:
+	GET_NEXT_VERTEX(x0, y0);
+	path->line_to(x0, y0);
+	_VERBOSE("LINETO");
+	break;
+ case CURVE3:
+	GET_NEXT_VERTEX(x0, y0);
+	GET_NEXT_VERTEX(x1, y1);
+	path->curve3(x0, y0, x1, y1);
+	path->curvy = true;
+	_VERBOSE("CURVE3");
+	break;
+ case CURVE4:
+	GET_NEXT_VERTEX(x0, y0);
+	GET_NEXT_VERTEX(x1, y1);
+	GET_NEXT_VERTEX(x2, y2);
+	path->curve4(x0, y0, x1, y1, x2, y2);
+	path->curvy = true;
+	_VERBOSE("CURVE4");
+	break;
+ case CLOSEPOLY:
+	path->close_polygon();
+	_VERBOSE("CLOSEPOLY");
+	break;
+ }
+ code_i += code_stride;
+ }
+ } catch(...) {
+ Py_XDECREF(vertices);
+ Py_XDECREF(codes);
+ delete path;
+ throw;
+ }
+
+ Py_XDECREF(vertices);
+ Py_XDECREF(codes);
+ 
+ return Py::asObject(path);
+}
+
+Py::Object
+RendererAgg::draw_path(const Py::Tuple& args) {
+ typedef agg::conv_transform<agg::path_storage> transformed_path_t;
+ typedef agg::conv_curve<transformed_path_t> curve_t;
+ typedef agg::conv_stroke<curve_t> stroke_t;
+ typedef agg::conv_dash<curve_t> dash_t;
+ typedef agg::conv_stroke<dash_t> stroke_dash_t;
+ //draw_path(gc, rgbFace, path, transform)
+ theRasterizer->reset_clipping();
+ 
+ _VERBOSE("RendererAgg::draw_path");
+ args.verify_length(4);
+
+ GCAgg gc = GCAgg(args[0], dpi);
+ Py::Object path_obj = args[1];
+ if (!PathAgg::check(path_obj))
+ throw Py::TypeError("Native path object is not of correct type");
+ PathAgg* path = static_cast<PathAgg*>(path_obj.ptr());
+ agg::trans_affine trans = py_sequence_to_agg_transformation_matrix(args[2]);
+ facepair_t face = _get_rgba_face(args[3], gc.alpha);
+
+ trans *= agg::trans_affine_scaling(1.0, -1.0);
+ trans *= agg::trans_affine_translation(0.0, (double)height);
+
+ transformed_path_t tpath(*path, trans);
+ // MGDTODO: See if there is any advantage to only curving if necessary
+ curve_t curve(tpath);
+
+ set_clipbox_rasterizer(gc.cliprect);
+ 
+ if (face.first) {
+ rendererAA->color(face.second);
+ theRasterizer->add_path(curve);
+ agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ }
+
+ if (gc.linewidth) {
+ if (gc.dasha == NULL) {
+ stroke_t stroke(curve);
+ stroke.width(gc.linewidth);
+ stroke.line_cap(gc.cap);
+ stroke.line_join(gc.join);
+ theRasterizer->add_path(stroke);
+ } else {
+ dash_t dash(curve);
+ for (size_t i = 0; i < (gc.Ndash / 2); ++i)
+	dash.add_dash(gc.dasha[2 * i], gc.dasha[2 * i + 1]);
+ stroke_dash_t stroke(dash);
+ stroke.line_cap(gc.cap);
+ stroke.line_join(gc.join);
+ stroke.width(gc.linewidth);
+ theRasterizer->add_path(stroke); //boyle freeze is herre
+ }
+ 
+ if ( gc.isaa ) {
+ rendererAA->color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA);
+ }
+ else {
+ rendererBin->color(gc.color);
+ agg::render_scanlines(*theRasterizer, *slineBin, *rendererBin);
+ }
+ }
+ 
+ return Py::Object();
+}
+
+
+Py::Object
 RendererAgg::write_rgba(const Py::Tuple& args) {
 _VERBOSE("RendererAgg::write_rgba");
 
@@ -1949,6 +2052,10 @@
 		 "draw_ellipse(gc, rgbFace, x, y, w, h)\n");
 add_varargs_method("draw_polygon", &RendererAgg::draw_polygon,
 		 "draw_polygon(gc, rgbFace, points)\n");
+ add_varargs_method("draw_path", &RendererAgg::draw_path,
+		 "draw_path(gc, rgbFace, native_path, transform)\n");
+ add_varargs_method("convert_to_native_path", &RendererAgg::convert_to_native_path,
+		 "convert_to_native_path(vertices, codes)\n");
 add_varargs_method("draw_lines", &RendererAgg::draw_lines,
 		 "draw_lines(gc, x, y,)\n");
 add_varargs_method("draw_markers", &RendererAgg::draw_markers,
@@ -1976,10 +2083,13 @@
 
 add_varargs_method("restore_region", &RendererAgg::restore_region,
 		 "restore_region(region)");
- 
- 
 }
 
+void PathAgg::init_type()
+{
+ behaviors().name("PathAgg");
+ behaviors().doc("A native Agg path object");
+}
 
 extern "C"
 DL_EXPORT(void)
Modified: branches/transforms/src/_backend_agg.h
===================================================================
--- branches/transforms/src/_backend_agg.h	2007年09月14日 13:03:31 UTC (rev 3851)
+++ branches/transforms/src/_backend_agg.h	2007年09月14日 17:57:52 UTC (rev 3852)
@@ -39,6 +39,14 @@
 #include "agg_scanline_p.h"
 #include "agg_vcgen_markers_term.h"
 
+// These are copied directly from path.py, and must be kept in sync
+#define STOP 0
+#define MOVETO 1
+#define LINETO 2
+#define CURVE3 3
+#define CURVE4 4
+#define CLOSEPOLY 0x0F
+
 typedef agg::pixfmt_rgba32 pixfmt;
 typedef agg::renderer_base<pixfmt> renderer_base;
 typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa;
@@ -163,6 +171,8 @@
 Py::Object draw_markers(const Py::Tuple & args);
 Py::Object draw_text_image(const Py::Tuple & args);
 Py::Object draw_image(const Py::Tuple & args);
+ Py::Object draw_path(const Py::Tuple & args);
+ Py::Object convert_to_native_path(const Py::Tuple & args);
 
 Py::Object write_rgba(const Py::Tuple & args);
 Py::Object write_png(const Py::Tuple & args);
@@ -229,7 +239,22 @@
 agg::path_storage *lastclippath;
 };
 
+// A completely opaque data type used only to pass native path
+// data to/from Python. Python can't do anything with the data
+// other than create and then use it.
+class PathAgg : 
+ public agg::path_storage, 
+ public Py::PythonExtension<PathAgg> {
 
+public:
+ PathAgg() : curvy(false) {}
+
+ static void init_type(void);
+
+ bool curvy;
+};
+
+
 // the extension module
 class _backend_agg_module : public Py::ExtensionModule<_backend_agg_module>
 {
@@ -240,6 +265,7 @@
 
 BufferRegion::init_type();
 RendererAgg::init_type();
+ PathAgg::init_type();
 
 add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer,
 		 "RendererAgg(width, height, dpi)");
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月14日 13:03:33
Revision: 3851
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3851&view=rev
Author: mdboom
Date: 2007年09月14日 06:03:31 -0700 (2007年9月14日)
Log Message:
-----------
Removed transforms on the C++ side -- removed many methods that depend
on it in backend_agg in preparation for path generalization. 
Lots of general renaming...
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/finance.py
 branches/transforms/lib/matplotlib/legend.py
 branches/transforms/lib/matplotlib/lines.py
 branches/transforms/lib/matplotlib/table.py
 branches/transforms/lib/matplotlib/text.py
 branches/transforms/lib/matplotlib/ticker.py
 branches/transforms/lib/matplotlib/widgets.py
 branches/transforms/setup.py
 branches/transforms/setupext.py
 branches/transforms/src/_backend_agg.cpp
 branches/transforms/src/_backend_agg.h
 branches/transforms/src/_gtkagg.cpp
 branches/transforms/src/_tkagg.cpp
Added Paths:
-----------
 branches/transforms/lib/matplotlib/transforms.py
Removed Paths:
-------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/src/_transforms.cpp
 branches/transforms/src/_transforms.h
Deleted: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -1,854 +0,0 @@
-"""
-A set of classes to handle transformations.
-
-2007 Michael Droettboom
-"""
-
-import numpy as npy
-from numpy.linalg import inv
-from sets import Set
-
-# MGDTODO: The name of this module is bad, since it deals with
-# non-affine transformations as well. It should probably just be
-# "transforms", but we already had one of those... ;)
-
-# MGDTODO: This creates a ton of cyclical references. We may want to
-# consider using weak references
-
-# MGDTODO: deep copying is probably incorrect wrt the parent/child
-# relationships
-
-class TransformNode(object):
- def __init__(self):
- self._parents = Set()
- 
- def invalidate(self):
- if not self._do_invalidation():
- for parent in self._parents:
- parent.invalidate()
-
- def _do_invalidation(self):
- return False
-
- def set_children(self, children):
- for child in children:
- getattr(self, child)._parents.add(self)
- self._children = children
-
-# def replace_child(self, index, child):
-# children = self._children
-# getattr(self, children[index])._parents.remove(self)
-# setattr(self, children[index], child)
-# # We have to reset children in case two or more
-# # of the children are the same
-# for child in children:
-# getattr(self, child)._parents.add(self)
-# self.invalidate()
- 
-class BboxBase(TransformNode):
- '''
- This is the read-only part of a bounding-box
- '''
- 
- def __init__(self):
- TransformNode.__init__(self)
- 
- def __array__(self):
- return self.get_points()
- 
- # MGDTODO: Probably a more efficient ways to do this...
- def _get_xmin(self):
- return self.get_points()[0, 0]
- xmin = property(_get_xmin)
- 
- def _get_ymin(self):
- return self.get_points()[0, 1]
- ymin = property(_get_ymin)
-
- def _get_xmax(self):
- return self.get_points()[1, 0]
- xmax = property(_get_xmax)
-
- def _get_ymax(self):
- return self.get_points()[1, 1]
- ymax = property(_get_ymax)
-
- def _get_min(self):
- return self.get_points()[0]
- min = property(_get_min)
- 
- def _get_max(self):
- return self.get_points()[1]
- max = property(_get_max)
- 
- def _get_intervalx(self):
- return self.get_points()[:, 0]
- intervalx = property(_get_intervalx)
-
- def _get_intervaly(self):
- return self.get_points()[:, 1]
- intervaly = property(_get_intervaly)
- 
- def _get_width(self):
- return self.xmax - self.xmin
- width = property(_get_width)
-
- def _get_height(self):
- return self.ymax - self.ymin
- height = property(_get_height)
-
- def _get_bounds(self):
- return (self.xmin, self.ymin,
- self.xmax - self.xmin, self.ymax - self.ymin)
- bounds = property(_get_bounds)
-
- def get_points(self):
- return NotImplementedError()
-
- # MGDTODO: Optimize
- def containsx(self, x):
- return x >= self.xmin and x <= self.xmax
-
- def containsy(self, y):
- return y >= self.ymin and y <= self.ymax
- 
- def contains(self, x, y):
- return self.containsx(x) and self.containsy(y)
-
- def overlapsx(self, other):
- return self.containsx(other.xmin) \
- or self.containsx(other.xmax)
-
- def overlapsy(self, other):
- return self.containsy(other.ymin) \
- or self.containsx(other.ymax)
- 
- def overlaps(self, other):
- return self.overlapsx(other) \
- and self.overlapsy(other)
- 
- def fully_containsx(self, x):
- return x > self.xmin and x < self.xmax
-
- def fully_containsy(self, y):
- return y > self.ymin and y < self.ymax
- 
- def fully_contains(self, x, y):
- return self.fully_containsx(x) \
- and self.fully_containsy(y)
-
- def fully_overlapsx(self, other):
- return self.fully_containsx(other.xmin) \
- or self.fully_containsx(other.xmax)
-
- def fully_overlapsy(self, other):
- return self.fully_containsy(other.ymin) \
- or self.fully_containsx(other.ymax)
- 
- def fully_overlaps(self, other):
- return self.fully_overlapsx(other) and \
- self.fully_overlapsy(other)
-
- 
-class Bbox(BboxBase):
- def __init__(self, points):
- BboxBase.__init__(self)
- self._points = npy.asarray(points, npy.float_)
-
- #@staticmethod
- def unit():
- return Bbox.from_lbrt(0., 0., 1., 1.)
- unit = staticmethod(unit)
-
- #@staticmethod
- def from_lbwh(left, bottom, width, height):
- return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
- from_lbwh = staticmethod(from_lbwh)
-
- #@staticmethod
- def from_lbrt(*args):
- points = npy.array(args, dtype=npy.float_).reshape(2, 2)
- return Bbox(points)
- from_lbrt = staticmethod(from_lbrt)
- 
- def __copy__(self):
- return Bbox(self._points.copy())
-
- def __deepcopy__(self, memo):
- return Bbox(self._points.copy())
- 
- def __cmp__(self, other):
- # MGDTODO: Totally suboptimal
- if isinstance(other, Bbox) and (self._points == other._points).all():
- return 0
- return -1
-
- def __repr__(self):
- return 'Bbox(%s)' % repr(self._points)
- __str__ = __repr__
-
- # JDH: the update method will update the box limits from the
- # existing limits and the new data; it appears here you are just
- # using the new data. We use an "ignore" flag to specify whether
- # you want to include the existing data or not in the update
- def update_from_data(self, x, y, ignore=True):
- self._points = npy.array(
- [[x.min(), y.min()], [x.max(), y.max()]],
- npy.float_)
- self.invalidate()
-
- # MGDTODO: Probably a more efficient ways to do this...
- def _set_xmin(self, val):
- self._points[0, 0] = val
- self.invalidate()
- xmin = property(BboxBase._get_xmin, _set_xmin)
-
- def _set_ymin(self, val):
- self._points[0, 1] = val
- self.invalidate()
- ymin = property(BboxBase._get_ymin, _set_ymin)
-
- def _set_xmax(self, val):
- self._points[1, 0] = val
- self.invalidate()
- xmax = property(BboxBase._get_xmax, _set_xmax)
-
- def _set_ymax(self, val):
- self._points[1, 1] = val
- self.invalidate()
- ymax = property(BboxBase._get_ymax, _set_ymax)
-
- def _set_min(self, val):
- self._points[0] = val
- self.invalidate()
- min = property(BboxBase._get_min, _set_min)
- 
- def _set_max(self, val):
- self._points[1] = val
- self.invalidate()
- max = property(BboxBase._get_max, _set_max)
- 
- def _set_intervalx(self, interval):
- self._points[:, 0] = interval
- self.invalidate()
- intervalx = property(BboxBase._get_intervalx, _set_intervalx)
-
- def _set_intervaly(self, interval):
- self._points[:, 1] = interval
- self.invalidate()
- intervaly = property(BboxBase._get_intervaly, _set_intervaly)
-
- def _set_bounds(self, bounds):
- l,b,w,h = bounds
- self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
- self.invalidate()
- bounds = property(BboxBase._get_bounds, _set_bounds)
-
- def get_points(self):
- return self._points
-
- def set_points(self, points):
- self._points = points
- self.invalidate()
-
- def set(self, other):
- self._points = other.get_points()
- self.invalidate()
- 
- def transformed(self, transform):
- return Bbox(transform(self._points))
-
- def inverse_transformed(self, transform):
- return Bbox(transform.inverted()(self._points))
- 
- def expanded(self, sw, sh):
- width = self.width
- height = self.height
- deltaw = (sw * width - width) / 2.0
- deltah = (sh * height - height) / 2.0
- a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
- return Bbox(self._points + a)
-
- #@staticmethod
- def union(bboxes):
- """
- Return the Bbox that bounds all bboxes
- """
- assert(len(bboxes))
-
- if len(bboxes) == 1:
- return bboxes[0]
-
- bbox = bboxes[0]
- xmin = bbox.xmin
- ymin = bbox.ymin
- xmax = bbox.xmax
- ymax = bbox.ymax
-
- for bbox in bboxes[1:]:
- xmin = min(xmin, bbox.xmin)
- ymin = min(ymin, bbox.ymin)
- xmax = max(xmax, bbox.xmax)
- ymax = max(ymax, bbox.ymax)
-
- return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
- union = staticmethod(union)
-
-class TransformedBbox(BboxBase):
- def __init__(self, bbox, transform):
- assert isinstance(bbox, Bbox)
- assert isinstance(transform, Transform)
-
- BboxBase.__init__(self)
- self.bbox = bbox
- self.transform = transform
- self.set_children(['bbox', 'transform'])
- self._points = None
-
- def __repr__(self):
- return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
- __str__ = __repr__
- 
- def _do_invalidation(self):
- self._points = None
-
- def get_points(self):
- if self._points is None:
- self._points = self.transform(self.bbox.get_points())
- return self._points
-
-# MGDTODO: This code probably works, but I don't think it's a good idea
-# (from a code clarity perspective)
-# class BlendedBbox(BboxBase):
-# def __init__(self, bbox_x, bbox_y):
-# assert isinstance(bbox_x, BboxBase)
-# assert isinstance(bbox_y, BboxBase)
-
-# BboxBase.__init__(self)
-# self._x = bbox_x
-# self._y = bbox_y
-# self.set_children(['_x', '_y'])
-# self._points = None
-
-# def __repr__(self):
-# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
-# __str__ = __repr__
- 
-# def _do_invalidation(self):
-# self._points = None
-
-# def get_points(self):
-# if self._points is None:
-# # MGDTODO: Optimize
-# if self._x == self._y:
-# self._points = self._x.get_points()
-# else:
-# x_points = self._x.get_points()
-# y_points = self._y.get_points()
-# self._points = npy.array(
-# [[x_points[0,0], y_points[0,1]],
-# [x_points[1,0], y_points[1,1]]],
-# npy.float_)
-# return self._points
-
-# def _set_intervalx(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
-# self.replace_child(0, bbox)
-# intervalx = property(BboxBase._get_intervalx, _set_intervalx)
-
-# def _set_intervaly(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
-# self.replace_child(1, bbox)
-# intervaly = property(BboxBase._get_intervaly, _set_intervaly)
- 
-class Transform(TransformNode):
- def __init__(self):
- TransformNode.__init__(self)
- 
- def __call__(self, points):
- raise NotImplementedError()
-
- def __add__(self, other):
- if isinstance(other, Transform):
- return composite_transform_factory(self, other)
- raise TypeError(
- "Can not add Transform to object of type '%s'" % type(other))
-
- def __radd__(self, other):
- if isinstance(other, Transform):
- return composite_transform_factory(other, self)
- raise TypeError(
- "Can not add Transform to object of type '%s'" % type(other))
-
- def transform_point(self, point):
- return self.__call__(npy.asarray([point]))[0]
- 
- def has_inverse(self):
- raise NotImplementedError()
- 
- def inverted(self):
- raise NotImplementedError()
-
- def is_separable(self):
- return False
-
- def is_affine(self):
- return False
-
-class Affine2DBase(Transform):
- input_dims = 2
- output_dims = 2
-
- def __init__(self):
- Transform.__init__(self)
- self._inverted = None
-
- def _do_invalidation(self):
- result = self._inverted is None
- self._inverted = None
- return result
-
- #@staticmethod
- def _concat(a, b):
- return npy.dot(b, a)
- _concat = staticmethod(_concat)
-
- #@staticmethod
- def concat(a, b):
- return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix()))
- concat = staticmethod(concat)
- 
- def to_values(self):
- mtx = self.get_matrix()
- return tuple(mtx[:2].swapaxes(0, 1).flatten())
- 
- #@staticmethod
- def matrix_from_values(a, b, c, d, e, f):
- affine = npy.zeros((3, 3), npy.float_)
- affine[0, ] = a, c, e
- affine[1, ] = b, d, f
- affine[2, 2] = 1
- return affine
- matrix_from_values = staticmethod(matrix_from_values)
-
- def get_matrix(self):
- raise NotImplementedError()
- 
- def __call__(self, points):
- """
- Applies the transformation to an array of 2D points and
- returns the result.
-
- points must be a numpy array of shape (N, 2), where N is the
- number of points.
- """
- # MGDTODO: The major speed trap here is just converting to
- # the points to an array in the first place. If we can use
- # more arrays upstream, that should help here.
- if not isinstance(points, npy.ndarray):
- import traceback
- print '-' * 60
- print 'A non-numpy array was passed in for transformation. Please '
- print 'correct this.'
- print "".join(traceback.format_stack())
- print points
- mtx = self.get_matrix()
- points = npy.asarray(points, npy.float_)
- points = points.transpose()
- points = npy.dot(mtx[0:2, 0:2], points)
- points = points + mtx[0:2, 2:]
- return points.transpose()
- 
- def inverted(self):
- if self._inverted is None:
- mtx = self.get_matrix()
- self._inverted = Affine2D(inv(mtx))
- return self._inverted
- 
- def is_separable(self):
- mtx = self.get_matrix()
- return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
-
- def is_affine(self):
- return True
-
- 
-class Affine2D(Affine2DBase):
- input_dims = 2
- output_dims = 2
- 
- def __init__(self, matrix = None):
- """
- Initialize an Affine transform from a 3x3 numpy float array.
-
- a c e
- b d f
- 0 0 1
- """
- Affine2DBase.__init__(self)
- if matrix is None:
- matrix = npy.identity(3)
- else:
- assert matrix.shape == (3, 3)
- self._mtx = matrix
- self._inverted = None
-
- def __repr__(self):
- return "Affine2D(%s)" % repr(self._mtx)
- __str__ = __repr__
-
- def __cmp__(self, other):
- if (isinstance(other, Affine2D) and
- (self.get_matrix() == other.get_matrix()).all()):
- return 0
- return -1
- 
- def __copy__(self):
- return Affine2D(self._mtx.copy())
- 
- def __deepcopy__(self, memo):
- return Affine2D(self._mtx.copy())
- 
- #@staticmethod
- def from_values(a, b, c, d, e, f):
- return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
- from_values = staticmethod(from_values)
-
- def get_matrix(self):
- return self._mtx
-
- def set_matrix(self, mtx):
- self._mtx = mtx
- self.invalidate()
-
- def set(self, other):
- self._mtx = other.get_matrix()
- self.invalidate()
- 
- #@staticmethod
- def identity():
- return Affine2D(npy.identity(3))
- identity = staticmethod(identity)
-
- def clear(self):
- self._mtx = npy.identity(3)
- self.invalidate()
- return self
- 
- def rotate(self, theta):
- a = npy.cos(theta)
- b = npy.sin(theta)
- rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
- self._mtx = self._concat(self._mtx, rotate_mtx)
- self.invalidate()
- return self
-
- def rotate_deg(self, degrees):
- return self.rotate(degrees*npy.pi/180.)
-
- def rotate_around(self, x, y, theta):
- return self.translate(-x, -y).rotate(theta).translate(x, y)
-
- def rotate_deg_around(self, x, y, degrees):
- return self.translate(-x, -y).rotate_deg(degrees).translate(x, y)
- 
- def translate(self, tx, ty):
- translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
- self._mtx = self._concat(self._mtx, translate_mtx)
- self.invalidate()
- return self
-
- def scale(self, sx, sy=None):
- if sy is None:
- sy = sx
- scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
- self._mtx = self._concat(self._mtx, scale_mtx)
- self.invalidate()
- return self
-
- def inverted(self):
- if self._inverted is None:
- mtx = self.get_matrix()
- self._inverted = Affine2D(inv(mtx))
- return self._inverted
- 
- def is_separable(self):
- mtx = self.get_matrix()
- return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
-
- def is_affine(self):
- return True
- 
-class BlendedTransform(Transform):
- def __init__(self, x_transform, y_transform):
- assert x_transform.is_separable()
- assert y_transform.is_separable()
-
- Transform.__init__(self)
- self._x = x_transform
- self._y = y_transform
- self.set_children(['_x', '_y'])
-
- def __call__(self, points):
- if self._x == self._y:
- return self._x(points)
- 
- x_points = self._x(points)
- y_points = self._y(points)
- # This works because we already know the transforms are
- # separable
- return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
-
-# def set_x_transform(self, x_transform):
-# self.replace_child(0, x_transform)
-
-# def set_y_transform(self, y_transform):
-# self.replace_child(1, y_transform)
- 
-class BlendedAffine2D(Affine2DBase, BlendedTransform):
- def __init__(self, x_transform, y_transform):
- assert x_transform.is_affine()
- assert y_transform.is_affine()
- assert x_transform.is_separable()
- assert y_transform.is_separable()
- BlendedTransform.__init__(self, x_transform, y_transform)
- 
- Affine2DBase.__init__(self)
- self._mtx = None
-
- def __repr__(self):
- return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
- __str__ = __repr__
- 
- def _do_invalidation(self):
- if self._mtx is not None:
- self._mtx = None
- Affine2DBase._do_invalidation(self)
- return False
- return True
-
- def is_separable(self):
- return True
-
- def get_matrix(self):
- if self._mtx is None:
- if self._x == self._y:
- self._mtx = self._x.get_matrix()
- else:
- x_mtx = self._x.get_matrix()
- y_mtx = self._y.get_matrix()
- # This works because we already know the transforms are
- # separable, though normally one would want to set b and
- # c to zero.
- self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
- return self._mtx
- 
-class CompositeTransform(Transform):
- def __init__(self, a, b):
- assert a.output_dims == b.input_dims
- self.input_dims = a.input_dims
- self.output_dims = b.output_dims
- 
- Transform.__init__(self)
- self._a = a
- self._b = b
- self.set_children(['_a', '_b'])
- 
- def __call__(self, points):
- return self._b(self._a(points))
- 
-class CompositeAffine2D(Affine2DBase):
- def __init__(self, a, b):
- assert a.is_affine()
- assert b.is_affine()
-
- Affine2DBase.__init__(self)
- self._a = a
- self._b = b
- self.set_children(['_a', '_b'])
- self._mtx = None
-
- def __repr__(self):
- return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
- __str__ = __repr__
-
- def _do_invalidation(self):
- self._mtx = None
- Affine2DBase._do_invalidation(self)
- 
- def get_matrix(self):
- if self._mtx is None:
- self._mtx = self._concat(
- self._a.get_matrix(),
- self._b.get_matrix())
- return self._mtx
-
-class BboxTransform(Affine2DBase):
- def __init__(self, boxin, boxout):
- assert isinstance(boxin, BboxBase)
- assert isinstance(boxout, BboxBase)
-
- Affine2DBase.__init__(self)
- self._boxin = boxin
- self._boxout = boxout
- self.set_children(['_boxin', '_boxout'])
- self._mtx = None
- self._inverted = None
-
- def __repr__(self):
- return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
- __str__ = __repr__
- 
- def _do_invalidation(self):
- if self._mtx is not None:
- self._mtx = None
- Affine2DBase._do_invalidation(self)
- return False
- return True
-
- def is_separable(self):
- return True
-
- def get_matrix(self):
- if self._mtx is None:
- boxin = self._boxin
- boxout = self._boxout
- x_scale = boxout.width / boxin.width
- y_scale = boxout.height / boxin.height
-
- # MGDTODO: Optimize
- affine = Affine2D() \
- .translate(-boxin.xmin, -boxin.ymin) \
- .scale(x_scale, y_scale) \
- .translate(boxout.xmin, boxout.ymin)
-
- self._mtx = affine._mtx
- return self._mtx
-
-def blend_xy_sep_transform(x_transform, y_transform):
- if x_transform.is_affine() and y_transform.is_affine():
- return BlendedAffine2D(x_transform, y_transform)
- return BlendedTransform(x_transform, y_transform)
-
-def composite_transform_factory(a, b):
- if a.is_affine() and b.is_affine():
- return CompositeAffine2D(a, b)
- return CompositeTransform(a, b)
-
-# MGDTODO: There's probably a better place for this
-def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
- '''
- Ensure the endpoints of a range are not too close together.
-
- "too close" means the interval is smaller than 'tiny' times
- the maximum absolute value.
-
- If they are too close, each will be moved by the 'expander'.
- If 'increasing' is True and vmin > vmax, they will be swapped,
- regardless of whether they are too close.
- '''
- swapped = False
- if vmax < vmin:
- vmin, vmax = vmax, vmin
- swapped = True
- if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
- if vmin == 0.0:
- vmin = -expander
- vmax = expander
- else:
- vmin -= expander*abs(vmin)
- vmax += expander*abs(vmax)
- if swapped and not increasing:
- vmin, vmax = vmax, vmin
- return vmin, vmax
-
-# MGDTODO: Optimize
-def interval_contains(interval, val):
- return interval[0] <= val and interval[1] >= val
-
-def interval_contains_open(interval, val):
- return interval[0] < val and interval[1] > val
- 
-if __name__ == '__main__':
- import copy
- from random import random
- import timeit
-
- bbox = Bbox.from_lbrt(10., 15., 20., 25.)
- assert bbox.xmin == 10
- assert bbox.ymin == 15
- assert bbox.xmax == 20
- assert bbox.ymax == 25
-
- assert npy.all(bbox.min == [10, 15])
- assert npy.all(bbox.max == [20, 25])
- assert npy.all(bbox.intervalx == (10, 20))
- assert npy.all(bbox.intervaly == (15, 25))
-
- assert bbox.width == 10
- assert bbox.height == 10
-
- assert bbox.bounds == (10, 15, 10, 10)
-
- print npy.asarray(bbox)
- 
- bbox.intervalx = (11, 21)
- bbox.intervaly = (16, 26)
- 
- assert bbox.bounds == (11, 16, 10, 10)
-
- bbox.xmin = 12
- bbox.ymin = 17
- bbox.xmax = 22
- bbox.ymax = 27
-
- assert bbox.bounds == (12, 17, 10, 10)
-
- bbox = Bbox.from_lbwh(10, 11, 12, 13)
- assert bbox.bounds == (10, 11, 12, 13)
-
- bbox_copy = copy.copy(bbox)
- assert bbox == bbox_copy
- bbox_copy.max = (14, 15)
- assert bbox.bounds == (10, 11, 12, 13)
- assert bbox_copy.bounds == (10, 11, 4, 4)
- 
- bbox1 = Bbox([[10., 15.], [20., 25.]])
- bbox2 = Bbox([[30., 35.], [40., 45.]])
- trans = BboxTransform(bbox1, bbox2)
- bbox3 = bbox1.transformed(trans)
- assert bbox3 == bbox2
-
- translation = Affine2D().translate(10, 20)
- assert translation.to_values() == (1, 0, 0, 1, 10, 20)
- scale = Affine2D().scale(10, 20)
- assert scale.to_values() == (10, 0, 0, 20, 0, 0)
- rotation = Affine2D().rotate_deg(30)
- print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
- -0.49999999999999994, 0.86602540378443871,
- 0.0, 0.0)
- 
- points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_)
- translated_points = translation(points)
- assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
- scaled_points = scale(points)
- print scaled_points
- rotated_points = rotation(points)
- print rotated_points
-
- tpoints1 = rotation(translation(scale(points)))
- trans_sum = scale + translation + rotation
- tpoints2 = trans_sum(points)
- print tpoints1, tpoints2
- print tpoints1 == tpoints2
- # Need to do some sort of fuzzy comparison here?
- # assert (tpoints1 == tpoints2).all()
-
- # Here are some timing tests
- points = npy.asarray([(random(), random()) for i in xrange(10000)])
- t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
- print "Time to transform 10000 x 10 points:", t.timeit(10)
- 
-__all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -1,7 +1,7 @@
 from __future__ import division
 import sys, re
 from cbook import iterable, flatten
-from affine import Affine2D
+from transforms import Affine2D
 import matplotlib.units as units
 
 ## Note, matplotlib artists use the doc strings for set and get
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -9,7 +9,6 @@
 rcParams = matplotlib.rcParams
 
 from matplotlib import artist as martist
-from matplotlib import affine as maffine
 from matplotlib import agg
 from matplotlib import axis as maxis
 from matplotlib import cbook
@@ -29,6 +28,7 @@
 from matplotlib import table as mtable
 from matplotlib import text as mtext
 from matplotlib import ticker as mticker
+from matplotlib import transforms as mtransforms
 
 iterable = cbook.iterable
 is_string_like = cbook.is_string_like
@@ -481,7 +481,7 @@
 
 """
 martist.Artist.__init__(self)
- self._position = maffine.Bbox.from_lbwh(*rect)
+ self._position = mtransforms.Bbox.from_lbwh(*rect)
 self._originalPosition = copy.deepcopy(self._position)
 self.set_axes(self)
 self.set_aspect('auto')
@@ -612,7 +612,7 @@
 """
 martist.Artist.set_figure(self, fig)
 
- self.bbox = maffine.TransformedBbox(self._position, fig.transFigure)
+ self.bbox = mtransforms.TransformedBbox(self._position, fig.transFigure)
 #these will be updated later as data is added
 self._set_lim_and_transforms()
 
@@ -631,7 +631,7 @@
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
-	Bbox = maffine.Bbox
+	Bbox = mtransforms.Bbox
 	self.viewLim = Bbox.unit()
 	
 if self._sharex is not None:
@@ -647,20 +647,11 @@
 
 	self.dataLim = Bbox.unit()
 	
- self.transAxes = maffine.BboxTransform(
+ self.transAxes = mtransforms.BboxTransform(
 Bbox.unit(), self.bbox)
 
- localTransData = maffine.BboxTransform(
+ self.transData = mtransforms.BboxTransform(
 self.viewLim, self.bbox)
-	if self._sharex:
-	 transDataX = self._sharex.transData
-	else:
-	 transDataX = localTransData
-	if self._sharey:
-	 transDataY = self._sharey.transData
-	else:
-	 transDataY = localTransData
-	self.transData = localTransData # maffine.blend_xy_sep_transform(transDataX, transDataY)
 	 
 	 
 def get_position(self, original=False):
@@ -1538,7 +1529,7 @@
 # and min(xmin, xmax)<=0):
 # raise ValueError('Cannot set nonpositive limits with log transform')
 
- xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
+ xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False)
 
 	self.viewLim.intervalx = (xmin, xmax)
 if emit:
@@ -1670,7 +1661,7 @@
 # and min(ymin, ymax)<=0):
 # raise ValueError('Cannot set nonpositive limits with log transform')
 
- ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
+ ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False)
 	self.viewLim.intervaly = (ymin, ymax)
 if emit:
 	 self.callbacks.process('ylim_changed', self)
@@ -2167,7 +2158,7 @@
 %(Annotation)s
 """
 a = mtext.Annotation(*args, **kwargs)
- a.set_transform(maffine.Affine2D())
+ a.set_transform(mtransforms.Affine2D())
 self._set_artist_props(a)
 if kwargs.has_key('clip_on'): a.set_clip_box(self.bbox)
 self.texts.append(a)
@@ -2206,7 +2197,7 @@
 %(Line2D)s
 """
 
- trans = maffine.blend_xy_sep_transform(self.transAxes, self.transData)
+ trans = mtransforms.blend_xy_sep_transform(self.transAxes, self.transData)
 l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs)
 return l
 
@@ -2242,7 +2233,7 @@
 %(Line2D)s
 """
 
- trans = maffine.blend_xy_sep_transform( self.transData, self.transAxes )
+ trans = mtransforms.blend_xy_sep_transform( self.transData, self.transAxes )
 l, = self.plot([x,x], [ymin,ymax] , transform=trans, scaley=False, **kwargs)
 return l
 
@@ -2281,7 +2272,7 @@
 %(Polygon)s
 """
 # convert y axis units
- trans = maffine.blend_xy_sep_transform( self.transAxes, self.transData)
+ trans = mtransforms.blend_xy_sep_transform( self.transAxes, self.transData)
 verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)
 p = mpatches.Polygon(verts, **kwargs)
 p.set_transform(trans)
@@ -2321,7 +2312,7 @@
 %(Polygon)s
 """
 # convert x axis units
- trans = maffine.blend_xy_sep_transform(self.transData, self.transAxes)
+ trans = mtransforms.blend_xy_sep_transform(self.transData, self.transAxes)
 verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)]
 p = mpatches.Polygon(verts, **kwargs)
 p.set_transform(trans)
@@ -4104,7 +4095,7 @@
 offsets = zip(x,y),
 transOffset = self.transData,
 )
- collection.set_transform(maffine.Affine2D())
+ collection.set_transform(mtransforms.Affine2D())
 collection.set_alpha(alpha)
 collection.update(kwargs)
 
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -15,10 +15,10 @@
 from ticker import NullFormatter, FixedFormatter, ScalarFormatter, LogFormatter
 from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, AutoLocator
 
-from affine import Affine2D, Bbox, blend_xy_sep_transform, interval_contains, \
- interval_contains_open
 from font_manager import FontProperties
 from text import Text, TextWithDash, _process_text_args
+from transforms import Affine2D, Bbox, blended_transform_factory, interval_contains, \
+ interval_contains_open
 from patches import bbox_artist
 
 import matplotlib.units as units
@@ -236,7 +236,7 @@
 xaxis=True,
 )
 
-	trans = blend_xy_sep_transform(
+	trans = blended_transform_factory(
 	 self.axes.transData, self.axes.transAxes)
 #offset the text downward with a post transformation
 	trans = trans + Affine2D().translate(0, -1 * self._padPixels)
@@ -261,7 +261,7 @@
 horizontalalignment='center',
 )
 
-	trans = blend_xy_sep_transform(
+	trans = blended_transform_factory(
 	 self.axes.transData, self.axes.transAxes)
 # offset the text upward with a post transformation
 trans = trans + Affine2D().translate(0, self._padPixels)
@@ -279,7 +279,7 @@
 marker = self._xtickmarkers[0],
 markersize=self._size,
 )
- l.set_transform(blend_xy_sep_transform(
+ l.set_transform(blended_transform_factory(
 		self.axes.transData, self.axes.transAxes) )
 self._set_artist_props(l)
 return l
@@ -295,7 +295,7 @@
 markersize=self._size,
 )
 
- l.set_transform(blend_xy_sep_transform(
+ l.set_transform(blended_transform_factory(
 		self.axes.transData, self.axes.transAxes) )
 self._set_artist_props(l)
 return l
@@ -310,7 +310,7 @@
 antialiased=False,
 )
 l.set_transform(
-	 blend_xy_sep_transform(
+	 blended_transform_factory(
 		self.axes.transData, self.axes.transAxes))
 l.set_clip_box(self.axes.bbox)
 self._set_artist_props(l)
@@ -359,7 +359,7 @@
 dashdirection=0,
 xaxis=False,
 )
- trans = blend_xy_sep_transform(
+ trans = blended_transform_factory(
 	 self.axes.transAxes, self.axes.transData)
 # offset the text leftward with a post transformation
 	trans = trans + Affine2D().translate(-1 * self._padPixels, 0)
@@ -382,7 +382,7 @@
 xaxis=False,
 horizontalalignment='left',
 )
- trans = blend_xy_sep_transform(
+ trans = blended_transform_factory(
 	 self.axes.transAxes, self.axes.transData)
 # offset the text rightward with a post transformation
 	trans = trans + Affine2D().translate(self._padPixels, 0)
@@ -401,7 +401,7 @@
 markersize=self._size,
 )
 l.set_transform(
-	 blend_xy_sep_transform(
+	 blended_transform_factory(
 		self.axes.transAxes, self.axes.transData))
 self._set_artist_props(l)
 return l
@@ -417,7 +417,7 @@
 )
 
 l.set_transform(
-	 blend_xy_sep_transform(
+	 blended_transform_factory(
 		self.axes.transAxes, self.axes.transData))
 self._set_artist_props(l)
 return l
@@ -432,7 +432,7 @@
 antialiased=False,
 )
 
- l.set_transform( blend_xy_sep_transform(
+ l.set_transform( blended_transform_factory(
 		self.axes.transAxes, self.axes.transData) )
 l.set_clip_box(self.axes.bbox)
 
@@ -979,7 +979,7 @@
 verticalalignment='top',
 horizontalalignment='center',
 )
- label.set_transform( blend_xy_sep_transform(
+ label.set_transform( blended_transform_factory(
 		self.axes.transAxes, Affine2D() ))
 
 self._set_artist_props(label)
@@ -994,7 +994,7 @@
 verticalalignment='top',
 horizontalalignment='right',
 )
- offsetText.set_transform( blend_xy_sep_transform(
+ offsetText.set_transform( blended_transform_factory(
 		self.axes.transAxes, Affine2D() ))
 self._set_artist_props(offsetText)
 self.offset_text_position='bottom'
@@ -1169,7 +1169,7 @@
 horizontalalignment='right',
 rotation='vertical',
 )
- label.set_transform( blend_xy_sep_transform(
+ label.set_transform( blended_transform_factory(
 		Affine2D(), self.axes.transAxes) )
 
 self._set_artist_props(label)
@@ -1184,7 +1184,7 @@
 verticalalignment = 'bottom',
 horizontalalignment = 'left',
 )
- offsetText.set_transform(blend_xy_sep_transform(
+ offsetText.set_transform(blended_transform_factory(
 		self.axes.transAxes, Affine2D()) )
 self._set_artist_props(offsetText)
 self.offset_text_position='left'
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -84,7 +84,7 @@
 from matplotlib.font_manager import findfont
 from matplotlib.ft2font import FT2Font, LOAD_DEFAULT
 from matplotlib.mathtext import MathTextParser
-from matplotlib.affine import Bbox
+from matplotlib.transforms import Bbox
 
 from _backend_agg import RendererAgg as _RendererAgg
 
@@ -115,15 +115,10 @@
 'debug-annoying')
 # self.draw_polygon = self._renderer.draw_polygon
 self.draw_rectangle = self._renderer.draw_rectangle
- self.draw_path = self._renderer.draw_path
 	# MGDTODO -- remove these lines
 # self.draw_lines = self._renderer.draw_lines
 # self.draw_markers = self._renderer.draw_markers
 self.draw_image = self._renderer.draw_image
- self.draw_line_collection = self._renderer.draw_line_collection
- self.draw_quad_mesh = self._renderer.draw_quad_mesh
- self.draw_poly_collection = self._renderer.draw_poly_collection
- self.draw_regpoly_collection = self._renderer.draw_regpoly_collection
 
 self.copy_from_bbox = self._renderer.copy_from_bbox
 self.restore_region = self._renderer.restore_region
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -18,8 +18,8 @@
 from text import Text, _process_text_args
 
 from legend import Legend
-from affine import Affine2D, Bbox, BboxTransform, TransformedBbox
 from ticker import FormatStrFormatter
+from transforms import Affine2D, Bbox, BboxTransform, TransformedBbox
 from cm import ScalarMappable
 from contour import ContourSet
 import warnings
Modified: branches/transforms/lib/matplotlib/finance.py
===================================================================
--- branches/transforms/lib/matplotlib/finance.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/finance.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -22,7 +22,7 @@
 from matplotlib.colors import colorConverter
 from lines import Line2D, TICKLEFT, TICKRIGHT
 from patches import Rectangle
-from matplotlib.affine import Affine2D
+from matplotlib.transforms import Affine2D
 
 
 
Modified: branches/transforms/lib/matplotlib/legend.py
===================================================================
--- branches/transforms/lib/matplotlib/legend.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/legend.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -34,7 +34,7 @@
 from patches import Patch, Rectangle, RegularPolygon, Shadow, bbox_artist, draw_bbox
 from collections import LineCollection, RegularPolyCollection, PatchCollection
 from text import Text
-from affine import Bbox, BboxTransform
+from transforms import Bbox, BboxTransform
 
 def line_cuts_bbox(line, bbox):
 """ Return True if and only if line cuts bbox. """
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -14,10 +14,10 @@
 import numerix.ma as ma
 from matplotlib import verbose
 import artist
-from affine import Bbox
 from artist import Artist, setp
 from cbook import iterable, is_string_like, is_numlike
 from colors import colorConverter
+from transforms import Bbox
 
 from matplotlib import rcParams
 
Modified: branches/transforms/lib/matplotlib/table.py
===================================================================
--- branches/transforms/lib/matplotlib/table.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/table.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -29,7 +29,7 @@
 from patches import Rectangle
 from cbook import enumerate, is_string_like, flatten
 from text import Text
-from affine import Bbox
+from transforms import Bbox
 
 
 
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -15,7 +15,7 @@
 from cbook import enumerate, is_string_like, maxdict, is_numlike
 from font_manager import FontProperties
 from patches import bbox_artist, YAArrow
-from affine import Affine2D, Bbox
+from transforms import Affine2D, Bbox
 from lines import Line2D
 
 import matplotlib.nxutils as nxutils
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月14日 12:24:20 UTC (rev 3850)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -109,7 +109,7 @@
 import matplotlib as mpl
 from matplotlib import verbose, rcParams
 from matplotlib import cbook
-from matplotlib import affine as maffine
+from matplotlib import transforms as mtransforms
 
 
 
@@ -540,7 +540,7 @@
 def autoscale(self):
 'autoscale the view limits'
 self.verify_intervals()
- return maffine.nonsingular(*self.dataInterval.get_bounds())
+ return mtransforms.nonsingular(*self.dataInterval.get_bounds())
 
 def pan(self, numsteps):
 'Pan numticks (can be positive or negative)'
@@ -682,7 +682,7 @@
 vmin = math.floor(scale*vmin)/scale
 vmax = math.ceil(scale*vmax)/scale
 
- return maffine.nonsingular(vmin, vmax)
+ return mtransforms.nonsingular(vmin, vmax)
 
 
 def closeto(x,y):
@@ -766,7 +766,7 @@
 vmin -=1
 vmax +=1
 
- return maffine.nonsingular(vmin, vmax)
+ return mtransforms.nonsingular(vmin, vmax)
 
 def scale_range(vmin, vmax, n = 1, threshold=100):
 dv = abs(vmax - vmin)
@@ -833,12 +833,12 @@
 
 def __call__(self):
 vmin, vmax = self.axis.get_view_interval()
- vmin, vmax = maffine.nonsingular(vmin, vmax, expander = 0.05)
+ vmin, vmax = mtransforms.nonsingular(vmin, vmax, expander = 0.05)
 return self.bin_boundaries(vmin, vmax)
 
 def autoscale(self):
 dmin, dmax = self.axis.get_data_interval()
- dmin, dmax = maffine.nonsingular(dmin, dmax, expander = 0.05)
+ dmin, dmax = mtransforms.nonsingular(dmin, dmax, expander = 0.05)
 return npy.take(self.bin_boundaries(dmin, dmax), [0,-1])
 
 
@@ -939,7 +939,7 @@
 if vmin==vmax:
 vmin = decade_down(vmin,self._base)
 vmax = decade_up(vmax,self._base)
- return maffine.nonsingular(vmin, vmax)
+ return mtransforms.nonsingular(vmin, vmax)
 
 class AutoLocator(MaxNLocator):
 def __init__(self):
Copied: branches/transforms/lib/matplotlib/transforms.py (from rev 3849, branches/transforms/lib/matplotlib/affine.py)
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月14日 13:03:31 UTC (rev 3851)
@@ -0,0 +1,852 @@
+"""
+A set of classes to handle transformations.
+
+2007 Michael Droettboom
+"""
+
+import numpy as npy
+from numpy.linalg import inv
+from sets import Set
+
+# MGDTODO: This creates a ton of cyclical references. We may want to
+# consider using weak references
+
+# MGDTODO: deep copying is probably incorrect wrt the parent/child
+# relationships
+
+class TransformNode(object):
+ def __init__(self):
+ self._parents = Set()
+ 
+ def invalidate(self):
+ if not self._do_invalidation():
+ for parent in self._parents:
+ parent.invalidate()
+
+ def _do_invalidation(self):
+ return False
+
+ def set_children(self, children):
+ for child in children:
+ getattr(self, child)._parents.add(self)
+ self._children = children
+
+ # MGDTODO: decide whether we need this in-place updating and
+ # remove if not
+# def replace_child(self, index, child):
+# children = self._children
+# getattr(self, children[index])._parents.remove(self)
+# setattr(self, children[index], child)
+# # We have to reset children in case two or more
+# # of the children are the same
+# for child in children:
+# getattr(self, child)._parents.add(self)
+# self.invalidate()
+ 
+class BboxBase(TransformNode):
+ '''
+ This is the read-only part of a bounding-box
+ '''
+ 
+ def __init__(self):
+ TransformNode.__init__(self)
+ 
+ def __array__(self):
+ return self.get_points()
+ 
+ # MGDTODO: Probably a more efficient ways to do this...
+ def _get_xmin(self):
+ return self.get_points()[0, 0]
+ xmin = property(_get_xmin)
+ 
+ def _get_ymin(self):
+ return self.get_points()[0, 1]
+ ymin = property(_get_ymin)
+
+ def _get_xmax(self):
+ return self.get_points()[1, 0]
+ xmax = property(_get_xmax)
+
+ def _get_ymax(self):
+ return self.get_points()[1, 1]
+ ymax = property(_get_ymax)
+
+ def _get_min(self):
+ return self.get_points()[0]
+ min = property(_get_min)
+ 
+ def _get_max(self):
+ return self.get_points()[1]
+ max = property(_get_max)
+ 
+ def _get_intervalx(self):
+ return self.get_points()[:, 0]
+ intervalx = property(_get_intervalx)
+
+ def _get_intervaly(self):
+ return self.get_points()[:, 1]
+ intervaly = property(_get_intervaly)
+ 
+ def _get_width(self):
+ return self.xmax - self.xmin
+ width = property(_get_width)
+
+ def _get_height(self):
+ return self.ymax - self.ymin
+ height = property(_get_height)
+
+ def _get_bounds(self):
+ return (self.xmin, self.ymin,
+ self.xmax - self.xmin, self.ymax - self.ymin)
+ bounds = property(_get_bounds)
+
+ def get_points(self):
+ return NotImplementedError()
+
+ # MGDTODO: Optimize
+ def containsx(self, x):
+ return x >= self.xmin and x <= self.xmax
+
+ def containsy(self, y):
+ return y >= self.ymin and y <= self.ymax
+ 
+ def contains(self, x, y):
+ return self.containsx(x) and self.containsy(y)
+
+ def overlapsx(self, other):
+ return self.containsx(other.xmin) \
+ or self.containsx(other.xmax)
+
+ def overlapsy(self, other):
+ return self.containsy(other.ymin) \
+ or self.containsx(other.ymax)
+ 
+ def overlaps(self, other):
+ return self.overlapsx(other) \
+ and self.overlapsy(other)
+ 
+ def fully_containsx(self, x):
+ return x > self.xmin and x < self.xmax
+
+ def fully_containsy(self, y):
+ return y > self.ymin and y < self.ymax
+ 
+ def fully_contains(self, x, y):
+ return self.fully_containsx(x) \
+ and self.fully_containsy(y)
+
+ def fully_overlapsx(self, other):
+ return self.fully_containsx(other.xmin) \
+ or self.fully_containsx(other.xmax)
+
+ def fully_overlapsy(self, other):
+ return self.fully_containsy(other.ymin) \
+ or self.fully_containsx(other.ymax)
+ 
+ def fully_overlaps(self, other):
+ return self.fully_overlapsx(other) and \
+ self.fully_overlapsy(other)
+
+ 
+class Bbox(BboxBase):
+ def __init__(self, points):
+ BboxBase.__init__(self)
+ self._points = npy.asarray(points, npy.float_)
+
+ #@staticmethod
+ def unit():
+ return Bbox.from_lbrt(0., 0., 1., 1.)
+ unit = staticmethod(unit)
+
+ #@staticmethod
+ def from_lbwh(left, bottom, width, height):
+ return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
+ from_lbwh = staticmethod(from_lbwh)
+
+ #@staticmethod
+ def from_lbrt(*args):
+ points = npy.array(args, dtype=npy.float_).reshape(2, 2)
+ return Bbox(points)
+ from_lbrt = staticmethod(from_lbrt)
+ 
+ def __copy__(self):
+ return Bbox(self._points.copy())
+
+ def __deepcopy__(self, memo):
+ return Bbox(self._points.copy())
+ 
+ def __cmp__(self, other):
+ # MGDTODO: Totally suboptimal
+ if isinstance(other, Bbox) and (self._points == other._points).all():
+ return 0
+ return -1
+
+ def __repr__(self):
+ return 'Bbox(%s)' % repr(self._points)
+ __str__ = __repr__
+
+ # JDH: the update method will update the box limits from the
+ # existing limits and the new data; it appears here you are just
+ # using the new data. We use an "ignore" flag to specify whether
+ # you want to include the existing data or not in the update
+ def update_from_data(self, x, y, ignore=True):
+ self._points = npy.array(
+ [[x.min(), y.min()], [x.max(), y.max()]],
+ npy.float_)
+ self.invalidate()
+
+ # MGDTODO: Probably a more efficient ways to do this...
+ def _set_xmin(self, val):
+ self._points[0, 0] = val
+ self.invalidate()
+ xmin = property(BboxBase._get_xmin, _set_xmin)
+
+ def _set_ymin(self, val):
+ self._points[0, 1] = val
+ self.invalidate()
+ ymin = property(BboxBase._get_ymin, _set_ymin)
+
+ def _set_xmax(self, val):
+ self._points[1, 0] = val
+ self.invalidate()
+ xmax = property(BboxBase._get_xmax, _set_xmax)
+
+ def _set_ymax(self, val):
+ self._points[1, 1] = val
+ self.invalidate()
+ ymax = property(BboxBase._get_ymax, _set_ymax)
+
+ def _set_min(self, val):
+ self._points[0] = val
+ self.invalidate()
+ min = property(BboxBase._get_min, _set_min)
+ 
+ def _set_max(self, val):
+ self._points[1] = val
+ self.invalidate()
+ max = property(BboxBase._get_max, _set_max)
+ 
+ def _set_intervalx(self, interval):
+ self._points[:, 0] = interval
+ self.invalidate()
+ intervalx = property(BboxBase._get_intervalx, _set_intervalx)
+
+ def _set_intervaly(self, interval):
+ self._points[:, 1] = interval
+ self.invalidate()
+ intervaly = property(BboxBase._get_intervaly, _set_intervaly)
+
+ def _set_bounds(self, bounds):
+ l,b,w,h = bounds
+ self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
+ self.invalidate()
+ bounds = property(BboxBase._get_bounds, _set_bounds)
+
+ def get_points(self):
+ return self._points
+
+ def set_points(self, points):
+ self._points = points
+ self.invalidate()
+
+ def set(self, other):
+ self._points = other.get_points()
+ self.invalidate()
+ 
+ def transformed(self, transform):
+ return Bbox(transform(self._points))
+
+ def inverse_transformed(self, transform):
+ return Bbox(transform.inverted()(self._points))
+ 
+ def expanded(self, sw, sh):
+ width = self.width
+ height = self.height
+ deltaw = (sw * width - width) / 2.0
+ deltah = (sh * height - height) / 2.0
+ a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
+ return Bbox(self._points + a)
+
+ #@staticmethod
+ def union(bboxes):
+ """
+ Return the Bbox that bounds all bboxes
+ """
+ assert(len(bboxes))
+
+ if len(bboxes) == 1:
+ return bboxes[0]
+
+ bbox = bboxes[0]
+ xmin = bbox.xmin
+ ymin = bbox.ymin
+ xmax = bbox.xmax
+ ymax = bbox.ymax
+
+ for bbox in bboxes[1:]:
+ xmin = min(xmin, bbox.xmin)
+ ymin = min(ymin, bbox.ymin)
+ xmax = max(xmax, bbox.xmax)
+ ymax = max(ymax, bbox.ymax)
+
+ return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+ union = staticmethod(union)
+
+class TransformedBbox(BboxBase):
+ def __init__(self, bbox, transform):
+ assert isinstance(bbox, Bbox)
+ assert isinstance(transform, Transform)
+
+ BboxBase.__init__(self)
+ self.bbox = bbox
+ self.transform = transform
+ self.set_children(['bbox', 'transform'])
+ self._points = None
+
+ def __repr__(self):
+ return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+ __str__ = __repr__
+ 
+ def _do_invalidation(self):
+ self._points = None
+
+ def get_points(self):
+ if self._points is None:
+ self._points = self.transform(self.bbox.get_points())
+ return self._points
+
+# MGDTODO: This code probably works, but I don't think it's a good idea
+# (from a code clarity perspective)
+# class BlendedBbox(BboxBase):
+# def __init__(self, bbox_x, bbox_y):
+# assert isinstance(bbox_x, BboxBase)
+# assert isinstance(bbox_y, BboxBase)
+
+# BboxBase.__init__(self)
+# self._x = bbox_x
+# self._y = bbox_y
+# self.set_children(['_x', '_y'])
+# self._points = None
+
+# def __repr__(self):
+# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+# __str__ = __repr__
+ 
+# def _do_invalidation(self):
+# self._points = None
+
+# def get_points(self):
+# if self._points is None:
+# # MGDTODO: Optimize
+# if self._x == self._y:
+# self._points = self._x.get_points()
+# else:
+# x_points = self._x.get_points()
+# y_points = self._y.get_points()
+# self._points = npy.array(
+# [[x_points[0,0], y_points[0,1]],
+# [x_points[1,0], y_points[1,1]]],
+# npy.float_)
+# return self._points
+
+# def _set_intervalx(self, pair):
+# # MGDTODO: Optimize
+# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
+# self.replace_child(0, bbox)
+# intervalx = property(BboxBase._get_intervalx, _set_intervalx)
+
+# def _set_intervaly(self, pair):
+# # MGDTODO: Optimize
+# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
+# self.replace_child(1, bbox)
+# intervaly = property(BboxBase._get_intervaly, _set_intervaly)
+ 
+class Transform(TransformNode):
+ def __init__(self):
+ TransformNode.__init__(self)
+ 
+ def __call__(self, points):
+ raise NotImplementedError()
+
+ def __add__(self, other):
+ if isinstance(other, Transform):
+ return composite_transform_factory(self, other)
+ raise TypeError(
+ "Can not add Transform to object of type '%s'" % type(other))
+
+ def __radd__(self, other):
+ if isinstance(other, Transform):
+ return composite_transform_factory(other, self)
+ raise TypeError(
+ "Can not add Transform to object of type '%s'" % type(other))
+
+ def transform_point(self, point):
+ return self.__call__(npy.asarray([point]))[0]
+ 
+ def has_inverse(self):
+ raise NotImplementedError()
+ 
+ def inverted(self):
+ raise NotImplementedError()
+
+ def is_separable(self):
+ return False
+
+ def is_affine(self):
+ return False
+
+class Affine2DBase(Transform):
+ input_dims = 2
+ output_dims = 2
+
+ def __init__(self):
+ Transform.__init__(self)
+ self._inverted = None
+
+ def _do_invalidation(self):
+ result = self._inverted is None
+ self._inverted = None
+ return result
+
+ #@staticmethod
+ def _concat(a, b):
+ return npy.dot(b, a)
+ _concat = staticmethod(_concat)
+
+ #@staticmethod
+ def concat(a, b):
+ return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix()))
+ concat = staticmethod(concat)
+ 
+ def to_values(self):
+ mtx = self.get_matrix()
+ return tuple(mtx[:2].swapaxes(0, 1).flatten())
+ 
+ #@staticmethod
+ def matrix_from_values(a, b, c, d, e, f):
+ affine = npy.zeros((3, 3), npy.float_)
+ affine[0, ] = a, c, e
+ affine[1, ] = b, d, f
+ affine[2, 2] = 1
+ return affine
+ matrix_from_values = staticmethod(matrix_from_values)
+
+ def get_matrix(self):
+ raise NotImplementedError()
+ 
+ def __call__(self, points):
+ """
+ Applies the transformation to an array of 2D points and
+ returns the result.
+
+ points must be a numpy array of shape (N, 2), where N is the
+ number of points.
+ """
+ # MGDTODO: The major speed trap here is just converting to
+ # the points to an array in the first place. If we can use
+ # more arrays upstream, that should help here.
+ if not isinstance(points, npy.ndarray):
+ import traceback
+ print '-' * 60
+ print 'A non-numpy array was passed in for transformation. Please '
+ print 'correct this.'
+ print "".join(traceback.format_stack())
+ print points
+ mtx = self.get_matrix()...
 
[truncated message content]
Revision: 3850
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3850&view=rev
Author: mdboom
Date: 2007年09月14日 05:24:20 -0700 (2007年9月14日)
Log Message:
-----------
Deleting this file to rename affine.py
Removed Paths:
-------------
 branches/transforms/lib/matplotlib/transforms.py
Deleted: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py	2007年09月14日 12:23:06 UTC (rev 3849)
+++ branches/transforms/lib/matplotlib/transforms.py	2007年09月14日 12:24:20 UTC (rev 3850)
@@ -1,652 +0,0 @@
-# """
-# The transforms module is broken into two parts, a collection of
-# classes written in the extension module _transforms to handle
-# efficient transformation of data, and some helper functions in
-# transforms to make it easy to instantiate and use those objects.
-# Hence the core of this module lives in _transforms.
-
-# The transforms class is built around the idea of a LazyValue. A
-# LazyValue is a base class that defines a method get that returns the
-# value. The concrete derived class Value wraps a float, and simply
-# returns the value of that float. The concrete derived class BinOp
-# allows binary operations on LazyValues, so you can add them, multiply
-# them, etc. When you do something like
-
-# inches = Value(8)
-# dpi = Value(72)
-# width = inches * dpi
-
-# width is a BinOp instance (that tells you the width of the figure in
-# pixels). Later, if the figure size in changed, ie we call
-
-# inches.set(10)
-
-# The width variable is automatically updated because it stores a
-# pointer to the inches variable, not the value. Since a BinOp is also
-# a lazy value, you can define binary operations on BinOps as well, such
-# as
-
-# middle = Value(0.5) * width
-
-# Pairs of LazyValue instances can occur as instances of two classes:
-
-# pt = Point( Value(x), Value(y)) # where x, y are numbers
-# pt.x(), pt.y() return Value(x), Value(y))
-
-# iv = Interval( Value(x), Value(y))
-# iv.contains(z) returns True if z is in the closed interval
-# iv.contains_open(z): same for open interval
-# iv.span() returns y-x as a float
-# iv.get_bounds() returns (x,y) as a tuple of floats
-# iv.set_bounds(x, y) allows input of new floats
-# iv.update(seq) updates the bounds to include all elements
-# in a sequence of floats
-# iv.shift(s) shifts the interval by s, a float
-
-# The bounding box class Bbox is also heavily used, and is defined by a
-# lower left point ll and an upper right point ur. The points ll and ur
-# are given by Point(x, y) instances, where x and y are LazyValues. So
-# you can represent a point such as
-
-# ll = Point( Value(0), Value(0) ) # the origin
-# ur = Point( width, height ) # the upper right of the figure
-
-# where width and height are defined as above, using the product of the
-# figure width in inches and the dpi. This is, in face, how the Figure
-# bbox is defined
-
-# bbox = Bbox(ll, ur)
-
-# A bbox basically defines an x,y coordinate system, with ll giving the
-# lower left of the coordinate system and ur giving the upper right.
-
-# The bbox methods are
-
-# ll() - return the lower left Point
-# ur() - return the upper right Point
-# contains(x,y) - return True if self contains point
-# overlaps(bbox) - return True if self overlaps bbox
-# overlapsx(bbox) - return True if self overlaps bbox in the x interval
-# overlapsy(bbox) - return True if self overlaps bbox in the y interval
-# intervalx() - return the x Interval instance
-# intervaly() - return the y interval instance
-# get_bounds() - get the left, bottom, width, height bounding tuple
-# update(xys, ignore) - update the bbox to bound all the xy tuples in
-# xys; if ignore is true ignore the current contents of bbox and
-# just bound the tuples. If ignore is false, bound self + tuples
-# width() - return the width of the bbox
-# height() - return the height of the bbox
-# xmax() - return the x coord of upper right
-# ymax() - return the y coord of upper right
-# xmin() - return the x coord of lower left
-# ymin() - return the y coord of lower left
-# scale(sx,sy) - scale the bbox by sx, sy
-# deepcopy() - return a deep copy of self (pointers are lost)
-
-
-# The basic transformation maps one bbox to another, with an optional
-# nonlinear transformation of one of coordinates (eg log scaling).
-
-# The base class for transformations is Transformation, and the concrete
-# derived classes are SeparableTransformation and Affine. Earlier
-# versions of matplotlib handled transformation of x and y separately
-# (ie we assumed all transformations were separable) but this makes it
-# difficult to do rotations or polar transformations, for example. All
-# artists contain their own transformation, defaulting to the identity
-# transform.
-
-# The signature of a separable transformation instance is
-
-# trans = SeparableTransformation(bbox1, bbox2, funcx, funcy)
-
-# where funcx and funcy operate on x and y. The typical linear
-# coordinate transformation maps one bounding box to another, with funcx
-# and funcy both identity. Eg,
-
-# transData = Transformation(viewLim, displayLim,
-# Func(IDENTITY), Func(IDENTITY))
-
-# maps the axes view limits to display limits. If the xaxis scaling is
-# changed to log, one simply calls
-
-# transData.get_funcx().set_type(LOG10)
-
-# For more general transformations including rotation, the Affine class
-# is provided, which is constructed with 6 LazyValue instances:
-# a, b, c, d, tx, ty. These give the values of the matrix transformation
-
-# [xo = |a c| [xi + [tx
-# yo] |b d| yi] ty]
-
-# where if sx, sy are the scaling components, tx, y are the translation
-# components, and alpha is the rotation
-
-# a = sx*cos(alpha);
-# b = -sx*sin(alpha);
-# c = sy*sin(alpha);
-# d = sy*cos(alpha);
-
-# The affine transformation can be accomplished for row vectors with a
-# single matrix multiplication
-# X_new = X_old * M
-# where
-# M = [ a b 0
-# c d 0
-# tx ty 1]
-# and each X is the row vector [x, y, 1]. Hence M is
-# the transpose of the matrix representation given in
-# http://en.wikipedia.org/wiki/Affine_transformation,
-# which is for the more usual column-vector representation
-# of the position.)
-
-
-
-# From a user perspective, the most important Tranformation methods are
-
-# All transformations
-# -------------------
-# freeze() - eval and freeze the lazy objects
-# thaw() - release the lazy objects
-
-# xy_tup(xy) - transform the tuple (x,y)
-# seq_x_y(x, y) - transform the python sequences x and y
-# numerix_x_y(x, y) - x and y are numerix 1D arrays
-# numerix_xy(xy) - xy is a numerix array of shape (N,2)
-# inverse_numerix_xy(xy)- inverse of the above
-# seq_xy_tups(seq) - seq is a sequence of xy tuples or a (N,2) array
-# inverse_xy_tup(xy) - apply the inverse transformation to tuple xy
-
-# set_offset(xy, trans) - xy is an x,y tuple and trans is a
-# Transformation instance. This will apply a post transformational
-# offset of all future transformations by xt,yt = trans.xy_tup(xy[0], xy[1])
-
-# deepcopy() - returns a deep copy; references are lost
-# shallowcopy() - returns a shallow copy excluding the offset
-
-# Separable transformations
-# -------------------------
-
-# get_bbox1() - return the input bbox
-# get_bbox2() - return the output bbox
-# set_bbox1() - set the input bbox
-# set_bbox2() - set the output bbox
-# get_funcx() - return the Func instance on x
-# get_funcy() - return the Func instance on y
-# set_funcx() - set the Func instance on x
-# set_funcy() - set the Func instance on y
-
-
-# Affine transformations
-# ----------------------
-
-# as_vec6() - return the affine as length 6 list of Values
-
-
-# In general, you shouldn't need to construct your own transformations,
-# but should use the helper functions defined in this module.
-
-
-# zero - return Value(0)
-# one - return Value(1)
-# origin - return Point(zero(), zero())
-# unit_bbox - return the 0,0 to 1,1 bounding box
-# identity_affine - An affine identity transformation
-# identity_transform - An identity separable transformation
-# translation_transform - a pure translational affine
-# scale_transform - a pure scale affine
-# scale_sep_transform - a pure scale separable transformation
-# scale_translation_transform - a scale and translate affine
-# bound_vertices - return the bbox that bounds all the xy tuples
-# bbox_all - return the bbox that bounds all the bboxes
-# lbwh_to_bbox - build a bbox from tuple
-# left, bottom, width, height tuple
-
-# multiply_affines - return the affine that is the matrix product of
-# the two affines
-
-# get_bbox_transform - return a SeparableTransformation instance that
-# transforms one bbox to another
-
-# blend_xy_sep_transform - mix the x and y components of two separable
-# transformations into a new transformation.
-# This allows you to specify x and y in
-# different coordinate systems
-
-# transform_bbox - apply a transformation to a bbox and return the
-# transformed bbox
-
-# inverse_transform_bbox - apply the inverse transformation of a bbox
-# and return the inverse transformed bbox
-
-# offset_copy - make a copy with an offset
-
-
-# The units/transform_unit.py code has many examples.
-
-# A related and partly overlapping class, PBox, has been added to the
-# original transforms module to facilitate Axes repositioning and resizing.
-# At present, the differences between Bbox and PBox include:
-
-# Bbox works with the bounding box, the coordinates of the lower-left
-# and upper-right corners; PBox works with the lower-left coordinates
-# and the width, height pair (left, bottom, width, height, or 'lbwh').
-# Obviously, these are equivalent, but lbwh is what is used by
-# Axes._position, and it is the natural specification for the types of
-# manipulations for which the PBox class was made.
-
-# Bbox uses LazyValues grouped in pairs as 'll' and 'ur' Point objects;
-# PBox uses a 4-element list, subclassed from the python list.
-
-# Bbox and PBox methods are mostly quite different, reflecting their
-# different original purposes. Similarly, the CXX implementation of
-# Bbox is good for methods such as update and for lazy evaluation, but
-# for PBox intended uses, involving very little calculation, pure
-# python probably is adequate.
-
-# In the future we may reimplement the PBox using Bbox
-# and transforms, or eliminate it entirely by adding its methods
-# and attributes to Bbox and/or putting them elsewhere in this module.
-# """
-# from __future__ import division
-# import math
-# import numpy as npy
-
-# from matplotlib._transforms import Value, Point, Interval, Bbox, Affine
-# from matplotlib._transforms import IDENTITY, LOG10, POLAR, Func, FuncXY
-# from matplotlib._transforms import SeparableTransformation
-# from matplotlib._transforms import NonseparableTransformation
-
-# def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
-# '''
-# Ensure the endpoints of a range are not too close together.
-
-# "too close" means the interval is smaller than 'tiny' times
-# the maximum absolute value.
-
-# If they are too close, each will be moved by the 'expander'.
-# If 'increasing' is True and vmin > vmax, they will be swapped,
-# regardless of whether they are too close.
-# '''
-# swapped = False
-# if vmax < vmin:
-# vmin, vmax = vmax, vmin
-# swapped = True
-# if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
-# if vmin==0.0:
-# vmin = -expander
-# vmax = expander
-# else:
-# vmin -= expander*abs(vmin)
-# vmax += expander*abs(vmax)
-# if swapped and not increasing:
-# vmin, vmax = vmax, vmin
-# return vmin, vmax
-
-
-# def zero(): return Value(0)
-
-# def one() : return Value(1)
-
-# def origin():
-# return Point( zero(), zero() )
-
-# def unit_bbox():
-# """
-# Get a 0,0 -> 1,1 Bbox instance
-# """
-# return Bbox( origin(), Point( one(), one() ) )
-
-# def identity_affine():
-# """
-# Get an affine transformation that maps x,y -> x,y
-# """
-
-# return Affine(one(), zero(), zero(), one(), zero(), zero())
-
-# def identity_transform():
-# """
-# Get an affine transformation that maps x,y -> x,y
-# """
-# return SeparableTransformation(unit_bbox(), unit_bbox(),
-# Func(IDENTITY),
-# Func(IDENTITY))
-
-# def translation_transform(tx, ty):
-# """
-# return a pure tranlational transformation tx and ty are LazyValue
-# instances (Values or binary operations on values)
-# """
-# return Affine(one(), zero(), zero(), one(), tx, ty)
-
-# def scale_transform(sx, sy):
-# """
-# Return a pure scale transformation as an Affine instance; sx and
-# sy are LazyValue instances (Values or binary opertations on
-# values)
-# """
-# return Affine(sx, zero(), zero(), sy, zero(), zero())
-
-# def scale_sep_transform(sx, sy):
-# """
-# Return a pure scale transformation as a SeparableTransformation;
-# sx and sy are LazyValue instances (Values or binary opertations on
-# values)
-# """
-
-# bboxin = unit_bbox()
-# bboxout = Bbox( Point( zero(), zero() ),
-# Point( sx, sy ) )
-# return SeparableTransformation(
-# bboxin, bboxout,
-# Func(IDENTITY), Func(IDENTITY))
-
-
-
-# def bound_vertices(verts):
-# """
-# Return the Bbox of the sequence of x,y tuples in verts
-# """
-# # this is a good candidate to move to _transforms
-# bbox = unit_bbox()
-# bbox.update(verts, 1)
-# return bbox
-
-# def bbox_all(bboxes):
-# """
-# Return the Bbox that bounds all bboxes
-# """
-# # this is a good candidate to move to _transforms
-# assert(len(bboxes))
-
-# if len(bboxes)==1: return bboxes[0]
-
-# bbox = bboxes[0]
-# minx = bbox.xmin()
-# miny = bbox.ymin()
-# maxx = bbox.xmax()
-# maxy = bbox.ymax()
-
-# for bbox in bboxes[1:]:
-# thisminx = bbox.xmin()
-# thisminy = bbox.ymin()
-# thismaxx = bbox.xmax()
-# thismaxy = bbox.ymax()
-
-# if thisminx < minx : minx = thisminx
-# if thismaxx > maxx : maxx = thismaxx
-# if thisminy < miny : miny = thisminy
-# if thismaxy > maxy : maxy = thismaxy
-
-# return Bbox( Point( Value(minx), Value(miny) ),
-# Point( Value(maxx), Value(maxy) )
-# )
-
-# def lbwh_to_bbox(l,b,w,h):
-# return Bbox( Point( Value(l), Value(b)),
-# Point( Value(l+w), Value(b + h) ) )
-
-
-# def invert_vec6(v):
-# """
-# v is a,b,c,d,tx,ty vec6 repr of an affine transformation.
-# Return the inverse of v as a vec6
-# """
-# a,b,c,d,tx,ty = v
-# M = npy.array([ [a,b,0], [c,d,0], [tx,ty,1]], dtype=npy.float64)
-# Mi = npy.linalg.inv(M)
-# return Mi[:,:2].ravel()
-
-# def multiply_affines( v1, v2):
-# """
-# v1 and v2 are Affine instances
-# """
-
-# a1, b1, c1, d1, tx1, ty1 = v1.as_vec6()
-# a2, b2, c2, d2, tx2, ty2 = v2.as_vec6()
-
-# a = a1 * a2 + c1 * b2
-# b = b1 * a2 + d1 * b2
-# c = a1 * c2 + c1 * d2
-# d = b1 * c2 + d1 * d2
-# tx = a1 * tx2 + c1 * ty2 + tx1
-# ty = b1 * tx2 + d1 * ty2 + ty1
-# return Affine(a,b,c,d,tx,ty)
-
-# def get_bbox_transform(boxin, boxout):
-# """
-# return the transform that maps transform one bounding box to
-# another
-# """
-# return SeparableTransformation(
-# boxin, boxout, Func(IDENTITY), Func( IDENTITY))
-
-
-# def blend_xy_sep_transform(trans1, trans2):
-# """
-# If trans1 and trans2 are SeparableTransformation instances, you can
-# build a new SeparableTransformation from them by extracting the x and y
-# bounding points and functions and recomposing a new SeparableTransformation
-
-# This function extracts all the relevant bits from trans1 and
-# trans2 and returns the new Transformation instance. This is
-# useful, for example, if you want to specify x in data coordinates
-# and y in axes coordinates.
-# """
-
-# inboxx = trans1.get_bbox1()
-# inboxy = trans2.get_bbox1()
-
-# outboxx = trans1.get_bbox2()
-# outboxy = trans2.get_bbox2()
-
-# xminIn = inboxx.ll().x()
-# xmaxIn = inboxx.ur().x()
-# xminOut = outboxx.ll().x()
-# xmaxOut = outboxx.ur().x()
-
-# yminIn = inboxy.ll().y()
-# ymaxIn = inboxy.ur().y()
-# yminOut = outboxy.ll().y()
-# ymaxOut = outboxy.ur().y()
-
-# funcx = trans1.get_funcx()
-# funcy = trans2.get_funcy()
-
-# boxin = Bbox( Point(xminIn, yminIn), Point(xmaxIn, ymaxIn) )
-# boxout = Bbox( Point(xminOut, yminOut), Point(xmaxOut, ymaxOut) )
-
-# return SeparableTransformation(boxin, boxout, funcx, funcy)
-
-
-# def transform_bbox(trans, bbox):
-# 'transform the bbox to a new bbox'
-# xmin, xmax = bbox.intervalx().get_bounds()
-# ymin, ymax = bbox.intervaly().get_bounds()
-
-# xmin, ymin = trans.xy_tup((xmin, ymin))
-# xmax, ymax = trans.xy_tup((xmax, ymax))
-
-# return Bbox(Point(Value(xmin), Value(ymin)),
-# Point(Value(xmax), Value(ymax)))
-
-# def inverse_transform_bbox(trans, bbox):
-# 'inverse transform the bbox'
-# xmin, xmax = bbox.intervalx().get_bounds()
-# ymin, ymax = bbox.intervaly().get_bounds()
-
-# xmin, ymin = trans.inverse_xy_tup((xmin, ymin))
-# xmax, ymax = trans.inverse_xy_tup((xmax, ymax))
-# return Bbox(Point(Value(xmin), Value(ymin)),
-# Point(Value(xmax), Value(ymax)))
-
-
-# def offset_copy(trans, fig=None, x=0, y=0, units='inches'):
-# '''
-# Return a shallow copy of a transform with an added offset.
-# args:
-# trans is any transform
-# kwargs:
-# fig is the current figure; it can be None if units are 'dots'
-# x, y give the offset
-# units is 'inches', 'points' or 'dots'
-# '''
-# newtrans = trans.shallowcopy()
-# if units == 'dots':
-# newtrans.set_offset((x,y), identity_transform())
-# return newtrans
-# if fig is None:
-# raise ValueError('For units of inches or points a fig kwarg is needed')
-# if units == 'points':
-# x /= 72.0
-# y /= 72.0
-# elif not units == 'inches':
-# raise ValueError('units must be dots, points, or inches')
-# tx = Value(x) * fig.dpi
-# ty = Value(y) * fig.dpi
-# newtrans.set_offset((0,0), translation_transform(tx, ty))
-# return newtrans
-
-
-# def get_vec6_scales(v):
-# 'v is an affine vec6 a,b,c,d,tx,ty; return sx, sy'
-# a,b,c,d = v[:4]
-# sx = math.sqrt(a**2 + b**2)
-# sy = math.sqrt(c**2 + d**2)
-# return sx, sy
-
-# def get_vec6_rotation(v):
-# 'v is an affine vec6 a,b,c,d,tx,ty; return rotation in degrees'
-# sx, sy = get_vec6_scales(v)
-# c,d = v[2:4]
-# angle = math.atan2(c,d)/math.pi*180
-# return angle
-
-
-
-# class PBox(list):
-# '''
-# A left-bottom-width-height (lbwh) specification of a bounding box,
-# such as is used to specify the position of an Axes object within
-# a Figure.
-# It is a 4-element list with methods for changing the size, shape,
-# and position relative to its container.
-# '''
-# coefs = {'C': (0.5, 0.5),
-# 'SW': (0,0),
-# 'S': (0.5, 0),
-# 'SE': (1.0, 0),
-# 'E': (1.0, 0.5),
-# 'NE': (1.0, 1.0),
-# 'N': (0.5, 1.0),
-# 'NW': (0, 1.0),
-# 'W': (0, 0.5)}
-# def __init__(self, box, container=None, llur=False):
-# if len(box) != 4:
-# raise ValueError("Argument must be iterable of length 4")
-# if llur:
-# box = [box[0], box[1], box[2]-box[0], box[3]-box[1]]
-# list.__init__(self, box)
-# self.set_container(container)
-
-# def as_llur(self):
-# return [self[0], self[1], self[0]+self[2], self[1]+self[3]]
-
-# def set_container(self, box=None):
-# if box is None:
-# box = self
-# if len(box) != 4:
-# raise ValueError("Argument must be iterable of length 4")
-# self._container = list(box)
-
-# def get_container(self, box):
-# return self._container
-
-# def anchor(self, c, container=None):
-# '''
-# Shift to position c within its container.
-
-# c can be a sequence (cx, cy) where cx, cy range from 0 to 1,
-# where 0 is left or bottom and 1 is right or top.
-
-# Alternatively, c can be a string: C for centered,
-# S for bottom-center, SE for bottom-left, E for left, etc.
-
-# Optional arg container is the lbwh box within which the
-# PBox is positioned; it defaults to the initial
-# PBox.
-# '''
-# if container is None:
-# container = self._container
-# l,b,w,h = container
-# if isinstance(c, str):
-# cx, cy = self.coefs[c]
-# else:
-# cx, cy = c
-# W,H = self[2:]
-# self[:2] = l + cx * (w-W), b + cy * (h-H)
-# return self
-
-# def shrink(self, mx, my):
-# '''
-# Shrink the box by mx in the x direction and my in the y direction.
-# The lower left corner of the box remains unchanged.
-# Normally mx and my will be <= 1, but this is not enforced.
-# '''
-# assert mx >= 0 and my >= 0
-# self[2:] = mx * self[2], my * self[3]
-# return self
-
-# def shrink_to_aspect(self, box_aspect, fig_aspect = 1):
-# '''
-# Shrink the box so that it is as large as it can be while
-# having the desired aspect ratio, box_aspect.
-# If the box coordinates are relative--that is, fractions of
-# a larger box such as a figure--then the physical aspect
-# ratio of that figure is specified with fig_aspect, so
-# that box_aspect can also be given as a ratio of the
-# absolute dimensions, not the relative dimensions.
-# '''
-# assert box_aspect > 0 and fig_aspect > 0
-# l,b,w,h = self._container
-# H = w * box_aspect/fig_aspect
-# if H <= h:
-# W = w
-# else:
-# W = h * fig_aspect/box_aspect
-# H = h
-# self[2:] = W,H
-# return self
-
-# def splitx(self, *args):
-# '''
-# e.g., PB.splitx(f1, f2, ...)
-
-# Returns a list of new PBoxes formed by
-# splitting the original one (PB) with vertical lines
-# at fractional positions f1, f2, ...
-# '''
-# boxes = []
-# xf = [0] + list(args) + [1]
-# l,b,w,h = self[:]
-# for xf0, xf1 in zip(xf[:-1], xf[1:]):
-# boxes.append(PBox([l+xf0*w, b, (xf1-xf0)*w, h]))
-# return boxes
-
-# def splity(self, *args):
-# '''
-# e.g., PB.splity(f1, f2, ...)
-
-# Returns a list of new PBoxes formed by
-# splitting the original one (PB) with horizontal lines
-# at fractional positions f1, f2, ..., with y measured
-# positive up.
-# '''
-# boxes = []
-# yf = [0] + list(args) + [1]
-# l,b,w,h = self[:]
-# for yf0, yf1 in zip(yf[:-1], yf[1:]):
-# boxes.append(PBox([l, b+yf0*h, w, (yf1-yf0)*h]))
-# return boxes
-
-
-
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月14日 12:23:11
Revision: 3849
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3849&view=rev
Author: mdboom
Date: 2007年09月14日 05:23:06 -0700 (2007年9月14日)
Log Message:
-----------
Committing this file so I can rename it
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月13日 18:00:10 UTC (rev 3848)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月14日 12:23:06 UTC (rev 3849)
@@ -847,12 +847,8 @@
 # assert (tpoints1 == tpoints2).all()
 
 # Here are some timing tests
- points = [(random(), random()) for i in xrange(10000)]
+ points = npy.asarray([(random(), random()) for i in xrange(10000)])
 t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
- print "Time to transform 10000 x 10 points as tuples:", t.timeit(10)
-
- points2 = npy.asarray(points)
- t = timeit.Timer("trans_sum(points2)", "from __main__ import trans_sum, points2")
- print "Time to transform 10000 x 10 points as numpy array:", t.timeit(10)
+ print "Time to transform 10000 x 10 points:", t.timeit(10)
 
 __all__ = ['Transform', 'Affine2D']
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月13日 18:00:12
Revision: 3848
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3848&view=rev
Author: mdboom
Date: 2007年09月13日 11:00:10 -0700 (2007年9月13日)
Log Message:
-----------
New milestone -- resizing figure window works. shared_axis_demo.py
works. (Uses callbacks to track changes between axes's).
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/pyplot.py
 branches/transforms/lib/matplotlib/text.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -20,284 +20,461 @@
 
 class TransformNode(object):
 def __init__(self):
-	self._parents = Set()
-	
+ self._parents = Set()
+ 
 def invalidate(self):
-	if not self._do_invalidation():
-	 for parent in self._parents:
-		parent.invalidate()
+ if not self._do_invalidation():
+ for parent in self._parents:
+ parent.invalidate()
 
 def _do_invalidation(self):
-	return False
-	 
- def add_children(self, children):
-	for child in children:
-	 child._parents.add(self)
+ return False
 
-class Bbox(TransformNode):
+ def set_children(self, children):
+ for child in children:
+ getattr(self, child)._parents.add(self)
+ self._children = children
+
+# def replace_child(self, index, child):
+# children = self._children
+# getattr(self, children[index])._parents.remove(self)
+# setattr(self, children[index], child)
+# # We have to reset children in case two or more
+# # of the children are the same
+# for child in children:
+# getattr(self, child)._parents.add(self)
+# self.invalidate()
+ 
+class BboxBase(TransformNode):
+ '''
+ This is the read-only part of a bounding-box
+ '''
+ 
+ def __init__(self):
+ TransformNode.__init__(self)
+ 
+ def __array__(self):
+ return self.get_points()
+ 
+ # MGDTODO: Probably a more efficient ways to do this...
+ def _get_xmin(self):
+ return self.get_points()[0, 0]
+ xmin = property(_get_xmin)
+ 
+ def _get_ymin(self):
+ return self.get_points()[0, 1]
+ ymin = property(_get_ymin)
+
+ def _get_xmax(self):
+ return self.get_points()[1, 0]
+ xmax = property(_get_xmax)
+
+ def _get_ymax(self):
+ return self.get_points()[1, 1]
+ ymax = property(_get_ymax)
+
+ def _get_min(self):
+ return self.get_points()[0]
+ min = property(_get_min)
+ 
+ def _get_max(self):
+ return self.get_points()[1]
+ max = property(_get_max)
+ 
+ def _get_intervalx(self):
+ return self.get_points()[:, 0]
+ intervalx = property(_get_intervalx)
+
+ def _get_intervaly(self):
+ return self.get_points()[:, 1]
+ intervaly = property(_get_intervaly)
+ 
+ def _get_width(self):
+ return self.xmax - self.xmin
+ width = property(_get_width)
+
+ def _get_height(self):
+ return self.ymax - self.ymin
+ height = property(_get_height)
+
+ def _get_bounds(self):
+ return (self.xmin, self.ymin,
+ self.xmax - self.xmin, self.ymax - self.ymin)
+ bounds = property(_get_bounds)
+
+ def get_points(self):
+ return NotImplementedError()
+
+ # MGDTODO: Optimize
+ def containsx(self, x):
+ return x >= self.xmin and x <= self.xmax
+
+ def containsy(self, y):
+ return y >= self.ymin and y <= self.ymax
+ 
+ def contains(self, x, y):
+ return self.containsx(x) and self.containsy(y)
+
+ def overlapsx(self, other):
+ return self.containsx(other.xmin) \
+ or self.containsx(other.xmax)
+
+ def overlapsy(self, other):
+ return self.containsy(other.ymin) \
+ or self.containsx(other.ymax)
+ 
+ def overlaps(self, other):
+ return self.overlapsx(other) \
+ and self.overlapsy(other)
+ 
+ def fully_containsx(self, x):
+ return x > self.xmin and x < self.xmax
+
+ def fully_containsy(self, y):
+ return y > self.ymin and y < self.ymax
+ 
+ def fully_contains(self, x, y):
+ return self.fully_containsx(x) \
+ and self.fully_containsy(y)
+
+ def fully_overlapsx(self, other):
+ return self.fully_containsx(other.xmin) \
+ or self.fully_containsx(other.xmax)
+
+ def fully_overlapsy(self, other):
+ return self.fully_containsy(other.ymin) \
+ or self.fully_containsx(other.ymax)
+ 
+ def fully_overlaps(self, other):
+ return self.fully_overlapsx(other) and \
+ self.fully_overlapsy(other)
+
+ 
+class Bbox(BboxBase):
 def __init__(self, points):
-	TransformNode.__init__(self)
-	self._points = npy.asarray(points, npy.float_)
-	self.track = False
+ BboxBase.__init__(self)
+ self._points = npy.asarray(points, npy.float_)
 
 #@staticmethod
 def unit():
-	return Bbox.from_lbrt(0., 0., 1., 1.)
+ return Bbox.from_lbrt(0., 0., 1., 1.)
 unit = staticmethod(unit)
 
 #@staticmethod
 def from_lbwh(left, bottom, width, height):
-	return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
+ return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
 from_lbwh = staticmethod(from_lbwh)
 
 #@staticmethod
 def from_lbrt(*args):
-	points = npy.array(args, dtype=npy.float_).reshape(2, 2)
-	return Bbox(points)
+ points = npy.array(args, dtype=npy.float_).reshape(2, 2)
+ return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
 def __copy__(self):
-	return Bbox(self._points.copy())
+ return Bbox(self._points.copy())
 
 def __deepcopy__(self, memo):
-	return Bbox(self._points.copy())
+ return Bbox(self._points.copy())
 
 def __cmp__(self, other):
-	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox) and (self._points == other._points).all():
-	 return 0
-	return -1
+ # MGDTODO: Totally suboptimal
+ if isinstance(other, Bbox) and (self._points == other._points).all():
+ return 0
+ return -1
 
 def __repr__(self):
-	return 'Bbox(%s)' % repr(self._points)
+ return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
- def __array__(self):
-	return self._points
- 
 # JDH: the update method will update the box limits from the
 # existing limits and the new data; it appears here you are just
 # using the new data. We use an "ignore" flag to specify whether
 # you want to include the existing data or not in the update
 def update_from_data(self, x, y, ignore=True):
-	self._points = npy.array([[x.min(), y.min()], [x.max(), y.max()]], npy.float_)
-	self.invalidate()
+ self._points = npy.array(
+ [[x.min(), y.min()], [x.max(), y.max()]],
+ npy.float_)
+ self.invalidate()
 
 # MGDTODO: Probably a more efficient ways to do this...
- def _get_xmin(self):
-	return self._points[0, 0]
 def _set_xmin(self, val):
-	self._points[0, 0] = val
-	self.invalidate()
- xmin = property(_get_xmin, _set_xmin)
+ self._points[0, 0] = val
+ self.invalidate()
+ xmin = property(BboxBase._get_xmin, _set_xmin)
 
- def _get_ymin(self):
-	return self._points[0, 1]
 def _set_ymin(self, val):
-	self._points[0, 1] = val
-	self.invalidate()
- ymin = property(_get_ymin, _set_ymin)
+ self._points[0, 1] = val
+ self.invalidate()
+ ymin = property(BboxBase._get_ymin, _set_ymin)
 
- def _get_xmax(self):
-	return self._points[1, 0]
 def _set_xmax(self, val):
-	self._points[1, 0] = val
-	self.invalidate()
- xmax = property(_get_xmax, _set_xmax)
+ self._points[1, 0] = val
+ self.invalidate()
+ xmax = property(BboxBase._get_xmax, _set_xmax)
 
- def _get_ymax(self):
-	return self._points[1, 1]
 def _set_ymax(self, val):
-	self._points[1, 1] = val
-	self.invalidate()
- ymax = property(_get_ymax, _set_ymax)
+ self._points[1, 1] = val
+ self.invalidate()
+ ymax = property(BboxBase._get_ymax, _set_ymax)
 
- def _get_min(self):
-	return self._points[0]
 def _set_min(self, val):
-	self._points[0] = val
-	self.invalidate()
- min = property(_get_min, _set_min)
+ self._points[0] = val
+ self.invalidate()
+ min = property(BboxBase._get_min, _set_min)
 
- def _get_max(self):
-	return self._points[1]
 def _set_max(self, val):
-	self._points[1] = val
-	self.invalidate()
- max = property(_get_max, _set_max)
+ self._points[1] = val
+ self.invalidate()
+ max = property(BboxBase._get_max, _set_max)
 
- def _get_intervalx(self):
-	return self._points[:,0]
 def _set_intervalx(self, interval):
-	self._points[:,0] = interval
-	self.invalidate()
- intervalx = property(_get_intervalx, _set_intervalx)
+ self._points[:, 0] = interval
+ self.invalidate()
+ intervalx = property(BboxBase._get_intervalx, _set_intervalx)
 
- def _get_intervaly(self):
-	return self._points[:,1]
 def _set_intervaly(self, interval):
-	self._points[:,1] = interval
-	self.invalidate()
- intervaly = property(_get_intervaly, _set_intervaly)
+ self._points[:, 1] = interval
+ self.invalidate()
+ intervaly = property(BboxBase._get_intervaly, _set_intervaly)
 
- def _get_width(self):
-	return self.xmax - self.xmin
- width = property(_get_width)
+ def _set_bounds(self, bounds):
+ l,b,w,h = bounds
+ self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
+ self.invalidate()
+ bounds = property(BboxBase._get_bounds, _set_bounds)
 
- def _get_height(self):
-	return self.ymax - self.ymin
- height = property(_get_height)
+ def get_points(self):
+ return self._points
 
- def _get_bounds(self):
-	return (self.xmin, self.ymin,
-		self.xmax - self.xmin, self.ymax - self.ymin)
- def _set_bounds(self, bounds):
-	l,b,w,h = bounds
-	self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
-	self.invalidate()
- bounds = property(_get_bounds, _set_bounds)
-	
+ def set_points(self, points):
+ self._points = points
+ self.invalidate()
+
+ def set(self, other):
+ self._points = other.get_points()
+ self.invalidate()
+ 
 def transformed(self, transform):
-	return Bbox(transform(self._points))
+ return Bbox(transform(self._points))
 
 def inverse_transformed(self, transform):
-	return Bbox(transform.inverted()(self._points))
+ return Bbox(transform.inverted()(self._points))
 
 def expanded(self, sw, sh):
-	width = self.width
-	height = self.height
-	deltaw = (sw * width - width) / 2.0
-	deltah = (sh * height - height) / 2.0
-	a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
-	return Bbox(self._points + a)
+ width = self.width
+ height = self.height
+ deltaw = (sw * width - width) / 2.0
+ deltah = (sh * height - height) / 2.0
+ a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
+ return Bbox(self._points + a)
 
- def contains(self, x, y):
-	return (x >= self.xmin and x <= self.xmax and
-		y >= self.ymin and y <= self.ymax)
-
 #@staticmethod
 def union(bboxes):
-	"""
-	Return the Bbox that bounds all bboxes
-	"""
-	assert(len(bboxes))
+ """
+ Return the Bbox that bounds all bboxes
+ """
+ assert(len(bboxes))
 
-	if len(bboxes) == 1:
-	 return bboxes[0]
+ if len(bboxes) == 1:
+ return bboxes[0]
 
-	bbox = bboxes[0]
-	xmin = bbox.xmin
-	ymin = bbox.ymin
-	xmax = bbox.xmax
-	ymax = bbox.ymax
+ bbox = bboxes[0]
+ xmin = bbox.xmin
+ ymin = bbox.ymin
+ xmax = bbox.xmax
+ ymax = bbox.ymax
 
-	for bbox in bboxes[1:]:
-	 xmin = min(xmin, bbox.xmin)
-	 ymin = min(ymin, bbox.ymin)
-	 xmax = max(xmax, bbox.xmax)
-	 ymax = max(ymax, bbox.ymax)
+ for bbox in bboxes[1:]:
+ xmin = min(xmin, bbox.xmin)
+ ymin = min(ymin, bbox.ymin)
+ xmax = max(xmax, bbox.xmax)
+ ymax = max(ymax, bbox.ymax)
 
-	return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
+ return Bbox.from_lbrt(xmin, ymin, xmax, ymax)
 union = staticmethod(union)
+
+class TransformedBbox(BboxBase):
+ def __init__(self, bbox, transform):
+ assert isinstance(bbox, Bbox)
+ assert isinstance(transform, Transform)
+
+ BboxBase.__init__(self)
+ self.bbox = bbox
+ self.transform = transform
+ self.set_children(['bbox', 'transform'])
+ self._points = None
+
+ def __repr__(self):
+ return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+ __str__ = __repr__
 
+ def _do_invalidation(self):
+ self._points = None
+
+ def get_points(self):
+ if self._points is None:
+ self._points = self.transform(self.bbox.get_points())
+ return self._points
+
+# MGDTODO: This code probably works, but I don't think it's a good idea
+# (from a code clarity perspective)
+# class BlendedBbox(BboxBase):
+# def __init__(self, bbox_x, bbox_y):
+# assert isinstance(bbox_x, BboxBase)
+# assert isinstance(bbox_y, BboxBase)
+
+# BboxBase.__init__(self)
+# self._x = bbox_x
+# self._y = bbox_y
+# self.set_children(['_x', '_y'])
+# self._points = None
+
+# def __repr__(self):
+# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
+# __str__ = __repr__
+ 
+# def _do_invalidation(self):
+# self._points = None
+
+# def get_points(self):
+# if self._points is None:
+# # MGDTODO: Optimize
+# if self._x == self._y:
+# self._points = self._x.get_points()
+# else:
+# x_points = self._x.get_points()
+# y_points = self._y.get_points()
+# self._points = npy.array(
+# [[x_points[0,0], y_points[0,1]],
+# [x_points[1,0], y_points[1,1]]],
+# npy.float_)
+# return self._points
+
+# def _set_intervalx(self, pair):
+# # MGDTODO: Optimize
+# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
+# self.replace_child(0, bbox)
+# intervalx = property(BboxBase._get_intervalx, _set_intervalx)
+
+# def _set_intervaly(self, pair):
+# # MGDTODO: Optimize
+# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
+# self.replace_child(1, bbox)
+# intervaly = property(BboxBase._get_intervaly, _set_intervaly)
+ 
 class Transform(TransformNode):
 def __init__(self):
-	TransformNode.__init__(self)
+ TransformNode.__init__(self)
 
 def __call__(self, points):
-	raise NotImplementedError()
+ raise NotImplementedError()
 
 def __add__(self, other):
-	if isinstance(other, Transform):
-	 return composite_transform_factory(self, other)
-	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
+ if isinstance(other, Transform):
+ return composite_transform_factory(self, other)
+ raise TypeError(
+ "Can not add Transform to object of type '%s'" % type(other))
 
 def __radd__(self, other):
-	if isinstance(other, Transform):
-	 return composite_transform_factory(other, self)
-	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
+ if isinstance(other, Transform):
+ return composite_transform_factory(other, self)
+ raise TypeError(
+ "Can not add Transform to object of type '%s'" % type(other))
 
 def transform_point(self, point):
-	return self.__call__(npy.asarray([point]))[0]
+ return self.__call__(npy.asarray([point]))[0]
 
 def has_inverse(self):
-	raise NotImplementedError()
+ raise NotImplementedError()
 
 def inverted(self):
-	raise NotImplementedError()
+ raise NotImplementedError()
 
 def is_separable(self):
-	return False
+ return False
 
 def is_affine(self):
-	return False
+ return False
 
 class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
 
 def __init__(self):
-	Transform.__init__(self)
-	self._inverted = None
+ Transform.__init__(self)
+ self._inverted = None
 
 def _do_invalidation(self):
-	result = self._inverted is None
-	self._inverted = None
-	return result
+ result = self._inverted is None
+ self._inverted = None
+ return result
 
 #@staticmethod
 def _concat(a, b):
 return npy.dot(b, a)
 _concat = staticmethod(_concat)
+
+ #@staticmethod
+ def concat(a, b):
+ return Affine2D(Affine2D._concat(a.get_matrix(), b.get_matrix()))
+ concat = staticmethod(concat)
 
 def to_values(self):
-	mtx = self.get_matrix()
-	return tuple(mtx[:2].swapaxes(0, 1).flatten())
+ mtx = self.get_matrix()
+ return tuple(mtx[:2].swapaxes(0, 1).flatten())
 
 #@staticmethod
 def matrix_from_values(a, b, c, d, e, f):
-	affine = npy.zeros((3,3), npy.float_)
-	affine[0,] = a, c, e
-	affine[1,] = b, d, f
-	affine[2,2] = 1
-	return affine
+ affine = npy.zeros((3, 3), npy.float_)
+ affine[0, ] = a, c, e
+ affine[1, ] = b, d, f
+ affine[2, 2] = 1
+ return affine
 matrix_from_values = staticmethod(matrix_from_values)
 
 def get_matrix(self):
-	raise NotImplementedError()
+ raise NotImplementedError()
 
 def __call__(self, points):
 """
 Applies the transformation to an array of 2D points and
-	returns the result.
+ returns the result.
 
-	points must be a numpy array of shape (N, 2), where N is the
-	number of points.
-	"""
-	# MGDTODO: The major speed trap here is just converting to
-	# the points to an array in the first place. If we can use
-	# more arrays upstream, that should help here.
-	mtx = self.get_matrix()
-	points = npy.asarray(points, npy.float_)
-	points = points.transpose()
-	points = npy.dot(mtx[0:2, 0:2], points)
-	points = points + mtx[0:2, 2:]
-	return points.transpose()
+ points must be a numpy array of shape (N, 2), where N is the
+ number of points.
+ """
+ # MGDTODO: The major speed trap here is just converting to
+ # the points to an array in the first place. If we can use
+ # more arrays upstream, that should help here.
+ if not isinstance(points, npy.ndarray):
+ import traceback
+ print '-' * 60
+ print 'A non-numpy array was passed in for transformation. Please '
+ print 'correct this.'
+ print "".join(traceback.format_stack())
+ print points
+ mtx = self.get_matrix()
+ points = npy.asarray(points, npy.float_)
+ points = points.transpose()
+ points = npy.dot(mtx[0:2, 0:2], points)
+ points = points + mtx[0:2, 2:]
+ return points.transpose()
 
 def inverted(self):
-	if self._inverted is None:
-	 mtx = self.get_matrix()
-	 self._inverted = Affine2D(inv(mtx))
-	return self._inverted
+ if self._inverted is None:
+ mtx = self.get_matrix()
+ self._inverted = Affine2D(inv(mtx))
+ return self._inverted
 
 def is_separable(self):
-	mtx = self.get_matrix()
-	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+ mtx = self.get_matrix()
+ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
 def is_affine(self):
-	return True
+ return True
 
-	
+ 
 class Affine2D(Affine2DBase):
 input_dims = 2
 output_dims = 2
@@ -310,29 +487,29 @@
 b d f
 0 0 1
 """
-	Affine2DBase.__init__(self)
-	if matrix is None:
-	 matrix = npy.identity(3)
-	else:
-	 assert matrix.shape == (3, 3)
-	self._mtx = matrix
-	self._inverted = None
+ Affine2DBase.__init__(self)
+ if matrix is None:
+ matrix = npy.identity(3)
+ else:
+ assert matrix.shape == (3, 3)
+ self._mtx = matrix
+ self._inverted = None
 
 def __repr__(self):
-	return "Affine2D(%s)" % repr(self._mtx)
+ return "Affine2D(%s)" % repr(self._mtx)
 __str__ = __repr__
 
 def __cmp__(self, other):
-	if (isinstance(other, Affine2D) and
-	 (self.get_matrix() == other.get_matrix()).all()):
-	 return 0
-	return -1
+ if (isinstance(other, Affine2D) and
+ (self.get_matrix() == other.get_matrix()).all()):
+ return 0
+ return -1
 
 def __copy__(self):
-	return Affine2D(self._mtx.copy())
+ return Affine2D(self._mtx.copy())
 
 def __deepcopy__(self, memo):
-	return Affine2D(self._mtx.copy())
+ return Affine2D(self._mtx.copy())
 
 #@staticmethod
 def from_values(a, b, c, d, e, f):
@@ -340,209 +517,224 @@
 from_values = staticmethod(from_values)
 
 def get_matrix(self):
-	return self._mtx
+ return self._mtx
+
+ def set_matrix(self, mtx):
+ self._mtx = mtx
+ self.invalidate()
+
+ def set(self, other):
+ self._mtx = other.get_matrix()
+ self.invalidate()
 
 #@staticmethod
- def concat(a, b):
-	return Affine2D(Affine2D._concat(a._mtx, b._mtx))
- concat = staticmethod(concat)
- 
- #@staticmethod
 def identity():
 return Affine2D(npy.identity(3))
 identity = staticmethod(identity)
 
+ def clear(self):
+ self._mtx = npy.identity(3)
+ self.invalidate()
+ return self
+ 
 def rotate(self, theta):
 a = npy.cos(theta)
 b = npy.sin(theta)
 rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
 self._mtx = self._concat(self._mtx, rotate_mtx)
-	self.invalidate()
-	return self
+ self.invalidate()
+ return self
 
 def rotate_deg(self, degrees):
 return self.rotate(degrees*npy.pi/180.)
 
+ def rotate_around(self, x, y, theta):
+ return self.translate(-x, -y).rotate(theta).translate(x, y)
+
+ def rotate_deg_around(self, x, y, degrees):
+ return self.translate(-x, -y).rotate_deg(degrees).translate(x, y)
+ 
 def translate(self, tx, ty):
 translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
 self._mtx = self._concat(self._mtx, translate_mtx)
-	self.invalidate()
-	return self
+ self.invalidate()
+ return self
 
 def scale(self, sx, sy=None):
-	if sy is None:
-	 sy = sx
-	scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
+ if sy is None:
+ sy = sx
+ scale_mtx = self.matrix_from_values(sx, 0., 0., sy, 0., 0.)
 self._mtx = self._concat(self._mtx, scale_mtx)
-	self.invalidate()
-	return self
+ self.invalidate()
+ return self
 
 def inverted(self):
-	if self._inverted is None:
-	 mtx = self.get_matrix()
-	 self._inverted = Affine2D(inv(mtx))
-	return self._inverted
+ if self._inverted is None:
+ mtx = self.get_matrix()
+ self._inverted = Affine2D(inv(mtx))
+ return self._inverted
 
 def is_separable(self):
-	mtx = self.get_matrix()
-	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+ mtx = self.get_matrix()
+ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
 
 def is_affine(self):
-	return True
+ return True
 
-class BlendedAffine2D(Affine2DBase):
+class BlendedTransform(Transform):
 def __init__(self, x_transform, y_transform):
-	assert x_transform.is_affine()
-	assert y_transform.is_affine()
-	assert x_transform.is_separable()
-	assert y_transform.is_separable()
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
 
-	Affine2DBase.__init__(self)
-	self.add_children([x_transform, y_transform])
-	self._x = x_transform
-	self._y = y_transform
-	self._mtx = None
+ Transform.__init__(self)
+ self._x = x_transform
+ self._y = y_transform
+ self.set_children(['_x', '_y'])
 
+ def __call__(self, points):
+ if self._x == self._y:
+ return self._x(points)
+ 
+ x_points = self._x(points)
+ y_points = self._y(points)
+ # This works because we already know the transforms are
+ # separable
+ return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
+
+# def set_x_transform(self, x_transform):
+# self.replace_child(0, x_transform)
+
+# def set_y_transform(self, y_transform):
+# self.replace_child(1, y_transform)
+ 
+class BlendedAffine2D(Affine2DBase, BlendedTransform):
+ def __init__(self, x_transform, y_transform):
+ assert x_transform.is_affine()
+ assert y_transform.is_affine()
+ assert x_transform.is_separable()
+ assert y_transform.is_separable()
+ BlendedTransform.__init__(self, x_transform, y_transform)
+ 
+ Affine2DBase.__init__(self)
+ self._mtx = None
+
 def __repr__(self):
-	return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
+ return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
 __str__ = __repr__
-	
+ 
 def _do_invalidation(self):
-	if self._mtx is not None:
-	 self._mtx = None
-	 Affine2DBase._do_invalidation(self)
-	 return False
-	return True
+ if self._mtx is not None:
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
+ return False
+ return True
 
- def _make__mtx(self):
-	if self._mtx is None:
-	 x_mtx = self._x.get_matrix()
-	 y_mtx = self._y.get_matrix()
-	 # This works because we already know the transforms are
-	 # separable, though normally one would want to set b and
-	 # c to zero.
-	 self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
-	
 def is_separable(self):
-	return True
+ return True
 
 def get_matrix(self):
-	self._make__mtx()
-	return self._mtx
+ if self._mtx is None:
+ if self._x == self._y:
+ self._mtx = self._x.get_matrix()
+ else:
+ x_mtx = self._x.get_matrix()
+ y_mtx = self._y.get_matrix()
+ # This works because we already know the transforms are
+ # separable, though normally one would want to set b and
+ # c to zero.
+ self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+ return self._mtx
+ 
+class CompositeTransform(Transform):
+ def __init__(self, a, b):
+ assert a.output_dims == b.input_dims
+ self.input_dims = a.input_dims
+ self.output_dims = b.output_dims
+ 
+ Transform.__init__(self)
+ self._a = a
+ self._b = b
+ self.set_children(['_a', '_b'])
+ 
+ def __call__(self, points):
+ return self._b(self._a(points))
 
-class BlendedTransform(Transform):
- def __init__(self, x_transform, y_transform):
-	assert x_transform.is_separable()
-	assert y_transform.is_separable()
-
-	Transform.__init__(self)
-	self.add_children([x_transform, y_transform])
-	self._x = x_transform
-	self._y = y_transform
-
- def __call__(self, points):
-	x_points = self._x(points)
-	y_points = self._y(points)
-	# This works because we already know the transforms are
-	# separable
-	return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
-
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
-	assert a.is_affine()
-	assert b.is_affine()
+ assert a.is_affine()
+ assert b.is_affine()
 
-	Affine2DBase.__init__(self)
-	self.add_children([a, b])
-	self._a = a
-	self._b = b
-	self._mtx = None
+ Affine2DBase.__init__(self)
+ self._a = a
+ self._b = b
+ self.set_children(['_a', '_b'])
+ self._mtx = None
 
 def __repr__(self):
-	return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
+ return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
 __str__ = __repr__
 
 def _do_invalidation(self):
-	self._mtx = None
-	Affine2DBase._do_invalidation(self)
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
 
- def _make__mtx(self):
-	if self._mtx is None:
-	 self._mtx = self._concat(
-		self._a.get_matrix(),
-		self._b.get_matrix())
-
 def get_matrix(self):
-	self._make__mtx()
-	return self._mtx
-	
-class CompositeTransform(Transform):
- def __init__(self, a, b):
-	assert a.output_dims == b.input_dims
-	self.input_dims = a.input_dims
-	self.output_dims = b.output_dims
-	
-	Transform.__init__(self)
-	self.add_children([a, b])
-	self._a = a
-	self._b = b
+ if self._mtx is None:
+ self._mtx = self._concat(
+ self._a.get_matrix(),
+ self._b.get_matrix())
+ return self._mtx
 
- def __call__(self, points):
-	return self._b(self._a(points))
-
 class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
-	assert isinstance(boxin, Bbox)
-	assert isinstance(boxout, Bbox)
+ assert isinstance(boxin, BboxBase)
+ assert isinstance(boxout, BboxBase)
 
-	Affine2DBase.__init__(self)
-	self.add_children([boxin, boxout])
-	self._boxin = boxin
-	self._boxout = boxout
-	self._mtx = None
-	self._inverted = None
+ Affine2DBase.__init__(self)
+ self._boxin = boxin
+ self._boxout = boxout
+ self.set_children(['_boxin', '_boxout'])
+ self._mtx = None
+ self._inverted = None
 
 def __repr__(self):
-	return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
+ return "BboxTransform(%s, %s)" % (self._boxin, self._boxout)
 __str__ = __repr__
-	
+ 
 def _do_invalidation(self):
-	if self._mtx is not None:
-	 self._mtx = None
-	 Affine2DBase._do_invalidation(self)
-	 return False
-	return True
+ if self._mtx is not None:
+ self._mtx = None
+ Affine2DBase._do_invalidation(self)
+ return False
+ return True
 
- def _make__mtx(self):
-	if self._mtx is None:
-	 boxin = self._boxin
-	 boxout = self._boxout
-	 x_scale = boxout.width / boxin.width
-	 y_scale = boxout.height / boxin.height
+ def is_separable(self):
+ return True
 
-	 # MGDTODO: Optimize
-	 affine = Affine2D() \
-		.translate(-boxin.xmin, -boxin.ymin) \
-		.scale(x_scale, y_scale) \
-		.translate(boxout.xmin, boxout.ymin)
+ def get_matrix(self):
+ if self._mtx is None:
+ boxin = self._boxin
+ boxout = self._boxout
+ x_scale = boxout.width / boxin.width
+ y_scale = boxout.height / boxin.height
 
-	 self._mtx = affine._mtx
-	
- def is_separable(self):
-	return True
+ # MGDTODO: Optimize
+ affine = Affine2D() \
+ .translate(-boxin.xmin, -boxin.ymin) \
+ .scale(x_scale, y_scale) \
+ .translate(boxout.xmin, boxout.ymin)
 
- def get_matrix(self):
-	self._make__mtx()
-	return self._mtx
- 
+ self._mtx = affine._mtx
+ return self._mtx
+
 def blend_xy_sep_transform(x_transform, y_transform):
 if x_transform.is_affine() and y_transform.is_affine():
-	return BlendedAffine2D(x_transform, y_transform)
+ return BlendedAffine2D(x_transform, y_transform)
 return BlendedTransform(x_transform, y_transform)
 
 def composite_transform_factory(a, b):
 if a.is_affine() and b.is_affine():
-	return CompositeAffine2D(a, b)
+ return CompositeAffine2D(a, b)
 return CompositeTransform(a, b)
 
 # MGDTODO: There's probably a better place for this
@@ -562,7 +754,7 @@
 vmin, vmax = vmax, vmin
 swapped = True
 if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny:
- if vmin==0.0:
+ if vmin == 0.0:
 vmin = -expander
 vmax = expander
 else:
@@ -635,8 +827,8 @@
 assert scale.to_values() == (10, 0, 0, 20, 0, 0)
 rotation = Affine2D().rotate_deg(30)
 print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
-				 -0.49999999999999994, 0.86602540378443871,
-				 0.0, 0.0)
+ -0.49999999999999994, 0.86602540378443871,
+ 0.0, 0.0)
 
 points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_)
 translated_points = translation(points)
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -21,7 +21,7 @@
 # http://groups.google.com/groups?hl=en&lr=&threadm=mailman.5090.1098044946.5135.python-list%40python.org&rnum=1&prev=/groups%3Fq%3D__doc__%2Bauthor%253Ajdhunter%2540ace.bsd.uchicago.edu%26hl%3Den%26btnG%3DGoogle%2BSearch
 
 
-class Artist:
+class Artist(object):
 """
 Abstract base class for someone who renders into a FigureCanvas
 """
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -436,8 +436,7 @@
 }
 
 def __str__(self):
- return "Axes(%g,%g;%gx%g)"%(self._position[0].get(),self._position[1].get(),
- self._position[2].get(),self._position[3].get())
+ return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds)
 def __init__(self, fig, rect,
 axisbg = None, # defaults to rc axes.facecolor
 frameon = True,
@@ -590,13 +589,13 @@
 
 def follow_foreign_ylim(ax):
 ymin, ymax = axforeign.get_ylim()
- # do not emit here or we'll get a ping png effect
+ # do not emit here or we'll get a ping pong effect
 self.set_ylim(ymin, ymax, emit=False)
 self.figure.canvas.draw_idle()
 
 def follow_self_ylim(ax):
 ymin, ymax = self.get_ylim()
- # do not emit here or we'll get a ping png effect
+ # do not emit here or we'll get a ping pong effect
 axforeign.set_ylim(ymin, ymax, emit=False)
 axforeign.figure.canvas.draw_idle()
 
@@ -613,65 +612,66 @@
 """
 martist.Artist.set_figure(self, fig)
 
- l, b, w, h = self._position.bounds
- xmin = fig.bbox.xmin
- xmax = fig.bbox.xmax
- ymin = fig.bbox.ymin
- ymax = fig.bbox.ymax
- figw = xmax-xmin
- figh = ymax-ymin
- self.left = l*figw
- self.bottom = b*figh
- self.right = (l+w)*figw
- self.top = (b+h)*figh
-
- self.bbox = maffine.Bbox.from_lbrt(
- self.left, self.bottom,
- self.right, self.top,
- )
+ self.bbox = maffine.TransformedBbox(self._position, fig.transFigure)
 #these will be updated later as data is added
 self._set_lim_and_transforms()
 
+ def _shared_xlim_callback(self, ax):
+	xmin, xmax = ax.get_xlim()
+	self.set_xlim(xmin, xmax, emit=False)
+	self.figure.canvas.draw_idle()
+
+ def _shared_ylim_callback(self, ax):
+	ymin, ymax = ax.get_ylim()
+	self.set_ylim(ymin, ymax, emit=False)
+	self.figure.canvas.draw_idle()
+	
 def _set_lim_and_transforms(self):
 """
 set the dataLim and viewLim BBox attributes and the
 transData and transAxes Transformation attributes
 """
- Bbox = maffine.Bbox
+	Bbox = maffine.Bbox
+	self.viewLim = Bbox.unit()
+	
 if self._sharex is not None:
- left = self._sharex.viewLim.xmin()
- right = self._sharex.viewLim.xmax()
- else:
- left = 0.0
- right = 1.0
+	 # MGDTODO: This may be doing at least one too many updates
+	 # than necessary
+	 self._sharex.callbacks.connect(
+ 		'xlim_changed', self._shared_xlim_callback)
+	 self.viewLim.intervalx = self._sharex.viewLim.intervalx
 if self._sharey is not None:
- bottom = self._sharey.viewLim.ymin()
- top = self._sharey.viewLim.ymax()
- else:
- bottom = 0.0
- top = 1.0
+ 	 self._sharey.callbacks.connect(
+ 		'ylim_changed', self._shared_ylim_callback)
+	 self.viewLim.intervaly = self._sharex.viewLim.intervaly
 
- self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
 	self.dataLim = Bbox.unit()
 	
- self.transData = maffine.BboxTransform(
- self.viewLim, self.bbox)
 self.transAxes = maffine.BboxTransform(
 Bbox.unit(), self.bbox)
 
-	# MGDTODO
-# if self._sharex:
-# self.transData.set_funcx(self._sharex.transData.get_funcx())
-
-# if self._sharey:
-# self.transData.set_funcy(self._sharey.transData.get_funcy())
-
+ localTransData = maffine.BboxTransform(
+ self.viewLim, self.bbox)
+	if self._sharex:
+	 transDataX = self._sharex.transData
+	else:
+	 transDataX = localTransData
+	if self._sharey:
+	 transDataY = self._sharey.transData
+	else:
+	 transDataY = localTransData
+	self.transData = localTransData # maffine.blend_xy_sep_transform(transDataX, transDataY)
+	 
+	 
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
+	# MGDTODO: This changed from returning a list to returning a Bbox
+	# If you get any errors with the result of this function, please
+	# update the calling code
 if original:
- return self._originalPosition.bounds
+ return copy.copy(self._originalPosition)
 else:
- return self._position.bounds
+ return copy.copy(self._position)
 	 # return [val.get() for val in self._position]
 
 def set_position(self, pos, which='both'):
@@ -690,14 +690,9 @@
 ACCEPTS: len(4) sequence of floats
 """
 if which in ('both', 'active'):
-	 # MGDTODO
-# # Change values within self._position--don't replace it.
-# for num,val in zip(pos, self._position):
-# val.set(num)
-	 self._position.bounds = pos.bounds
-	 # MGDTODO: side-effects
+	 self._position.set(pos)
 if which in ('both', 'original'):
- self._originalPosition.bounds = pos.bounds
+ self._originalPosition.set(pos)
 	 
 	 
 def _set_artist_props(self, a):
@@ -1546,7 +1541,14 @@
 xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
 
 	self.viewLim.intervalx = (xmin, xmax)
-	
+ if emit:
+	 self.callbacks.process('xlim_changed', self)
+	 # MGDTODO: It would be nice to do this is in the above callback list,
+	 # but it's difficult to tell how to initialize this at the
+	 # right time
+	 if self._sharex:
+		self._sharex.set_xlim(*self.viewLim.intervalx)
+	 
 return xmin, xmax
 
 def get_xscale(self):
@@ -1650,7 +1652,6 @@
 
 ACCEPTS: len(2) sequence of floats
 """
-
 if ymax is None and iterable(ymin):
 ymin,ymax = ymin
 
@@ -1671,8 +1672,14 @@
 
 ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
 	self.viewLim.intervaly = (ymin, ymax)
- if emit: self.callbacks.process('ylim_changed', self)
-	
+ if emit:
+	 self.callbacks.process('ylim_changed', self)
+	 # MGDTODO: It would be nice to do this is in the above callback list,
+	 # but it's difficult to tell how to initialize this at the
+	 # right time
+	 if self._sharey:
+		self._sharey.set_ylim(*self.viewLim.intervaly)
+	 
 return ymin, ymax
 
 def get_yscale(self):
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -1028,9 +1028,8 @@
 x,y = self.label.get_position()
 if self.label_position == 'bottom':
 if not len(bboxes):
- bottom = self.axes.bbox.ymin()
+ bottom = self.axes.bbox.ymin
 else:
-
 bbox = Bbox.union(bboxes)
 bottom = bbox.ymin
 
@@ -1041,7 +1040,6 @@
 if not len(bboxes2):
 top = self.axes.bbox.ymax
 else:
-
 bbox = bbox_union(bboxes2)
 top = bbox.ymax
 
@@ -1054,7 +1052,7 @@
 """
 x,y = self.offsetText.get_position()
 if not len(bboxes):
- bottom = self.axes.bbox.ymin()
+ bottom = self.axes.bbox.ymin
 else:
 bbox = Bbox.union(bboxes)
 bottom = bbox.ymin
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -752,7 +752,8 @@
 else: # Just found one hit
 self.inaxes = axes_list[0]
 
- try: xdata, ydata = self.inaxes.transData.inverted()([[x, y]])[0]
+ try:
+	 xdata, ydata = self.inaxes.transData.inverted().transform_point((x, y))
 except ValueError:
 self.xdata = None
 self.ydata = None
@@ -1584,8 +1585,8 @@
 lims.append( (xmin, xmax, ymin, ymax) )
 # Store both the original and modified positions
 pos.append( (
- tuple( a.get_position(True) ),
- tuple( a.get_position() ) ) )
+		 a.get_position(True),
+ a.get_position() ) )
 self._views.push(lims)
 self._positions.push(pos)
 self.set_history_buttons()
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -18,7 +18,7 @@
 from text import Text, _process_text_args
 
 from legend import Legend
-from affine import Bbox, BboxTransform
+from affine import Affine2D, Bbox, BboxTransform, TransformedBbox
 from ticker import FormatStrFormatter
 from cm import ScalarMappable
 from contour import ContourSet
@@ -128,17 +128,15 @@
 if facecolor is None: facecolor = rcParams['figure.facecolor']
 if edgecolor is None: edgecolor = rcParams['figure.edgecolor']
 
+	self._dpi_scale_trans = Affine2D()
 self.dpi = dpi
-	figwidth = figsize[0] * dpi
-	figheight = figsize[1] * dpi
-	self.bbox = Bbox.from_lbwh(0, 0, figwidth, figheight)
+	self.bbox_inches = Bbox.from_lbwh(0, 0, *figsize)
+	self.bbox = TransformedBbox(self.bbox_inches, self._dpi_scale_trans)
 	
 self.frameon = frameon
 
- self.transFigure = BboxTransform( Bbox.unit(), self.bbox)
+ self.transFigure = BboxTransform(Bbox.unit(), self.bbox)
 
-
-
 self.figurePatch = Rectangle(
 xy=(0,0), width=1, height=1,
 facecolor=facecolor, edgecolor=edgecolor,
@@ -160,6 +158,15 @@
 
 self._cachedRenderer = None
 
+ def _get_dpi(self):
+	return self._dpi
+ def _set_dpi(self, dpi):
+	print "setting dpi"
+	self._dpi = dpi
+	self._dpi_scale_trans.clear().scale(dpi, dpi)
+	print self._dpi_scale_trans
+ dpi = property(_get_dpi, _set_dpi)
+	
 def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'):
 """
 A common use case is a number of subplots with shared xaxes
@@ -325,7 +332,7 @@
 w,h = args
 
 	dpival = self.dpi
-	self.bbox.max = w * dpival, h * dpival
+	self.bbox_inches.max = w, h
 # self.figwidth.set(w) MGDTODO
 # self.figheight.set(h)
 	
@@ -339,7 +346,7 @@
 manager.resize(int(canvasw), int(canvash))
 
 def get_size_inches(self):
- return self.bbox.max
+ return self.bbox_inches.max
 # return self.figwidth.get(), self.figheight.get() MGDTODO
 
 def get_edgecolor(self):
@@ -352,12 +359,12 @@
 
 def get_figwidth(self):
 'Return the figwidth as a float'
-	return self.bbox.xmax
+	return self.bbox_inches.xmax
 # return self.figwidth.get() MGDTODO
 
 def get_figheight(self):
 'Return the figheight as a float'
- return self.bbox.ymax
+ return self.bbox_inches.ymax
 
 def get_dpi(self):
 'Return the dpi as a float'
@@ -400,7 +407,7 @@
 ACCEPTS: float
 """
 # self.figwidth.set(val) MGDTODO
-	self.bbox.xmax = val
+	self.bbox_inches.xmax = val
 	
 def set_figheight(self, val):
 """
@@ -409,7 +416,7 @@
 ACCEPTS: float
 """
 	# MGDTODO (set())
-	self.bbox.ymax = val
+	self.bbox_inches.ymax = val
 
 def set_frameon(self, b):
 """
Modified: branches/transforms/lib/matplotlib/pyplot.py
===================================================================
--- branches/transforms/lib/matplotlib/pyplot.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/pyplot.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -481,7 +481,7 @@
 byebye = []
 for other in fig.axes:
 if other==a: continue
- if bbox.overlaps(other.bbox, ignoreend=True):
+ if bbox.fully_overlaps(other.bbox):
 byebye.append(other)
 for ax in byebye: delaxes(ax)
 
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月13日 12:50:05 UTC (rev 3847)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月13日 18:00:10 UTC (rev 3848)
@@ -15,7 +15,7 @@
 from cbook import enumerate, is_string_like, maxdict, is_numlike
 from font_manager import FontProperties
 from patches import bbox_artist, YAArrow
-from affine import Bbox
+from affine import Affine2D, Bbox
 from lines import Line2D
 
 import matplotlib.nxutils as nxutils
@@ -213,30 +213,32 @@
 M = self.get_rotation_matrix(xmin, ymin)
 
 # the corners of the unrotated bounding box
- cornersHoriz = ( (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin) )
- offsetLayout = []
+ cornersHoriz = npy.array(
+	 [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)],
+	 npy.float_)
+ offsetLayout = npy.zeros((len(lines), 2))
 # now offset the individual text lines within the box
 if len(lines)>1: # do the multiline aligment
 malign = self._get_multialignment()
- for line, thisx, thisy, w, h in horizLayout:
+ for i, (line, thisx, thisy, w, h) in enumerate(horizLayout):
 if malign=='center': offsetx = width/2.0-w/2.0
 elif malign=='right': offsetx = width-w
 else: offsetx = 0
 thisx += offsetx
- offsetLayout.append( (thisx, thisy ))
+		offsetLayout[i] = (thisx, thisy)
 else: # no additional layout needed
- offsetLayout = [ (thisx, thisy) for line, thisx, thisy, w, h in horizLayout]
+ offsetLayout[0] = horizLayout[0][1:3]
 
 # now rotate the bbox
 
- cornersRotated = [npy.dot(M,npy.array([[thisx],[thisy],[1]])) for thisx, thisy in cornersHoriz]
+ cornersRotated = M(cornersHoriz)
 
- txs = [float(v[0][0]) for v in cornersRotated]
- tys = [float(v[1][0]) for v in cornersRotated]
+ txs = cornersRotated[:, 0]
+ tys = cornersRotated[:, 1]
 
 # compute the bounds of the rotated box
- xmin, xmax = min(txs), max(txs)
- ymin, ymax = min(tys), max(tys)
+ xmin, xmax = txs.min(), txs.max()
+ ymin, ymax = tys.min(), tys.max()
 width = xmax - xmin
 height = ymax - ymin
 
@@ -264,17 +266,18 @@
 
 bbox = Bbox.from_lbwh(xmin, ymin, width, height)
 
+	
 
 # now rotate the positions around the first x,y position
- xys = [npy.dot(M,npy.array([[thisx],[thisy],[1]])) for thisx, thisy in offsetLayout]
+ xys = M(offsetLayout)
+	tx = xys[:, 0]
+	ty = xys[:, 1]
+	tx += offsetx
+	ty += offsety
 
-
- tx = [float(v[0][0])+offsetx for v in xys]
- ty = [float(v[1][0])+offsety for v in xys]
-
 # now inverse transform back to data coords
 	inverse_transform = self.get_transform().inverted()
- xys = inverse_transform(zip(tx, ty))
+ xys = inverse_transform(xys)
 
 xs, ys = zip(*xys)
 
@@ -327,7 +330,7 @@
 return
 
 for line, wh, x, y in info:
- x, y = trans([[x, y]])[0]
+ x, y = trans.transform_point((x, y))
 
 if renderer.flipy():
 canvasw, canvash = renderer.get_canvas_width_height()
@@ -435,29 +438,9 @@
 bbox, info = self._get_layout(self._renderer)
 return bbox
 
-
-
 def get_rotation_matrix(self, x0, y0):
+	return Affine2D().rotate_deg_around(x0, y0, self.get_rotation())
 
- theta = npy.pi/180.0*self.get_rotation()
- # translate x0,y0 to origin
- Torigin = npy.array([ [1, 0, -x0],
- [0, 1, -y0],
- [0, 0, 1 ]])
-
- # rotate by theta
- R = npy.array([ [npy.cos(theta), -npy.sin(theta), 0],
- [npy.sin(theta), npy.cos(theta), 0],
- [0, 0, 1]])
-
- # translate origin back to x0,y0
- Tback = npy.array([ [1, 0, x0],
- [0, 1, y0],
- [0, 0, 1 ]])
-
-
- return npy.dot(npy.dot(Tback,R), Torigin)
-
 def set_backgroundcolor(self, color):
 """
 Set the background color of the text by updating the bbox (see set_bbox for more info)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月13日 12:50:07
Revision: 3847
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3847&view=rev
Author: mdboom
Date: 2007年09月13日 05:50:05 -0700 (2007年9月13日)
Log Message:
-----------
Merged revisions 3836-3846 via svnmerge from 
http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib
........
 r3844 | jdh2358 | 2007年09月12日 16:37:41 -0400 (2007年9月12日) | 1 line
 
 fixed a bar units bug
........
 r3845 | jouni | 2007年09月13日 02:29:14 -0400 (2007年9月13日) | 3 lines
 
 More work on dviread and usetex in pdf. It is more usable now,
 so I am renaming the method from _draw_tex to draw_tex.
........
Modified Paths:
--------------
 branches/transforms/API_CHANGES
 branches/transforms/CHANGELOG
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/backends/backend_pdf.py
 branches/transforms/lib/matplotlib/dviread.py
 branches/transforms/lib/matplotlib/mlab.py
 branches/transforms/lib/matplotlib/patches.py
Added Paths:
-----------
 branches/transforms/examples/units/bar_demo2.py
Property Changed:
----------------
 branches/transforms/
Property changes on: branches/transforms
___________________________________________________________________
Name: svnmerge-integrated
 - /trunk/matplotlib:1-3835
 + /trunk/matplotlib:1-3846
Modified: branches/transforms/API_CHANGES
===================================================================
--- branches/transforms/API_CHANGES	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/API_CHANGES	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -1,3 +1,5 @@
+ Made skiprows=1 the default on csv2rec
+
 The gd and paint backends have been deleted.
 
 The errorbar method and function now accept additional kwargs
Modified: branches/transforms/CHANGELOG
===================================================================
--- branches/transforms/CHANGELOG	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/CHANGELOG	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -1,3 +1,10 @@
+2007年09月13日 The usetex support in the pdf backend is more usable now,
+ so I am enabling it. - JKS
+
+2007年09月12日 Fixed a Axes.bar unit bug - JDH
+
+2007年09月10日 Made skiprows=1 the default on csv2rec - JDH
+
 2007年09月09日 Split out the plotting part of pylab and put it in
 pyplot.py; removed numerix from the remaining pylab.py,
 which imports everything from pyplot.py. The intention
Copied: branches/transforms/examples/units/bar_demo2.py (from rev 3845, trunk/matplotlib/examples/units/bar_demo2.py)
===================================================================
--- branches/transforms/examples/units/bar_demo2.py	 (rev 0)
+++ branches/transforms/examples/units/bar_demo2.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -0,0 +1,34 @@
+"""
+plot using a variety of cm vs inches conversions. The example shows
+how default unit instrospection works (ax1), how various keywords can
+be used to set the x and y units to override the defaults (ax2, ax3,
+ax4) and how one can set the xlimits using scalars (ax3, current units
+assumed) or units (conversions applied to get the numbers to current
+units)
+
+"""
+from basic_units import cm, inch
+from pylab import figure, show, nx
+
+cms = cm *nx.arange(0, 10, 2)
+bottom=0*cm
+width=0.8*cm
+
+fig = figure()
+
+ax1 = fig.add_subplot(2,2,1)
+ax1.bar(cms, cms, bottom=bottom)
+
+ax2 = fig.add_subplot(2,2,2)
+ax2.bar(cms, cms, bottom=bottom, width=width, xunits=cm, yunits=inch)
+
+ax3 = fig.add_subplot(2,2,3)
+ax3.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=cm)
+ax3.set_xlim(3, 6) # scalars are interpreted in current units
+
+ax4 = fig.add_subplot(2,2,4)
+ax4.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=inch)
+#fig.savefig('simple_conversion_plot.png')
+ax4.set_xlim(3*cm, 6*cm) # cm are converted to inches
+
+show()
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -51,7 +51,7 @@
 self._remove_method = None
 
 def remove(self):
- '''
+ """
 Remove the artist from the figure if possible. The effect will not
 be visible until the figure is redrawn, e.g., with ax.draw_idle().
 Call ax.relim() to update the axes limits if desired.
@@ -60,7 +60,7 @@
 was added to axes with autolim=True.
 
 Note: there is no support for removing the artist's legend entry.
- '''
+ """
 
 # There is no method to set the callback. Instead the parent should set
 # the _remove_method attribute directly. This would be a protected
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -1193,23 +1193,27 @@
 def _process_unit_info(self, xdata=None, ydata=None, kwargs=None):
 'look for unit kwargs and update the axis instances as necessary'
 
- if self.xaxis is None or self.xaxis is None: return
+ if self.xaxis is None or self.yaxis is None: return
 
-
+ #print 'processing', self.get_geometry()
 if xdata is not None:
 self.xaxis.update_units(xdata)
+ #print '\tset from xdata', self.xaxis.units
 
 if ydata is not None:
 self.yaxis.update_units(ydata)
+ #print '\tset from ydata', self.yaxis.units
 
 # process kwargs 2nd since these will override default units
 if kwargs is not None:
 xunits = kwargs.pop( 'xunits', self.xaxis.units)
 if xunits!=self.xaxis.units:
+ #print '\tkw setting xunits', xunits
 self.xaxis.set_units(xunits)
 
 yunits = kwargs.pop('yunits', self.yaxis.units)
 if yunits!=self.yaxis.units:
+ #print '\tkw setting yunits', yunits
 self.yaxis.set_units(yunits)
 
 def in_axes(self, xwin, ywin):
@@ -3122,11 +3126,13 @@
 else:
 raise ValueError, 'invalid orientation: %s' % orientation
 
- left = npy.asarray(left)
- height = npy.asarray(height)
- width = npy.asarray(width)
- bottom = npy.asarray(bottom)
 
+ # do not convert to array here as unit info is lost
+ #left = npy.asarray(left)
+ #height = npy.asarray(height)
+ #width = npy.asarray(width)
+ #bottom = npy.asarray(bottom)
+
 if len(linewidth) == 1: linewidth = linewidth * nbars
 
 # if color looks like a color string, an RGB tuple or a
@@ -3169,14 +3175,14 @@
 # lets do some conversions now
 if self.xaxis is not None:
 xconv = self.xaxis.converter
- if ( xconv ):
+ if xconv is not None:
 units = self.xaxis.get_units()
 left = xconv.convert( left, units )
 width = xconv.convert( width, units )
 
 if self.yaxis is not None:
 yconv = self.yaxis.converter
- if ( yconv ):
+ if yconv is not None :
 units = self.yaxis.get_units()
 bottom = yconv.convert( bottom, units )
 height = yconv.convert( height, units )
@@ -3216,12 +3222,14 @@
 
 if xerr is not None or yerr is not None:
 if orientation == 'vertical':
- x = left + 0.5*width
- y = bottom + height
+ # using list comps rather than arrays to preserve unit info
+ x = [l+0.5*w for l, w in zip(left, width)]
+ y = [b+h for b,h in zip(bottom, height)]
 
 elif orientation == 'horizontal':
- x = left + width
- y = bottom + 0.5*height
+ # using list comps rather than arrays to preserve unit info
+ x = [l+w for l,w in zip(left, width)]
+ y = [b+0.5*h for b,h in zip(bottom, height)]
 
 self.errorbar(
 x, y,
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -821,7 +821,7 @@
 return x
 
 ret = self.converter.convert(x, self.units)
- #print 'convert_units converting: units=%s, converter=%s, in=%s, out=%s'%(self.units, self.converter, x, ret)
+ #print 'convert_units converting: axis=%s, units=%s, converter=%s, in=%s, out=%s'%(self, self.units, self.converter, x, ret)
 return ret
 
 def set_units(self, u):
Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_pdf.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/backends/backend_pdf.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -527,7 +527,7 @@
 widths.append(afmdata.get_width_from_char_name(ch))
 except KeyError:
 matplotlib.verbose.report(
- 'No width for %s in %s' % (ch, fullname), 'debug')
+ 'No width for %s in %s' % (ch, fullname), 'debug-annoying')
 widths.append(0)
 
 differencesArray = [ Name(ch) for ch in enc ]
@@ -561,7 +561,7 @@
 except KeyError:
 matplotlib.verbose.report(
 'No name for glyph %d in %s' % (ch, fullname), 
- 'debug')
+ 'debug-annoying')
 need_idx = True
 
 
@@ -1449,9 +1449,7 @@
 # Pop off the global transformation
 self.file.output(Op.grestore)
 
- def _draw_tex(self, gc, x, y, s, prop, angle):
- # Rename to draw_tex to enable
-
+ def draw_tex(self, gc, x, y, s, prop, angle):
 texmanager = self.get_texmanager()
 fontsize = prop.get_size_in_points()
 dvifile = texmanager.make_dvi(s, fontsize)
@@ -1494,7 +1492,7 @@
 elt[3][-1] += next[3][0]
 elt[4] += next[4]-next[1]
 else:
- elt[3] += [offset, next[3][0]]
+ elt[3] += [offset*1000.0/dvifont.size, next[3][0]]
 elt[4] = next[4]
 del seq[i+1]
 continue
Modified: branches/transforms/lib/matplotlib/dviread.py
===================================================================
--- branches/transforms/lib/matplotlib/dviread.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/dviread.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -84,16 +84,22 @@
 e = 0 # zero depth
 else: # glyph
 x,y,font,g,w = elt
- h = (font.scale * font.tfm.height[g]) >> 20
- e = (font.scale * font.tfm.depth[g]) >> 20
+ h = _mul2012(font._scale, font._tfm.height[g])
+ e = _mul2012(font._scale, font._tfm.depth[g])
 minx = min(minx, x)
 miny = min(miny, y - h)
 maxx = max(maxx, x + w)
 maxy = max(maxy, y + e)
 maxy_pure = max(maxy_pure, y)
 
+ if self.dpi is None:
+ # special case for ease of debugging: output raw dvi coordinates
+ return mpl_cbook.Bunch(text=self.text, boxes=self.boxes,
+ width=maxx-minx, height=maxy_pure-miny,
+ descent=maxy-maxy_pure)
+
 d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units
- text = [ ((x-minx)*d, (maxy-y)*d, DviFont(f), g, w*d) 
+ text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) 
 for (x,y,f,g,w) in self.text ]
 boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ]
 
@@ -110,11 +116,11 @@
 while True:
 byte = ord(self.file.read(1))
 self._dispatch(byte)
- if self.state == _dvistate.inpage:
- matplotlib.verbose.report(
- 'Dvi._read: after %d at %f,%f' % 
- (byte, self.h, self.v), 
- 'debug-annoying')
+# if self.state == _dvistate.inpage:
+# matplotlib.verbose.report(
+# 'Dvi._read: after %d at %f,%f' % 
+# (byte, self.h, self.v), 
+# 'debug-annoying')
 if byte == 140: # end of page
 return True
 if self.state == _dvistate.post_post: # end of file
@@ -225,21 +231,11 @@
 # I think we can assume this is constant
 self.state = _dvistate.outer
 
- def _width_of(self, char, font):
- width = font.tfm.width.get(char, None)
- if width is not None:
- return (width * font.scale) >> 20
-
- matplotlib.verbose.report(
- 'No width for char %d in font %s' % (char, font.name),
- 'debug')
- return 0
-
 def _set_char(self, char):
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced set_char in dvi file"
 self._put_char(char)
- self.h += self._width_of(char, self.fonts[self.f])
+ self.h += self.fonts[self.f]._width_of(char)
 
 def _set_rule(self, a, b):
 if self.state != _dvistate.inpage:
@@ -251,20 +247,33 @@
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced put_char in dvi file"
 font = self.fonts[self.f]
- if font.vf is None:
+ if font._vf is None:
 self.text.append((self.h, self.v, font, char, 
- self._width_of(char, font)))
+ font._width_of(char)))
+# matplotlib.verbose.report(
+# 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char), 
+# 'debug-annoying')
 else:
- self.text.extend([(self.h + x, self.v + y, f, g, w)
- for x, y, f, g, w in font.vf[char].text])
- self.boxes.extend([(self.h + x, self.v + y, a, b)
- for x, y, a, b in font.vf[char].boxes])
+ scale = font._scale
+ for x, y, f, g, w in font._vf[char].text:
+ newf = DviFont(scale=_mul2012(scale, f._scale),
+ tfm=f._tfm, texname=f.texname, vf=f._vf)
+ self.text.append((self.h + _mul2012(x, scale),
+ self.v + _mul2012(y, scale),
+ newf, g, newf._width_of(g)))
+ self.boxes.extend([(self.h + _mul2012(x, scale),
+ self.v + _mul2012(y, scale),
+ _mul2012(a, scale), _mul2012(b, scale))
+ for x, y, a, b in font._vf[char].boxes])
 
 def _put_rule(self, a, b):
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced put_rule in dvi file"
 if a > 0 and b > 0:
 self.boxes.append((self.h, self.v, a, b))
+# matplotlib.verbose.report(
+# 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b),
+# 'debug-annoying')
 
 def _nop(self):
 pass
@@ -357,7 +366,7 @@
 
 vf = _vffile(n[-l:])
 
- self.fonts[k] = mpl_cbook.Bunch(scale=s, tfm=tfm, name=n, vf=vf)
+ self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf)
 
 def _post(self):
 if self.state != _dvistate.outer:
@@ -370,17 +379,20 @@
 raise NotImplementedError
 
 class DviFont(object):
- __slots__ = ('texname', 'size')
+ """
+ Object that holds a font's texname and size and supports comparison.
+ There are also internal attributes (for use by dviread.py) that
+ are _not_ used for comparison.
 
- def __init__(self, f):
- """
- Object that holds a font's texname and size and supports comparison.
+ The size is in Adobe points (converted from TeX points).
+ """
+ __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm')
 
- The size is in Adobe points (converted from TeX points).
- """
+ def __init__(self, scale, tfm, texname, vf):
+ self._scale, self._tfm, self.texname, self._vf = \
+ scale, tfm, texname, vf
 # TODO: would it make more sense to have the size in dpi units?
- self.texname = f.name
- self.size = f.scale * (72.0 / (72.27 * 2**16))
+ self.size = scale * (72.0 / (72.27 * 2**16))
 
 def __eq__(self, other):
 return self.__class__ == other.__class__ and \
@@ -389,6 +401,16 @@
 def __ne__(self, other):
 return not self.__eq__(other)
 
+ def _width_of(self, char):
+ width = self._tfm.width.get(char, None)
+ if width is not None:
+ return _mul2012(width, self._scale)
+
+ matplotlib.verbose.report(
+ 'No width for char %d in font %s' % (char, self.texname),
+ 'debug')
+ return 0
+
 class Vf(Dvi):
 """
 A virtual font (*.vf file) containing subroutines for dvi files.
@@ -465,7 +487,8 @@
 raise ValueError, "pre command in middle of vf file"
 if i != 202:
 raise ValueError, "Unknown vf format %d" % i
- matplotlib.verbose.report('vf file comment: ' + x, 'debug')
+ if len(x):
+ matplotlib.verbose.report('vf file comment: ' + x, 'debug')
 self.state = _dvistate.outer
 # cs = checksum, ds = design size
 
@@ -474,7 +497,7 @@
 if self._first_font is None:
 self._first_font = k
 
-def fix2comp(num):
+def _fix2comp(num):
 """
 Convert from two's complement to negative.
 """
@@ -484,6 +507,13 @@
 else:
 return num
 
+def _mul2012(num1, num2):
+ """
+ Multiply two numbers in 20.12 fixed point format.
+ """
+ # Separated into a function because >> has surprising precedence
+ return (num1*num2) >> 20
+
 class Tfm(object):
 """
 A TeX Font Metric file. This implementation covers only the bare
@@ -497,6 +527,7 @@
 (this is a dict because indexing may not start from 0)
 height[i], depth[i]: height and depth of character #i
 """
+ __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth')
 
 def __init__(self, filename):
 matplotlib.verbose.report('opening tfm file ' + filename, 'debug')
@@ -525,9 +556,9 @@
 [ struct.unpack('!%dI' % (len(x)/4), x) 
 for x in (widths, heights, depths) ]
 for i in range(ec-bc):
- self.width[bc+i] = fix2comp(widths[ord(char_info[4*i])])
- self.height[bc+i] = fix2comp(heights[ord(char_info[4*i+1]) >> 4])
- self.depth[bc+i] = fix2comp(depths[ord(char_info[4*i+1]) & 0xf])
+ self.width[bc+i] = _fix2comp(widths[ord(char_info[4*i])])
+ self.height[bc+i] = _fix2comp(heights[ord(char_info[4*i+1]) >> 4])
+ self.depth[bc+i] = _fix2comp(depths[ord(char_info[4*i+1]) & 0xf])
 
 
 class PsfontsMap(object):
@@ -552,6 +583,7 @@
 the pdf-related files perhaps only avoid the "Base 14" pdf fonts.
 But the user may have configured these files differently.
 """
+ __slots__ = ('_font',)
 
 def __init__(self, filename):
 self._font = {}
@@ -627,7 +659,17 @@
 encoding=encoding, filename=filename)
 
 class Encoding(object):
+ """
+ Parses a *.enc file referenced from a psfonts.map style file.
+ The format this class understands is a very limited subset of
+ PostScript.
 
+ Usage (subject to change):
+ for name in Encoding(filename): 
+ whatever(name)
+ """
+ __slots__ = ('encoding',)
+
 def __init__(self, filename):
 file = open(filename, 'rt')
 try:
@@ -694,6 +736,10 @@
 
 return result
 
+# With multiple text objects per figure (e.g. tick labels) we may end
+# up reading the same tfm and vf files many times, so we implement a
+# simple cache. TODO: is this worth making persistent?
+
 _tfmcache = {}
 _vfcache = {}
 
@@ -721,19 +767,22 @@
 
 
 if __name__ == '__main__':
- matplotlib.verbose.set_level('debug')
- dvi = Dvi('foo.dvi', 72)
+ import sys
+ matplotlib.verbose.set_level('debug-annoying')
+ fname = sys.argv[1]
+ try: dpi = float(sys.argv[2])
+ except IndexError: dpi = None
+ dvi = Dvi(fname, dpi)
 fontmap = PsfontsMap(find_tex_file('pdftex.map'))
- for text,boxes in dvi:
+ for page in dvi:
 print '=== new page ==='
 fPrev = None
- for x,y,f,c in text:
- texname = dvi.fonts[f].name
- print x,y,c,chr(c),texname
+ for x,y,f,c,w in page.text:
 if f != fPrev:
- print 'font', texname, '=', fontmap[texname].__dict__
+ print 'font', f.texname, 'scaled', f._scale/pow(2.0,20)
 fPrev = f
- for x,y,w,h in boxes:
+ print x,y,c, 32 <= c < 128 and chr(c) or '.', w
+ for x,y,w,h in page.boxes:
 print x,y,'BOX',w,h
 
 
Modified: branches/transforms/lib/matplotlib/mlab.py
===================================================================
--- branches/transforms/lib/matplotlib/mlab.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/mlab.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -1253,9 +1253,9 @@
 if r==1 or c==1:
 X.shape = max(r,c),
 if unpack: return X.transpose()
- return X
+ else: return X
 
-def csv2rec(fname, comments='#', skiprows=0, checkrows=5, delimiter=',',
+def csv2rec(fname, comments='#', skiprows=1, checkrows=5, delimiter=',',
 converterd=None, names=None, missing=None):
 """
 Load data from comma/space/tab delimited file in fname into a
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月13日 12:44:16 UTC (rev 3846)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月13日 12:50:05 UTC (rev 3847)
@@ -77,6 +77,8 @@
 if len(kwargs): artist.setp(self, **kwargs)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
+
+
 def contains(self, mouseevent):
 """Test whether the mouse event occurred in the patch.
 
@@ -352,7 +354,6 @@
 Return the vertices of the rectangle
 """
 x, y = self.xy
-
 left, right = self.convert_xunits((x, x + self.width))
 bottom, top = self.convert_yunits((y, y + self.height))
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月13日 12:44:23
Revision: 3846
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3846&view=rev
Author: mdboom
Date: 2007年09月13日 05:44:16 -0700 (2007年9月13日)
Log Message:
-----------
Minor changes -- committing so I can merge again.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/patches.py
 branches/transforms/lib/matplotlib/text.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -4,7 +4,7 @@
 2007 Michael Droettboom
 """
 
-import numpy as N
+import numpy as npy
 from numpy.linalg import inv
 from sets import Set
 
@@ -37,7 +37,7 @@
 class Bbox(TransformNode):
 def __init__(self, points):
 	TransformNode.__init__(self)
-	self._points = N.asarray(points, N.float_)
+	self._points = npy.asarray(points, npy.float_)
 	self.track = False
 
 #@staticmethod
@@ -52,7 +52,7 @@
 
 #@staticmethod
 def from_lbrt(*args):
-	points = N.array(args, dtype=N.float_).reshape(2, 2)
+	points = npy.array(args, dtype=npy.float_).reshape(2, 2)
 	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
@@ -72,12 +72,15 @@
 	return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
+ def __array__(self):
+	return self._points
+ 
 # JDH: the update method will update the box limits from the
 # existing limits and the new data; it appears here you are just
 # using the new data. We use an "ignore" flag to specify whether
 # you want to include the existing data or not in the update
 def update_from_data(self, x, y, ignore=True):
-	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
+	self._points = npy.array([[x.min(), y.min()], [x.max(), y.max()]], npy.float_)
 	self.invalidate()
 
 # MGDTODO: Probably a more efficient ways to do this...
@@ -150,7 +153,7 @@
 		self.xmax - self.xmin, self.ymax - self.ymin)
 def _set_bounds(self, bounds):
 	l,b,w,h = bounds
-	self._points = N.array([[l, b], [l+w, b+h]], N.float_)
+	self._points = npy.array([[l, b], [l+w, b+h]], npy.float_)
 	self.invalidate()
 bounds = property(_get_bounds, _set_bounds)
 	
@@ -165,7 +168,7 @@
 	height = self.height
 	deltaw = (sw * width - width) / 2.0
 	deltah = (sh * height - height) / 2.0
-	a = N.array([[-deltaw, -deltah], [deltaw, deltah]])
+	a = npy.array([[-deltaw, -deltah], [deltaw, deltah]])
 	return Bbox(self._points + a)
 
 def contains(self, x, y):
@@ -215,7 +218,7 @@
 	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
 
 def transform_point(self, point):
-	return self.__call__([point])[0]
+	return self.__call__(npy.asarray([point]))[0]
 
 def has_inverse(self):
 	raise NotImplementedError()
@@ -229,8 +232,6 @@
 def is_affine(self):
 	return False
 
-# MGDTODO: Separate out Affine2DBase / Affine2DConcrete so BlendedAffine and CompositeAffine don't have translate/scale/rotate members
-
 class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
@@ -246,7 +247,7 @@
 
 #@staticmethod
 def _concat(a, b):
- return N.dot(b, a)
+ return npy.dot(b, a)
 _concat = staticmethod(_concat)
 
 def to_values(self):
@@ -255,7 +256,7 @@
 
 #@staticmethod
 def matrix_from_values(a, b, c, d, e, f):
-	affine = N.zeros((3,3), N.float_)
+	affine = npy.zeros((3,3), npy.float_)
 	affine[0,] = a, c, e
 	affine[1,] = b, d, f
 	affine[2,2] = 1
@@ -267,7 +268,7 @@
 
 def __call__(self, points):
 """
- Applies the transformation to a set of 2D points and
+ Applies the transformation to an array of 2D points and
 	returns the result.
 
 	points must be a numpy array of shape (N, 2), where N is the
@@ -277,9 +278,9 @@
 	# the points to an array in the first place. If we can use
 	# more arrays upstream, that should help here.
 	mtx = self.get_matrix()
-	points = N.asarray(points, N.float_)
+	points = npy.asarray(points, npy.float_)
 	points = points.transpose()
-	points = N.dot(mtx[0:2, 0:2], points)
+	points = npy.dot(mtx[0:2, 0:2], points)
 	points = points + mtx[0:2, 2:]
 	return points.transpose()
 
@@ -311,7 +312,7 @@
 """
 	Affine2DBase.__init__(self)
 	if matrix is None:
-	 matrix = N.identity(3)
+	 matrix = npy.identity(3)
 	else:
 	 assert matrix.shape == (3, 3)
 	self._mtx = matrix
@@ -348,19 +349,19 @@
 
 #@staticmethod
 def identity():
- return Affine2D(N.identity(3))
+ return Affine2D(npy.identity(3))
 identity = staticmethod(identity)
 
 def rotate(self, theta):
- a = N.cos(theta)
- b = N.sin(theta)
+ a = npy.cos(theta)
+ b = npy.sin(theta)
 rotate_mtx = self.matrix_from_values(a, b, -b, a, 0, 0)
 self._mtx = self._concat(self._mtx, rotate_mtx)
 	self.invalidate()
 	return self
 
 def rotate_deg(self, degrees):
- return self.rotate(degrees*N.pi/180.)
+ return self.rotate(degrees*npy.pi/180.)
 
 def translate(self, tx, ty):
 translate_mtx = self.matrix_from_values(1., 0., 0., 1., tx, ty)
@@ -420,7 +421,7 @@
 	 # This works because we already know the transforms are
 	 # separable, though normally one would want to set b and
 	 # c to zero.
-	 self._mtx = N.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
+	 self._mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 	
 def is_separable(self):
 	return True
@@ -444,7 +445,7 @@
 	y_points = self._y(points)
 	# This works because we already know the transforms are
 	# separable
-	return N.hstack((x_points[:, 0:1], y_points[:, 1:2]))
+	return npy.hstack((x_points[:, 0:1], y_points[:, 1:2]))
 
 class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
@@ -579,6 +580,7 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ import copy
 from random import random
 import timeit
 
@@ -588,36 +590,38 @@
 assert bbox.xmax == 20
 assert bbox.ymax == 25
 
- assert N.all(bbox.min == [10, 15])
- assert N.all(bbox.max == [20, 25])
- assert N.all(bbox.intervalx == (10, 20))
- assert N.all(bbox.intervaly == (15, 25))
+ assert npy.all(bbox.min == [10, 15])
+ assert npy.all(bbox.max == [20, 25])
+ assert npy.all(bbox.intervalx == (10, 20))
+ assert npy.all(bbox.intervaly == (15, 25))
 
 assert bbox.width == 10
 assert bbox.height == 10
 
- assert bbox.get_bounds() == (10, 15, 10, 10)
+ assert bbox.bounds == (10, 15, 10, 10)
 
+ print npy.asarray(bbox)
+ 
 bbox.intervalx = (11, 21)
 bbox.intervaly = (16, 26)
 
- assert bbox.get_bounds() == (11, 16, 10, 10)
+ assert bbox.bounds == (11, 16, 10, 10)
 
 bbox.xmin = 12
 bbox.ymin = 17
 bbox.xmax = 22
 bbox.ymax = 27
 
- assert bbox.get_bounds() == (12, 17, 10, 10)
+ assert bbox.bounds == (12, 17, 10, 10)
 
 bbox = Bbox.from_lbwh(10, 11, 12, 13)
- assert bbox.get_bounds() == (10, 11, 12, 13)
+ assert bbox.bounds == (10, 11, 12, 13)
 
- bbox_copy = bbox.copy()
+ bbox_copy = copy.copy(bbox)
 assert bbox == bbox_copy
 bbox_copy.max = (14, 15)
- assert bbox.get_bounds() == (10, 11, 12, 13)
- assert bbox_copy.get_bounds() == (10, 11, 4, 4)
+ assert bbox.bounds == (10, 11, 12, 13)
+ assert bbox_copy.bounds == (10, 11, 4, 4)
 
 bbox1 = Bbox([[10., 15.], [20., 25.]])
 bbox2 = Bbox([[30., 35.], [40., 45.]])
@@ -634,7 +638,7 @@
 				 -0.49999999999999994, 0.86602540378443871,
 				 0.0, 0.0)
 
- points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
+ points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_)
 translated_points = translation(points)
 assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
 scaled_points = scale(points)
@@ -655,7 +659,7 @@
 t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
 print "Time to transform 10000 x 10 points as tuples:", t.timeit(10)
 
- points2 = N.asarray(points)
+ points2 = npy.asarray(points)
 t = timeit.Timer("trans_sum(points2)", "from __main__ import trans_sum, points2")
 print "Time to transform 10000 x 10 points as numpy array:", t.timeit(10)
 
Modified: branches/transforms/lib/matplotlib/patches.py
===================================================================
--- branches/transforms/lib/matplotlib/patches.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/patches.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -356,9 +356,9 @@
 left, right = self.convert_xunits((x, x + self.width))
 bottom, top = self.convert_yunits((y, y + self.height))
 
- return ( (left, bottom), (left, top),
- (right, top), (right, bottom),
- )
+ return npy.array([[left, bottom], [left, top],
+			 [right, top], [right, bottom]],
+			 npy.float_)
 
 def get_x(self):
 "Return the left coord of the rectangle"
Modified: branches/transforms/lib/matplotlib/text.py
===================================================================
--- branches/transforms/lib/matplotlib/text.py	2007年09月13日 06:29:14 UTC (rev 3845)
+++ branches/transforms/lib/matplotlib/text.py	2007年09月13日 12:44:16 UTC (rev 3846)
@@ -149,7 +149,7 @@
 def _get_xy_display(self):
 'get the (possibly unit converted) transformed x,y in display coords'
 x, y = self.get_position()
- return self.get_transform()([[x,y]])[0]
+ return self.get_transform().transform_point((x,y))
 
 def _get_multialignment(self):
 if self._multialignment is not None: return self._multialignment
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jo...@us...> - 2007年09月13日 06:29:33
Revision: 3845
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3845&view=rev
Author: jouni
Date: 2007年09月12日 23:29:14 -0700 (2007年9月12日)
Log Message:
-----------
More work on dviread and usetex in pdf. It is more usable now,
so I am renaming the method from _draw_tex to draw_tex.
Modified Paths:
--------------
 trunk/matplotlib/CHANGELOG
 trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
 trunk/matplotlib/lib/matplotlib/dviread.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG	2007年09月12日 20:37:41 UTC (rev 3844)
+++ trunk/matplotlib/CHANGELOG	2007年09月13日 06:29:14 UTC (rev 3845)
@@ -1,3 +1,6 @@
+2007年09月13日 The usetex support in the pdf backend is more usable now,
+ so I am enabling it. - JKS
+
 2007年09月12日 Fixed a Axes.bar unit bug - JDH
 
 2007年09月10日 Made skiprows=1 the default on csv2rec - JDH
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py	2007年09月12日 20:37:41 UTC (rev 3844)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_pdf.py	2007年09月13日 06:29:14 UTC (rev 3845)
@@ -527,7 +527,7 @@
 widths.append(afmdata.get_width_from_char_name(ch))
 except KeyError:
 matplotlib.verbose.report(
- 'No width for %s in %s' % (ch, fullname), 'debug')
+ 'No width for %s in %s' % (ch, fullname), 'debug-annoying')
 widths.append(0)
 
 differencesArray = [ Name(ch) for ch in enc ]
@@ -561,7 +561,7 @@
 except KeyError:
 matplotlib.verbose.report(
 'No name for glyph %d in %s' % (ch, fullname), 
- 'debug')
+ 'debug-annoying')
 need_idx = True
 
 
@@ -1449,9 +1449,7 @@
 # Pop off the global transformation
 self.file.output(Op.grestore)
 
- def _draw_tex(self, gc, x, y, s, prop, angle):
- # Rename to draw_tex to enable
-
+ def draw_tex(self, gc, x, y, s, prop, angle):
 texmanager = self.get_texmanager()
 fontsize = prop.get_size_in_points()
 dvifile = texmanager.make_dvi(s, fontsize)
@@ -1494,7 +1492,7 @@
 elt[3][-1] += next[3][0]
 elt[4] += next[4]-next[1]
 else:
- elt[3] += [offset, next[3][0]]
+ elt[3] += [offset*1000.0/dvifont.size, next[3][0]]
 elt[4] = next[4]
 del seq[i+1]
 continue
Modified: trunk/matplotlib/lib/matplotlib/dviread.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/dviread.py	2007年09月12日 20:37:41 UTC (rev 3844)
+++ trunk/matplotlib/lib/matplotlib/dviread.py	2007年09月13日 06:29:14 UTC (rev 3845)
@@ -84,16 +84,22 @@
 e = 0 # zero depth
 else: # glyph
 x,y,font,g,w = elt
- h = (font.scale * font.tfm.height[g]) >> 20
- e = (font.scale * font.tfm.depth[g]) >> 20
+ h = _mul2012(font._scale, font._tfm.height[g])
+ e = _mul2012(font._scale, font._tfm.depth[g])
 minx = min(minx, x)
 miny = min(miny, y - h)
 maxx = max(maxx, x + w)
 maxy = max(maxy, y + e)
 maxy_pure = max(maxy_pure, y)
 
+ if self.dpi is None:
+ # special case for ease of debugging: output raw dvi coordinates
+ return mpl_cbook.Bunch(text=self.text, boxes=self.boxes,
+ width=maxx-minx, height=maxy_pure-miny,
+ descent=maxy-maxy_pure)
+
 d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units
- text = [ ((x-minx)*d, (maxy-y)*d, DviFont(f), g, w*d) 
+ text = [ ((x-minx)*d, (maxy-y)*d, f, g, w*d) 
 for (x,y,f,g,w) in self.text ]
 boxes = [ ((x-minx)*d, (maxy-y)*d, h*d, w*d) for (x,y,h,w) in self.boxes ]
 
@@ -110,11 +116,11 @@
 while True:
 byte = ord(self.file.read(1))
 self._dispatch(byte)
- if self.state == _dvistate.inpage:
- matplotlib.verbose.report(
- 'Dvi._read: after %d at %f,%f' % 
- (byte, self.h, self.v), 
- 'debug-annoying')
+# if self.state == _dvistate.inpage:
+# matplotlib.verbose.report(
+# 'Dvi._read: after %d at %f,%f' % 
+# (byte, self.h, self.v), 
+# 'debug-annoying')
 if byte == 140: # end of page
 return True
 if self.state == _dvistate.post_post: # end of file
@@ -225,21 +231,11 @@
 # I think we can assume this is constant
 self.state = _dvistate.outer
 
- def _width_of(self, char, font):
- width = font.tfm.width.get(char, None)
- if width is not None:
- return (width * font.scale) >> 20
-
- matplotlib.verbose.report(
- 'No width for char %d in font %s' % (char, font.name),
- 'debug')
- return 0
-
 def _set_char(self, char):
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced set_char in dvi file"
 self._put_char(char)
- self.h += self._width_of(char, self.fonts[self.f])
+ self.h += self.fonts[self.f]._width_of(char)
 
 def _set_rule(self, a, b):
 if self.state != _dvistate.inpage:
@@ -251,20 +247,33 @@
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced put_char in dvi file"
 font = self.fonts[self.f]
- if font.vf is None:
+ if font._vf is None:
 self.text.append((self.h, self.v, font, char, 
- self._width_of(char, font)))
+ font._width_of(char)))
+# matplotlib.verbose.report(
+# 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char), 
+# 'debug-annoying')
 else:
- self.text.extend([(self.h + x, self.v + y, f, g, w)
- for x, y, f, g, w in font.vf[char].text])
- self.boxes.extend([(self.h + x, self.v + y, a, b)
- for x, y, a, b in font.vf[char].boxes])
+ scale = font._scale
+ for x, y, f, g, w in font._vf[char].text:
+ newf = DviFont(scale=_mul2012(scale, f._scale),
+ tfm=f._tfm, texname=f.texname, vf=f._vf)
+ self.text.append((self.h + _mul2012(x, scale),
+ self.v + _mul2012(y, scale),
+ newf, g, newf._width_of(g)))
+ self.boxes.extend([(self.h + _mul2012(x, scale),
+ self.v + _mul2012(y, scale),
+ _mul2012(a, scale), _mul2012(b, scale))
+ for x, y, a, b in font._vf[char].boxes])
 
 def _put_rule(self, a, b):
 if self.state != _dvistate.inpage:
 raise ValueError, "misplaced put_rule in dvi file"
 if a > 0 and b > 0:
 self.boxes.append((self.h, self.v, a, b))
+# matplotlib.verbose.report(
+# 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b),
+# 'debug-annoying')
 
 def _nop(self):
 pass
@@ -357,7 +366,7 @@
 
 vf = _vffile(n[-l:])
 
- self.fonts[k] = mpl_cbook.Bunch(scale=s, tfm=tfm, name=n, vf=vf)
+ self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf)
 
 def _post(self):
 if self.state != _dvistate.outer:
@@ -370,17 +379,20 @@
 raise NotImplementedError
 
 class DviFont(object):
- __slots__ = ('texname', 'size')
+ """
+ Object that holds a font's texname and size and supports comparison.
+ There are also internal attributes (for use by dviread.py) that
+ are _not_ used for comparison.
 
- def __init__(self, f):
- """
- Object that holds a font's texname and size and supports comparison.
+ The size is in Adobe points (converted from TeX points).
+ """
+ __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm')
 
- The size is in Adobe points (converted from TeX points).
- """
+ def __init__(self, scale, tfm, texname, vf):
+ self._scale, self._tfm, self.texname, self._vf = \
+ scale, tfm, texname, vf
 # TODO: would it make more sense to have the size in dpi units?
- self.texname = f.name
- self.size = f.scale * (72.0 / (72.27 * 2**16))
+ self.size = scale * (72.0 / (72.27 * 2**16))
 
 def __eq__(self, other):
 return self.__class__ == other.__class__ and \
@@ -389,6 +401,16 @@
 def __ne__(self, other):
 return not self.__eq__(other)
 
+ def _width_of(self, char):
+ width = self._tfm.width.get(char, None)
+ if width is not None:
+ return _mul2012(width, self._scale)
+
+ matplotlib.verbose.report(
+ 'No width for char %d in font %s' % (char, self.texname),
+ 'debug')
+ return 0
+
 class Vf(Dvi):
 """
 A virtual font (*.vf file) containing subroutines for dvi files.
@@ -465,7 +487,8 @@
 raise ValueError, "pre command in middle of vf file"
 if i != 202:
 raise ValueError, "Unknown vf format %d" % i
- matplotlib.verbose.report('vf file comment: ' + x, 'debug')
+ if len(x):
+ matplotlib.verbose.report('vf file comment: ' + x, 'debug')
 self.state = _dvistate.outer
 # cs = checksum, ds = design size
 
@@ -474,7 +497,7 @@
 if self._first_font is None:
 self._first_font = k
 
-def fix2comp(num):
+def _fix2comp(num):
 """
 Convert from two's complement to negative.
 """
@@ -484,6 +507,13 @@
 else:
 return num
 
+def _mul2012(num1, num2):
+ """
+ Multiply two numbers in 20.12 fixed point format.
+ """
+ # Separated into a function because >> has surprising precedence
+ return (num1*num2) >> 20
+
 class Tfm(object):
 """
 A TeX Font Metric file. This implementation covers only the bare
@@ -497,6 +527,7 @@
 (this is a dict because indexing may not start from 0)
 height[i], depth[i]: height and depth of character #i
 """
+ __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth')
 
 def __init__(self, filename):
 matplotlib.verbose.report('opening tfm file ' + filename, 'debug')
@@ -525,9 +556,9 @@
 [ struct.unpack('!%dI' % (len(x)/4), x) 
 for x in (widths, heights, depths) ]
 for i in range(ec-bc):
- self.width[bc+i] = fix2comp(widths[ord(char_info[4*i])])
- self.height[bc+i] = fix2comp(heights[ord(char_info[4*i+1]) >> 4])
- self.depth[bc+i] = fix2comp(depths[ord(char_info[4*i+1]) & 0xf])
+ self.width[bc+i] = _fix2comp(widths[ord(char_info[4*i])])
+ self.height[bc+i] = _fix2comp(heights[ord(char_info[4*i+1]) >> 4])
+ self.depth[bc+i] = _fix2comp(depths[ord(char_info[4*i+1]) & 0xf])
 
 
 class PsfontsMap(object):
@@ -552,6 +583,7 @@
 the pdf-related files perhaps only avoid the "Base 14" pdf fonts.
 But the user may have configured these files differently.
 """
+ __slots__ = ('_font',)
 
 def __init__(self, filename):
 self._font = {}
@@ -627,7 +659,17 @@
 encoding=encoding, filename=filename)
 
 class Encoding(object):
+ """
+ Parses a *.enc file referenced from a psfonts.map style file.
+ The format this class understands is a very limited subset of
+ PostScript.
 
+ Usage (subject to change):
+ for name in Encoding(filename): 
+ whatever(name)
+ """
+ __slots__ = ('encoding',)
+
 def __init__(self, filename):
 file = open(filename, 'rt')
 try:
@@ -694,6 +736,10 @@
 
 return result
 
+# With multiple text objects per figure (e.g. tick labels) we may end
+# up reading the same tfm and vf files many times, so we implement a
+# simple cache. TODO: is this worth making persistent?
+
 _tfmcache = {}
 _vfcache = {}
 
@@ -721,19 +767,22 @@
 
 
 if __name__ == '__main__':
- matplotlib.verbose.set_level('debug')
- dvi = Dvi('foo.dvi', 72)
+ import sys
+ matplotlib.verbose.set_level('debug-annoying')
+ fname = sys.argv[1]
+ try: dpi = float(sys.argv[2])
+ except IndexError: dpi = None
+ dvi = Dvi(fname, dpi)
 fontmap = PsfontsMap(find_tex_file('pdftex.map'))
- for text,boxes in dvi:
+ for page in dvi:
 print '=== new page ==='
 fPrev = None
- for x,y,f,c in text:
- texname = dvi.fonts[f].name
- print x,y,c,chr(c),texname
+ for x,y,f,c,w in page.text:
 if f != fPrev:
- print 'font', texname, '=', fontmap[texname].__dict__
+ print 'font', f.texname, 'scaled', f._scale/pow(2.0,20)
 fPrev = f
- for x,y,w,h in boxes:
+ print x,y,c, 32 <= c < 128 and chr(c) or '.', w
+ for x,y,w,h in page.boxes:
 print x,y,'BOX',w,h
 
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jd...@us...> - 2007年09月12日 20:37:47
Revision: 3844
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3844&view=rev
Author: jdh2358
Date: 2007年09月12日 13:37:41 -0700 (2007年9月12日)
Log Message:
-----------
fixed a bar units bug
Modified Paths:
--------------
 trunk/matplotlib/API_CHANGES
 trunk/matplotlib/CHANGELOG
 trunk/matplotlib/lib/matplotlib/artist.py
 trunk/matplotlib/lib/matplotlib/axes.py
 trunk/matplotlib/lib/matplotlib/axis.py
 trunk/matplotlib/lib/matplotlib/mlab.py
 trunk/matplotlib/lib/matplotlib/patches.py
Added Paths:
-----------
 trunk/matplotlib/examples/units/bar_demo2.py
Modified: trunk/matplotlib/API_CHANGES
===================================================================
--- trunk/matplotlib/API_CHANGES	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/API_CHANGES	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -1,3 +1,5 @@
+ Made skiprows=1 the default on csv2rec
+
 The gd and paint backends have been deleted.
 
 The errorbar method and function now accept additional kwargs
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/CHANGELOG	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -1,3 +1,7 @@
+2007年09月12日 Fixed a Axes.bar unit bug - JDH
+
+2007年09月10日 Made skiprows=1 the default on csv2rec - JDH
+
 2007年09月09日 Split out the plotting part of pylab and put it in
 pyplot.py; removed numerix from the remaining pylab.py,
 which imports everything from pyplot.py. The intention
Added: trunk/matplotlib/examples/units/bar_demo2.py
===================================================================
--- trunk/matplotlib/examples/units/bar_demo2.py	 (rev 0)
+++ trunk/matplotlib/examples/units/bar_demo2.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -0,0 +1,34 @@
+"""
+plot using a variety of cm vs inches conversions. The example shows
+how default unit instrospection works (ax1), how various keywords can
+be used to set the x and y units to override the defaults (ax2, ax3,
+ax4) and how one can set the xlimits using scalars (ax3, current units
+assumed) or units (conversions applied to get the numbers to current
+units)
+
+"""
+from basic_units import cm, inch
+from pylab import figure, show, nx
+
+cms = cm *nx.arange(0, 10, 2)
+bottom=0*cm
+width=0.8*cm
+
+fig = figure()
+
+ax1 = fig.add_subplot(2,2,1)
+ax1.bar(cms, cms, bottom=bottom)
+
+ax2 = fig.add_subplot(2,2,2)
+ax2.bar(cms, cms, bottom=bottom, width=width, xunits=cm, yunits=inch)
+
+ax3 = fig.add_subplot(2,2,3)
+ax3.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=cm)
+ax3.set_xlim(3, 6) # scalars are interpreted in current units
+
+ax4 = fig.add_subplot(2,2,4)
+ax4.bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=inch)
+#fig.savefig('simple_conversion_plot.png')
+ax4.set_xlim(3*cm, 6*cm) # cm are converted to inches
+
+show()
Modified: trunk/matplotlib/lib/matplotlib/artist.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/artist.py	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/lib/matplotlib/artist.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -51,7 +51,7 @@
 self._remove_method = None
 
 def remove(self):
- '''
+ """
 Remove the artist from the figure if possible. The effect will not
 be visible until the figure is redrawn, e.g., with ax.draw_idle().
 Call ax.relim() to update the axes limits if desired.
@@ -60,7 +60,7 @@
 was added to axes with autolim=True.
 
 Note: there is no support for removing the artist's legend entry.
- '''
+ """
 
 # There is no method to set the callback. Instead the parent should set
 # the _remove_method attribute directly. This would be a protected
Modified: trunk/matplotlib/lib/matplotlib/axes.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axes.py	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/lib/matplotlib/axes.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -1198,23 +1198,27 @@
 def _process_unit_info(self, xdata=None, ydata=None, kwargs=None):
 'look for unit kwargs and update the axis instances as necessary'
 
- if self.xaxis is None or self.xaxis is None: return
+ if self.xaxis is None or self.yaxis is None: return
 
-
+ #print 'processing', self.get_geometry()
 if xdata is not None:
 self.xaxis.update_units(xdata)
+ #print '\tset from xdata', self.xaxis.units
 
 if ydata is not None:
 self.yaxis.update_units(ydata)
+ #print '\tset from ydata', self.yaxis.units
 
 # process kwargs 2nd since these will override default units
 if kwargs is not None:
 xunits = kwargs.pop( 'xunits', self.xaxis.units)
 if xunits!=self.xaxis.units:
+ #print '\tkw setting xunits', xunits
 self.xaxis.set_units(xunits)
 
 yunits = kwargs.pop('yunits', self.yaxis.units)
 if yunits!=self.yaxis.units:
+ #print '\tkw setting yunits', yunits
 self.yaxis.set_units(yunits)
 
 def in_axes(self, xwin, ywin):
@@ -3114,11 +3118,13 @@
 else:
 raise ValueError, 'invalid orientation: %s' % orientation
 
- left = npy.asarray(left)
- height = npy.asarray(height)
- width = npy.asarray(width)
- bottom = npy.asarray(bottom)
 
+ # do not convert to array here as unit info is lost
+ #left = npy.asarray(left)
+ #height = npy.asarray(height)
+ #width = npy.asarray(width)
+ #bottom = npy.asarray(bottom)
+
 if len(linewidth) == 1: linewidth = linewidth * nbars
 
 # if color looks like a color string, an RGB tuple or a
@@ -3161,14 +3167,14 @@
 # lets do some conversions now
 if self.xaxis is not None:
 xconv = self.xaxis.converter
- if ( xconv ):
+ if xconv is not None:
 units = self.xaxis.get_units()
 left = xconv.convert( left, units )
 width = xconv.convert( width, units )
 
 if self.yaxis is not None:
 yconv = self.yaxis.converter
- if ( yconv ):
+ if yconv is not None :
 units = self.yaxis.get_units()
 bottom = yconv.convert( bottom, units )
 height = yconv.convert( height, units )
@@ -3208,12 +3214,14 @@
 
 if xerr is not None or yerr is not None:
 if orientation == 'vertical':
- x = left + 0.5*width
- y = bottom + height
+ # using list comps rather than arrays to preserve unit info
+ x = [l+0.5*w for l, w in zip(left, width)]
+ y = [b+h for b,h in zip(bottom, height)]
 
 elif orientation == 'horizontal':
- x = left + width
- y = bottom + 0.5*height
+ # using list comps rather than arrays to preserve unit info
+ x = [l+w for l,w in zip(left, width)]
+ y = [b+0.5*h for b,h in zip(bottom, height)]
 
 self.errorbar(
 x, y,
Modified: trunk/matplotlib/lib/matplotlib/axis.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/axis.py	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/lib/matplotlib/axis.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -828,7 +828,7 @@
 return x
 
 ret = self.converter.convert(x, self.units)
- #print 'convert_units converting: units=%s, converter=%s, in=%s, out=%s'%(self.units, self.converter, x, ret)
+ #print 'convert_units converting: axis=%s, units=%s, converter=%s, in=%s, out=%s'%(self, self.units, self.converter, x, ret)
 return ret
 
 def set_units(self, u):
Modified: trunk/matplotlib/lib/matplotlib/mlab.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mlab.py	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/lib/matplotlib/mlab.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -1253,9 +1253,9 @@
 if r==1 or c==1:
 X.shape = max(r,c),
 if unpack: return X.transpose()
- return X
+ else: return X
 
-def csv2rec(fname, comments='#', skiprows=0, checkrows=5, delimiter=',',
+def csv2rec(fname, comments='#', skiprows=1, checkrows=5, delimiter=',',
 converterd=None, names=None, missing=None):
 """
 Load data from comma/space/tab delimited file in fname into a
Modified: trunk/matplotlib/lib/matplotlib/patches.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/patches.py	2007年09月12日 20:25:17 UTC (rev 3843)
+++ trunk/matplotlib/lib/matplotlib/patches.py	2007年09月12日 20:37:41 UTC (rev 3844)
@@ -77,6 +77,8 @@
 if len(kwargs): artist.setp(self, **kwargs)
 __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
 
+
+
 def contains(self, mouseevent):
 """Test whether the mouse event occurred in the patch.
 
@@ -347,7 +349,6 @@
 Return the vertices of the rectangle
 """
 x, y = self.xy
-
 left, right = self.convert_xunits((x, x + self.width))
 bottom, top = self.convert_yunits((y, y + self.height))
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jd...@us...> - 2007年09月12日 20:25:19
Revision: 3843
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3843&view=rev
Author: jdh2358
Date: 2007年09月12日 13:25:17 -0700 (2007年9月12日)
Log Message:
-----------
minor changes for gtk navigation
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/backends/backend_gtk.py
 branches/transforms/lib/matplotlib/backends/backend_gtkagg.py
Modified: branches/transforms/lib/matplotlib/backends/backend_gtk.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_gtk.py	2007年09月12日 19:47:56 UTC (rev 3842)
+++ branches/transforms/lib/matplotlib/backends/backend_gtk.py	2007年09月12日 20:25:17 UTC (rev 3843)
@@ -405,8 +405,8 @@
 self.toolbar = self._get_toolbar(canvas)
 
 # calculate size for window
- w = int (self.canvas.figure.bbox.width())
- h = int (self.canvas.figure.bbox.height())
+ w = int (self.canvas.figure.bbox.width)
+ h = int (self.canvas.figure.bbox.height)
 
 if self.toolbar is not None:
 self.toolbar.show()
@@ -518,7 +518,7 @@
 
 gc = drawable.new_gc()
 
- height = self.canvas.figure.bbox.height()
+ height = self.canvas.figure.bbox.height
 y1 = height - y1
 y0 = height - y0
 
@@ -639,8 +639,8 @@
 toolfig.subplots_adjust(top=0.9)
 tool = SubplotTool(self.canvas.figure, toolfig)
 
- w = int (toolfig.bbox.width())
- h = int (toolfig.bbox.height())
+ w = int (toolfig.bbox.width)
+ h = int (toolfig.bbox.height)
 
 
 window = gtk.Window()
Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py	2007年09月12日 19:47:56 UTC (rev 3842)
+++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py	2007年09月12日 20:25:17 UTC (rev 3843)
@@ -60,8 +60,9 @@
 w,h = widget.window.get_size()
 if w==1 or h==1: return # empty fig
 
+	# dpival = self.figure.dpi.get() MGDTODO
 # compute desired figure size in inches
- dpival = self.figure.dpi.get()
+ dpival = self.figure.dpi
 winch = w/dpival
 hinch = h/dpival
 self.figure.set_size_inches(winch, hinch)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 19:48:00
Revision: 3842
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3842&view=rev
Author: mdboom
Date: 2007年09月12日 12:47:56 -0700 (2007年9月12日)
Log Message:
-----------
More progress. Zooming and panning working thanks to John's patch.
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/artist.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/backend_bases.py
 branches/transforms/lib/matplotlib/backends/backend_agg.py
 branches/transforms/lib/matplotlib/backends/backend_tkagg.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -8,9 +8,16 @@
 from numpy.linalg import inv
 from sets import Set
 
+# MGDTODO: The name of this module is bad, since it deals with
+# non-affine transformations as well. It should probably just be
+# "transforms", but we already had one of those... ;)
+
 # MGDTODO: This creates a ton of cyclical references. We may want to
 # consider using weak references
 
+# MGDTODO: deep copying is probably incorrect wrt the parent/child
+# relationships
+
 class TransformNode(object):
 def __init__(self):
 	self._parents = Set()
@@ -48,29 +55,31 @@
 	points = N.array(args, dtype=N.float_).reshape(2, 2)
 	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
+ 
+ def __copy__(self):
+	return Bbox(self._points.copy())
 
+ def __deepcopy__(self, memo):
+	return Bbox(self._points.copy())
+ 
 def __cmp__(self, other):
 	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox):
-	 if (self._points == other._points).all():
-		return 0
+	if isinstance(other, Bbox) and (self._points == other._points).all():
+	 return 0
 	return -1
- 
+
+ def __repr__(self):
+	return 'Bbox(%s)' % repr(self._points)
+ __str__ = __repr__
+
 # JDH: the update method will update the box limits from the
 # existing limits and the new data; it appears here you are just
 # using the new data. We use an "ignore" flag to specify whether
 # you want to include the existing data or not in the update
- def update_from_data(self, x, y):
+ def update_from_data(self, x, y, ignore=True):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
- 
- def copy(self):
-	return Bbox(self._points.copy())
 
- def __repr__(self):
-	return 'Bbox(%s)' % repr(self._points)
- __str__ = __repr__
-
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
 	return self._points[0, 0]
@@ -136,19 +145,24 @@
 	return self.ymax - self.ymin
 height = property(_get_height)
 
+ def _get_bounds(self):
+	return (self.xmin, self.ymin,
+		self.xmax - self.xmin, self.ymax - self.ymin)
+ def _set_bounds(self, bounds):
+	l,b,w,h = bounds
+	self._points = N.array([[l, b], [l+w, b+h]], N.float_)
+	self.invalidate()
+ bounds = property(_get_bounds, _set_bounds)
+	
 def transformed(self, transform):
 	return Bbox(transform(self._points))
 
 def inverse_transformed(self, transform):
 	return Bbox(transform.inverted()(self._points))
 
- def get_bounds(self):
-	return (self.xmin, self.ymin,
-		self.xmax - self.xmin, self.ymax - self.ymin)
-
 def expanded(self, sw, sh):
-	width = self.width()
-	height = self.height()
+	width = self.width
+	height = self.height
 	deltaw = (sw * width - width) / 2.0
 	deltah = (sh * height - height) / 2.0
 	a = N.array([[-deltaw, -deltah], [deltaw, deltah]])
@@ -199,6 +213,9 @@
 	if isinstance(other, Transform):
 	 return composite_transform_factory(other, self)
 	raise TypeError("Can not add Transform to object of type '%s'" % type(other))
+
+ def transform_point(self, point):
+	return self.__call__([point])[0]
 
 def has_inverse(self):
 	raise NotImplementedError()
@@ -211,49 +228,27 @@
 
 def is_affine(self):
 	return False
-	
-class Affine2D(Transform):
+
+# MGDTODO: Separate out Affine2DBase / Affine2DConcrete so BlendedAffine and CompositeAffine don't have translate/scale/rotate members
+
+class Affine2DBase(Transform):
 input_dims = 2
 output_dims = 2
- 
- def __init__(self, matrix = None):
- """
- Initialize an Affine transform from a 3x3 numpy float array.
 
- a c e
- b d f
- 0 0 1
- """
+ def __init__(self):
 	Transform.__init__(self)
-	if matrix is None:
-	 matrix = N.identity(3)
-	else:
-	 assert matrix.shape == (3, 3)
-	self._mtx = matrix
 	self._inverted = None
 
- def __repr__(self):
-	return "Affine2D(%s)" % repr(self._mtx)
- __str__ = __repr__
-
- def __cmp__(self, other):
-	# MGDTODO: We need to decide if we want deferred transforms
-	# to be equal to this one
-	if isinstance(other, Affine2D):
-	 if (self.get_matrix() == other.get_matrix()).all():
-		return 0
-	return -1
- 
 def _do_invalidation(self):
 	result = self._inverted is None
 	self._inverted = None
 	return result
+
+ #@staticmethod
+ def _concat(a, b):
+ return N.dot(b, a)
+ _concat = staticmethod(_concat)
 
- #@staticmethod
- def from_values(a, b, c, d, e, f):
- return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
- from_values = staticmethod(from_values)
-
 def to_values(self):
 	mtx = self.get_matrix()
 	return tuple(mtx[:2].swapaxes(0, 1).flatten())
@@ -268,7 +263,7 @@
 matrix_from_values = staticmethod(matrix_from_values)
 
 def get_matrix(self):
-	return self._mtx
+	raise NotImplementedError()
 
 def __call__(self, points):
 """
@@ -278,26 +273,74 @@
 	points must be a numpy array of shape (N, 2), where N is the
 	number of points.
 	"""
-	# MGDTODO: This involves a copy. We may need to do something like
-	# http://neuroimaging.scipy.org/svn/ni/ni/trunk/neuroimaging/core/reference/mapping.py
-	# to separate the matrix out into the translation and scale components
-	# and apply each separately (which is still sub-optimal)
-
-	# This is easier for now, however, since we can just keep a
-	# regular affine matrix around
-	# MGDTODO: Trap cases where this isn't an array and fix there
+	# MGDTODO: The major speed trap here is just converting to
+	# the points to an array in the first place. If we can use
+	# more arrays upstream, that should help here.
 	mtx = self.get_matrix()
 	points = N.asarray(points, N.float_)
-	new_points = points.swapaxes(0, 1)
-	new_points = N.vstack((new_points, N.ones((1, points.shape[0]))))
-	result = N.dot(mtx, new_points)[:2]
-	return result.swapaxes(0, 1)
+	points = points.transpose()
+	points = N.dot(mtx[0:2, 0:2], points)
+	points = points + mtx[0:2, 2:]
+	return points.transpose()
 
+ def inverted(self):
+	if self._inverted is None:
+	 mtx = self.get_matrix()
+	 self._inverted = Affine2D(inv(mtx))
+	return self._inverted
+ 
+ def is_separable(self):
+	mtx = self.get_matrix()
+	return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0
+
+ def is_affine(self):
+	return True
+
+	
+class Affine2D(Affine2DBase):
+ input_dims = 2
+ output_dims = 2
+ 
+ def __init__(self, matrix = None):
+ """
+ Initialize an Affine transform from a 3x3 numpy float array.
+
+ a c e
+ b d f
+ 0 0 1
+ """
+	Affine2DBase.__init__(self)
+	if matrix is None:
+	 matrix = N.identity(3)
+	else:
+	 assert matrix.shape == (3, 3)
+	self._mtx = matrix
+	self._inverted = None
+
+ def __repr__(self):
+	return "Affine2D(%s)" % repr(self._mtx)
+ __str__ = __repr__
+
+ def __cmp__(self, other):
+	if (isinstance(other, Affine2D) and
+	 (self.get_matrix() == other.get_matrix()).all()):
+	 return 0
+	return -1
+ 
+ def __copy__(self):
+	return Affine2D(self._mtx.copy())
+ 
+ def __deepcopy__(self, memo):
+	return Affine2D(self._mtx.copy())
+ 
 #@staticmethod
- def _concat(a, b):
- return N.dot(b, a)
- _concat = staticmethod(_concat)
+ def from_values(a, b, c, d, e, f):
+ return Affine2D(Affine2D.matrix_from_values(a, b, c, d, e, f))
+ from_values = staticmethod(from_values)
 
+ def get_matrix(self):
+	return self._mtx
+ 
 #@staticmethod
 def concat(a, b):
 	return Affine2D(Affine2D._concat(a._mtx, b._mtx))
@@ -346,19 +389,18 @@
 def is_affine(self):
 	return True
 
-class BlendedAffine2D(Affine2D):
+class BlendedAffine2D(Affine2DBase):
 def __init__(self, x_transform, y_transform):
 	assert x_transform.is_affine()
 	assert y_transform.is_affine()
 	assert x_transform.is_separable()
 	assert y_transform.is_separable()
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([x_transform, y_transform])
 	self._x = x_transform
 	self._y = y_transform
 	self._mtx = None
-	self._inverted = None
 
 def __repr__(self):
 	return "BlendedAffine2D(%s,%s)" % (self._x, self._y)
@@ -367,7 +409,7 @@
 def _do_invalidation(self):
 	if self._mtx is not None:
 	 self._mtx = None
-	 Affine2D._do_invalidation(self)
+	 Affine2DBase._do_invalidation(self)
 	 return False
 	return True
 
@@ -376,8 +418,9 @@
 	 x_mtx = self._x.get_matrix()
 	 y_mtx = self._y.get_matrix()
 	 # This works because we already know the transforms are
-	 # separable
-	 self._mtx = N.vstack([x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]])
+	 # separable, though normally one would want to set b and
+	 # c to zero.
+	 self._mtx = N.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]))
 	
 def is_separable(self):
 	return True
@@ -397,20 +440,22 @@
 	self._y = y_transform
 
 def __call__(self, points):
-	# MGDTODO: Implement me
-	pass
+	x_points = self._x(points)
+	y_points = self._y(points)
+	# This works because we already know the transforms are
+	# separable
+	return N.hstack((x_points[:, 0:1], y_points[:, 1:2]))
 
-class CompositeAffine2D(Affine2D):
+class CompositeAffine2D(Affine2DBase):
 def __init__(self, a, b):
 	assert a.is_affine()
 	assert b.is_affine()
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([a, b])
 	self._a = a
 	self._b = b
 	self._mtx = None
-	self._inverted = None
 
 def __repr__(self):
 	return "CompositeAffine2D(%s, %s)" % (self._a, self._b)
@@ -418,7 +463,7 @@
 
 def _do_invalidation(self):
 	self._mtx = None
-	Affine2D._do_invalidation(self)
+	Affine2DBase._do_invalidation(self)
 
 def _make__mtx(self):
 	if self._mtx is None:
@@ -433,22 +478,23 @@
 class CompositeTransform(Transform):
 def __init__(self, a, b):
 	assert a.output_dims == b.input_dims
-
+	self.input_dims = a.input_dims
+	self.output_dims = b.output_dims
+	
 	Transform.__init__(self)
 	self.add_children([a, b])
 	self._a = a
 	self._b = b
 
 def __call__(self, points):
-	# MGDTODO: Optimize here by concatenating affines if possible
 	return self._b(self._a(points))
 
-class BboxTransform(Affine2D):
+class BboxTransform(Affine2DBase):
 def __init__(self, boxin, boxout):
 	assert isinstance(boxin, Bbox)
 	assert isinstance(boxout, Bbox)
 
-	Transform.__init__(self)
+	Affine2DBase.__init__(self)
 	self.add_children([boxin, boxout])
 	self._boxin = boxin
 	self._boxout = boxout
@@ -462,7 +508,7 @@
 def _do_invalidation(self):
 	if self._mtx is not None:
 	 self._mtx = None
-	 Affine2D._do_invalidation(self)
+	 Affine2DBase._do_invalidation(self)
 	 return False
 	return True
 
@@ -481,14 +527,6 @@
 
 	 self._mtx = affine._mtx
 	
- def __call__(self, points):
-	self._make__mtx()
-	return Affine2D.__call__(self, points)
-
- def inverted(self):
-	self._make__mtx()
-	return Affine2D.inverted(self)
-
 def is_separable(self):
 	return True
 
@@ -541,6 +579,9 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ from random import random
+ import timeit
+
 bbox = Bbox.from_lbrt(10., 15., 20., 25.)
 assert bbox.xmin == 10
 assert bbox.ymin == 15
@@ -589,7 +630,9 @@
 scale = Affine2D().scale(10, 20)
 assert scale.to_values() == (10, 0, 0, 20, 0, 0)
 rotation = Affine2D().rotate_deg(30)
- print rotation.to_values() == (0.86602540378443871, 0.49999999999999994, -0.49999999999999994, 0.86602540378443871, 0.0, 0.0)
+ print rotation.to_values() == (0.86602540378443871, 0.49999999999999994,
+				 -0.49999999999999994, 0.86602540378443871,
+				 0.0, 0.0)
 
 points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
 translated_points = translation(points)
@@ -600,11 +643,20 @@
 print rotated_points
 
 tpoints1 = rotation(translation(scale(points)))
- trans_sum = rotation + translation + scale
+ trans_sum = scale + translation + rotation
 tpoints2 = trans_sum(points)
 print tpoints1, tpoints2
 print tpoints1 == tpoints2
 # Need to do some sort of fuzzy comparison here?
 # assert (tpoints1 == tpoints2).all()
+
+ # Here are some timing tests
+ points = [(random(), random()) for i in xrange(10000)]
+ t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points")
+ print "Time to transform 10000 x 10 points as tuples:", t.timeit(10)
+
+ points2 = N.asarray(points)
+ t = timeit.Timer("trans_sum(points2)", "from __main__ import trans_sum, points2")
+ print "Time to transform 10000 x 10 points as numpy array:", t.timeit(10)
 
 __all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/artist.py
===================================================================
--- branches/transforms/lib/matplotlib/artist.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/artist.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -337,7 +337,7 @@
 def _set_gc_clip(self, gc):
 'set the clip properly for the gc'
 if self.clipbox is not None:
- gc.set_clip_rectangle(self.clipbox.get_bounds())
+ gc.set_clip_rectangle(self.clipbox.bounds)
 gc.set_clip_path(self._clippath)
 
 def draw(self, renderer, *args, **kwargs):
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -1,5 +1,5 @@
 from __future__ import division, generators
-import math, sys, warnings
+import math, sys, warnings, copy
 
 import numpy as npy
 
@@ -483,7 +483,7 @@
 """
 martist.Artist.__init__(self)
 self._position = maffine.Bbox.from_lbwh(*rect)
- self._originalPosition = self._position.copy()
+ self._originalPosition = copy.deepcopy(self._position)
 self.set_axes(self)
 self.set_aspect('auto')
 self.set_adjustable('box')
@@ -613,7 +613,7 @@
 """
 martist.Artist.set_figure(self, fig)
 
- l, b, w, h = self._position.get_bounds()
+ l, b, w, h = self._position.bounds
 xmin = fig.bbox.xmin
 xmax = fig.bbox.xmax
 ymin = fig.bbox.ymin
@@ -669,9 +669,9 @@
 def get_position(self, original=False):
 'Return the axes rectangle left, bottom, width, height'
 if original:
- return self._originalPosition[:]
+ return self._originalPosition.bounds
 else:
- return self._position[:]
+ return self._position.bounds
 	 # return [val.get() for val in self._position]
 
 def set_position(self, pos, which='both'):
@@ -694,10 +694,10 @@
 # # Change values within self._position--don't replace it.
 # for num,val in zip(pos, self._position):
 # val.set(num)
-	 self._position = pos
+	 self._position.bounds = pos.bounds
 	 # MGDTODO: side-effects
 if which in ('both', 'original'):
- self._originalPosition = pos
+ self._originalPosition.bounds = pos.bounds
 	 
 	 
 def _set_artist_props(self, a):
@@ -1547,7 +1547,9 @@
 
 def get_xscale(self):
 'return the xaxis scale string: log or linear'
- return self.scaled[self.transData.get_funcx().get_type()]
+	# MGDTODO
+ # return self.scaled[self.transData.get_funcx().get_type()]
+	return 'linear'
 
 def set_xscale(self, value, basex = 10, subsx=None):
 """
@@ -1671,7 +1673,8 @@
 
 def get_yscale(self):
 'return the yaxis scale string: log or linear'
- return self.scaled[self.transData.get_funcy().get_type()]
+ # return self.scaled[self.transData.get_funcy().get_type()]
+	return 'linear'
 
 def set_yscale(self, value, basey=10, subsy=None):
 """
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backend_bases.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -4,7 +4,7 @@
 """
 
 from __future__ import division
-import os, sys, warnings
+import os, sys, warnings, copy
 
 import numpy as npy
 import matplotlib.numerix.npyma as ma
@@ -1070,7 +1070,7 @@
 def get_width_height(self):
 """return the figure width and height in points or pixels
 (depending on the backend), truncated to integers"""
- return int(self.figure.bbox.width()), int(self.figure.bbox.height())
+ return int(self.figure.bbox.width), int(self.figure.bbox.height)
 
 filetypes = {
 'emf': 'Enhanced Metafile',
@@ -1544,7 +1544,7 @@
 xmin, xmax = a.get_xlim()
 ymin, ymax = a.get_ylim()
 lim = xmin, xmax, ymin, ymax
- self._xypress.append((x, y, a, i, lim,a.transData.deepcopy()))
+ self._xypress.append((x, y, a, i, lim, copy.deepcopy(a.transData)))
 self.canvas.mpl_disconnect(self._idDrag)
 self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan)
 
@@ -1571,7 +1571,7 @@
 xmin, xmax = a.get_xlim()
 ymin, ymax = a.get_ylim()
 lim = xmin, xmax, ymin, ymax
- self._xypress.append(( x, y, a, i, lim, a.transData.deepcopy() ))
+ self._xypress.append(( x, y, a, i, lim, copy.deepcopy(a.transData) ))
 
 self.press(event)
 
@@ -1637,8 +1637,9 @@
 #safer to use the recorded button at the press than current button:
 #multiple button can get pressed during motion...
 if self._button_pressed==1:
- lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
- x, y = trans.inverse_xy_tup( (event.x, event.y) )
+		inverse = trans.inverted()
+ lastx, lasty = inverse.transform_point((lastx, lasty))
+ x, y = inverse.transform_point( (event.x, event.y) )
 if a.get_xscale()=='log':
 dx=1-lastx/x
 else:
@@ -1664,15 +1665,16 @@
 ymax -= dy
 elif self._button_pressed==3:
 try:
- dx=(lastx-event.x)/float(a.bbox.width())
- dy=(lasty-event.y)/float(a.bbox.height())
+ dx=(lastx-event.x)/float(a.bbox.width)
+ dy=(lasty-event.y)/float(a.bbox.height)
 dx,dy=format_deltas(event,dx,dy)
 if a.get_aspect() != 'auto':
 dx = 0.5*(dx + dy)
 dy = dx
 alphax = pow(10.0,dx)
 alphay = pow(10.0,dy)#use logscaling, avoid singularities and smother scaling...
- lastx, lasty = trans.inverse_xy_tup( (lastx, lasty) )
+		 inverse = trans.inverted()
+ lastx, lasty = inverse.transform_point( (lastx, lasty) )
 if a.get_xscale()=='log':
 xmin = lastx*(xmin/lastx)**alphax
 xmax = lastx*(xmax/lastx)**alphax
@@ -1710,8 +1712,9 @@
 xmin, ymin, xmax, ymax = lim
 
 # zoom to rect
- lastx, lasty = a.transData.inverse_xy_tup( (lastx, lasty) )
- x, y = a.transData.inverse_xy_tup( (x, y) )
+	 inverse = a.transData.inverted()
+ lastx, lasty = inverse.transform_point( (lastx, lasty) )
+ x, y = inverse.transform_point( (x, y) )
 Xmin,Xmax=a.get_xlim()
 Ymin,Ymax=a.get_ylim()
 
Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backends/backend_agg.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -398,7 +398,7 @@
 self.figure.draw(self.renderer)
 
 def get_renderer(self):
- l,b,w,h = self.figure.bbox.get_bounds()
+ l,b,w,h = self.figure.bbox.bounds
 	# MGDTODO
 # key = w, h, self.figure.dpi.get()
 key = w, h, self.figure.dpi
Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 18:22:24 UTC (rev 3841)
+++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py	2007年09月12日 19:47:56 UTC (rev 3842)
@@ -147,7 +147,7 @@
 def __init__(self, figure, master=None, resize_callback=None):
 FigureCanvasAgg.__init__(self, figure)
 self._idle = True
- t1,t2,w,h = self.figure.bbox.get_bounds()
+ t1,t2,w,h = self.figure.bbox.bounds
 w, h = int(w), int(h)
 self._tkcanvas = Tk.Canvas(
 master=master, width=w, height=h, borderwidth=4)
@@ -288,7 +288,7 @@
 self.window.wm_title("Figure %d" % num)
 self.canvas = canvas
 self._num = num
- t1,t2,w,h = canvas.figure.bbox.get_bounds()
+ t1,t2,w,h = canvas.figure.bbox.bounds
 w, h = int(w), int(h)
 self.window.minsize(int(w*3/4),int(h*3/4))
 if matplotlib.rcParams['toolbar']=='classic':
@@ -436,7 +436,7 @@
 self.canvas = canvas
 self.window = window
 
- xmin, xmax = canvas.figure.bbox.intervalx().get_bounds()
+ xmin, xmax = canvas.figure.bbox.intervalx
 height, width = 50, xmax-xmin
 Tk.Frame.__init__(self, master=self.window,
 width=width, height=height,
@@ -582,7 +582,7 @@
 self.message.set(s)
 
 def draw_rubberband(self, event, x0, y0, x1, y1):
- height = self.canvas.figure.bbox.height()
+ height = self.canvas.figure.bbox.height
 y0 = height-y0
 y1 = height-y1
 try: self.lastrect
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <js...@us...> - 2007年09月12日 18:22:26
Revision: 3841
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3841&view=rev
Author: jswhit
Date: 2007年09月12日 11:22:24 -0700 (2007年9月12日)
Log Message:
-----------
regenerate with Cython 0.9.6.6
Modified Paths:
--------------
 trunk/toolkits/basemap/src/_geod.c
 trunk/toolkits/basemap/src/_proj.c
Modified: trunk/toolkits/basemap/src/_geod.c
===================================================================
--- trunk/toolkits/basemap/src/_geod.c	2007年09月12日 18:14:38 UTC (rev 3840)
+++ trunk/toolkits/basemap/src/_geod.c	2007年09月12日 18:22:24 UTC (rev 3841)
@@ -1,4 +1,4 @@
-/* Generated by Pyrex 0.9.6.5 on Wed Sep 12 12:12:33 2007 */
+/* Generated by Cython 0.9.6.6 on Wed Sep 12 12:20:59 2007 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -50,8 +50,14 @@
 
 
 #ifdef __GNUC__
+/* Test for GCC > 2.95 */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) 
 #define likely(x) __builtin_expect(!!(x), 1)
 #define unlikely(x) __builtin_expect(!!(x), 0)
+#else /* __GNUC__ > 2 ... */
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ > 2 ... */
 #else /* __GNUC__ */
 #define likely(x) (x)
 #define unlikely(x) (x)
Modified: trunk/toolkits/basemap/src/_proj.c
===================================================================
--- trunk/toolkits/basemap/src/_proj.c	2007年09月12日 18:14:38 UTC (rev 3840)
+++ trunk/toolkits/basemap/src/_proj.c	2007年09月12日 18:22:24 UTC (rev 3841)
@@ -1,4 +1,4 @@
-/* Generated by Pyrex 0.9.6.3 on Fri Aug 31 08:42:47 2007 */
+/* Generated by Cython 0.9.6.6 on Wed Sep 12 12:21:02 2007 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -12,6 +12,8 @@
 #define PY_SSIZE_T_MIN INT_MIN
 #define PyInt_FromSsize_t(z) PyInt_FromLong(z)
 #define PyInt_AsSsize_t(o) PyInt_AsLong(o)
+ #define PyNumber_Index(o) PyNumber_Int(o)
+ #define PyIndex_Check(o) PyNumber_Check(o)
 #endif
 #ifdef __cplusplus
 #define __PYX_EXTERN_C extern "C"
@@ -37,6 +39,8 @@
 typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
 typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
 
+#define __pyx_PyIndex_AsSsize_t(b) PyInt_AsSsize_t(PyNumber_Index(b))
+
 #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
 static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
 if (x == Py_True) return 1;
@@ -46,8 +50,14 @@
 
 
 #ifdef __GNUC__
+/* Test for GCC > 2.95 */
+#if __GNUC__ > 2 || (__GNUC__ == 2 && (__GNUC_MINOR__ > 95)) 
 #define likely(x) __builtin_expect(!!(x), 1)
 #define unlikely(x) __builtin_expect(!!(x), 0)
+#else /* __GNUC__ > 2 ... */
+#define likely(x) (x)
+#define unlikely(x) (x)
+#endif /* __GNUC__ > 2 ... */
 #else /* __GNUC__ */
 #define likely(x) (x)
 #define unlikely(x) (x)
@@ -111,13 +121,10 @@
 
 static PyObject *__pyx_k2p;
 
-static PyObject *__pyx_f_5_proj_set_datapath(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_f_5_proj_set_datapath(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
- PyObject *__pyx_v_datapath = 0;
+static PyObject *__pyx_f_5_proj_set_datapath(PyObject *__pyx_self, PyObject *__pyx_v_datapath); /*proto*/
+static PyObject *__pyx_f_5_proj_set_datapath(PyObject *__pyx_self, PyObject *__pyx_v_datapath) {
 char (*__pyx_v_searchpath);
 PyObject *__pyx_r;
- static char *__pyx_argnames[] = {"datapath",0};
- if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "O", __pyx_argnames, &__pyx_v_datapath))) return 0;
 Py_INCREF(__pyx_v_datapath);
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_proj.pyx":7
@@ -401,15 +408,13 @@
 
 static PyObject *__pyx_n___class__;
 
-static PyObject *__pyx_f_5_proj_4Proj___reduce__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_f_5_proj_4Proj___reduce__(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
 static char __pyx_doc_5_proj_4Proj___reduce__[] = "special method that allows pyproj.Proj instance to be pickled";
-static PyObject *__pyx_f_5_proj_4Proj___reduce__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_f_5_proj_4Proj___reduce__(PyObject *__pyx_v_self, PyObject *unused) {
 PyObject *__pyx_r;
 PyObject *__pyx_1 = 0;
 PyObject *__pyx_2 = 0;
 PyObject *__pyx_3 = 0;
- static char *__pyx_argnames[] = {0};
- if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames))) return 0;
 Py_INCREF(__pyx_v_self);
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_proj.pyx":37
@@ -570,7 +575,7 @@
 __pyx_4 = PyNumber_Divide(__pyx_2, __pyx_3); if (unlikely(!__pyx_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; goto __pyx_L1;}
 Py_DECREF(__pyx_2); __pyx_2 = 0;
 Py_DECREF(__pyx_3); __pyx_3 = 0;
- __pyx_5 = PyInt_AsSsize_t(__pyx_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; goto __pyx_L1;}
+ __pyx_5 = __pyx_PyIndex_AsSsize_t(__pyx_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 60; goto __pyx_L1;}
 Py_DECREF(__pyx_4); __pyx_4 = 0;
 __pyx_v_ndim = __pyx_5;
 
@@ -922,7 +927,7 @@
 __pyx_4 = PyNumber_Divide(__pyx_2, __pyx_3); if (unlikely(!__pyx_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; goto __pyx_L1;}
 Py_DECREF(__pyx_2); __pyx_2 = 0;
 Py_DECREF(__pyx_3); __pyx_3 = 0;
- __pyx_5 = PyInt_AsSsize_t(__pyx_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; goto __pyx_L1;}
+ __pyx_5 = __pyx_PyIndex_AsSsize_t(__pyx_4); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 106; goto __pyx_L1;}
 Py_DECREF(__pyx_4); __pyx_4 = 0;
 __pyx_v_ndim = __pyx_5;
 
@@ -1142,13 +1147,11 @@
 return __pyx_r;
 }
 
-static PyObject *__pyx_f_5_proj_4Proj_is_latlong(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_f_5_proj_4Proj_is_latlong(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_f_5_proj_4Proj_is_latlong(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static PyObject *__pyx_f_5_proj_4Proj_is_latlong(PyObject *__pyx_v_self, PyObject *unused) {
 int __pyx_v_i;
 PyObject *__pyx_r;
 int __pyx_1;
- static char *__pyx_argnames[] = {0};
- if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames))) return 0;
 Py_INCREF(__pyx_v_self);
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_proj.pyx":133
@@ -1203,13 +1206,11 @@
 return __pyx_r;
 }
 
-static PyObject *__pyx_f_5_proj_4Proj_is_geocent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
-static PyObject *__pyx_f_5_proj_4Proj_is_geocent(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_f_5_proj_4Proj_is_geocent(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
+static PyObject *__pyx_f_5_proj_4Proj_is_geocent(PyObject *__pyx_v_self, PyObject *unused) {
 int __pyx_v_i;
 PyObject *__pyx_r;
 int __pyx_1;
- static char *__pyx_argnames[] = {0};
- if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames))) return 0;
 Py_INCREF(__pyx_v_self);
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_proj.pyx":142
@@ -1609,7 +1610,7 @@
 * if not radians and p2.is_latlong():
 * for i from 0 <= i < npts:
 */
- __pyx_7 = PyInt_AsLong(__pyx_v_ierr); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;}
+ __pyx_7 = PyInt_AsLong(__pyx_v_ierr); if (unlikely((__pyx_7 == -1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;}
 __pyx_4 = PyString_FromString(pj_strerrno(__pyx_7)); if (unlikely(!__pyx_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;}
 __pyx_3 = PyTuple_New(1); if (unlikely(!__pyx_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 178; goto __pyx_L1;}
 PyTuple_SET_ITEM(__pyx_3, 0, __pyx_4);
@@ -1791,11 +1792,11 @@
 }
 
 static struct PyMethodDef __pyx_methods_5_proj_Proj[] = {
- {"__reduce__", (PyCFunction)__pyx_f_5_proj_4Proj___reduce__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_proj_4Proj___reduce__},
+ {"__reduce__", (PyCFunction)__pyx_f_5_proj_4Proj___reduce__, METH_NOARGS, __pyx_doc_5_proj_4Proj___reduce__},
 {"_fwd", (PyCFunction)__pyx_f_5_proj_4Proj__fwd, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_proj_4Proj__fwd},
 {"_inv", (PyCFunction)__pyx_f_5_proj_4Proj__inv, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_proj_4Proj__inv},
- {"is_latlong", (PyCFunction)__pyx_f_5_proj_4Proj_is_latlong, METH_VARARGS|METH_KEYWORDS, 0},
- {"is_geocent", (PyCFunction)__pyx_f_5_proj_4Proj_is_geocent, METH_VARARGS|METH_KEYWORDS, 0},
+ {"is_latlong", (PyCFunction)__pyx_f_5_proj_4Proj_is_latlong, METH_NOARGS, 0},
+ {"is_geocent", (PyCFunction)__pyx_f_5_proj_4Proj_is_geocent, METH_NOARGS, 0},
 {0, 0, 0, 0}
 };
 
@@ -1924,7 +1925,7 @@
 };
 
 static struct PyMethodDef __pyx_methods[] = {
- {"set_datapath", (PyCFunction)__pyx_f_5_proj_set_datapath, METH_VARARGS|METH_KEYWORDS, 0},
+ {"set_datapath", (PyCFunction)__pyx_f_5_proj_set_datapath, METH_O, 0},
 {"_transform", (PyCFunction)__pyx_f_5_proj__transform, METH_VARARGS|METH_KEYWORDS, 0},
 {0, 0, 0, 0}
 };
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <js...@us...> - 2007年09月12日 18:14:42
Revision: 3840
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3840&view=rev
Author: jswhit
Date: 2007年09月12日 11:14:38 -0700 (2007年9月12日)
Log Message:
-----------
fix isnan check
Modified Paths:
--------------
 trunk/toolkits/basemap/src/_geod.c
 trunk/toolkits/basemap/src/_geod.pyx
Modified: trunk/toolkits/basemap/src/_geod.c
===================================================================
--- trunk/toolkits/basemap/src/_geod.c	2007年09月12日 17:25:19 UTC (rev 3839)
+++ trunk/toolkits/basemap/src/_geod.c	2007年09月12日 18:14:38 UTC (rev 3840)
@@ -1,4 +1,4 @@
-/* Generated by Pyrex 0.9.6.3 on Fri Aug 31 08:42:50 2007 */
+/* Generated by Pyrex 0.9.6.5 on Wed Sep 12 12:12:33 2007 */
 
 #define PY_SSIZE_T_CLEAN
 #include "Python.h"
@@ -12,6 +12,8 @@
 #define PY_SSIZE_T_MIN INT_MIN
 #define PyInt_FromSsize_t(z) PyInt_FromLong(z)
 #define PyInt_AsSsize_t(o) PyInt_AsLong(o)
+ #define PyNumber_Index(o) PyNumber_Int(o)
+ #define PyIndex_Check(o) PyNumber_Check(o)
 #endif
 #ifdef __cplusplus
 #define __PYX_EXTERN_C extern "C"
@@ -37,6 +39,8 @@
 typedef struct {PyObject **p; char *s;} __Pyx_InternTabEntry; /*proto*/
 typedef struct {PyObject **p; char *s; long n;} __Pyx_StringTabEntry; /*proto*/
 
+#define __pyx_PyIndex_AsSsize_t(b) PyInt_AsSsize_t(PyNumber_Index(b))
+
 #define __Pyx_PyBool_FromLong(b) ((b) ? (Py_INCREF(Py_True), Py_True) : (Py_INCREF(Py_False), Py_False))
 static INLINE int __Pyx_PyObject_IsTrue(PyObject* x) {
 if (x == Py_True) return 1;
@@ -337,15 +341,13 @@
 
 static PyObject *__pyx_n___class__;
 
-static PyObject *__pyx_f_5_geod_4Geod___reduce__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
+static PyObject *__pyx_f_5_geod_4Geod___reduce__(PyObject *__pyx_v_self, PyObject *unused); /*proto*/
 static char __pyx_doc_5_geod_4Geod___reduce__[] = "special method that allows pyproj.Geod instance to be pickled";
-static PyObject *__pyx_f_5_geod_4Geod___reduce__(PyObject *__pyx_v_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
+static PyObject *__pyx_f_5_geod_4Geod___reduce__(PyObject *__pyx_v_self, PyObject *unused) {
 PyObject *__pyx_r;
 PyObject *__pyx_1 = 0;
 PyObject *__pyx_2 = 0;
 PyObject *__pyx_3 = 0;
- static char *__pyx_argnames[] = {0};
- if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames))) return 0;
 Py_INCREF(__pyx_v_self);
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":27
@@ -421,6 +423,7 @@
 PyObject *__pyx_5 = 0;
 Py_ssize_t __pyx_6;
 double __pyx_7;
+ int __pyx_8;
 static char *__pyx_argnames[] = {"lons","lats","az","dist","radians",0};
 __pyx_v_radians = __pyx_k3;
 if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "OOOO|O", __pyx_argnames, &__pyx_v_lons, &__pyx_v_lats, &__pyx_v_az, &__pyx_v_dist, &__pyx_v_radians))) return 0;
@@ -571,7 +574,7 @@
 __pyx_5 = PyNumber_Divide(__pyx_3, __pyx_4); if (unlikely(!__pyx_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; goto __pyx_L1;}
 Py_DECREF(__pyx_3); __pyx_3 = 0;
 Py_DECREF(__pyx_4); __pyx_4 = 0;
- __pyx_6 = PyInt_AsSsize_t(__pyx_5); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; goto __pyx_L1;}
+ __pyx_6 = __pyx_PyIndex_AsSsize_t(__pyx_5); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 51; goto __pyx_L1;}
 Py_DECREF(__pyx_5); __pyx_5 = 0;
 __pyx_v_ndim = __pyx_6;
 
@@ -781,7 +784,7 @@
 * geod_for(&self.geodesic_t)
 * if pj_errno != 0: # <<<<<<<<<<<<<< 
 * raise RuntimeError(pj_strerrno(pj_errno))
- * if isnan(self.geodesic_t.ALPHA21) == FP_NAN:
+ * if isnan(self.geodesic_t.ALPHA21):
 */
 __pyx_1 = (pj_errno != 0);
 if (__pyx_1) {
@@ -790,7 +793,7 @@
 * geod_for(&self.geodesic_t)
 * if pj_errno != 0:
 * raise RuntimeError(pj_strerrno(pj_errno)) # <<<<<<<<<<<<<< 
- * if isnan(self.geodesic_t.ALPHA21) == FP_NAN:
+ * if isnan(self.geodesic_t.ALPHA21):
 * raise ValueError('undefined forward geodesic (may be an equatorial arc)')
 */
 __pyx_3 = PyString_FromString(pj_strerrno(pj_errno)); if (unlikely(!__pyx_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 72; goto __pyx_L1;}
@@ -809,16 +812,16 @@
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":73
 * if pj_errno != 0:
 * raise RuntimeError(pj_strerrno(pj_errno))
- * if isnan(self.geodesic_t.ALPHA21) == FP_NAN: # <<<<<<<<<<<<<< 
+ * if isnan(self.geodesic_t.ALPHA21): # <<<<<<<<<<<<<< 
 * raise ValueError('undefined forward geodesic (may be an equatorial arc)')
 * if radians:
 */
- __pyx_2 = (isnan(((struct __pyx_obj_5_geod_Geod *)__pyx_v_self)->geodesic_t.ALPHA21) == FP_NAN);
- if (__pyx_2) {
+ __pyx_8 = isnan(((struct __pyx_obj_5_geod_Geod *)__pyx_v_self)->geodesic_t.ALPHA21);
+ if (__pyx_8) {
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":74
 * raise RuntimeError(pj_strerrno(pj_errno))
- * if isnan(self.geodesic_t.ALPHA21) == FP_NAN:
+ * if isnan(self.geodesic_t.ALPHA21):
 * raise ValueError('undefined forward geodesic (may be an equatorial arc)') # <<<<<<<<<<<<<< 
 * if radians:
 * lonsdata[i] = self.geodesic_t.p2.v
@@ -836,14 +839,14 @@
 __pyx_L12:;
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":75
- * if isnan(self.geodesic_t.ALPHA21) == FP_NAN:
+ * if isnan(self.geodesic_t.ALPHA21):
 * raise ValueError('undefined forward geodesic (may be an equatorial arc)')
 * if radians: # <<<<<<<<<<<<<< 
 * lonsdata[i] = self.geodesic_t.p2.v
 * latsdata[i] = self.geodesic_t.p2.u
 */
- __pyx_1 = PyObject_IsTrue(__pyx_v_radians); if (unlikely(__pyx_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; goto __pyx_L1;}
- if (__pyx_1) {
+ __pyx_2 = PyObject_IsTrue(__pyx_v_radians); if (unlikely(__pyx_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 75; goto __pyx_L1;}
+ if (__pyx_2) {
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":76
 * raise ValueError('undefined forward geodesic (may be an equatorial arc)')
@@ -980,6 +983,7 @@
 PyObject *__pyx_5 = 0;
 Py_ssize_t __pyx_6;
 double __pyx_7;
+ int __pyx_8;
 static char *__pyx_argnames[] = {"lons1","lats1","lons2","lats2","radians",0};
 __pyx_v_radians = __pyx_k4;
 if (unlikely(!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "OOOO|O", __pyx_argnames, &__pyx_v_lons1, &__pyx_v_lats1, &__pyx_v_lons2, &__pyx_v_lats2, &__pyx_v_radians))) return 0;
@@ -1130,7 +1134,7 @@
 __pyx_5 = PyNumber_Divide(__pyx_3, __pyx_4); if (unlikely(!__pyx_5)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; goto __pyx_L1;}
 Py_DECREF(__pyx_3); __pyx_3 = 0;
 Py_DECREF(__pyx_4); __pyx_4 = 0;
- __pyx_6 = PyInt_AsSsize_t(__pyx_5); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; goto __pyx_L1;}
+ __pyx_6 = __pyx_PyIndex_AsSsize_t(__pyx_5); if (unlikely(PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 105; goto __pyx_L1;}
 Py_DECREF(__pyx_5); __pyx_5 = 0;
 __pyx_v_ndim = __pyx_6;
 
@@ -1281,7 +1285,7 @@
 * self.geodesic_t.p2.v = _dg2rad*azdata[i]
 * self.geodesic_t.p2.u = _dg2rad*distdata[i] # <<<<<<<<<<<<<< 
 * geod_inv(&self.geodesic_t)
- * if isnan(self.geodesic_t.DIST) == FP_NAN:
+ * if isnan(self.geodesic_t.DIST):
 */
 __pyx_3 = __Pyx_GetName(__pyx_m, __pyx_n__dg2rad); if (unlikely(!__pyx_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; goto __pyx_L1;}
 __pyx_4 = PyFloat_FromDouble((__pyx_v_distdata[__pyx_v_i])); if (unlikely(!__pyx_4)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 120; goto __pyx_L1;}
@@ -1298,7 +1302,7 @@
 * self.geodesic_t.p2.v = _dg2rad*azdata[i]
 * self.geodesic_t.p2.u = _dg2rad*distdata[i]
 * geod_inv(&self.geodesic_t) # <<<<<<<<<<<<<< 
- * if isnan(self.geodesic_t.DIST) == FP_NAN:
+ * if isnan(self.geodesic_t.DIST):
 * raise ValueError('undefined inverse geodesic (may be an antipodal point)')
 */
 geod_inv((&((struct __pyx_obj_5_geod_Geod *)__pyx_v_self)->geodesic_t));
@@ -1306,16 +1310,16 @@
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":122
 * self.geodesic_t.p2.u = _dg2rad*distdata[i]
 * geod_inv(&self.geodesic_t)
- * if isnan(self.geodesic_t.DIST) == FP_NAN: # <<<<<<<<<<<<<< 
+ * if isnan(self.geodesic_t.DIST): # <<<<<<<<<<<<<< 
 * raise ValueError('undefined inverse geodesic (may be an antipodal point)')
 * if pj_errno != 0:
 */
- __pyx_2 = (isnan(((struct __pyx_obj_5_geod_Geod *)__pyx_v_self)->geodesic_t.DIST) == FP_NAN);
- if (__pyx_2) {
+ __pyx_8 = isnan(((struct __pyx_obj_5_geod_Geod *)__pyx_v_self)->geodesic_t.DIST);
+ if (__pyx_8) {
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":123
 * geod_inv(&self.geodesic_t)
- * if isnan(self.geodesic_t.DIST) == FP_NAN:
+ * if isnan(self.geodesic_t.DIST):
 * raise ValueError('undefined inverse geodesic (may be an antipodal point)') # <<<<<<<<<<<<<< 
 * if pj_errno != 0:
 * raise RuntimeError(pj_strerrno(pj_errno))
@@ -1333,14 +1337,14 @@
 __pyx_L10:;
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":124
- * if isnan(self.geodesic_t.DIST) == FP_NAN:
+ * if isnan(self.geodesic_t.DIST):
 * raise ValueError('undefined inverse geodesic (may be an antipodal point)')
 * if pj_errno != 0: # <<<<<<<<<<<<<< 
 * raise RuntimeError(pj_strerrno(pj_errno))
 * if radians:
 */
- __pyx_1 = (pj_errno != 0);
- if (__pyx_1) {
+ __pyx_2 = (pj_errno != 0);
+ if (__pyx_2) {
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":125
 * raise ValueError('undefined inverse geodesic (may be an antipodal point)')
@@ -1369,8 +1373,8 @@
 * lonsdata[i] = self.geodesic_t.ALPHA12
 * latsdata[i] = self.geodesic_t.ALPHA21
 */
- __pyx_2 = PyObject_IsTrue(__pyx_v_radians); if (unlikely(__pyx_2 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;}
- if (__pyx_2) {
+ __pyx_1 = PyObject_IsTrue(__pyx_v_radians); if (unlikely(__pyx_1 < 0)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 126; goto __pyx_L1;}
+ if (__pyx_1) {
 
 /* "/Volumes/User/jwhitaker/python/pyproj/_geod.pyx":127
 * raise RuntimeError(pj_strerrno(pj_errno))
@@ -1868,7 +1872,7 @@
 }
 
 static struct PyMethodDef __pyx_methods_5_geod_Geod[] = {
- {"__reduce__", (PyCFunction)__pyx_f_5_geod_4Geod___reduce__, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_geod_4Geod___reduce__},
+ {"__reduce__", (PyCFunction)__pyx_f_5_geod_4Geod___reduce__, METH_NOARGS, __pyx_doc_5_geod_4Geod___reduce__},
 {"_fwd", (PyCFunction)__pyx_f_5_geod_4Geod__fwd, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_geod_4Geod__fwd},
 {"_inv", (PyCFunction)__pyx_f_5_geod_4Geod__inv, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_geod_4Geod__inv},
 {"_npts", (PyCFunction)__pyx_f_5_geod_4Geod__npts, METH_VARARGS|METH_KEYWORDS, __pyx_doc_5_geod_4Geod__npts},
Modified: trunk/toolkits/basemap/src/_geod.pyx
===================================================================
--- trunk/toolkits/basemap/src/_geod.pyx	2007年09月12日 17:25:19 UTC (rev 3839)
+++ trunk/toolkits/basemap/src/_geod.pyx	2007年09月12日 18:14:38 UTC (rev 3840)
@@ -70,7 +70,7 @@
 geod_for(&self.geodesic_t)
 if pj_errno != 0:
 raise RuntimeError(pj_strerrno(pj_errno))
- if isnan(self.geodesic_t.ALPHA21) == FP_NAN:
+ if isnan(self.geodesic_t.ALPHA21):
 raise ValueError('undefined forward geodesic (may be an equatorial arc)')
 if radians:
 lonsdata[i] = self.geodesic_t.p2.v
@@ -119,7 +119,7 @@
 self.geodesic_t.p2.v = _dg2rad*azdata[i]
 self.geodesic_t.p2.u = _dg2rad*distdata[i]
 geod_inv(&self.geodesic_t)
- if isnan(self.geodesic_t.DIST) == FP_NAN:
+ if isnan(self.geodesic_t.DIST):
 raise ValueError('undefined inverse geodesic (may be an antipodal point)')
 if pj_errno != 0:
 raise RuntimeError(pj_strerrno(pj_errno))
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 17:25:26
Revision: 3839
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3839&view=rev
Author: mdboom
Date: 2007年09月12日 10:25:19 -0700 (2007年9月12日)
Log Message:
-----------
Milestone -- simple_plot.py working with new affine framework (with
the exception of dpi propagation)
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/axes.py
 branches/transforms/lib/matplotlib/figure.py
 branches/transforms/lib/matplotlib/lines.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -33,29 +33,29 @@
 	self._points = N.asarray(points, N.float_)
 	self.track = False
 
- # JDH: if you define a del method, the garbage collector won't
- # destory cyclic references, so make sure you either manage these
- # yourself or remove the __del__ after testing
- def __del__(self):
-	if self.track:
-	 print "Bbox::__del__"
-	
 #@staticmethod
 def unit():
-	return Bbox([[0,0], [1,1]])
+	return Bbox.from_lbrt(0., 0., 1., 1.)
 unit = staticmethod(unit)
 
 #@staticmethod
 def from_lbwh(left, bottom, width, height):
-	return Bbox([[left, bottom], [left + width, bottom + height]])
+	return Bbox.from_lbrt(left, bottom, left + width, bottom + height)
 from_lbwh = staticmethod(from_lbwh)
 
 #@staticmethod
- def from_lbrt(left, bottom, right, top):
-	return Bbox([[left, bottom], [right, top]])
+ def from_lbrt(*args):
+	points = N.array(args, dtype=N.float_).reshape(2, 2)
+	return Bbox(points)
 from_lbrt = staticmethod(from_lbrt)
 
-
+ def __cmp__(self, other):
+	# MGDTODO: Totally suboptimal
+	if isinstance(other, Bbox):
+	 if (self._points == other._points).all():
+		return 0
+	return -1
+ 
 # JDH: the update method will update the box limits from the
 # existing limits and the new data; it appears here you are just
 # using the new data. We use an "ignore" flag to specify whether
@@ -63,31 +63,18 @@
 def update_from_data(self, x, y):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
-	if self.track:
-	 print "Bbox::update_from_data", self._points
 
 def copy(self):
-	if self.track:
-	 print "Bbox::copy"
 	return Bbox(self._points.copy())
 
 def __repr__(self):
 	return 'Bbox(%s)' % repr(self._points)
 __str__ = __repr__
 
- def __cmp__(self, other):
-	# MGDTODO: Totally suboptimal
-	if isinstance(other, Bbox):
-	 return (self._points == other._points).all()
-	return -1
- 
 # MGDTODO: Probably a more efficient ways to do this...
 def _get_xmin(self):
-	if self.track:
-	 print "Bbox::_get_xmin"
 	return self._points[0, 0]
 def _set_xmin(self, val):
-	print "Bbox::_set_xmin"
 	self._points[0, 0] = val
 	self.invalidate()
 xmin = property(_get_xmin, _set_xmin)
@@ -150,10 +137,10 @@
 height = property(_get_height)
 
 def transformed(self, transform):
-	return Bbox(self.transform(self._points))
+	return Bbox(transform(self._points))
 
 def inverse_transformed(self, transform):
-	return Bbox(self.transform.inverted()(self._points))
+	return Bbox(transform.inverted()(self._points))
 
 def get_bounds(self):
 	return (self.xmin, self.ymin,
@@ -249,6 +236,14 @@
 	return "Affine2D(%s)" % repr(self._mtx)
 __str__ = __repr__
 
+ def __cmp__(self, other):
+	# MGDTODO: We need to decide if we want deferred transforms
+	# to be equal to this one
+	if isinstance(other, Affine2D):
+	 if (self.get_matrix() == other.get_matrix()).all():
+		return 0
+	return -1
+ 
 def _do_invalidation(self):
 	result = self._inverted is None
 	self._inverted = None
@@ -380,10 +375,9 @@
 	if self._mtx is None:
 	 x_mtx = self._x.get_matrix()
 	 y_mtx = self._y.get_matrix()
+	 # This works because we already know the transforms are
+	 # separable
 	 self._mtx = N.vstack([x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0]])
-# 	 self._mtx = self.matrix_from_values(
-# 		x_mtx[0,0], 0.0, 0.0, y_mtx[1,1], x_mtx[0,2], y_mtx[1,2])
-	 print "Blended", x_mtx, y_mtx, self._mtx
 	
 def is_separable(self):
 	return True
@@ -429,8 +423,8 @@
 def _make__mtx(self):
 	if self._mtx is None:
 	 self._mtx = self._concat(
-		self._b.get_matrix(),
-		self._a.get_matrix())
+		self._a.get_matrix(),
+		self._b.get_matrix())
 
 def get_matrix(self):
 	self._make__mtx()
@@ -547,12 +541,70 @@
 return interval[0] < val and interval[1] > val
 
 if __name__ == '__main__':
+ bbox = Bbox.from_lbrt(10., 15., 20., 25.)
+ assert bbox.xmin == 10
+ assert bbox.ymin == 15
+ assert bbox.xmax == 20
+ assert bbox.ymax == 25
+
+ assert N.all(bbox.min == [10, 15])
+ assert N.all(bbox.max == [20, 25])
+ assert N.all(bbox.intervalx == (10, 20))
+ assert N.all(bbox.intervaly == (15, 25))
+
+ assert bbox.width == 10
+ assert bbox.height == 10
+
+ assert bbox.get_bounds() == (10, 15, 10, 10)
+
+ bbox.intervalx = (11, 21)
+ bbox.intervaly = (16, 26)
+ 
+ assert bbox.get_bounds() == (11, 16, 10, 10)
+
+ bbox.xmin = 12
+ bbox.ymin = 17
+ bbox.xmax = 22
+ bbox.ymax = 27
+
+ assert bbox.get_bounds() == (12, 17, 10, 10)
+
+ bbox = Bbox.from_lbwh(10, 11, 12, 13)
+ assert bbox.get_bounds() == (10, 11, 12, 13)
+
+ bbox_copy = bbox.copy()
+ assert bbox == bbox_copy
+ bbox_copy.max = (14, 15)
+ assert bbox.get_bounds() == (10, 11, 12, 13)
+ assert bbox_copy.get_bounds() == (10, 11, 4, 4)
+ 
 bbox1 = Bbox([[10., 15.], [20., 25.]])
 bbox2 = Bbox([[30., 35.], [40., 45.]])
 trans = BboxTransform(bbox1, bbox2)
- print trans(bbox1._points)
+ bbox3 = bbox1.transformed(trans)
+ assert bbox3 == bbox2
 
- bbox2.intervalx = 50, 55
- print trans(bbox1._points)
+ translation = Affine2D().translate(10, 20)
+ assert translation.to_values() == (1, 0, 0, 1, 10, 20)
+ scale = Affine2D().scale(10, 20)
+ assert scale.to_values() == (10, 0, 0, 20, 0, 0)
+ rotation = Affine2D().rotate_deg(30)
+ print rotation.to_values() == (0.86602540378443871, 0.49999999999999994, -0.49999999999999994, 0.86602540378443871, 0.0, 0.0)
 
+ points = N.array([[1,2],[3,4],[5,6],[7,8]], N.float_)
+ translated_points = translation(points)
+ assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all()
+ scaled_points = scale(points)
+ print scaled_points
+ rotated_points = rotation(points)
+ print rotated_points
+
+ tpoints1 = rotation(translation(scale(points)))
+ trans_sum = rotation + translation + scale
+ tpoints2 = trans_sum(points)
+ print tpoints1, tpoints2
+ print tpoints1 == tpoints2
+ # Need to do some sort of fuzzy comparison here?
+ # assert (tpoints1 == tpoints2).all()
+ 
 __all__ = ['Transform', 'Affine2D']
Modified: branches/transforms/lib/matplotlib/axes.py
===================================================================
--- branches/transforms/lib/matplotlib/axes.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/axes.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -653,15 +653,12 @@
 
 self.viewLim = Bbox.from_lbrt(left, bottom, right, top)
 	self.dataLim = Bbox.unit()
-	self.dataLim.track = True
 	
 self.transData = maffine.BboxTransform(
 self.viewLim, self.bbox)
 self.transAxes = maffine.BboxTransform(
 Bbox.unit(), self.bbox)
 
-	print "_set_lim_and_transforms", self.viewLim, self.transData, self.dataLim, self.transAxes, self.bbox
-
 	# MGDTODO
 # if self._sharex:
 # self.transData.set_funcx(self._sharex.transData.get_funcx())
@@ -697,7 +694,6 @@
 # # Change values within self._position--don't replace it.
 # for num,val in zip(pos, self._position):
 # val.set(num)
-	 print "set_position", self._position, pos
 	 self._position = pos
 	 # MGDTODO: side-effects
 if which in ('both', 'original'):
@@ -1182,9 +1178,7 @@
 #print type(x), type(y)
 	# MGDTODO
 ## self.dataLim.update_numerix(x, y, -1)
-	print "update_datalim_numerix", self.dataLim,
 	self.dataLim.update_from_data(x, y)
-	print self.dataLim
 
 def _get_verts_in_data_coords(self, trans, xys):
 if trans == self.transData:
@@ -1245,8 +1239,6 @@
 axis direction reversal that has already been done.
 """
 # if image data only just use the datalim
-	print "autoscale_view", self._autoscaleon, scalex, scaley
-	
 if not self._autoscaleon: return
 if (tight or (len(self.images)>0 and
 len(self.lines)==0 and
@@ -1274,7 +1266,7 @@
 
 def draw(self, renderer=None, inframe=False):
 "Draw everything (plot lines, axes, labels)"
- if renderer is None:
+	if renderer is None:
 renderer = self._cachedRenderer
 
 if renderer is None:
@@ -1550,7 +1542,6 @@
 xmin, xmax = maffine.nonsingular(xmin, xmax, increasing=False)
 
 	self.viewLim.intervalx = (xmin, xmax)
-	print 'set_xlim', self.viewLim, xmin, xmax
 	
 return xmin, xmax
 
@@ -1654,7 +1645,6 @@
 ACCEPTS: len(2) sequence of floats
 """
 
-	print "set_ylim", ymin, ymax, emit
 if ymax is None and iterable(ymin):
 ymin,ymax = ymin
 
@@ -1676,7 +1666,6 @@
 ymin, ymax = maffine.nonsingular(ymin, ymax, increasing=False)
 	self.viewLim.intervaly = (ymin, ymax)
 if emit: self.callbacks.process('ylim_changed', self)
-	print "set_ylim", self.viewLim
 	
 return ymin, ymax
 
Modified: branches/transforms/lib/matplotlib/figure.py
===================================================================
--- branches/transforms/lib/matplotlib/figure.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/figure.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -326,7 +326,6 @@
 
 	dpival = self.dpi
 	self.bbox.max = w * dpival, h * dpival
-	print self.bbox
 # self.figwidth.set(w) MGDTODO
 # self.figheight.set(h)
 	
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py	2007年09月12日 15:41:22 UTC (rev 3838)
+++ branches/transforms/lib/matplotlib/lines.py	2007年09月12日 17:25:19 UTC (rev 3839)
@@ -389,7 +389,6 @@
 
 
 def set_axes(self, ax):
-	print "set_axes"
 Artist.set_axes(self, ax)
 if ax.xaxis is not None:
 self._xcid = ax.xaxis.callbacks.connect('units', self.recache)
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <jd...@us...> - 2007年09月12日 15:41:28
Revision: 3838
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3838&view=rev
Author: jdh2358
Date: 2007年09月12日 08:41:22 -0700 (2007年9月12日)
Log Message:
-----------
removed Interval from canonical tickers and formatters
Modified Paths:
--------------
 branches/transforms/lib/matplotlib/affine.py
 branches/transforms/lib/matplotlib/axis.py
 branches/transforms/lib/matplotlib/ticker.py
Modified: branches/transforms/lib/matplotlib/affine.py
===================================================================
--- branches/transforms/lib/matplotlib/affine.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/affine.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -33,6 +33,9 @@
 	self._points = N.asarray(points, N.float_)
 	self.track = False
 
+ # JDH: if you define a del method, the garbage collector won't
+ # destory cyclic references, so make sure you either manage these
+ # yourself or remove the __del__ after testing
 def __del__(self):
 	if self.track:
 	 print "Bbox::__del__"
@@ -52,6 +55,11 @@
 	return Bbox([[left, bottom], [right, top]])
 from_lbrt = staticmethod(from_lbrt)
 
+
+ # JDH: the update method will update the box limits from the
+ # existing limits and the new data; it appears here you are just
+ # using the new data. We use an "ignore" flag to specify whether
+ # you want to include the existing data or not in the update
 def update_from_data(self, x, y):
 	self._points = N.array([[x.min(), y.min()], [x.max(), y.max()]], N.float_)
 	self.invalidate()
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/axis.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -855,9 +855,9 @@
 ACCEPTS: A Formatter instance
 """
 self.major.formatter = formatter
- self.major.formatter.set_view_interval( self.get_view_interval() )
- self.major.formatter.set_data_interval( self.get_data_interval() )
+ self.major.formatter.set_axis(self)
 
+
 def set_minor_formatter(self, formatter):
 """
 Set the formatter of the minor ticker
@@ -865,8 +865,7 @@
 ACCEPTS: A Formatter instance
 """
 self.minor.formatter = formatter
- self.minor.formatter.set_view_interval( self.get_view_interval() )
- self.minor.formatter.set_data_interval( self.get_data_interval() )
+ self.minor.formatter.set_axis(self)
 
 
 def set_major_locator(self, locator):
@@ -876,8 +875,7 @@
 ACCEPTS: a Locator instance
 """
 self.major.locator = locator
- self.major.locator.set_view_interval( self.get_view_interval() )
- self.major.locator.set_data_interval( self.get_data_interval() )
+ self.major.locator.set_axis(self)
 
 
 def set_minor_locator(self, locator):
@@ -887,8 +885,7 @@
 ACCEPTS: a Locator instance
 """
 self.minor.locator = locator
- self.minor.locator.set_view_interval( self.get_view_interval() )
- self.minor.locator.set_data_interval( self.get_data_interval() )
+ self.minor.locator.set_axis(self)
 
 def set_pickradius(self, pickradius):
 """
Modified: branches/transforms/lib/matplotlib/ticker.py
===================================================================
--- branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 14:46:03 UTC (rev 3837)
+++ branches/transforms/lib/matplotlib/ticker.py	2007年09月12日 15:41:22 UTC (rev 3838)
@@ -99,13 +99,7 @@
 minor ticks. See the matplotlib.dates module for more information and
 examples of using date locators and formatters.
 
-DEVELOPERS NOTE
 
-If you are implementing your own class or modifying one of these, it
-is critical that you use viewlim and dataInterval READ ONLY MODE so
-multiple axes can share the same locator w/o side effects!
-
-
 """
 
 
@@ -121,37 +115,11 @@
 
 
 class TickHelper:
+ axis = None
+ def set_axis(self, axis):
+ self.axis = axis
 
- viewInterval = None
- dataInterval = None
 
- def verify_intervals(self):
- if self.dataInterval is None:
- raise RuntimeError("You must set the data interval to use this function")
-
- if self.viewInterval is None:
- raise RuntimeError("You must set the view interval to use this function")
-
-
- def set_view_interval(self, interval):
- self.viewInterval = interval
-
- def set_data_interval(self, interval):
- self.dataInterval = interval
-
- def set_bounds(self, vmin, vmax):
- '''
- Set dataInterval and viewInterval from numeric vmin, vmax.
-
- This is for stand-alone use of Formatters and/or
- Locators that require these intervals; that is, for
- cases where the Intervals do not need to be updated
- automatically.
- '''
-	# MGDTODO: Interval no longer exists
- self.dataInterval = maffine.Interval([vmin, vmax])
- self.viewInterval = maffine.Interval([vmin, vmax])
-
 class Formatter(TickHelper):
 """
 Convert the tick location to a string
@@ -341,9 +309,8 @@
 'set the locations of the ticks'
 self.locs = locs
 if len(self.locs) > 0:
- self.verify_intervals()
-	 vmin, vmax = self.viewInterval
- d = abs(vmax - vmin)
+ vmin, vmax = self.axis.get_view_interval()
+ d = abs(vmax-vmin)
 if self._useOffset: self._set_offset(d)
 self._set_orderOfMagnitude(d)
 self._set_format()
@@ -865,14 +832,12 @@
 
 
 def __call__(self):
- self.verify_intervals()
- vmin, vmax = self.viewInterval
+ vmin, vmax = self.axis.get_view_interval()
 vmin, vmax = maffine.nonsingular(vmin, vmax, expander = 0.05)
 return self.bin_boundaries(vmin, vmax)
 
 def autoscale(self):
- self.verify_intervals()
- dmin, dmax = self.dataInterval
+ dmin, dmax = self.axis.get_data_interval()
 dmin, dmax = maffine.nonsingular(dmin, dmax, expander = 0.05)
 return npy.take(self.bin_boundaries(dmin, dmax), [0,-1])
 
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
From: <md...@us...> - 2007年09月12日 14:46:06
Revision: 3837
 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3837&view=rev
Author: mdboom
Date: 2007年09月12日 07:46:03 -0700 (2007年9月12日)
Log Message:
-----------
Adding pbox.py
Added Paths:
-----------
 branches/transforms/lib/matplotlib/pbox.py
Added: branches/transforms/lib/matplotlib/pbox.py
===================================================================
--- branches/transforms/lib/matplotlib/pbox.py	 (rev 0)
+++ branches/transforms/lib/matplotlib/pbox.py	2007年09月12日 14:46:03 UTC (rev 3837)
@@ -0,0 +1,126 @@
+# MGDTODO: Just included verbatim for now
+
+class PBox(list):
+ '''
+ A left-bottom-width-height (lbwh) specification of a bounding box,
+ such as is used to specify the position of an Axes object within
+ a Figure.
+ It is a 4-element list with methods for changing the size, shape,
+ and position relative to its container.
+ '''
+ coefs = {'C': (0.5, 0.5),
+ 'SW': (0,0),
+ 'S': (0.5, 0),
+ 'SE': (1.0, 0),
+ 'E': (1.0, 0.5),
+ 'NE': (1.0, 1.0),
+ 'N': (0.5, 1.0),
+ 'NW': (0, 1.0),
+ 'W': (0, 0.5)}
+ def __init__(self, box, container=None, llur=False):
+ if len(box) != 4:
+ raise ValueError("Argument must be iterable of length 4")
+ if llur:
+ box = [box[0], box[1], box[2]-box[0], box[3]-box[1]]
+ list.__init__(self, box)
+ self.set_container(container)
+
+ def as_llur(self):
+ return [self[0], self[1], self[0]+self[2], self[1]+self[3]]
+
+ def set_container(self, box=None):
+ if box is None:
+ box = self
+ if len(box) != 4:
+ raise ValueError("Argument must be iterable of length 4")
+ self._container = list(box)
+
+ def get_container(self, box):
+ return self._container
+
+ def anchor(self, c, container=None):
+ '''
+ Shift to position c within its container.
+
+ c can be a sequence (cx, cy) where cx, cy range from 0 to 1,
+ where 0 is left or bottom and 1 is right or top.
+
+ Alternatively, c can be a string: C for centered,
+ S for bottom-center, SE for bottom-left, E for left, etc.
+
+ Optional arg container is the lbwh box within which the
+ PBox is positioned; it defaults to the initial
+ PBox.
+ '''
+ if container is None:
+ container = self._container
+ l,b,w,h = container
+ if isinstance(c, str):
+ cx, cy = self.coefs[c]
+ else:
+ cx, cy = c
+ W,H = self[2:]
+ self[:2] = l + cx * (w-W), b + cy * (h-H)
+ return self
+
+ def shrink(self, mx, my):
+ '''
+ Shrink the box by mx in the x direction and my in the y direction.
+ The lower left corner of the box remains unchanged.
+ Normally mx and my will be <= 1, but this is not enforced.
+ '''
+ assert mx >= 0 and my >= 0
+ self[2:] = mx * self[2], my * self[3]
+ return self
+
+ def shrink_to_aspect(self, box_aspect, fig_aspect = 1):
+ '''
+ Shrink the box so that it is as large as it can be while
+ having the desired aspect ratio, box_aspect.
+ If the box coordinates are relative--that is, fractions of
+ a larger box such as a figure--then the physical aspect
+ ratio of that figure is specified with fig_aspect, so
+ that box_aspect can also be given as a ratio of the
+ absolute dimensions, not the relative dimensions.
+ '''
+ assert box_aspect > 0 and fig_aspect > 0
+ l,b,w,h = self._container
+ H = w * box_aspect/fig_aspect
+ if H <= h:
+ W = w
+ else:
+ W = h * fig_aspect/box_aspect
+ H = h
+ self[2:] = W,H
+ return self
+
+ def splitx(self, *args):
+ '''
+ e.g., PB.splitx(f1, f2, ...)
+
+ Returns a list of new PBoxes formed by
+ splitting the original one (PB) with vertical lines
+ at fractional positions f1, f2, ...
+ '''
+ boxes = []
+ xf = [0] + list(args) + [1]
+ l,b,w,h = self[:]
+ for xf0, xf1 in zip(xf[:-1], xf[1:]):
+ boxes.append(PBox([l+xf0*w, b, (xf1-xf0)*w, h]))
+ return boxes
+
+ def splity(self, *args):
+ '''
+ e.g., PB.splity(f1, f2, ...)
+
+ Returns a list of new PBoxes formed by
+ splitting the original one (PB) with horizontal lines
+ at fractional positions f1, f2, ..., with y measured
+ positive up.
+ '''
+ boxes = []
+ yf = [0] + list(args) + [1]
+ l,b,w,h = self[:]
+ for yf0, yf1 in zip(yf[:-1], yf[1:]):
+ boxes.append(PBox([l, b+yf0*h, w, (yf1-yf0)*h]))
+ return boxes
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.

Showing results of 5455

<< < 1 .. 204 205 206 207 208 .. 219 > >> (Page 206 of 219)
Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.
Thanks for helping keep SourceForge clean.
X





Briefly describe the problem (required):
Upload screenshot of ad (required):
Select a file, or drag & drop file here.
Screenshot instructions:

Click URL instructions:
Right-click on the ad, choose "Copy Link", then paste here →
(This may not be possible with some types of ads)

More information about our ad policies

Ad destination/click URL:

AltStyle によって変換されたページ (->オリジナル) /