From: <md...@us...> - 2007-10-04 18:57:29
|
Revision: 3914 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3914&view=rev Author: mdboom Date: 2007-10-04 11:57:27 -0700 (Thu, 04 Oct 2007) Log Message: ----------- Progress on agg_buffer_to_array example. Modified Paths: -------------- branches/transforms/examples/agg_buffer_to_array.py branches/transforms/examples/polar_demo.py branches/transforms/lib/matplotlib/artist.py branches/transforms/lib/matplotlib/image.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/examples/agg_buffer_to_array.py =================================================================== --- branches/transforms/examples/agg_buffer_to_array.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/examples/agg_buffer_to_array.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -12,7 +12,7 @@ # grab rhe pixel buffer and dumpy it into a numpy array buf = fig.canvas.buffer_rgba(0,0) -l, b, w, h = fig.bbox.get_bounds() +l, b, w, h = fig.bbox.bounds X = npy.fromstring(buf, npy.uint8) X.shape = h,w,4 Modified: branches/transforms/examples/polar_demo.py =================================================================== --- branches/transforms/examples/polar_demo.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/examples/polar_demo.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -40,7 +40,7 @@ # information on how to customize the grid locations and labels import numpy as npy -from matplotlib.pyplot import figure, show, rc +from matplotlib.pyplot import figure, show, rc, grid # radar green, solid grid lines rc('grid', color='#316931', linewidth=1, linestyle='-') @@ -55,6 +55,7 @@ theta = 2*npy.pi*r ax.plot(theta, r, color='#ee8d18', lw=3) ax.set_rmax(2.0) +grid(True) ax.set_title("And there was much rejoicing!", fontsize=20) show() Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -350,7 +350,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.bounds) + gc.set_clip_rectangle(self.clipbox) gc.set_clip_path(self._clippath) def draw(self, renderer, *args, **kwargs): Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/lib/matplotlib/image.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -149,17 +149,17 @@ dyintv = ymax-ymin # the viewport scale factor - sx = dxintv/self.axes.viewLim.width() - sy = dyintv/self.axes.viewLim.height() + sx = dxintv/self.axes.viewLim.width + sy = dyintv/self.axes.viewLim.height if im.get_interpolation()!=_image.NEAREST: im.apply_translation(-1, -1) # the viewport translation - tx = (xmin-self.axes.viewLim.xmin())/dxintv * numcols - ty = (ymin-self.axes.viewLim.ymin())/dyintv * numrows + tx = (xmin-self.axes.viewLim.xmin)/dxintv * numcols + ty = (ymin-self.axes.viewLim.ymin)/dyintv * numrows - l, b, widthDisplay, heightDisplay = self.axes.bbox.get_bounds() + l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds widthDisplay *= magnification heightDisplay *= magnification @@ -180,8 +180,9 @@ def draw(self, renderer, *args, **kwargs): if not self.get_visible(): return im = self.make_image(renderer.get_image_magnification()) - l, b, widthDisplay, heightDisplay = self.axes.bbox.get_bounds() - renderer.draw_image(l, b, im, self.axes.bbox) + l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds + print self.axes.bbox.frozen() + renderer.draw_image(l, b, im, self.axes.bbox.frozen()) def contains(self, mouseevent): """Test whether the mouse event occured within the image. Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -12,14 +12,29 @@ IdentityTransform, Transform, TransformWrapper class PolarAxes(Axes): + """ + A polar graph projection, where the input dimensions are theta, r. + + Theta starts pointing east and goes anti-clockwise. + """ name = 'polar' class PolarTransform(Transform): + """ + The base polar transform. This handles projection theta and r into + Cartesian coordinate space, but does not perform the ultimate affine + transformation into the correct position. + """ input_dims = 2 output_dims = 2 is_separable = False def __init__(self, resolution): + """ + Create a new polar transform. Resolution is the number of steps + to interpolate between each input line segment to approximate its + path in curved polar space. + """ Transform.__init__(self) self._resolution = resolution @@ -32,19 +47,34 @@ x += r * npy.cos(t) y += r * npy.sin(t) return xy + transform.__doc__ = Transform.transform.__doc__ + transform_non_affine = transform + transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ def transform_path(self, path): if len(path.vertices) == 2: path = path.interpolated(self._resolution) return Path(self.transform(path.vertices), path.codes) + transform_path.__doc__ = Transform.transform_path.__doc__ + transform_path_non_affine = transform_path + transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ def inverted(self): return PolarAxes.InvertedPolarTransform() + inverted.__doc__ = Transform.inverted.__doc__ class PolarAffine(Affine2DBase): + """ + The affine part of the polar projection. Scales the output so + that maximum radius rests on the edge of the axes circle. + """ def __init__(self, limits): + """ + limits is the view limit of the data. The only part of + its bounds that is used is ymax (for the radius maximum). + """ Affine2DBase.__init__(self) self._limits = limits self.set_children(limits) @@ -60,8 +90,13 @@ self._inverted = None self._invalid = 0 return self._mtx + get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ class InvertedPolarTransform(Transform): + """ + The inverse of the polar transform, mapping Cartesian + coordinate space back to t and r. + """ input_dims = 2 output_dims = 2 is_separable = False @@ -73,21 +108,34 @@ theta = npy.arccos(x / r) theta = npy.where(y < 0, 2 * npy.pi - theta, theta) return npy.concatenate((theta, r), 1) + transform.__doc__ = Transform.transform.__doc__ def inverted(self): return PolarAxes.PolarTransform() + inverted.__doc__ = Transform.inverted.__doc__ class ThetaFormatter(Formatter): + """ + Used to format the theta tick labels. Converts the native + unit of radians into degrees and adds a degree symbol. + """ def __call__(self, x, pos=None): + # \u00b0 : degree symbol return u"%d\u00b0" % ((x / npy.pi) * 180.0) class RadialLocator(Locator): + """ + Used to locate radius ticks. + + Ensures that all ticks are strictly positive. For all other + tasks, it delegates to the base Locator (which may be + different depending on the scale of the r-axis. + """ def __init__(self, base): self.base = base def __call__(self): ticks = self.base() - # MGDTODO: Use numpy return [x for x in ticks if x > 0] def autoscale(self): @@ -105,6 +153,10 @@ RESOLUTION = 100 def __init__(self, *args, **kwargs): + """ + Create a new Polar Axes for a polar plot. + """ + self._rpad = 0.05 Axes.__init__(self, *args, **kwargs) self.set_aspect('equal', adjustable='box', anchor='C') @@ -120,7 +172,7 @@ self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) def _set_lim_and_transforms(self): - self.dataLim = Bbox([[0.0, 0.0], [npy.pi * 2.0, 1.0]]) + self.dataLim = Bbox.unit() self.viewLim = Bbox.unit() self.transAxes = BboxTransform(Bbox.unit(), self.bbox) @@ -134,14 +186,20 @@ # An affine transformation on the data, generally to limit the # range of the axes self.transProjectionAffine = self.PolarAffine(self.viewLim) - + + # The complete data transformation stack -- from data all the + # way to display coordinates self.transData = self.transScale + self.transProjection + \ (self.transProjectionAffine + self.transAxes) + # This is the transform for theta-axis ticks. It is + # equivalent to transData, except it always puts r == 1.0 at + # the edge of the axis circle. self._xaxis_transform = ( self.transProjection + self.PolarAffine(Bbox.unit()) + self.transAxes) + # The theta labels are moved from radius == 0.0 to radius == 1.1 self._theta_label1_position = Affine2D().translate(0.0, 1.1) self._xaxis_text1_transform = ( self._theta_label1_position + @@ -150,10 +208,14 @@ self._xaxis_text2_transform = ( self._theta_label2_position + self._xaxis_transform) - + + # This is the transform for r-axis ticks. It scales the theta + # axis so the gridlines from 0.0 to 1.0, now go from 0.0 to + # 2pi. self._yaxis_transform = ( Affine2D().scale(npy.pi * 2.0, 1.0) + self.transData) + # The r-axis labels are put at an angle and padded in the r-direction self._r_label1_position = Affine2D().translate(22.5, self._rpad) self._yaxis_text1_transform = ( self._r_label1_position + @@ -166,6 +228,9 @@ Affine2D().scale(1.0 / 360.0, 1.0) + self._yaxis_transform ) + + def get_xaxis_transform(self): + return self._xaxis_transform def get_xaxis_text1_transform(self, pixelPad): return self._xaxis_text1_transform, 'center', 'center' @@ -173,6 +238,9 @@ def get_xaxis_text2_transform(self, pixelPad): return self._xaxis_text2_transform, 'center', 'center' + def get_yaxis_transform(self): + return self._yaxis_transform + def get_yaxis_text1_transform(self, pixelPad): return self._yaxis_text1_transform, 'center', 'center' @@ -181,63 +249,7 @@ def get_axes_patch(self): return Circle((0.5, 0.5), 0.5) - - def start_pan(self, x, y, button): - angle = self._r_label1_position.to_values()[4] / 180.0 * npy.pi - mode = '' - if button == 1: - epsilon = npy.pi / 45.0 - t, r = self.transData.inverted().transform_point((x, y)) - if t >= angle - epsilon and t <= angle + epsilon: - mode = 'drag_r_labels' - elif button == 3: - mode = 'zoom' - self._pan_start = cbook.Bunch( - rmax = self.get_rmax(), - trans = self.transData.frozen(), - trans_inverse = self.transData.inverted().frozen(), - r_label_angle = self._r_label1_position.to_values()[4], - x = x, - y = y, - mode = mode - ) - - def end_pan(self): - del self._pan_start - - def drag_pan(self, button, key, x, y): - p = self._pan_start - - if p.mode == 'drag_r_labels': - startt, startr = p.trans_inverse.transform_point((p.x, p.y)) - t, r = p.trans_inverse.transform_point((x, y)) - - # Deal with theta - dt0 = t - startt - dt1 = startt - t - if abs(dt1) < abs(dt0): - dt = abs(dt1) * sign(dt0) * -1.0 - else: - dt = dt0 * -1.0 - dt = (dt / npy.pi) * 180.0 - - rpad = self._r_label1_position.to_values()[5] - self._r_label1_position.clear().translate( - p.r_label_angle - dt, rpad) - self._r_label2_position.clear().translate( - p.r_label_angle - dt, -rpad) - - elif p.mode == 'zoom': - startt, startr = p.trans_inverse.transform_point((p.x, p.y)) - t, r = p.trans_inverse.transform_point((x, y)) - - dr = r - startr - - # Deal with r - scale = r / startr - self.set_rmax(p.rmax / scale) - def set_rmax(self, rmax): self.viewLim.ymax = rmax angle = self._r_label1_position.to_values()[4] @@ -249,6 +261,11 @@ def get_rmax(self): return self.viewLim.ymax + def set_yscale(self, *args, **kwargs): + Axes.set_yscale(self, *args, **kwargs) + self.yaxis.set_major_locator( + self.RadialLocator(self.yaxis.get_major_locator())) + set_rscale = Axes.set_yscale set_rticks = Axes.set_yticks @@ -330,24 +347,19 @@ set_rgrids.__doc__ = cbook.dedent(set_rgrids.__doc__) % kwdocd - def set_rscale(self, *args, **kwargs): - return self.set_yscale(*args, **kwargs) - def set_xscale(self, *args, **kwargs): raise NotImplementedError("You can not set the xscale on a polar plot.") - def set_yscale(self, *args, **kwargs): - Axes.set_yscale(self, *args, **kwargs) - self.yaxis.set_major_locator( - self.RadialLocator(self.yaxis.get_major_locator())) - def set_xlim(self, *args, **kargs): - # The xlim's a fixed, no matter what you do + # The xlim is fixed, no matter what you do self.viewLim.intervalx = (0.0, npy.pi * 2.0) def format_coord(self, theta, r): 'return a format string formatting the coordinate' theta /= math.pi + # \u03b8: lower-case theta + # \u03c0: lower-case pi + # \u00b0: degree symbol return u'\u03b8=%0.3f\u03c0 (%0.3f\u00b0), r=%0.3f' % (theta, theta * 180.0, r) def get_data_ratio(self): @@ -356,7 +368,65 @@ this should always be 1.0 ''' return 1.0 + + ### Interactive panning + def start_pan(self, x, y, button): + angle = self._r_label1_position.to_values()[4] / 180.0 * npy.pi + mode = '' + if button == 1: + epsilon = npy.pi / 45.0 + t, r = self.transData.inverted().transform_point((x, y)) + if t >= angle - epsilon and t <= angle + epsilon: + mode = 'drag_r_labels' + elif button == 3: + mode = 'zoom' + + self._pan_start = cbook.Bunch( + rmax = self.get_rmax(), + trans = self.transData.frozen(), + trans_inverse = self.transData.inverted().frozen(), + r_label_angle = self._r_label1_position.to_values()[4], + x = x, + y = y, + mode = mode + ) + + def end_pan(self): + del self._pan_start + + def drag_pan(self, button, key, x, y): + p = self._pan_start + + if p.mode == 'drag_r_labels': + startt, startr = p.trans_inverse.transform_point((p.x, p.y)) + t, r = p.trans_inverse.transform_point((x, y)) + + # Deal with theta + dt0 = t - startt + dt1 = startt - t + if abs(dt1) < abs(dt0): + dt = abs(dt1) * sign(dt0) * -1.0 + else: + dt = dt0 * -1.0 + dt = (dt / npy.pi) * 180.0 + + rpad = self._r_label1_position.to_values()[5] + self._r_label1_position.clear().translate( + p.r_label_angle - dt, rpad) + self._r_label2_position.clear().translate( + p.r_label_angle - dt, -rpad) + + elif p.mode == 'zoom': + startt, startr = p.trans_inverse.transform_point((p.x, p.y)) + t, r = p.trans_inverse.transform_point((x, y)) + + dr = r - startr + + # Deal with r + scale = r / startr + self.set_rmax(p.rmax / scale) + # These are a couple of aborted attempts to project a polar plot using # cubic bezier curves. Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-04 18:57:27 UTC (rev 3914) @@ -191,7 +191,7 @@ return Bbox(self.get_points().copy()) frozen.__doc__ = TransformNode.__doc__ - def __array__(self): + def __array__(self, *args, **kwargs): return self.get_points() def _get_xmin(self): Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/src/_backend_agg.cpp 2007-10-04 18:57:27 UTC (rev 3914) @@ -187,7 +187,6 @@ GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), - cliprect(NULL), Ndash(0), dashOffset(0.0), dasha(NULL) { _VERBOSE("GCAgg::GCAgg"); @@ -295,34 +294,14 @@ } } -// MGDTODO: Convert directly from Bbox object (numpy) void GCAgg::_set_clip_rectangle( const Py::Object& gc) { //set the clip rectangle from the gc _VERBOSE("GCAgg::_set_clip_rectangle"); - - delete [] cliprect; - cliprect = NULL; - + Py::Object o ( gc.getAttr( "_cliprect" ) ); - if (o.ptr() == Py_None) { - return; - } - - Py::SeqBase<Py::Object> rect( o ); - - double l = Py::Float(rect[0]) ; - double b = Py::Float(rect[1]) ; - double w = Py::Float(rect[2]) ; - double h = Py::Float(rect[3]) ; - - cliprect = new double[4]; - //todo check for memory alloc failure - cliprect[0] = l; - cliprect[1] = b; - cliprect[2] = w; - cliprect[3] = h; + cliprect = o; } void @@ -387,25 +366,29 @@ }; - template<class R> void -RendererAgg::set_clipbox(double *cliprect, R rasterizer) { +RendererAgg::set_clipbox(Py::Object& cliprect, R rasterizer) { //set the clip rectangle from the gc _VERBOSE("RendererAgg::set_clipbox"); - if (cliprect!=NULL) { + if (cliprect.ptr() != Py_None) { + PyArrayObject* bbox = (PyArrayObject*) PyArray_FromObject(cliprect.ptr(), PyArray_DOUBLE, 2, 2); + + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) + throw Py::TypeError + ("Expected a Bbox object."); - double l = cliprect[0] ; - double b = cliprect[1] ; - double w = cliprect[2] ; - double h = cliprect[3] ; - - rasterizer->clip_box((int)l, (int)(height-(b+h)), (int)(l+w), (int)(height-b)); + double l = *(double*)PyArray_GETPTR2(bbox, 0, 0); + double b = *(double*)PyArray_GETPTR2(bbox, 0, 1); + double r = *(double*)PyArray_GETPTR2(bbox, 1, 0); + double t = *(double*)PyArray_GETPTR2(bbox, 1, 1); + + rasterizer->clip_box((int)l, (int)(height-t), (int)r, (int)(height-b)); } + _VERBOSE("RendererAgg::set_clipbox done"); - } std::pair<bool, agg::rgba> @@ -485,17 +468,24 @@ RendererAgg::copy_from_bbox(const Py::Tuple& args) { //copy region in bbox to buffer and return swig/agg buffer object args.verify_length(1); + + Py::Object box_obj = args[0]; + + PyArrayObject* bbox = (PyArrayObject*) PyArray_FromObject(box_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) + throw Py::TypeError + ("Expected a Bbox object."); + + double l = *(double*)PyArray_GETPTR2(bbox, 0, 0); + double b = *(double*)PyArray_GETPTR2(bbox, 0, 1); + double r = *(double*)PyArray_GETPTR2(bbox, 1, 0); + double t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - agg::rect r = bbox_to_rect<int>(args[0]); - /* - r.x1 -=5; - r.y1 -=5; - r.x2 +=5; - r.y2 +=5; - */ - int boxwidth = r.x2-r.x1; - int boxheight = r.y2-r.y1; + agg::rect rect((int)l, (int)(height-t), (int)r, (int)(height-b)); + + int boxwidth = rect.x2-rect.x1; + int boxheight = rect.y2-rect.y1; int boxstride = boxwidth*4; agg::buffer buf(boxwidth, boxheight, boxstride, false); if (buf.data ==NULL) { @@ -508,8 +498,8 @@ pixfmt pf(rbuf); renderer_base rb(pf); //rb.clear(agg::rgba(1, 0, 0)); //todo remove me - rb.copy_from(*renderingBuffer, &r, -r.x1, -r.y1); - BufferRegion* reg = new BufferRegion(buf, r, true); + rb.copy_from(*renderingBuffer, &rect, -rect.x1, -rect.y1); + BufferRegion* reg = new BufferRegion(buf, rect, true); return Py::asObject(reg); } @@ -535,64 +525,6 @@ 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 || 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]; - double r = bbox->data[2]; - double t = bbox->data[3]; - T height = (T)(b - t); - - agg::rect_base<T> rect((T)l, height-(T)t, (T)r, height-(T)b ) ; - if (!rect.is_valid()) - throw Py::ValueError("Invalid rectangle in bbox_to_rect"); - return rect; -} - -void -RendererAgg::set_clip_from_bbox(const Py::Object& o) { - - // do not puut this in the else below. We want to unconditionally - // clear the clip - theRasterizer->reset_clipping(); - rendererBase->reset_clipping(true); - - if (o.ptr() != Py_None) { //using clip - // Bbox::check(args[0]) failing; something about cross module? - // set the clip rectangle - // flipy - agg::rect_base<double> r = bbox_to_rect<double>(o); - theRasterizer->clip_box(r.x1, r.y1, r.x2, r.y2); - rendererBase->clip_box((int)r.x1, (int)r.y1, (int)r.x2, (int)r.y2); - } - -} - -/****************************/ - -int RendererAgg::intersectCheck(double yCoord, double x1, double y1, double x2, double y2, int* intersectPoint) -{ - /* Returns 0 if no intersection or 1 if yes */ - /* If yes, changes intersectPoint to the x coordinate of the point of intersection */ - if ((y1>=yCoord) != (y2>=yCoord)) { - /* Don't need to check for y1==y2 because the above condition rejects it automatically */ - *intersectPoint = (int)( ( x1 * (y2 - yCoord) + x2 * (yCoord - y1) ) / (y2 - y1) + 0.5); - return 1; - } - return 0; -} - bool RendererAgg::render_clippath(const GCAgg& gc) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef agg::conv_curve<transformed_path_t> curve_t; @@ -633,6 +565,7 @@ 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; + rendererBase->reset_clipping(true); theRasterizer->reset_clipping(); args.verify_length(5, 6); @@ -802,6 +735,7 @@ }; +// MGDTODO: Support clip paths Py::Object RendererAgg::draw_text_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_text"); @@ -877,6 +811,7 @@ } +// MGDTODO: Support clip paths Py::Object RendererAgg::draw_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_image"); @@ -885,8 +820,11 @@ float x = Py::Float(args[0]); float y = Py::Float(args[1]); Image *image = static_cast<Image*>(args[2].ptr()); + Py::Object box_obj = args[3]; - set_clip_from_bbox(args[3]); + theRasterizer->reset_clipping(); + rendererBase->reset_clipping(true); + set_clipbox(box_obj, rendererBase); pixfmt pixf(*(image->rbufOut)); Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-04 17:22:01 UTC (rev 3913) +++ branches/transforms/src/_backend_agg.h 2007-10-04 18:57:27 UTC (rev 3914) @@ -111,7 +111,6 @@ ~GCAgg() { delete [] dasha; - delete [] cliprect; } double dpi; @@ -126,7 +125,7 @@ double alpha; agg::rgba color; - double *cliprect; + Py::Object cliprect; Py::Object clippath; agg::trans_affine clippath_trans; @@ -214,16 +213,12 @@ const int debug; protected: - template<class T> - agg::rect_base<T> bbox_to_rect( const Py::Object& o); double points_to_pixels( const Py::Object& points); double points_to_pixels_snapto( const Py::Object& points); - int intersectCheck(double, double, double, double, double, int*); - void set_clip_from_bbox(const Py::Object& o); agg::rgba rgb_to_color(const Py::SeqBase<Py::Object>& rgb, double alpha); facepair_t _get_rgba_face(const Py::Object& rgbFace, double alpha); template<class R> - void set_clipbox(double *cliprect, R rasterizer); + void set_clipbox(Py::Object& cliprect, R rasterizer); bool render_clippath(const GCAgg& gc); private: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-05 19:25:35
|
Revision: 3924 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3924&view=rev Author: mdboom Date: 2007-10-05 12:25:33 -0700 (Fri, 05 Oct 2007) Log Message: ----------- Simplified sharing axes again. Plowing through -- making more examples work. First pass at updating collections (LineCollection mostly works) Modified Paths: -------------- branches/transforms/examples/clippath_test.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/backends/backend_agg.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/image.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/examples/clippath_test.py =================================================================== --- branches/transforms/examples/clippath_test.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/examples/clippath_test.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -13,7 +13,7 @@ self.poly = RegularPolygon( (200, 200), numVertices=10, radius=100, facecolor='yellow', alpha=0.25, - transform=transforms.identity_transform()) + transform=transforms.IdentityTransform()) ax.add_patch(self.poly) self.canvas.mpl_connect('button_press_event', self.onpress) @@ -21,7 +21,6 @@ self.canvas.mpl_connect('motion_notify_event', self.onmove) self.x, self.y = None, None - def onpress(self, event): self.x, self.y = event.x, event.y @@ -42,17 +41,7 @@ self._clip() def _clip(self): - fig = self.ax.figure - l,b,w,h = fig.bbox.get_bounds() - path = agg.path_storage() - - for i, xy in enumerate(self.poly.get_verts()): - x,y = xy - y = h-y - if i==0: path.move_to(x,y) - else: path.line_to(x,y) - path.close_polygon() - self.line.set_clip_path(path) + self.line.set_clip_path(self.poly.get_path(), self.poly.get_transform()) self.canvas.draw_idle() Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -335,6 +335,11 @@ 'Return artist clip path' return self._clippath + def get_transformed_clip_path_and_affine(self): + if self._clippath is not None: + return self._clippath.get_transformed_path_and_affine() + return None, None + def set_clip_on(self, b): """ Set whether artist uses clipping Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -488,13 +488,9 @@ self._sharey = sharey if sharex is not None: self._shared_x_axes.join(self, sharex) - if sharey is not None: + 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 - if sharex: sharex._masterx = True - if sharey: sharey._mastery = True + self.set_label(label) self.set_figure(fig) @@ -822,7 +818,8 @@ Use self._aspect and self._adjustable to modify the axes box or the view limits. ''' - + #MGDTODO: Numpify + if self._aspect == 'auto': self.set_position( self._originalPosition , 'active') return @@ -834,7 +831,7 @@ #Ensure at drawing time that any Axes involved in axis-sharing # does not have its position changed. - if self._masterx or self._mastery or self._sharex or self._sharey: + if self in self._shared_x_axes or self in self._shared_y_axes: self._adjustable = 'datalim' figW,figH = self.get_figure().get_size_inches() @@ -847,6 +844,11 @@ return + xmin,xmax = self.get_xlim() + xsize = max(math.fabs(xmax-xmin), 1e-30) + ymin,ymax = self.get_ylim() + ysize = max(math.fabs(ymax-ymin), 1e-30) + l,b,w,h = self.get_position(original=True).bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -858,8 +860,8 @@ #print 'good enough already' return dL = self.dataLim - xr = 1.05 * dL.width() - yr = 1.05 * dL.height() + xr = 1.05 * dL.width + yr = 1.05 * dL.height xmarg = xsize - xr ymarg = ysize - yr Ysize = data_ratio * xsize @@ -871,10 +873,10 @@ #print 'xmin, xmax, ymin, ymax', xmin, xmax, ymin, ymax #print 'xsize, Xsize, ysize, Ysize', xsize, Xsize, ysize, Ysize - changex = ((self._sharey or self._mastery) and not - (self._sharex or self._masterx)) - changey = ((self._sharex or self._masterx) and not - (self._sharey or self._mastery)) + changex = (self in self._shared_y_axes + and self not in self._shared_x_axes) + changey = (self in self._shared_x_axes + and self not in self._shared_y_axes) if changex and changey: warnings.warn("adjustable='datalim' cannot work with shared x and y axes") return @@ -2200,7 +2202,8 @@ %(Line2D)s """ - trans = mtransforms.blend_xy_sep_transform(self.transAxes, self.transData) + trans = mtransforms.blended_transform_factory( + self.transAxes, self.transData) l, = self.plot([xmin,xmax], [y,y], transform=trans, scalex=False, **kwargs) return l @@ -2236,7 +2239,8 @@ %(Line2D)s """ - trans = mtransforms.blend_xy_sep_transform( self.transData, self.transAxes ) + trans = mtransforms.blended_transform_factory( + self.transData, self.transAxes) l, = self.plot([x,x], [ymin,ymax] , transform=trans, scaley=False, **kwargs) return l @@ -2275,7 +2279,8 @@ %(Polygon)s """ # convert y axis units - trans = mtransforms.blend_xy_sep_transform( self.transAxes, self.transData) + trans = mtransforms.blended_transform_factory( + self.transAxes, self.transData) verts = (xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin) p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -2315,7 +2320,8 @@ %(Polygon)s """ # convert x axis units - trans = mtransforms.blend_xy_sep_transform(self.transData, self.transAxes) + trans = mtransforms.blended_transform_factory( + self.transData, self.transAxes) verts = [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin)] p = mpatches.Polygon(verts, **kwargs) p.set_transform(trans) @@ -2386,7 +2392,7 @@ return coll hlines.__doc__ = cbook.dedent(hlines.__doc__) - def vlines(self, x, ymin, ymax, colors='k', linestyle='solid', + def vlines(self, x, ymin, ymax, colors='k', linestyles='solid', label='', **kwargs): """ VLINES(x, ymin, ymax, color='k') @@ -2438,7 +2444,7 @@ for thisx, (thisymin, thisymax) in zip(x,Y)] #print 'creating line collection' coll = mcoll.LineCollection(verts, colors=colors, - linestyle=linestyle, label=label) + linestyles=linestyles, label=label) self.add_collection(coll) coll.update(kwargs) @@ -3660,7 +3666,7 @@ else: lower = y-yerr[0] upper = y+yerr[1] - + barcols.append( self.vlines(x, lower, upper, **lines_kw) ) if capsize > 0: Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -1098,9 +1098,9 @@ default resets the tick positions to the default: ticks on both positions, labels at bottom. - ACCEPTS: [ 'top' | 'bottom' | 'both' | 'default' ] + ACCEPTS: [ 'top' | 'bottom' | 'both' | 'default' | 'none' ] """ - assert position == 'top' or position == 'bottom' or position == 'both' or position == 'default' + assert position in ('top', 'bottom', 'both', 'default', 'none') ticks = list( self.get_major_ticks() ) # a copy @@ -1124,6 +1124,10 @@ t.tick2On = True t.label1On = True t.label2On = False + elif position == 'none': + for t in ticks: + t.tick1On = False + t.tick2On = False else: for t in ticks: t.tick1On = True @@ -1306,9 +1310,9 @@ default resets the tick positions to the default: ticks on both positions, labels on the left. - ACCEPTS: [ 'left' | 'right' | 'both' | 'default' ] + ACCEPTS: [ 'left' | 'right' | 'both' | 'default' | 'none' ] """ - assert position == 'left' or position == 'right' or position == 'both' or position == 'default' + assert position in ('left', 'right', 'both', 'default', 'none') ticks = list( self.get_major_ticks() ) # a copy ticks.extend( self.get_minor_ticks() ) @@ -1334,6 +1338,10 @@ t.tick2On = True t.label1On = True t.label2On = False + elif position == 'none': + for t in ticks: + t.tick1On = False + t.tick2On = False else: self.set_offset_position('left') for t in ticks: Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -83,322 +83,322 @@ ## 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): - """ - 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 +# def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, +# rotation): +# """ +# 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 - If the color rgbFace is not None, fill the arc with it. - """ - raise NotImplementedError +# If the color rgbFace is not None, fill the arc with it. +# """ +# raise NotImplementedError - def draw_line_collection(self, segments, transform, clipbox, - colors, linewidths, linestyle, antialiaseds, - offsets, transOffset): - """ - This is a function for optimized line drawing. If you need to draw - many line segments with similar properties, it is faster to avoid the - overhead of all the object creation etc. The lack of total - configurability is compensated for with efficiency. Hence we don't use - a GC and many of the line props it supports. See - matplotlib.collections for more details. +# def draw_line_collection(self, segments, transform, clipbox, +# colors, linewidths, linestyle, antialiaseds, +# offsets, transOffset): +# """ +# This is a function for optimized line drawing. If you need to draw +# many line segments with similar properties, it is faster to avoid the +# overhead of all the object creation etc. The lack of total +# configurability is compensated for with efficiency. Hence we don't use +# a GC and many of the line props it supports. See +# matplotlib.collections for more details. - segments is a sequence of ( line0, line1, line2), where linen = - is an Mx2 array with columns x, y. Each line can be a - different length +# segments is a sequence of ( line0, line1, line2), where linen = +# is an Mx2 array with columns x, y. Each line can be a +# different length - transform is used to Transform the lines +# transform is used to Transform the lines - clipbox is a xmin, ymin, width, height clip rect +# clipbox is a xmin, ymin, width, height clip rect - colors is a tuple of RGBA tuples +# colors is a tuple of RGBA tuples - linewidths is a tuple of linewidths - *** really should be called 'dashes' not 'linestyle', since - we call gc.set_dashes() not gc.set_linestyle() *** +# linewidths is a tuple of linewidths +# *** really should be called 'dashes' not 'linestyle', since +# we call gc.set_dashes() not gc.set_linestyle() *** - linestyle is an (offset, onoffseq) tuple or None,None for solid +# linestyle is an (offset, onoffseq) tuple or None,None for solid - antialiseds is a tuple of ones or zeros indicating whether the - segment should be aa or not +# antialiseds is a tuple of ones or zeros indicating whether the +# segment should be aa or not - offsets, if not None, is an Nx2 array of x,y offsets to - translate the lines by after transform is used to transform - the offset coords +# offsets, if not None, is an Nx2 array of x,y offsets to +# translate the lines by after transform is used to transform +# the offset coords - This function could be overridden in the backend to possibly implement - faster drawing, but it is already much faster than using draw_lines() - by itself. - """ +# This function could be overridden in the backend to possibly implement +# faster drawing, but it is already much faster than using draw_lines() +# by itself. +# """ - newstyle = getattr(self, 'draw_markers', None) is not None - identity = transforms.identity_transform() - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) - gc.set_dashes(*linestyle) +# newstyle = getattr(self, 'draw_markers', None) is not None +# identity = transforms.identity_transform() +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) +# gc.set_dashes(*linestyle) - Nc = len(colors) - Nlw = len(linewidths) - Naa = len(antialiaseds) - Nsegments = len(segments) +# Nc = len(colors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) +# Nsegments = len(segments) - usingOffsets = offsets is not None - Noffsets = 0 - if usingOffsets: - Noffsets = offsets.shape[0] - offsets = transOffset.numerix_xy(offsets) +# usingOffsets = offsets is not None +# Noffsets = 0 +# if usingOffsets: +# Noffsets = offsets.shape[0] +# offsets = transOffset.numerix_xy(offsets) - for i in xrange(max(Noffsets, Nsegments)): - color = colors[i % Nc] - rgb = color[0], color[1], color[2] - alpha = color[-1] +# for i in xrange(max(Noffsets, Nsegments)): +# color = colors[i % Nc] +# rgb = color[0], color[1], color[2] +# alpha = color[-1] - gc.set_foreground(rgb, isRGB=True) - gc.set_alpha( alpha ) - gc.set_linewidth( linewidths[i % Nlw] ) - gc.set_antialiased( antialiaseds[i % Naa] ) - seg = segments[i % Nsegments] - if not len(seg): continue - xy = transform.numerix_xy(seg) - if usingOffsets: - xy = xy + offsets[i % Noffsets] +# gc.set_foreground(rgb, isRGB=True) +# gc.set_alpha( alpha ) +# gc.set_linewidth( linewidths[i % Nlw] ) +# gc.set_antialiased( antialiaseds[i % Naa] ) +# seg = segments[i % Nsegments] +# if not len(seg): continue +# xy = transform.numerix_xy(seg) +# if usingOffsets: +# xy = xy + offsets[i % Noffsets] - if newstyle: self.draw_lines(gc, xy[:,0], xy[:,1], identity) - else: self.draw_lines(gc, xy[:,0], xy[:,1]) +# if newstyle: self.draw_lines(gc, xy[:,0], xy[:,1], identity) +# else: self.draw_lines(gc, xy[:,0], xy[:,1]) - def draw_line(self, gc, x1, y1, x2, y2): - """ - Draw a single line from x1,y1 to x2,y2 - """ - raise NotImplementedError +# def draw_line(self, gc, x1, y1, x2, y2): +# """ +# Draw a single line from x1,y1 to x2,y2 +# """ +# raise NotImplementedError - def draw_lines(self, gc, x, y, transform=None): - """ - x and y are equal length arrays, draw lines connecting each - point in x, y - """ - raise NotImplementedError +# def draw_lines(self, gc, x, y, transform=None): +# """ +# x and y are equal length arrays, draw lines connecting each +# point in x, y +# """ +# raise NotImplementedError - def draw_point(self, gc, x, y): - """ - Draw a single point at x,y - Where 'point' is a device-unit point (or pixel), not a matplotlib point - """ - raise NotImplementedError +# def draw_point(self, gc, x, y): +# """ +# Draw a single point at x,y +# Where 'point' is a device-unit point (or pixel), not a matplotlib point +# """ +# raise NotImplementedError - def draw_quad_mesh(self, meshWidth, meshHeight, colors, - xCoords, yCoords, clipbox, - transform, offsets, transOffset, showedges): - """ - Draw a quadrilateral mesh - See documentation in QuadMesh class in collections.py for details - """ - # print "draw_quad_mesh not found, using function in backend_bases" - verts = npy.zeros(((meshWidth * meshHeight), 4, 2), npy.float32) - indices = npy.arange((meshWidth + 1) * (meshHeight + 1)) - indices = npy.compress((indices + 1) % (meshWidth + 1), indices) - indices = indices[:(meshWidth * meshHeight)] - verts[:, 0, 0] = npy.take(xCoords, indices) - verts[:, 0, 1] = npy.take(yCoords, indices) - verts[:, 1, 0] = npy.take(xCoords, (indices + 1)) - verts[:, 1, 1] = npy.take(yCoords, (indices + 1)) - verts[:, 2, 0] = npy.take(xCoords, (indices + meshWidth + 2)) - verts[:, 2, 1] = npy.take(yCoords, (indices + meshWidth + 2)) - verts[:, 3, 0] = npy.take(xCoords, (indices + meshWidth + 1)) - verts[:, 3, 1] = npy.take(yCoords, (indices + meshWidth + 1)) - if (showedges): - edgecolors = colors - else: - edgecolors = (0, 0, 0, 0), - self.draw_poly_collection(verts, transform, - clipbox, colors, edgecolors, - (0.25,), (0,), offsets, transOffset) +# def draw_quad_mesh(self, meshWidth, meshHeight, colors, +# xCoords, yCoords, clipbox, +# transform, offsets, transOffset, showedges): +# """ +# Draw a quadrilateral mesh +# See documentation in QuadMesh class in collections.py for details +# """ +# # print "draw_quad_mesh not found, using function in backend_bases" +# verts = npy.zeros(((meshWidth * meshHeight), 4, 2), npy.float32) +# indices = npy.arange((meshWidth + 1) * (meshHeight + 1)) +# indices = npy.compress((indices + 1) % (meshWidth + 1), indices) +# indices = indices[:(meshWidth * meshHeight)] +# verts[:, 0, 0] = npy.take(xCoords, indices) +# verts[:, 0, 1] = npy.take(yCoords, indices) +# verts[:, 1, 0] = npy.take(xCoords, (indices + 1)) +# verts[:, 1, 1] = npy.take(yCoords, (indices + 1)) +# verts[:, 2, 0] = npy.take(xCoords, (indices + meshWidth + 2)) +# verts[:, 2, 1] = npy.take(yCoords, (indices + meshWidth + 2)) +# verts[:, 3, 0] = npy.take(xCoords, (indices + meshWidth + 1)) +# verts[:, 3, 1] = npy.take(yCoords, (indices + meshWidth + 1)) +# if (showedges): +# edgecolors = colors +# else: +# edgecolors = (0, 0, 0, 0), +# self.draw_poly_collection(verts, transform, +# clipbox, colors, edgecolors, +# (0.25,), (0,), offsets, transOffset) - def draw_poly_collection( - self, verts, transform, clipbox, facecolors, edgecolors, - linewidths, antialiaseds, offsets, transOffset): - """ - Draw a polygon collection +# def draw_poly_collection( +# self, verts, transform, clipbox, facecolors, edgecolors, +# linewidths, antialiaseds, offsets, transOffset): +# """ +# Draw a polygon collection - verts are a sequence of polygon vectors, where each polygon - vector is a sequence of x,y tuples of vertices +# verts are a sequence of polygon vectors, where each polygon +# vector is a sequence of x,y tuples of vertices - facecolors and edgecolors are a sequence of RGBA tuples - linewidths are a sequence of linewidths - antialiaseds are a sequence of 0,1 integers whether to use aa +# facecolors and edgecolors are a sequence of RGBA tuples +# linewidths are a sequence of linewidths +# antialiaseds are a sequence of 0,1 integers whether to use aa - If a linewidth is zero or an edgecolor alpha is zero, the - line will be omitted; similarly, the fill will be omitted - if the facecolor alpha is zero. - """ - ## line and/or fill OK - Nface = len(facecolors) - Nedge = len(edgecolors) - Nlw = len(linewidths) - Naa = len(antialiaseds) +# If a linewidth is zero or an edgecolor alpha is zero, the +# line will be omitted; similarly, the fill will be omitted +# if the facecolor alpha is zero. +# """ +# ## line and/or fill OK +# Nface = len(facecolors) +# Nedge = len(edgecolors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) - usingOffsets = offsets is not None - Noffsets = 0 - Nverts = len(verts) - if usingOffsets: - Noffsets = len(offsets) +# usingOffsets = offsets is not None +# Noffsets = 0 +# Nverts = len(verts) +# if usingOffsets: +# Noffsets = len(offsets) - N = max(Noffsets, Nverts) +# N = max(Noffsets, Nverts) - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) - for i in xrange(N): - polyverts = ma.filled(verts[i % Nverts], npy.nan) - if npy.any(npy.isnan(polyverts)): - continue - linewidth = linewidths[i % Nlw] - rf,gf,bf,af = facecolors[i % Nface] - re,ge,be,ae = edgecolors[i % Nedge] - if af==0: - if ae==0 or linewidth == 0: - continue - rgbFace = None - alpha = ae - else: - rgbFace = rf,gf,bf - if ae==0: - alpha = af - gc.set_linewidth(0) - else: - # the draw_poly interface can't handle separate alphas for - # edge and face so we'll just use the maximum - alpha = max(af,ae) - gc.set_foreground( (re,ge,be), isRGB=True) - gc.set_linewidth( linewidths[i % Nlw] ) - #print 'verts', zip(thisxverts, thisyverts) +# for i in xrange(N): +# polyverts = ma.filled(verts[i % Nverts], npy.nan) +# if npy.any(npy.isnan(polyverts)): +# continue +# linewidth = linewidths[i % Nlw] +# rf,gf,bf,af = facecolors[i % Nface] +# re,ge,be,ae = edgecolors[i % Nedge] +# if af==0: +# if ae==0 or linewidth == 0: +# continue +# rgbFace = None +# alpha = ae +# else: +# rgbFace = rf,gf,bf +# if ae==0: +# alpha = af +# gc.set_linewidth(0) +# else: +# # the draw_poly interface can't handle separate alphas for +# # edge and face so we'll just use the maximum +# alpha = max(af,ae) +# gc.set_foreground( (re,ge,be), isRGB=True) +# gc.set_linewidth( linewidths[i % Nlw] ) +# #print 'verts', zip(thisxverts, thisyverts) - gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? - gc.set_alpha( alpha ) - tverts = transform.seq_xy_tups(polyverts) - if usingOffsets: - xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) - tverts = [(x+xo,y+yo) for x,y in tverts] +# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? +# gc.set_alpha( alpha ) +# tverts = transform.seq_xy_tups(polyverts) +# if usingOffsets: +# xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) +# tverts = [(x+xo,y+yo) for x,y in tverts] - self.draw_polygon(gc, rgbFace, tverts) +# self.draw_polygon(gc, rgbFace, tverts) - def draw_polygon(self, gc, rgbFace, points): - """ - Draw a polygon using the GraphicsContext instance gc. - points is a len vertices tuple, each element - giving the x,y coords a vertex +# def draw_polygon(self, gc, rgbFace, points): +# """ +# Draw a polygon using the GraphicsContext instance gc. +# points is a len vertices tuple, each element +# giving the x,y coords a vertex - If the color rgbFace is not None, fill the polygon with it - """ - raise NotImplementedError +# If the color rgbFace is not None, fill the polygon with it +# """ +# raise NotImplementedError - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - """ - Draw a non-filled rectangle using the GraphicsContext instance gcEdge, - with lower left at x,y with width and height. +# def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): +# """ +# Draw a non-filled rectangle using the GraphicsContext instance gcEdge, +# with lower left at x,y with width and height. - If rgbFace is not None, fill the rectangle with it. - """ - 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) +# If rgbFace is not None, fill the rectangle with it. +# """ +# 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): - """ - Draw a regular poly collection +# def draw_regpoly_collection( +# self, clipbox, offsets, transOffset, verts, sizes, +# facecolors, edgecolors, linewidths, antialiaseds): +# """ +# Draw a regular poly collection - offsets - is a sequence is x,y tuples - transOffset - maps this to display coords +# offsets - is a sequence is x,y tuples +# transOffset - maps this to display coords - verts - are the vertices of the regular polygon at the origin +# verts - are the vertices of the regular polygon at the origin - sizes are the area of the circle that circumscribes the - polygon in points^2 +# sizes are the area of the circle that circumscribes the +# polygon in points^2 - facecolors and edgecolors are a sequence of RGBA tuples - linewidths are a sequence of linewidths - antialiaseds are a sequence of 0,1 integers whether to use aa - """ - ## line and/or fill OK - gc = self.new_gc() - if clipbox is not None: - gc.set_clip_rectangle(clipbox.get_bounds()) +# facecolors and edgecolors are a sequence of RGBA tuples +# linewidths are a sequence of linewidths +# antialiaseds are a sequence of 0,1 integers whether to use aa +# """ +# ## line and/or fill OK +# gc = self.new_gc() +# if clipbox is not None: +# gc.set_clip_rectangle(clipbox.get_bounds()) - xverts, yverts = zip(*verts) - xverts = npy.asarray(xverts) - yverts = npy.asarray(yverts) +# xverts, yverts = zip(*verts) +# xverts = npy.asarray(xverts) +# yverts = npy.asarray(yverts) - Nface = len(facecolors) - Nedge = len(edgecolors) - Nlw = len(linewidths) - Naa = len(antialiaseds) - Nsizes = len(sizes) +# Nface = len(facecolors) +# Nedge = len(edgecolors) +# Nlw = len(linewidths) +# Naa = len(antialiaseds) +# Nsizes = len(sizes) - for i, loc in enumerate(offsets): - xo,yo = transOffset.xy_tup(loc) - #print 'xo, yo', loc, (xo, yo) - scale = sizes[i % Nsizes] +# for i, loc in enumerate(offsets): +# xo,yo = transOffset.xy_tup(loc) +# #print 'xo, yo', loc, (xo, yo) +# scale = sizes[i % Nsizes] - thisxverts = scale*xverts + xo - thisyverts = scale*yverts + yo - #print 'xverts', xverts +# thisxverts = scale*xverts + xo +# thisyverts = scale*yverts + yo +# #print 'xverts', xverts - linewidth = linewidths[i % Nlw] - rf,gf,bf,af = facecolors[i % Nface] - re,ge,be,ae = edgecolors[i % Nedge] - if af==0: - if ae==0 or linewidth == 0: - continue - rgbFace = None - alpha = ae - else: - rgbFace = rf,gf,bf - if ae==0: - alpha = af - gc.set_linewidth(0) - else: - # the draw_poly interface can't handle separate alphas for - # edge and face so we'll just use the maximum - alpha = max(af,ae) - gc.set_foreground( (re,ge,be), isRGB=True) - gc.set_linewidth( linewidths[i % Nlw] ) - #print 'verts', zip(thisxverts, thisyverts) +# linewidth = linewidths[i % Nlw] +# rf,gf,bf,af = facecolors[i % Nface] +# re,ge,be,ae = edgecolors[i % Nedge] +# if af==0: +# if ae==0 or linewidth == 0: +# continue +# rgbFace = None +# alpha = ae +# else: +# rgbFace = rf,gf,bf +# if ae==0: +# alpha = af +# gc.set_linewidth(0) +# else: +# # the draw_poly interface can't handle separate alphas for +# # edge and face so we'll just use the maximum +# alpha = max(af,ae) +# gc.set_foreground( (re,ge,be), isRGB=True) +# gc.set_linewidth( linewidths[i % Nlw] ) +# #print 'verts', zip(thisxverts, thisyverts) - gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? - gc.set_alpha( alpha ) - #print 'verts', zip(thisxverts, thisyverts) - self.draw_polygon(gc, rgbFace, zip(thisxverts, thisyverts)) +# gc.set_antialiased( antialiaseds[i % Naa] ) # Used for fill only? +# gc.set_alpha( alpha ) +# #print 'verts', zip(thisxverts, thisyverts) +# self.draw_polygon(gc, rgbFace, zip(thisxverts, thisyverts)) - def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): - raise NotImplementedError +# def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!'): +# raise NotImplementedError - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): - """ - Draw the text.Text instance s at x,y (display coords) with font - properties instance prop at angle in degrees, using GraphicsContext gc +# def draw_text(self, gc, x, y, s, prop, angle, ismath=False): +# """ +# Draw the text.Text instance s at x,y (display coords) with font +# properties instance prop at angle in degrees, using GraphicsContext gc - **backend implementers note** +# **backend implementers note** - When you are trying to determine if you have gotten your bounding box - right (which is what enables the text layout/alignment to work - properly), it helps to change the line in text.py +# When you are trying to determine if you have gotten your bounding box +# right (which is what enables the text layout/alignment to work +# properly), it helps to change the line in text.py - if 0: bbox_artist(self, renderer) +# if 0: bbox_artist(self, renderer) - to if 1, and then the actual bounding box will be blotted along with - your text. - """ - raise NotImplementedError +# to if 1, and then the actual bounding box will be blotted along with +# your text. +# """ +# raise NotImplementedError def flipy(self): """return true if y small numbers are top for renderer @@ -594,6 +594,7 @@ """ Set the clip path and transformation """ + assert path is None or isinstance(path, transforms.TransformedPath) self._clippath = path def set_dashes(self, dash_offset, dash_list): Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -129,6 +129,13 @@ assert marker_trans.is_affine assert trans.is_affine self._renderer.draw_markers(gc, marker_path, marker_trans.frozen(), path, trans.frozen(), rgbFace) + + def draw_path_collection(self, master_transform, clipbox, clippath, clippath_trans, + paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds): + assert master_transform.is_affine + self._renderer.draw_path_collection( + master_transform.frozen(), clipbox, clippath, clippath_trans, + paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds) def draw_mathtext(self, gc, x, y, s, prop, angle): """ Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -981,12 +981,16 @@ >>> g.joined('a', 'c') True >>> g.joined('a', 'd') - False""" + False + """ def __init__(self, init=[]): mapping = self._mapping = {} for x in init: mapping[x] = [x] - + + def __contains__(self, item): + return item in self._mapping + def join(self, a, *args): """ Join given arguments into the same set. @@ -1019,7 +1023,7 @@ def __iter__(self): """ - Returns an iterator returning each of the disjoint sets as a list. + Returns an iterator yielding each of the disjoint sets as a list. """ seen = set() for elem, group in self._mapping.iteritems(): Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -17,7 +17,11 @@ import matplotlib.artist as artist import matplotlib.backend_bases as backend_bases import matplotlib.nxutils as nxutils +import matplotlib.path as path +# MGDTODO: Now that everything draws through draw_path_collection, +# perhaps more stuff could be moved into the Collection base class +# here class Collection(artist.Artist): """ @@ -616,9 +620,10 @@ linewidths = None, colors = None, antialiaseds = None, - linestyle = 'solid', - offsets = None, - transOffset = None,#transforms.identity_transform(), + linestyles = 'solid', + # MGDTODO: Deal with offsets (mayb +# offsets = None, +# transOffset = None,#transforms.identity_transform(), norm = None, cmap = None, pickradius = 5, @@ -663,13 +668,11 @@ matrix _A is not None (ie a call to set_array has been made), at draw time a call to scalar mappable will be made to set the colors. """ - Collection.__init__(self) cm.ScalarMappable.__init__(self, norm, cmap) if linewidths is None : linewidths = (mpl.rcParams['lines.linewidth'], ) - if colors is None : colors = (mpl.rcParams['lines.color'],) if antialiaseds is None : @@ -678,19 +681,20 @@ self._colors = _colors.colorConverter.to_rgba_list(colors) self._aa = self._get_value(antialiaseds) self._lw = self._get_value(linewidths) - self.set_linestyle(linestyle) + self.set_linestyles(linestyles) self._uniform_offsets = None - if offsets is not None: - offsets = npy.asarray(offsets) - if len(offsets.shape) == 1: - offsets = offsets[npy.newaxis,:] # Make it Nx2. - if transOffset is None: - if offsets is not None: - self._uniform_offsets = offsets - offsets = None - transOffset = transforms.identity_transform() - self._offsets = offsets - self._transOffset = transOffset + # MGDTODO: Deal with offsets +# if offsets is not None: +# offsets = npy.asarray(offsets) +# if len(offsets.shape) == 1: +# offsets = offsets[npy.newaxis,:] # Make it Nx2. +# if transOffset is None: +# if offsets is not None: +# self._uniform_offsets = offsets +# offsets = None +# transOffset = transforms.IdentityTransform() +# self._offsets = offsets +# self._transOffset = transOffset self.set_segments(segments) self.pickradius = pickradius self.update(kwargs) @@ -712,9 +716,10 @@ mx,my = mouseevent.x,mouseevent.y transform = self.get_transform() + # MGDTODO: Numpify ind = [] for this in xrange(len(self._segments)): - xy = transform.seq_xy_tups(self._segments[this]) + xy = transform.transform_point(self._segments[this]) this_ind = ML.segment_hits(mx,my,xy[:,0],xy[:,1],self.pickradius) ind.extend([(this,k) for k in this_ind]) return len(ind)>0,dict(ind=ind) @@ -722,45 +727,47 @@ def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius - def get_transoffset(self): - if self._transOffset is None: - self._transOffset = transforms.identity_transform() - return self._transOffset + # MGDTODO: Support offsets (maybe) +# def get_transoffset(self): +# if self._transOffset is None: +# self._transOffset = transforms.identity_transform() +# return self._transOffset def set_segments(self, segments): if segments is None: return - self._segments = [npy.asarray(seg) for seg in segments] - if self._uniform_offsets is not None: - self._add_offsets() + self._paths = [path.Path(seg, closed=False) for seg in segments] + +# if self._uniform_offsets is not None: +# self._add_offsets() set_verts = set_segments # for compatibility with PolyCollection - def _add_offsets(self): - segs = self._segments - offsets = self._uniform_offsets - Nsegs = len(segs) - Noffs = offsets.shape[0] - if Noffs == 1: - for i in range(Nsegs): - segs[i] = segs[i] + i * offsets - else: - for i in range(Nsegs): - io = i%Noffs - segs[i] = segs[i] + offsets[io:io+1] + # MGDTODO: Support offsets (maybe) +# def _add_offsets(self): +# segs = self._segments +# offsets = self._uniform_offsets +# Nsegs = len(segs) +# Noffs = offsets.shape[0] +# if Noffs == 1: +# for i in range(Nsegs): +# segs[i] = segs[i] + i * offsets +# else: +# for i in range(Nsegs): +# io = i%Noffs +# segs[i] = segs[i] + offsets[io:io+1] - def draw(self, renderer): if not self.get_visible(): return renderer.open_group('linecollection') transform = self.get_transform() - transoffset = self.get_transoffset() + # MGDTODO: Deal with offsets (maybe) +# transoffset = self.get_transoffset() - transform.freeze() - transoffset.freeze() + # segments = self._segments + # MGDTODO: Deal with offsets (maybe) + # offsets = self._offsets - segments = self._segments - offsets = self._offsets - + # MGDTODO: Transform the paths (since we don't keep track of segments anymore if self.have_units(): segments = [] for segment in self._segments: @@ -768,20 +775,18 @@ xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) segments.append(zip(xs, ys)) - if self._offsets is not None: - xs = self.convert_xunits(self._offsets[:0]) - ys = self.convert_yunits(self._offsets[:1]) - offsets = zip(xs, ys) - +# if self._offsets is not None: +# xs = self.convert_xunits(self._offsets[:0]) +# ys = self.convert_yunits(self._offsets[:1]) +# offsets = zip(xs, ys) + self.update_scalarmappable() #print 'calling renderer draw line collection' - renderer.draw_line_collection( - segments, transform, self.clipbox, - self._colors, self._lw, self._ls, self._aa, offsets, - transoffset) - transform.thaw() - transoffset.thaw() - + clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + renderer.draw_path_collection( + transform, self.clipbox, clippath, clippath_trans, + self._paths, [None], [None], + self._colors, self._lw, self._ls, self._aa) renderer.close_group('linecollection') def set_linewidth(self, lw): @@ -795,18 +800,34 @@ self._lw = self._get_value(lw) - def set_linestyle(self, ls): + def set_linestyles(self, ls): """ Set the linestyles(s) for the collection. ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | (offset, on-off-dash-seq) ] """ - if cbook.is_string_like(ls): - dashes = backend_bases.GraphicsContextBase.dashd[ls] - elif cbook.iterable(ls) and len(ls)==2: - dashes = ls - else: raise ValueError('Do not know how to convert %s to dashes'%ls) + try: + if cbook.is_string_like(ls): + dashes = [backend_bases.GraphicsContextBase.dashd[ls]] + elif cbook.iterable(ls): + try: + dashes = [] + for x in ls: + if cbook.is_string_like(x): + dashes.append(backend_bases.GraphicsContextBase.dashd[ls]) + elif cbook.iterator(x) and len(x) == 2: + dashes.append(x) + else: + raise ValueError() + except ValueError: + if len(ls)==2: + dashes = ls + else: + raise ValueError() + else: + raise ValueError() + except ValueError: + raise ValueError('Do not know how to convert %s to dashes'%ls) - self._ls = dashes def set_color(self, c): @@ -860,23 +881,6 @@ return self._colors get_colors = get_color # for compatibility with old versions - def get_verts(self, dataTrans=None): - '''Return vertices in data coordinates. - The calculation is incomplete in general; it is based - on the segments or the offsets, whichever is using - dataTrans as its transformation, so it does not take - into account the combined effect of segments and offsets. - ''' - verts = [] - if self._offsets is None: - for seg in self._segments: - verts.extend(seg) - return [tuple(xy) for xy in verts] - if self.get_transoffset() == dataTrans: - return [tuple(xy) for xy in self._offsets] - raise NotImplementedError('Vertices in data coordinates are calculated\n' - + 'with offsets only if _transOffset == dataTrans.') - def update_scalarmappable(self): """ If the scalar mappable array is not none, update colors Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/image.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -181,7 +181,6 @@ if not self.get_visible(): return im = self.make_image(renderer.get_image_magnification()) l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds - print self.axes.bbox.frozen() renderer.draw_image(l, b, im, self.axes.bbox.frozen()) def contains(self, mouseevent): Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -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 transforms import Bbox, BboxTransform +from transforms import Affine2D, Bbox, BboxTransform def line_cuts_bbox(line, bbox): """ Return True if and only if line cuts bbox. """ @@ -164,8 +164,9 @@ else: raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent - self.set_transform( BboxTransform(Bbox.unit(), parent.bbox) ) - + self._offsetTransform = Affine2D() + self.set_transform( self._offsetTransform + BboxTransform(Bbox.unit(), parent.bbox) ) + if loc is None: loc = rcParams["legend.loc"] if not self.isaxes and loc in [0,'best']: @@ -429,24 +430,8 @@ def _offset(self, ox, oy): 'Move all the artists by ox,oy (axes coords)' - for t in self.texts: - x,y = t.get_position() - t.set_position( (x+ox, y+oy) ) + self._offsetTransform.clear().translate(ox, oy) - for h in self.legendHandles: - if isinstance(h, Line2D): - x,y = h.get_xdata(orig=False), h.get_ydata(orig=False) - h.set_data( x+ox, y+oy) - elif isinstance(h, Rectangle): - h.xy[0] = h.xy[0] + ox - h.xy[1] = h.xy[1] + oy - elif isinstance(h, RegularPolygon): - h.verts = [(x + ox, y + oy) for x, y in h.verts] - - x, y = self.legendPatch.get_x(), self.legendPatch.get_y() - self.legendPatch.set_x(x+ox) - self.legendPatch.set_y(y+oy) - def _find_best_position(self, width, height, consider=None): """Determine the best location to place the legend. Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -349,6 +349,7 @@ self._picker = p def get_window_extent(self, renderer): + # MGDTODO: Numpify xy = self.get_transform().transform(self._xy) x = xy[:, 0] @@ -690,7 +691,7 @@ def _draw_pixel(self, renderer, gc, path, path_trans): rgbFace = self._get_rgb_face() transform = Affine2D().translate(-0.5, -0.5) - renderer.draw_markers(gc, Path.unit_rectangle, transform, + renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -221,8 +221,11 @@ path = self.get_path() transform = self.get_transform() - - renderer.draw_path(gc, path, transform, rgbFace) + # MGDTODO: Use a transformed path here? + tpath = transform.transform_path_non_affine(path) + affine = transform.get_affine() + + renderer.draw_path(gc, tpath, affine, rgbFace) #renderer.close_group('patch') @@ -234,8 +237,7 @@ def get_window_extent(self, renderer=None): - return Bbox.from_lbrt( - get_path_extents(self.get_path(), self.get_patch_transform())) + return self.get_path().get_extents(self.get_transform()) def set_lw(self, val): @@ -441,21 +443,49 @@ Valid kwargs are: %(Patch)s """ + self._xy = xy + self._orientation = orientation + self._radius = radius + self._path = Path.unit_regular_polygon(numVertices) + self._poly_transform = transforms.Affine2D() + self._update_transform() + Patch.__init__(self, **kwargs) + + __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - self._path = Path.unit_regular_polygon(numVertices) - self._poly_transform = transforms.Affine2D() \ - .scale(radius) \ - .rotate(orientation) \ - .translate(*xy) + def _update_transform(self): + self._poly_transform.clear() \ + .scale(self.radius) \ + .rotate(self.orientation) \ + .translate(*self.xy) - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def _get_xy(self): + return self._xy + def _set_xy(self, xy): + self._xy = xy + self._update_transform() + xy = property(_get_xy, _set_xy) + def _get_orientation(self): + return self._orientation + def _set_orientation(self, xy): + self._orientation = xy + self._update_transform() + orientation = property(_get_orientation, _set_orientation) + + def _get_radius(self): + return self._radius + def _set_radius(self, xy): + self._radius = xy + self._update_transform() + radius = property(_get_radius, _set_radius) + def get_path(self): return self._path def get_patch_transform(self): - return self._poly_transform + return self._poly_transform class Polygon(Patch): """ @@ -492,10 +522,8 @@ """ Patch.__init__(self, **kwargs) - self.theta1 = theta1 - self.theta2 = theta2 self._path = Path.wedge(theta1, theta2) - self._path_transform = transforms.Affine2D() \ + self._patch_transform = transforms.Affine2D() \ .scale(r).translate(*center) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd @@ -503,7 +531,7 @@ return self._path def get_patch_transform(self): - return self._path_transform + return self._patch_transform class Arrow(Polygon): """ @@ -515,6 +543,12 @@ cx,cy = (x1+x2)/2.,(y1+y2)/2. return "Arrow(%g,%g)"%(cx,cy) + _path = Path( [ + [ 0.0, 0.1 ], [ 0.0, -0.1], + [ 0.8, -0.1 ], [ 0.8, -0.3], + [ 1.0, 0.0 ], [ 0.8, 0.3], + [ 0.8, 0.1 ] ] ) + def __init__( self, x, y, dx, dy, width=1.0, **kwargs ): """Draws an arrow, starting at (x,y), direction and length given by (dx,dy) the width of the arrow is scaled by width @@ -522,22 +556,23 @@ 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], - [ 1.0, 0.0 ], [ 0.8, 0.3], - [ 0.8, 0.1 ] ] ) L = npy.sqrt(dx**2+dy**2) or 1 # account for div by zero - arrow[:,0] *= L - arrow[:,1] *= width cx = float(dx)/L sx = float(dy)/L - M = npy.array( [ [ cx, sx],[ -sx, cx ] ] ) - verts = npy.dot( arrow, M )+ [x,y] - Polygon.__init__( self, [ tuple(t) for t in verts ], **kwargs ) + + trans1 = transforms.Affine2D().scale(L, width) + trans2 = transforms.Affine2D.from_values(cx, sx, -sx, cx, 0.0, 0.0) + trans3 = transforms.Affine2d().translate(x, y) + trans = trans1 + trans2 + trans3 + self._patch_transform = trans.frozen() __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def get_path(self): + return self._path + + def get_patch_transform(self): + return self._patch_transform + class FancyArrow(Polygon): """Like Arrow, but lets you set head width and head height independently.""" @@ -614,7 +649,7 @@ Polygon.__init__(self, map(tuple, verts), **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd -class YAArrow(Polygon): +class YAArrow(Patch): """ Yet another arrow class @@ -640,25 +675,25 @@ %(Patch)s """ - # MGDTODO: Implement me self.dpi = dpi self.xytip = xytip self.xybase = xybase self.width = width self.frac = frac self.headwidth = headwidth - verts = self.get_verts() - Polygon.__init__(self, verts, **kwargs) + Patch.__init__(self, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - - def get_verts(self): + def get_path(self): + # MGDTODO: Since this is dpi dependent, we need to recompute + # the path every time. Perhaps this can be plugged through the + # dpi transform instead (if only we know how to get it...) + # the base vertices x1, y1 = self.xytip x2, y2 = self.xybase - k1 = self.width*self.dpi.get()/72./2. - k2 = self.headwidth*self.dpi.get()/72./2. + k1 = self.width*self.dpi/72./2. + k2 = self.headwidth*self.dpi/72./2. xb1, yb1, xb2, yb2 = self.getpoints(x1, y1, x2, y2, k1) # a point on the segment 20% of the distance from the tip to the base @@ -669,12 +704,14 @@ xc1, yc1, xc2, yc2 = self.getpoints(x1, y1, xm, ym, k1) xd1, yd1, xd2, yd2 = self.getpoints(x1, y1, xm, ym, k2) - xs = self.convert_xunits([xb1, xb2, xc2, xd2, x1, xd1, xc1]) ys = self.convert_yunits([yb1, yb2, yc2, yd2, y1, yd1, yc1]) - return zip(xs, ys) + return Path(zip(xs, ys)) + def get_patch_transform(self): + return transforms.IdentityTransform() + def getpoints(self, x1,y1,x2,y2, k): """ for line segment defined by x1,y1 and x2,y2, return the points on Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-05 18:56:10 UTC (rev 3923) +++ branches/transforms/lib/matplotlib/path.py 2007-10-05 19:25:33 UTC (rev 3924) @@ -87,12 +87,14 @@ vertices = ma.asarray(vertices, npy.float_) if codes is None: - if closed: + if len(vertices) == 0: + codes = npy.zeros((0, ), self.code_type) + elif closed: codes = self.LINETO * npy.ones( vertices.shape[0] + 1, self.code_type) codes[0] = self.MOVETO - codes[-1] = self.CLOSEPOLY - vertices = npy.concatenate((vertices, [[0.0, 0.0]])) + codes[-1] = self.LINETO + vertices = npy.concatenate((vertices, [vertices[0]])) else: codes = self.LINETO * npy.ones( vertices.shape[0], self.code_type) @@ -187,9 +189,9 @@ algorithm will take into account the curves and deal with control points appropriately. """ - from transforms import Bbox, IdentityTransform + from transforms import Affine2D, Bbox if transform is None: - transform = IdentityTransform + transform = Affine2D() return Bbox.from_lbrt(*get_path_extents(self, transform)) def i... [truncated message content] |
From: <md...@us...> - 2007-10-05 19:37:21
|
Revision: 3925 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3925&view=rev Author: mdboom Date: 2007-10-05 12:37:18 -0700 (Fri, 05 Oct 2007) Log Message: ----------- Merged revisions 3909-3924 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3910 | jrevans | 2007-10-03 18:23:48 -0400 (Wed, 03 Oct 2007) | 4 lines Moved a couple of routines from the Agg version of the FigureCanvas to the base qt version where they belong. Added a couple of overloaded qt methods that should be there and reduce having to inherit when embedding in another QWidget. ........ r3911 | jrevans | 2007-10-03 19:05:30 -0400 (Wed, 03 Oct 2007) | 3 lines Removed an erroneous print statment in backend_qt.py. Added a feature to keep track of axes inversions. ........ r3916 | sameerd | 2007-10-04 17:39:07 -0400 (Thu, 04 Oct 2007) | 3 lines Fix for "NameError: global name 'ones' is not defined" ........ r3917 | jrevans | 2007-10-04 18:13:18 -0400 (Thu, 04 Oct 2007) | 5 lines axes.py: Reverted get/set xlim/ylim methods to original state Added get/set xbound/ybound to handle axes inversion maintenance Removed inverted axes flags patches.py: Added some logic to xform an Ellipse angle as per the Ellipse's transformation. ........ r3918 | efiring | 2007-10-05 02:18:25 -0400 (Fri, 05 Oct 2007) | 2 lines Minor cleanup of arguments and docstring in contour ........ r3919 | efiring | 2007-10-05 02:58:15 -0400 (Fri, 05 Oct 2007) | 2 lines Tweaked automatic contour level calculation ........ r3920 | jrevans | 2007-10-05 12:29:17 -0400 (Fri, 05 Oct 2007) | 2 lines Fixed a typo in the Ellipse code that was causing the ellipse angle to go in the wrong direction. When I was testing I had forgotten to turn off the axes inversion test. ........ r3921 | jrevans | 2007-10-05 13:01:36 -0400 (Fri, 05 Oct 2007) | 2 lines Fixed an error in calculating the mid-point of a bar since the values are now lists and not arrays, they need to be iterated to perform the arithmetic. ........ r3923 | dsdale | 2007-10-05 14:56:10 -0400 (Fri, 05 Oct 2007) | 1 line remove generator expressions from texmanager and mpltraits ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/examples/simple_plot.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/config/mpltraits.py branches/transforms/lib/matplotlib/contour.py branches/transforms/lib/matplotlib/texmanager.py branches/transforms/lib/matplotlib/ticker.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3908 + /trunk/matplotlib:1-3924 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/CHANGELOG 2007-10-05 19:37:18 UTC (rev 3925) @@ -1,3 +1,6 @@ +2007-10-05 remove generator expressions from texmanager and mpltraits. + generator expressions are not supported by python-2.3 - DSD + 2007-10-01 Made matplotlib.use() raise an exception if called after backends has been imported. Modified: branches/transforms/examples/simple_plot.py =================================================================== --- branches/transforms/examples/simple_plot.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/examples/simple_plot.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -17,4 +17,6 @@ #savefig('simple_plot.png') savefig('simple_plot') +axes().set_xlim(5, -5) + show() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -844,9 +844,9 @@ return - xmin,xmax = self.get_xlim() + xmin,xmax = self.get_xbound() xsize = max(math.fabs(xmax-xmin), 1e-30) - ymin,ymax = self.get_ylim() + ymin,ymax = self.get_ybound() ysize = max(math.fabs(ymax-ymin), 1e-30) l,b,w,h = self.get_position(original=True).bounds @@ -895,14 +895,14 @@ yc = 0.5*(ymin+ymax) y0 = yc - Ysize/2.0 y1 = yc + Ysize/2.0 - self.set_ylim((y0, y1)) + self.set_ybound((y0, y1)) #print 'New y0, y1:', y0, y1 #print 'New ysize, ysize/xsize', y1-y0, (y1-y0)/xsize else: xc = 0.5*(xmin+xmax) x0 = xc - Xsize/2.0 x1 = xc + Xsize/2.0 - self.set_xlim((x0, x1)) + self.set_xbound((x0, x1)) #print 'New x0, x1:', x0, x1 #print 'New xsize, ysize/xsize', x1-x0, ysize/(x1-x0) @@ -1186,24 +1186,20 @@ len(self.lines)==0 and len(self.patches)==0)): - if scalex: self.set_xlim(self.dataLim.intervalx().get_bounds()) + if scalex: self.set_xbound(self.dataLim.intervalx().get_bounds()) - if scaley: self.set_ylim(self.dataLim.intervaly().get_bounds()) + if scaley: self.set_ybound(self.dataLim.intervaly().get_bounds()) return if scalex: - xl = self.get_xlim() + xl = self.get_xbound() XL = self.xaxis.get_major_locator().autoscale() - if xl[1] < xl[0]: - XL = XL[::-1] - self.set_xlim(XL) + self.set_xbound(XL) if scaley: ylocator = self.yaxis.get_major_locator() - yl = self.get_ylim() + yl = self.get_ybound() YL = ylocator.autoscale() - if yl[1] < yl[0]: - YL = YL[::-1] - self.set_ylim(YL) + self.set_ybound(YL) #### Drawing def draw(self, renderer=None, inframe=False): @@ -1427,14 +1423,47 @@ ### data limits, ticks, tick labels, and formatting - def invert_xaxis(self, invert=True): - "Invert the x-axis if 'invert' is True." - self._invertedx = invert + def invert_xaxis(self): + "Invert the x-axis." + left, right = self.get_xlim() + self.set_xlim(right, left) def xaxis_inverted(self): 'Returns True if the x-axis is inverted.' - return self._invertedx + left, right = self.get_xlim() + return right < left + def get_xbound(self): + "Returns the x-axis numerical bounds in the form of lowerBound < upperBound" + left, right = self.get_xlim() + if left < right: + return left, right + else: + return right, left + + def set_xbound(self, lower=None, upper=None): + """Set the lower and upper numerical bounds of the x-axis. + This method will honor axes inversion regardless of parameter order. + """ + if upper is None and iterable(lower): + lower,upper = lower + + old_lower,old_upper = self.get_xbound() + + if lower is None: lower = old_lower + if upper is None: upper = old_upper + + if self.xaxis_inverted(): + if lower < upper: + self.set_xlim(upper, lower) + else: + self.set_xlim(lower, upper) + else: + if lower < upper: + self.set_xlim(lower, upper) + else: + self.set_xlim(upper, lower) + def get_xlim(self): """Get the x-axis range [xmin, xmax] @@ -1483,21 +1512,9 @@ if xmin is None: xmin = old_xmin if xmax is None: xmax = old_xmax - # provided for backwards compatability - if ( xmax < xmin ): - # swap the values so that xmin < xmax and set inverted flag - tmp = xmin - xmin = xmax - xmax = tmp - self.invert_xaxis( True ) - - if ( self._invertedx ): - xmax, xmin = mtransforms.nonsingular(xmax, xmin, increasing=False) - self.viewLim.intervalx = (xmax, xmin) - else: - xmin, xmax = mtransforms.nonsingular(xmin, xmax, increasing=False) - self.viewLim.intervalx = (xmin, xmax) - + xmax, xmin = mtransforms.nonsingular(xmax, xmin, increasing=False) + self.viewLim.intervalx = (xmin, xmax) + if emit: self.callbacks.process('xlim_changed', self) # Call all of the other x-axes that are shared with this one @@ -1566,14 +1583,47 @@ return self.xaxis.set_ticklabels(labels, fontdict, **kwargs) set_xticklabels.__doc__ = cbook.dedent(set_xticklabels.__doc__) % martist.kwdocd - def invert_yaxis(self, invert=True): - "Invert the y-axis if 'invert' is True." - self._invertedy = invert + def invert_yaxis(self): + "Invert the y-axis." + left, right = self.get_ylim() + self.set_ylim(right, left) def yaxis_inverted(self): 'Returns True if the y-axis is inverted.' - return self._invertedy + left, right = self.get_ylim() + return right < left + def get_ybound(self): + "Returns the y-axis numerical bounds in the form of lowerBound < upperBound" + left, right = self.get_ylim() + if left < right: + return left, right + else: + return right, left + + def set_ybound(self, lower=None, upper=None): + """Set the lower and upper numerical bounds of the y-axis. + This method will honor axes inversion regardless of parameter order. + """ + if upper is None and iterable(lower): + lower,upper = lower + + old_lower,old_upper = self.get_ybound() + + if lower is None: lower = old_lower + if upper is None: upper = old_upper + + if self.yaxis_inverted(): + if lower < upper: + self.set_ylim(upper, lower) + else: + self.set_ylim(lower, upper) + else: + if lower < upper: + self.set_ylim(lower, upper) + else: + self.set_ylim(upper, lower) + def get_ylim(self): """Get the y-axis range [xmin, xmax] @@ -1620,21 +1670,9 @@ if ymin is None: ymin = old_ymin if ymax is None: ymax = old_ymax - # provided for backwards compatability - if ( ymax < ymin ): - # swap the values so that ymin < ymax and set inverted flag - tmp = ymin - ymin = ymax - ymax = tmp - self.invert_yaxis( True ) + ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False) + self.viewLim.intervaly = (ymin, ymax) - if ( self._invertedy ): - ymax, ymin = mtransforms.nonsingular(ymax, ymin, increasing=False) - self.viewLim.intervaly = (ymax, ymin) - else: - ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False) - self.viewLim.intervaly = (ymin, ymax) - if emit: self.callbacks.process('ylim_changed', self) # Call all of the other y-axes that are shared with this one @@ -2357,9 +2395,9 @@ y = npy.asarray(y) if len(xmin)==1: - xmin = xmin*ones(y.shape, y.dtype) + xmin = xmin*npy.ones(y.shape, y.dtype) if len(xmax)==1: - xmax = xmax*ones(y.shape, y.dtype) + xmax = xmax*npy.ones(y.shape, y.dtype) xmin = npy.asarray(xmin) xmax = npy.asarray(xmax) @@ -3199,9 +3237,9 @@ pass elif align == 'center': if orientation == 'vertical': - left = left - width/2. + left = [left[i] - width[i]/2. for i in range(len(left))] elif orientation == 'horizontal': - bottom = bottom-height/2. + bottom = [bottom[i] - height[i]/2. for i in range(len(bottom))] else: raise ValueError, 'invalid alignment: %s' % align Modified: branches/transforms/lib/matplotlib/config/mpltraits.py =================================================================== --- branches/transforms/lib/matplotlib/config/mpltraits.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/lib/matplotlib/config/mpltraits.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -46,7 +46,7 @@ def info(self): be = self.backends.keys() be.sort - return "one of %s"% ', '.join('%s'%i for i in be) + return "one of %s"% ', '.join(['%s'%i for i in be]) class BoolHandler(T.TraitHandler): @@ -73,7 +73,7 @@ return self.error(object, name, value) def info(self): - return "one of %s"% ', '.join('%s'%i for i in self.bools.keys()) + return "one of %s"% ', '.join(['%s'%i for i in self.bools.keys()]) flexible_true = T.Trait(True, BoolHandler()) flexible_false = T.Trait(False, BoolHandler()) Modified: branches/transforms/lib/matplotlib/contour.py =================================================================== --- branches/transforms/lib/matplotlib/contour.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/lib/matplotlib/contour.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -397,12 +397,7 @@ cmap = kwargs.get('cmap', None) self.colors = kwargs.get('colors', None) norm = kwargs.get('norm', None) - self.clip_ends = kwargs.get('clip_ends', None) ######## self.extend = kwargs.get('extend', 'neither') - if self.clip_ends is not None: - warnings.warn("'clip_ends' has been replaced by 'extend'") - self.levels = self.levels[1:-1] # discard specified end levels - self.extend = 'both' # regenerate end levels self.antialiased = kwargs.get('antialiased', True) self.nchunk = kwargs.get('nchunk', 0) self.locator = kwargs.get('locator', None) @@ -436,10 +431,8 @@ _mask = None if self.filled: - if self.linewidths is None: - self.linewidths = 0.05 # Good default for Postscript. - if cbook.iterable(self.linewidths): - self.linewidths = self.linewidths[0] + if self.linewidths is not None: + warnings.warn('linewidths is ignored by contourf') C = _cntr.Cntr(x, y, z.filled(), _mask) lowers = self._levels[:-1] uppers = self._levels[1:] @@ -447,7 +440,6 @@ nlist = C.trace(level, level_upper, points = 0, nchunk = self.nchunk) col = collections.PolyCollection(nlist, - linewidths = (self.linewidths,), antialiaseds = (self.antialiased,), edgecolors= 'None') self.ax.add_collection(col) @@ -500,16 +492,18 @@ one contour line, but two filled regions, and therefore three levels to provide boundaries for both regions. ''' - zmax = self.zmax - zmin = self.zmin - zmargin = (zmax - zmin) * 0.001 # so z < (zmax + zmargin) - zmax = zmax + zmargin - intv = transforms.Interval(transforms.Value(zmin), transforms.Value(zmax)) if self.locator is None: self.locator = ticker.MaxNLocator(N+1) - self.locator.set_view_interval(intv) - self.locator.set_data_interval(intv) - lev = self.locator() + locator = self.locator + zmax = self.zmax + zmin = self.zmin + locator.set_bounds(zmin, zmax) + lev = locator() + zmargin = (zmax - zmin) * 0.000001 # so z < (zmax + zmargin) + if zmax >= lev[-1]: + lev[-1] += zmargin + if zmin <= lev[0]: + lev[0] -= zmargin self._auto = True if self.filled: return lev @@ -627,16 +621,16 @@ self._levels = npy.asarray(self._levels) self.vmin = npy.amin(self.levels) # alternative would be self.layers self.vmax = npy.amax(self.levels) - if self.extend in ('both', 'min') or self.clip_ends: + if self.extend in ('both', 'min'): self.vmin = 2 * self.levels[0] - self.levels[1] - if self.extend in ('both', 'max') or self.clip_ends: + if self.extend in ('both', 'max'): self.vmax = 2 * self.levels[-1] - self.levels[-2] self.layers = self._levels # contour: a line is a thin layer if self.filled: self.layers = 0.5 * (self._levels[:-1] + self._levels[1:]) - if self.extend in ('both', 'min') or self.clip_ends: + if self.extend in ('both', 'min'): self.layers[0] = 0.5 * (self.vmin + self._levels[1]) - if self.extend in ('both', 'max') or self.clip_ends: + if self.extend in ('both', 'max'): self.layers[-1] = 0.5 * (self.vmax + self._levels[-2]) return (x, y, z) @@ -774,7 +768,6 @@ contour levels if they are not given explicitly via the V argument. - ***** New: ***** * extend = 'neither', 'both', 'min', 'max' Unless this is 'neither' (default), contour levels are automatically added to one or both ends of the range so that @@ -782,8 +775,7 @@ mapped to the special colormap values which default to the ends of the colormap range, but can be set via Colormap.set_under() and Colormap.set_over() methods. - To replace clip_ends=True and V = [-100, 2, 1, 0, 1, 2, 100], - use extend='both' and V = [2, 1, 0, 1, 2]. + **************** contour only: @@ -799,29 +791,13 @@ matplotlibrc is used contourf only: - ***** Obsolete: **** - * clip_ends = True - If False, the limits for color scaling are set to the - minimum and maximum contour levels. - True (default) clips the scaling limits. Example: - if the contour boundaries are V = [-100, 2, 1, 0, 1, 2, 100], - then the scaling limits will be [-100, 100] if clip_ends - is False, and [-3, 3] if clip_ends is True. - * linewidths = None or a number; default of 0.05 works for - Postscript; a value of about 0.5 seems better for Agg. - * antialiased = True (default) or False; if False, there is - no need to increase the linewidths for Agg, but True gives - nicer color boundaries. If antialiased is True and linewidths - is too small, then there may be light-colored lines at the - color boundaries caused by the antialiasing. + * antialiased = True (default) or False * nchunk = 0 (default) for no subdivision of the domain; specify a positive integer to divide the domain into subdomains of roughly nchunk by nchunk points. This may never actually be advantageous, so this option may be removed. Chunking introduces artifacts at the chunk - boundaries unless antialiased = False, or linewidths is - set to a large enough value for the particular renderer and - resolution. + boundaries unless antialiased = False """ Modified: branches/transforms/lib/matplotlib/texmanager.py =================================================================== --- branches/transforms/lib/matplotlib/texmanager.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/lib/matplotlib/texmanager.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -110,7 +110,7 @@ _rc_cache = None _rc_cache_keys = ('text.latex.preamble', )\ - + tuple('font.'+n for n in ('family', ) + font_families) + + tuple(['font.'+n for n in ('family', ) + font_families]) def __init__(self): @@ -125,7 +125,7 @@ fontconfig = [self.font_family] for font_family, font_family_attr in \ - ((ff, ff.replace('-', '_')) for ff in self.font_families): + [(ff, ff.replace('-', '_')) for ff in self.font_families]: for font in rcParams['font.'+font_family]: if font.lower() in self.font_info: found_font = self.font_info[font.lower()] @@ -163,7 +163,7 @@ def get_font_config(self): "Reinitializes self if rcParams self depends on have changed." if self._rc_cache is None: - self._rc_cache = dict((k,None) for k in self._rc_cache_keys) + self._rc_cache = dict([(k,None) for k in self._rc_cache_keys]) changed = [par for par in self._rc_cache_keys if rcParams[par] != \ self._rc_cache[par]] if changed: Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-10-05 19:25:33 UTC (rev 3924) +++ branches/transforms/lib/matplotlib/ticker.py 2007-10-05 19:37:18 UTC (rev 3925) @@ -370,7 +370,7 @@ self.format = '$%s$' % self.format elif self._useMathText: self.format = '$\mathdefault{%s}$' % self.format - + def pprint_val(self, x): xp = (x-self.offset)/10**self.orderOfMagnitude if npy.absolute(xp) < 1e-8: xp = 0 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-08 18:10:13
|
Revision: 3928 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3928&view=rev Author: mdboom Date: 2007-10-08 11:10:11 -0700 (Mon, 08 Oct 2007) Log Message: ----------- More work on collections. Modified Paths: -------------- branches/transforms/examples/collections_demo.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/setupext.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Modified: branches/transforms/examples/collections_demo.py =================================================================== --- branches/transforms/examples/collections_demo.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/examples/collections_demo.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -45,6 +45,8 @@ a = fig.add_subplot(2,2,1) col = collections.LineCollection([spiral], offsets=xyo, transOffset=a.transData) +trans = transforms.Affine2D().scale(fig.dpi/72.0) +col.set_transform(trans) # the points to pixels transform # Note: the first argument to the collection initializer # must be a list of sequences of x,y tuples; we have only # one sequence, but we still have to put it in a list. @@ -59,9 +61,6 @@ # Make a transform for the line segments such that their size is # given in points: -trans = transforms.scale_transform(fig.dpi/transforms.Value(72.), - fig.dpi/transforms.Value(72.)) -col.set_transform(trans) # the points to pixels transform col.set_color(colors) a.autoscale_view() # See comment above, after a.add_collection. @@ -74,28 +73,25 @@ col = collections.PolyCollection([spiral], offsets=xyo, transOffset=a.transData) -a.add_collection(col, autolim=True) -trans = transforms.scale_transform(fig.dpi/transforms.Value(72.), - fig.dpi/transforms.Value(72.)) +trans = transforms.Affine2D().scale(fig.dpi/72.0) col.set_transform(trans) # the points to pixels transform +a.add_collection(col, autolim=True) col.set_color(colors) a.autoscale_view() a.set_title('PolyCollection using offsets') - # 7-sided regular polygons a = fig.add_subplot(2,2,3) col = collections.RegularPolyCollection(fig.dpi, 7, - sizes = N.fabs(xx)*10, offsets=xyo, + sizes = N.fabs(xx) / 10.0, offsets=xyo, transOffset=a.transData) -a.add_collection(col, autolim=True) -trans = transforms.scale_transform(fig.dpi/transforms.Value(72.), - fig.dpi/transforms.Value(72.)) +trans = transforms.Affine2D().scale(fig.dpi/72.0) col.set_transform(trans) # the points to pixels transform +a.add_collection(col, autolim=True) col.set_color(colors) a.autoscale_view() a.set_title('RegularPolyCollection using offsets') Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -1046,7 +1046,7 @@ self._set_artist_props(collection) collection.set_clip_path(self.axesPatch) if autolim: - self.update_datalim(collection.get_verts(self.transData)) + self.update_datalim(collection.get_datalim(self.transData)) collection._remove_method = lambda h: self.collections.remove(h) def add_line(self, line): @@ -1105,6 +1105,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 + # MGDTODO: This isn't always the most efficient way to do this... in + # some cases things should use update_datalim_bounds + if not ma.isMaskedArray(xys): xys = npy.asarray(xys) self.update_datalim_numerix(xys[:, 0], xys[:, 1]) @@ -1119,6 +1122,10 @@ self.dataLim.update_from_data(x, y, self.ignore_existing_data_limits) self.ignore_existing_data_limits = False + def update_datalim_bounds(self, bounds): + # MGDTODO: Document me + self.dataLim.bounds = Bbox.union([self.dataLim, bounds]).bounds + def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: return xys @@ -4006,8 +4013,8 @@ shading='faceted --> edgecolors=None edgecolors also can be any mpl color or sequence of colors. - Optional kwargs control the PatchCollection properties: - %(PatchCollection)s + Optional kwargs control the Collection properties: + %(Collection)s """ if not self._hold: self.cla() @@ -4439,7 +4446,7 @@ * alpha=1.0 : the alpha blending value - Return value is a mcoll.PatchCollection + Return value is a mcoll.Collection object Grid Orientation @@ -4627,7 +4634,7 @@ * alpha=1.0 : the alpha blending value - Return value is a collections.PatchCollection + Return value is a collections.Collection object See pcolor for an explantion of the grid orientation and the Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -131,11 +131,15 @@ self._renderer.draw_markers(gc, marker_path, marker_trans.frozen(), path, trans.frozen(), rgbFace) def draw_path_collection(self, master_transform, clipbox, clippath, clippath_trans, - paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds): + paths, transforms, offsets, transOffset, facecolors, edgecolors, + linewidths, linestyles, antialiaseds): assert master_transform.is_affine + if transOffset is not None: + transOffset = transOffset.frozen() self._renderer.draw_path_collection( master_transform.frozen(), clipbox, clippath, clippath_trans, - paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds) + paths, transforms, offsets, transOffset, facecolors, edgecolors, linewidths, + linestyles, antialiaseds) def draw_mathtext(self, gc, x, y, s, prop, angle): """ Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -19,67 +19,20 @@ import matplotlib.nxutils as nxutils import matplotlib.path as path -# MGDTODO: Now that everything draws through draw_path_collection, -# perhaps more stuff could be moved into the Collection base class -# here +# MGDTODO: Move this stuff +from matplotlib.backends._backend_agg import get_path_collection_extents, \ + point_in_path_collection -class Collection(artist.Artist): +class Collection(artist.Artist, cm.ScalarMappable): """ + Base class for Collections. Must be subclassed to be usable. + All properties in a collection must be sequences or scalars; if scalars, they will be converted to sequences. The property of the ith element of the collection is the prop[i % len(props)]. - """ - - def __init__(self): - artist.Artist.__init__(self) - - - def get_verts(self): - 'return seq of (x,y) in collection' - raise NotImplementedError('Derived must override') - - def _get_value(self, val): - try: return (float(val), ) - except TypeError: - if cbook.iterable(val) and len(val): - try: float(val[0]) - except TypeError: pass # raise below - else: return val - - raise TypeError('val must be a float or nonzero sequence of floats') - - -# these are not available for the object inspector until after the -# class is built so we define an initial set here for the init -# function and they will be overridden after object defn -artist.kwdocd['PatchCollection'] = """\ - Valid PatchCollection kwargs are: - - edgecolors=None, - facecolors=None, - linewidths=None, - antialiaseds = None, - offsets = None, - transOffset = transforms.identity_transform(), - norm = None, # optional for cm.ScalarMappable - cmap = None, # ditto - - offsets and transOffset are used to translate the patch after - rendering (default no offsets) - - If any of edgecolors, facecolors, linewidths, antialiaseds are - None, they default to their patch.* rc params setting, in sequence - form. -""" - -class PatchCollection(Collection, cm.ScalarMappable): - """ - Base class for filled regions such as PolyCollection etc. - It must be subclassed to be usable. - kwargs are: edgecolors=None, @@ -103,30 +56,45 @@ draw time a call to scalar mappable will be made to set the face colors. """ + _offsets = npy.zeros((1, 2)) + _transOffset = transforms.IdentityTransform() + + _facecolors = [None] + _edgecolors = [None] + _lw = [1.0] + _ls = [None] + _aa = [True] + _pickradius = 5.0 + _transforms = [None] + zorder = 1 def __init__(self, edgecolors=None, facecolors=None, linewidths=None, + linestyles='solid', antialiaseds = None, offsets = None, transOffset = None, norm = None, # optional for ScalarMappable cmap = None, # ditto + pickradius = 5.0, + **kwargs ): """ Create a PatchCollection %(PatchCollection)s """ - Collection.__init__(self) + artist.Artist.__init__(self) cm.ScalarMappable.__init__(self, norm, cmap) if facecolors is None: facecolors = mpl.rcParams['patch.facecolor'] if edgecolors is None: edgecolors = mpl.rcParams['patch.edgecolor'] if linewidths is None: linewidths = (mpl.rcParams['patch.linewidth'],) if antialiaseds is None: antialiaseds = (mpl.rcParams['patch.antialiased'],) - + self.set_linestyles(linestyles) + self._facecolors = _colors.colorConverter.to_rgba_list(facecolors) if edgecolors == 'None': self._edgecolors = self._facecolors @@ -135,13 +103,80 @@ self._edgecolors = _colors.colorConverter.to_rgba_list(edgecolors) self._linewidths = self._get_value(linewidths) self._antialiaseds = self._get_value(antialiaseds) - #self._offsets = offsets - self._offsets = offsets - self._transOffset = transOffset - self._verts = [] - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + self._uniform_offsets = None + self._offsets = npy.zeros((1, 2)) + if offsets is not None: + offsets = npy.asarray(offsets) + if len(offsets.shape) == 1: + offsets = offsets[npy.newaxis,:] # Make it Nx2. + if transOffset is not None: + Affine2D = transforms.Affine2D + self._offsets = offsets + self._transOffset = transOffset + else: + self._uniform_offsets = offsets + self._pickradius = pickradius + self.update(kwargs) + + def _get_value(self, val): + try: return (float(val), ) + except TypeError: + if cbook.iterable(val) and len(val): + try: float(val[0]) + except TypeError: pass # raise below + else: return val + + raise TypeError('val must be a float or nonzero sequence of floats') + + def get_paths(self): + raise NotImplementedError + + def get_transforms(self): + return self._transforms + + def get_datalim(self, transData): + result = transforms.Bbox.from_lbrt(*get_path_collection_extents( + self.get_transform().frozen(), + self.get_paths(), + self.get_transforms(), + self._offsets, + self._transOffset.frozen())) + result = result.transformed(transData.inverted()) + return result + + def draw(self, renderer): + if not self.get_visible(): return + renderer.open_group(self.__class__.__name__) + transform = self.get_transform() + transOffset = self._transOffset + offsets = self._offsets + + # MGDTODO: Transform the paths (since we don't keep track of segments anymore + if self.have_units(): + segments = [] + for segment in self._segments: + xs, ys = zip(*segment) + xs = self.convert_xunits(xs) + ys = self.convert_yunits(ys) + segments.append(zip(xs, ys)) +# if self._offsets is not None: +# xs = self.convert_xunits(self._offsets[:0]) +# ys = self.convert_yunits(self._offsets[:1]) +# offsets = zip(xs, ys) + + self.update_scalarmappable() + + #print 'calling renderer draw line collection' + clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + + renderer.draw_path_collection( + transform, self.clipbox, clippath, clippath_trans, + self.get_paths(), self.get_transforms(), offsets, transOffset, + self._facecolors, self._edgecolors, self._lw, self._ls, self._aa) + renderer.close_group(self.__class__.__name__) + def contains(self, mouseevent): """ Test whether the mouse event occurred in the collection. @@ -149,25 +184,13 @@ Returns T/F, dict(ind=itemlist), where every item in itemlist contains the event. """ if callable(self._contains): return self._contains(self,mouseevent) - # TODO: Consider doing the test in data coordinates - # Patch transforms the mouse into data coordinates and does the - # test for membership there. This is more efficient though it - # may not match the visual appearance of the polygon on the - # screen. Regardless, patch and patch collection should use - # the same algorithm. Here's the code in patch: - # - # x, y = self.get_transform().inverse_xy_tup((mouseevent.x, mouseevent.y)) - # xyverts = self.get_verts() - # inside = nxutils.pnpoly(x, y, xyverts) - # - ind = [] - x, y = mouseevent.x, mouseevent.y - for i, thispoly in enumerate(self.get_transformed_patches()): - inside = nxutils.pnpoly(x, y, thispoly) - if inside: ind.append(i) + ind = point_in_path_collection( + mouseevent.x, mouseevent.y, self._pickradius, + self.get_transform(), self._paths, self._transforms, self._offsets, + self._offsetTrans, self._facecolors) return len(ind)>0,dict(ind=ind) - + # MGDTODO def get_transformed_patches(self): """ get a sequence of the polygons in the collection in display (transformed) space @@ -206,12 +229,9 @@ data.append(tverts) return data - def get_transoffset(self): - if self._transOffset is None: - self._transOffset = transforms.identity_transform() - return self._transOffset - - + def set_pickradius(self,pickradius): self.pickradius = 5 + def get_pickradius(self): return self.pickradius + def set_linewidth(self, lw): """ Set the linewidth(s) for the collection. lw can be a scalar or a @@ -224,6 +244,36 @@ def set_linewidths(self, lw): self.set_linewidth(lw) + def set_linestyles(self, ls): + """ + Set the linestyles(s) for the collection. + ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | (offset, on-off-dash-seq) ] + """ + try: + if cbook.is_string_like(ls): + dashes = [backend_bases.GraphicsContextBase.dashd[ls]] + elif cbook.iterable(ls): + try: + dashes = [] + for x in ls: + if cbook.is_string_like(x): + dashes.append(backend_bases.GraphicsContextBase.dashd[ls]) + elif cbook.iterator(x) and len(x) == 2: + dashes.append(x) + else: + raise ValueError() + except ValueError: + if len(ls)==2: + dashes = ls + else: + raise ValueError() + else: + raise ValueError() + except ValueError: + raise ValueError('Do not know how to convert %s to dashes'%ls) + + self._ls = dashes + def set_color(self, c): """ Set both the edgecolor and the facecolor. @@ -277,6 +327,15 @@ if cbook.is_string_like(self._edgecolors) and self._edgecolors != 'None': self._edgecolors = [(r,g,b,alpha) for r,g,b,a in self._edgecolors] + def get_linewidth(self): + return self._lw + + def get_linestyle(self): + return self._ls + + def get_dashes(self): + return self._ls + def update_scalarmappable(self): """ If the scalar mappable array is not none, update facecolors @@ -289,7 +348,31 @@ self._facecolors = self.to_rgba(self._A, self._alpha) #print self._facecolors -class QuadMesh(PatchCollection): + +# these are not available for the object inspector until after the +# class is built so we define an initial set here for the init +# function and they will be overridden after object defn +artist.kwdocd['Collection'] = """\ + Valid Collection kwargs are: + + edgecolors=None, + facecolors=None, + linewidths=None, + antialiaseds = None, + offsets = None, + transOffset = transforms.identity_transform(), + norm = None, # optional for cm.ScalarMappable + cmap = None, # ditto + + offsets and transOffset are used to translate the patch after + rendering (default no offsets) + + If any of edgecolors, facecolors, linewidths, antialiaseds are + None, they default to their patch.* rc params setting, in sequence + form. +""" + +class QuadMesh(Collection): """ Class for the efficient drawing of a quadrilateral mesh. A quadrilateral mesh consists of a grid of vertices. The dimensions @@ -315,7 +398,7 @@ (0, 2) .. (0, meshWidth), (1, 0), (1, 1), and so on. """ def __init__(self, meshWidth, meshHeight, coordinates, showedges): - PatchCollection.__init__(self) + Collection.__init__(self) self._meshWidth = meshWidth self._meshHeight = meshHeight self._coordinates = coordinates @@ -329,7 +412,7 @@ # when creating/changing ****** Why not? speed? if not self.get_visible(): return transform = self.get_transform() - transoffset = self.get_transoffset() + transoffset = self._transOffset transform.freeze() transoffset.freeze() #print 'QuadMesh draw' @@ -342,63 +425,26 @@ transform.thaw() transoffset.thaw() -class PolyCollection(PatchCollection): +class PolyCollection(Collection): def __init__(self, verts, **kwargs): """ verts is a sequence of ( verts0, verts1, ...) where verts_i is a sequence of xy tuples of vertices, or an equivalent numpy array of shape (nv,2). - %(PatchCollection)s + %(Collection)s """ - PatchCollection.__init__(self,**kwargs) - self._verts = verts + Collection.__init__(self,**kwargs) + self.set_verts(verts) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def set_verts(self, verts): '''This allows one to delay initialization of the vertices.''' - self._verts = verts + self._paths = [path.Path(v, closed=True) for v in verts] - def draw(self, renderer): - if not self.get_visible(): return - renderer.open_group('polycollection') - transform = self.get_transform() - transoffset = self.get_transoffset() - - - transform.freeze() - transoffset.freeze() - self.update_scalarmappable() - if cbook.is_string_like(self._edgecolors) and self._edgecolors[:2] == 'No': - self._linewidths = (0,) - #self._edgecolors = self._facecolors - renderer.draw_poly_collection( - self._verts, transform, self.clipbox, - self._facecolors, self._edgecolors, - self._linewidths, self._antialiaseds, - self._offsets, transoffset) - transform.thaw() - transoffset.thaw() - renderer.close_group('polycollection') - - - def get_verts(self, dataTrans=None): - '''Return vertices in data coordinates. - The calculation is incomplete in general; it is based - on the vertices or the offsets, whichever is using - dataTrans as its transformation, so it does not take - into account the combined effect of segments and offsets. - ''' - verts = [] - if self._offsets is None: - for seg in self._verts: - verts.extend(seg) - return [tuple(xy) for xy in verts] - if self.get_transoffset() == dataTrans: - return [tuple(xy) for xy in self._offsets] - raise NotImplementedError('Vertices in data coordinates are calculated\n' - + 'with offsets only if _transOffset == dataTrans.') - + def get_paths(self): + return self._paths + class BrokenBarHCollection(PolyCollection): """ A colleciton of horizontal bars spanning yrange with a sequence of @@ -409,7 +455,7 @@ xranges : sequence of (xmin, xwidth) yrange : ymin, ywidth - %(PatchCollection)s + %(Collection)s """ ymin, ywidth = yrange ymax = ymin + ywidth @@ -417,7 +463,7 @@ PolyCollection.__init__(self, verts, **kwargs) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd -class RegularPolyCollection(PatchCollection): +class RegularPolyCollection(Collection): def __init__(self, dpi, numsides, @@ -437,7 +483,7 @@ * rotation is the rotation of the polygon in radians - %(PatchCollection)s + %(Collection)s Example: see examples/dynamic_collection.py for complete example @@ -459,14 +505,18 @@ """ - PatchCollection.__init__(self,**kwargs) + Collection.__init__(self,**kwargs) self._sizes = sizes self._dpi = dpi - self.numsides = numsides - self.rotation = rotation - self._update_verts() + self._paths = [path.Path.unit_regular_polygon(numsides)] + self._transforms = [transforms.Affine2D().scale(x) for x in sizes] + __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd + def get_paths(self): + return self._paths + + # MGDTODO def get_transformed_patches(self): # Shouldn't need all these calls to asarray; # the variables should be converted when stored. @@ -485,62 +535,6 @@ return polys - def _update_verts(self): - r = 1.0/math.sqrt(math.pi) # unit area - theta = (2*math.pi/self.numsides)*npy.arange(self.numsides) + self.rotation - self._verts = zip( r*npy.sin(theta), r*npy.cos(theta) ) - - def draw(self, renderer): - if not self.get_visible(): return - renderer.open_group('regpolycollection') - transform = self.get_transform() - transoffset = self.get_transoffset() - - transform.freeze() - transoffset.freeze() - self.update_scalarmappable() - self._update_verts() - scales = npy.sqrt(npy.asarray(self._sizes)*self._dpi.get()/72.0) - - - offsets = self._offsets - if self._offsets is not None: - xs, ys = zip(*offsets) - #print 'converting: units=%s, converter=%s'%(self.axes.xaxis.units, self.axes.xaxis.converter) - xs = self.convert_xunits(xs) - ys = self.convert_yunits(ys) - offsets = zip(xs, ys) - else: - offsets = None - - #print 'drawing offsets', offsets - #print 'drawing verts', self._verts - #print 'drawing scales', scales - if cbook.is_string_like(self._edgecolors) and self._edgecolors[:2] == 'No': - #self._edgecolors = self._facecolors - self._linewidths = (0,) - renderer.draw_regpoly_collection( - self.clipbox, - offsets, transoffset, - self._verts, scales, - self._facecolors, self._edgecolors, - self._linewidths, self._antialiaseds) - - transform.thaw() - transoffset.thaw() - renderer.close_group('regpolycollection') - - - def get_verts(self, dataTrans=None): - '''Return vertices in data coordinates. - The calculation is incomplete; it uses only - the offsets, and only if _transOffset is dataTrans. - ''' - if self.get_transoffset() == dataTrans: - return [tuple(xy) for xy in self._offsets] - raise NotImplementedError('Vertices in data coordinates are calculated\n' - + 'only with offsets and only if _transOffset == dataTrans.') - class StarPolygonCollection(RegularPolyCollection): def __init__(self, dpi, @@ -561,7 +555,7 @@ * rotation is the rotation of the polygon in radians - %(PatchCollection)s + %(Collection)s """ RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) @@ -595,7 +589,7 @@ * rotation is the rotation of the polygon in radians - %(PatchCollection)s + %(Collection)s """ RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) @@ -621,9 +615,8 @@ colors = None, antialiaseds = None, linestyles = 'solid', - # MGDTODO: Deal with offsets (mayb -# offsets = None, -# transOffset = None,#transforms.identity_transform(), + offsets = None, + transOffset = None, norm = None, cmap = None, pickradius = 5, @@ -668,168 +661,52 @@ matrix _A is not None (ie a call to set_array has been made), at draw time a call to scalar mappable will be made to set the colors. """ - Collection.__init__(self) - cm.ScalarMappable.__init__(self, norm, cmap) + if colors is None: colors = mpl.rcParams['lines.color'] + if linewidths is None: linewidths = (mpl.rcParams['lines.linewidth'],) + if antialiaseds is None: antialiaseds = (mpl.rcParams['lines.antialiased'],) + self.set_linestyles(linestyles) - if linewidths is None : - linewidths = (mpl.rcParams['lines.linewidth'], ) - if colors is None : - colors = (mpl.rcParams['lines.color'],) - if antialiaseds is None : - antialiaseds = (mpl.rcParams['lines.antialiased'], ) + Collection.__init__( + self, + edgecolors=colors, + linewidths=linewidths, + linestyles=linestyles, + antialiaseds=antialiaseds, + offsets=offsets, + transOffset=transOffset, + norm=norm, + cmap=cmap, + pickradius=pickradius, + **kwargs) - self._colors = _colors.colorConverter.to_rgba_list(colors) - self._aa = self._get_value(antialiaseds) - self._lw = self._get_value(linewidths) - self.set_linestyles(linestyles) - self._uniform_offsets = None - # MGDTODO: Deal with offsets -# if offsets is not None: -# offsets = npy.asarray(offsets) -# if len(offsets.shape) == 1: -# offsets = offsets[npy.newaxis,:] # Make it Nx2. -# if transOffset is None: -# if offsets is not None: -# self._uniform_offsets = offsets -# offsets = None -# transOffset = transforms.IdentityTransform() -# self._offsets = offsets -# self._transOffset = transOffset + self._facecolors = [None] self.set_segments(segments) - self.pickradius = pickradius - self.update(kwargs) - def contains(self, mouseevent): - """ - Test whether the mouse event occurred in the collection. - - Returns T/F, dict(ind=itemlist), where every item in itemlist contains the event. - """ - import matplotlib.lines as ML - if callable(self._contains): return self._contains(self,mouseevent) - - # TODO: add offset processing; adjusting the mouse for each offset - # will be somewhat cheaper than adjusting the segments. - if self._offsets != None: - raise NotImplementedError, "LineCollection does not yet support picking with offsets" - - mx,my = mouseevent.x,mouseevent.y - transform = self.get_transform() - - # MGDTODO: Numpify - ind = [] - for this in xrange(len(self._segments)): - xy = transform.transform_point(self._segments[this]) - this_ind = ML.segment_hits(mx,my,xy[:,0],xy[:,1],self.pickradius) - ind.extend([(this,k) for k in this_ind]) - return len(ind)>0,dict(ind=ind) - - def set_pickradius(self,pickradius): self.pickradius = 5 - def get_pickradius(self): return self.pickradius - - # MGDTODO: Support offsets (maybe) -# def get_transoffset(self): -# if self._transOffset is None: -# self._transOffset = transforms.identity_transform() -# return self._transOffset - + def get_paths(self): + return self._paths + def set_segments(self, segments): if segments is None: return + segments = [npy.asarray(seg, npy.float_) for seg in segments] + if self._uniform_offsets is not None: + segments = self._add_offsets(segments) self._paths = [path.Path(seg, closed=False) for seg in segments] -# if self._uniform_offsets is not None: -# self._add_offsets() - set_verts = set_segments # for compatibility with PolyCollection - # MGDTODO: Support offsets (maybe) -# def _add_offsets(self): -# segs = self._segments -# offsets = self._uniform_offsets -# Nsegs = len(segs) -# Noffs = offsets.shape[0] -# if Noffs == 1: -# for i in range(Nsegs): -# segs[i] = segs[i] + i * offsets -# else: -# for i in range(Nsegs): -# io = i%Noffs -# segs[i] = segs[i] + offsets[io:io+1] + def _add_offsets(self, segs): + offsets = self._uniform_offsets + Nsegs = len(segs) + Noffs = offsets.shape[0] + if Noffs == 1: + for i in range(Nsegs): + segs[i] = segs[i] + i * offsets + else: + for i in range(Nsegs): + io = i%Noffs + segs[i] = segs[i] + offsets[io:io+1] + return segs - def draw(self, renderer): - if not self.get_visible(): return - renderer.open_group('linecollection') - transform = self.get_transform() - # MGDTODO: Deal with offsets (maybe) -# transoffset = self.get_transoffset() - - # segments = self._segments - # MGDTODO: Deal with offsets (maybe) - # offsets = self._offsets - - # MGDTODO: Transform the paths (since we don't keep track of segments anymore - if self.have_units(): - segments = [] - for segment in self._segments: - xs, ys = zip(*segment) - xs = self.convert_xunits(xs) - ys = self.convert_yunits(ys) - segments.append(zip(xs, ys)) -# if self._offsets is not None: -# xs = self.convert_xunits(self._offsets[:0]) -# ys = self.convert_yunits(self._offsets[:1]) -# offsets = zip(xs, ys) - - self.update_scalarmappable() - #print 'calling renderer draw line collection' - clippath, clippath_trans = self.get_transformed_clip_path_and_affine() - renderer.draw_path_collection( - transform, self.clipbox, clippath, clippath_trans, - self._paths, [None], [None], - self._colors, self._lw, self._ls, self._aa) - renderer.close_group('linecollection') - - def set_linewidth(self, lw): - """ - Set the linewidth(s) for the collection. lw can be a scalar or a - sequence; if it is a sequence the patches will cycle through the - sequence - - ACCEPTS: float or sequence of floats - """ - - self._lw = self._get_value(lw) - - def set_linestyles(self, ls): - """ - Set the linestyles(s) for the collection. - ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | (offset, on-off-dash-seq) ] - """ - try: - if cbook.is_string_like(ls): - dashes = [backend_bases.GraphicsContextBase.dashd[ls]] - elif cbook.iterable(ls): - try: - dashes = [] - for x in ls: - if cbook.is_string_like(x): - dashes.append(backend_bases.GraphicsContextBase.dashd[ls]) - elif cbook.iterator(x) and len(x) == 2: - dashes.append(x) - else: - raise ValueError() - except ValueError: - if len(ls)==2: - dashes = ls - else: - raise ValueError() - else: - raise ValueError() - except ValueError: - raise ValueError('Do not know how to convert %s to dashes'%ls) - - self._ls = dashes - def set_color(self, c): """ Set the color(s) of the line collection. c can be a @@ -839,7 +716,7 @@ ACCEPTS: matplotlib color arg or sequence of rgba tuples """ - self._colors = _colors.colorConverter.to_rgba_list(c) + self._edgecolors = _colors.colorConverter.to_rgba_list(c) def color(self, c): """ @@ -853,48 +730,12 @@ warnings.warn('LineCollection.color deprecated; use set_color instead') return self.set_color(c) - def set_alpha(self, alpha): - """ - Set the alpha tranpancies of the collection. Alpha can be a - float, in which case it is applied to the entire collection, - or a sequence of floats - - ACCEPTS: float or sequence of floats - """ - - try: float(alpha) - except TypeError: raise TypeError('alpha must be a float') - else: - artist.Artist.set_alpha(self, alpha) - self._colors = [(r,g,b,alpha) for r,g,b,a in self._colors] - - def get_linewidth(self): - return self._lw - - def get_linestyle(self): - return self._ls - - def get_dashes(self): - return self._ls - def get_color(self): - return self._colors + return self._edgecolors get_colors = get_color # for compatibility with old versions - def update_scalarmappable(self): - """ - If the scalar mappable array is not none, update colors - from scalar data - """ - if self._A is None: return - if len(self._A.shape)>1: - raise ValueError('LineCollections can only map rank 1 arrays') - self._colors = self.to_rgba(self._A, self._alpha) - - -artist.kwdocd['Collection'] = artist.kwdoc(Collection) -artist.kwdocd['PatchCollection'] = patchstr = artist.kwdoc(PatchCollection) +artist.kwdocd['Collection'] = patchstr = artist.kwdoc(Collection) for k in ('QuadMesh', 'PolyCollection', 'BrokenBarHCollection', 'RegularPolyCollection', 'StarPolygonCollection'): artist.kwdocd[k] = patchstr Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -32,7 +32,7 @@ from lines import Line2D from mlab import segments_intersect from patches import Patch, Rectangle, RegularPolygon, Shadow, bbox_artist, draw_bbox -from collections import LineCollection, RegularPolyCollection, PatchCollection +from collections import LineCollection, RegularPolyCollection from text import Text from transforms import Affine2D, Bbox, BboxTransform Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -349,24 +349,14 @@ self._picker = p def get_window_extent(self, renderer): - # MGDTODO: Numpify - xy = self.get_transform().transform(self._xy) + bbox = Bbox() + bbox.update_from_data(self.get_transform().transform(self._xy)) - x = xy[:, 0] - y = xy[:, 1] - left = x.min() - bottom = y.min() - width = x.max() - left - height = y.max() - bottom - # correct for marker size, if any if self._marker is not None: ms = self._markersize / 72.0 * self.figure.dpi - left -= ms/2 - bottom -= ms/2 - width += ms - height += ms - return Bbox.from_lbwh(left, bottom, width, height) + bbox = Bbox(bbox.get_points() + [[-ms/2.0, ms/2.0]]) + return bbox def set_axes(self, ax): Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -395,6 +395,8 @@ when False, include the existing bounds of the Bbox. when None, use the last value passed to Bbox.ignore(). """ + # MGDTODO: It may be more efficient for some callers to use update_from_data_xy instead + if ignore is None: ignore = self._ignore @@ -430,6 +432,18 @@ npy.float_) self._minpos = npy.minimum(minpos, self._minpos) self.invalidate() + + def update_from_data_xy(self, xy, ignore=None): + """ + Update the bounds of the Bbox based on the passed in data. + + xy: a numpy array of 2D points + ignore: + when True, ignore the existing bounds of the Bbox. + when False, include the existing bounds of the Bbox. + when None, use the last value passed to Bbox.ignore(). + """ + return self.update_from_data(xy[:, 0], xy[:, 1], ignore) def _set_xmin(self, val): self._points[0, 0] = val Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/setupext.py 2007-10-08 18:10:11 UTC (rev 3928) @@ -352,6 +352,7 @@ try_pkgconfig(module, 'libpng', 'png') module.libraries.append('z') add_base_flags(module) + add_numpy_flags(module) module.include_dirs.extend(['src','swig', '%s/include'%AGG_VERSION, '.']) # put these later for correct link order @@ -823,7 +824,7 @@ # add agg flags before pygtk because agg only supports freetype1 # and pygtk includes freetype2. This is a bit fragile. - + add_tk_flags(module) # do this first add_agg_flags(module) add_ft2font_flags(module) Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/src/_backend_agg.cpp 2007-10-08 18:10:11 UTC (rev 3928) @@ -336,9 +336,11 @@ if (bbox_obj.ptr() != Py_None) { PyArrayObject* bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.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) { + Py_XDECREF(bbox); throw Py::TypeError ("Expected a Bbox object."); + } *l = *(double*)PyArray_GETPTR2(bbox, 0, 0); double _b = *(double*)PyArray_GETPTR2(bbox, 0, 1); @@ -346,8 +348,11 @@ double _t = *(double*)PyArray_GETPTR2(bbox, 1, 1); *b = height - _t; *t = height - _b; + + Py_XDECREF(bbox); return true; } + return false; } @@ -920,7 +925,7 @@ Py::Object RendererAgg::draw_path_collection(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_path_collection"); - args.verify_length(11); + args.verify_length(13); //segments, trans, clipbox, colors, linewidths, antialiaseds agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); @@ -929,23 +934,30 @@ agg::trans_affine clippath_trans = py_to_agg_transformation_matrix(args[3], false); Py::SeqBase<Py::Object> paths = args[4]; Py::SeqBase<Py::Object> transforms_obj = args[5]; - Py::SeqBase<Py::Object> facecolors_obj = args[6]; - Py::SeqBase<Py::Object> edgecolors_obj = args[7]; - Py::SeqBase<Py::Float> linewidths = args[8]; - Py::SeqBase<Py::Object> linestyles_obj = args[9]; - Py::SeqBase<Py::Int> antialiaseds = args[10]; + Py::Object offsets_obj = args[6]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7], false); + Py::SeqBase<Py::Object> facecolors_obj = args[8]; + Py::SeqBase<Py::Object> edgecolors_obj = args[9]; + Py::SeqBase<Py::Float> linewidths = args[10]; + Py::SeqBase<Py::Object> linestyles_obj = args[11]; + Py::SeqBase<Py::Int> antialiaseds = args[12]; GCAgg gc(dpi, false); + PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!offsets || offsets->dimensions[1] != 2) + throw Py::ValueError("Offsets array must be Nx2"); + size_t Npaths = paths.length(); - size_t Ntransforms = std::min(transforms_obj.length(), Npaths); - size_t Nfacecolors = std::min(facecolors_obj.length(), Npaths); - size_t Nedgecolors = std::min(edgecolors_obj.length(), Npaths); + size_t Noffsets = offsets->dimensions[0]; + size_t N = std::max(Npaths, Noffsets); + size_t Ntransforms = std::min(transforms_obj.length(), N); + size_t Nfacecolors = std::min(facecolors_obj.length(), N); + size_t Nedgecolors = std::min(edgecolors_obj.length(), N); size_t Nlinewidths = linewidths.length(); - size_t Nlinestyles = std::min(linestyles_obj.length(), Npaths); + size_t Nlinestyles = std::min(linestyles_obj.length(), N); size_t Naa = antialiaseds.length(); - size_t N = Npaths; size_t i = 0; // Convert all of the transforms up front @@ -983,7 +995,7 @@ } } - // Convert all of the edges up front + // Convert all of the edgecolors up front typedef std::vector<agg::rgba> edgecolors_t; edgecolors_t edgecolors; edgecolors.reserve(Nedgecolors); @@ -1016,18 +1028,23 @@ bool has_clippath = render_clippath(clippath, clippath_trans); for (i = 0; i < N; ++i) { - facepair_t& face = facecolors[i % Nfacecolors]; - gc.color = edgecolors[i % Nedgecolors]; - gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; - gc.dashes = dashes[i % Nlinestyles].second; - gc.dashOffset = dashes[i % Nlinestyles].first; - gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + agg::trans_affine_translation transOffset(xo, yo); agg::trans_affine& trans = transforms[i % Ntransforms]; - PathIterator path(paths[i]); + facepair_t& face = facecolors[i % Nfacecolors]; + gc.color = edgecolors[i % Nedgecolors]; + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + PathIterator path(paths[i % Npaths]); bool snap = (path.total_vertices() == 2); - _draw_path(path, trans, snap, has_clippath, face, gc); + _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); } + Py_XDECREF(offsets); return Py::Object(); } @@ -1482,11 +1499,9 @@ void get_path_extents(PathIterator& path, agg::trans_affine& trans, double* x0, double* y0, double* x1, double* y1) { - typedef agg::conv_transform<PathIterator> transformed_path_t; - typedef agg::conv_curve<transformed_path_t> curve_t; + typedef agg::conv_curve<PathIterator> curve_t; - transformed_path_t trans_path(path, trans); - curve_t curved_path(trans_path); + curve_t curved_path(path); double x, y; curved_path.rewind(0); @@ -1505,6 +1520,9 @@ if (x > *x1) *x1 = x; if (y > *y1) *y1 = y; } + + trans.transform(x0, y0); + trans.transform(x1, y1); } Py::Object _backend_agg_module::get_path_extents(const Py::Tuple& args) { @@ -1524,6 +1542,133 @@ return result; } +struct PathCollectionExtents { + double x0, y0, x1, y1; +}; + +Py::Object _backend_agg_module::get_path_collection_extents(const Py::Tuple& args) { + args.verify_length(5); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); + Py::SeqBase<Py::Object> paths = args[1]; + Py::SeqBase<Py::Object> transforms_obj = args[2]; + Py::SeqBase<Py::Object> offsets = args[3]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[4], false); + + size_t Npaths = paths.length(); + size_t Noffsets = offsets.length(); + size_t N = std::max(Npaths, Noffsets); + size_t Ntransforms = std::min(transforms_obj.length(), N); + size_t i; + + // Convert all of the transforms up front + typedef std::vector<agg::trans_affine> transforms_t; + transforms_t transforms; + transforms.reserve(Ntransforms); + for (i = 0; i < Ntransforms; ++i) { + agg::trans_affine trans = py_to_agg_transformation_matrix + (transforms_obj[i], false); + trans *= master_transform; + transforms.push_back(trans); + } + + typedef std::vector<PathCollectionExtents> path_extents_t; + path_extents_t path_extents; + path_extents.resize(Npaths); + + // Get each of the path extents first + i = 0; + for (path_extents_t::iterator p = path_extents.begin(); + p != path_extents.end(); ++p, ++i) { + PathIterator path(paths[i]); + agg::trans_affine& trans = transforms[i % Ntransforms]; + ::get_path_extents(path, trans, &p->x0, &p->y0, &p->x1, &p->y1); + } + + // The offset each of those and collect the mins/maxs + double x0 = std::numeric_limits<double>::infinity(); + double y0 = std::numeric_limits<double>::infinity(); + double x1 = -std::numeric_limits<double>::infinity(); + double y1 = -std::numeric_limits<double>::infinity(); + for (i = 0; i < N; ++i) { + Py::SeqBase<Py::Float> offset = Py::SeqBase<Py::Float>(offsets[i % Noffsets]); + double xo = Py::Float(offset[0]); + double yo = Py::Float(offset[1]); + offset_trans.transform(&xo, &yo); + PathCollectionExtents& ext = path_extents[i % Npaths]; + + x0 = std::min(x0, ext.x0 + xo); + y0 = std::min(y0, ext.y0 + yo); + x1 = std::max(x1, ext.x1 + xo); + y1 = std::max(y1, ext.y1 + yo); + } + + Py::Tuple result(4); + result[0] = Py::Float(x0); + result[1] = Py::Float(y0); + result[2] = Py::Float(x1); + result[3] = Py::Float(y1); + return result; +} + +Py::Object _backend_agg_module::point_in_path_collection(const Py::Tuple& args) { + args.verify_length(9); + + //segments, trans, clipbox, colors, linewidths, antialiaseds + double x = Py::Float(args[0]); + double y = Py::Float(args[1]); + double radius = Py::Float(args[2]); + agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[3]); + Py::SeqBase<Py::Object> paths = args[4]; + Py::SeqBase<Py::Object> transforms_obj = args[5]; + Py::SeqBase<Py::Object> offsets = args[6]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7], false); + Py::SeqBase<Py::Object> facecolors = args[8]; + + size_t Npaths = paths.length(); + size_t Noffsets = offsets.length(); + size_t N = std::max(Npaths, Noffsets); + size_t Ntransforms = std::min(transforms_obj.length(), N); + size_t Ncolors = facecolors.length(); + size_t i; + + // Convert all of the transforms up front + typedef std::vector<agg::trans_affine> transforms_t; + transforms_t transforms; + transforms.reserve(Ntransforms); + for (i = 0; i < Ntransforms; ++i) { + agg::trans_affine trans = py_to_agg_transformation_matrix + (transforms_obj[i], false); + trans *= master_transform; + transforms.push_back(trans); + } + + Py::List result; + + for (i = 0; i < N; ++i) { + PathIterator path(paths[i % Npaths]); + + Py::SeqBase<Py::Float> offset = Py::SeqBase<Py::Float>(offsets[i % Noffsets]); + double xo = Py::Float(offset[0]); + double yo = Py::Float(offset[1]); + offset_trans.transform(&xo, &yo); + agg::trans_affine_translation transOffset(xo, yo); + agg::trans_affine trans = transforms[i % Ntransforms] * transOffset; + + const Py::Object& facecolor_obj = facecolors[i & Ncolors]; + if (facecolor_obj.ptr() == Py_None) { + if (::point_on_path(x, y, radius, path, trans)) + result.append(Py::Int((int)i)); + } else { + if (::point_in_path(x, y, path, trans)) + result.append(Py::Int((int)i)); + } + } + + return result; +} + /* ------------ module methods ------------- */ Py::Object _backend_agg_module::new_renderer (const Py::Tuple &args, const Py::Dict &kws) @@ -1563,7 +1708,7 @@ add_varargs_method("draw_path", &RendererAgg::draw_path, "draw_path(gc, path, transform, rgbFace)\n"); add_varargs_method("draw_path_collection", &RendererAgg::draw_path_collection, - "draw_path_collection(master_transform, cliprect, clippath, clippath_trans, paths, transforms, facecolors, edgecolors, linewidths, linestyles, antialiaseds)\n"); + "draw_path_collection(master_transform, cliprect, clippath, clippath_trans, paths, transforms, offsets, offsetTrans, facecolors, edgecolors, linewidths, linestyles, antialiaseds)\n"); add_varargs_method("draw_markers", &RendererAgg::draw_markers, "draw_markers(gc, marker_path, marker_trans, path, rgbFace)\n"); add_varargs_method("draw_text_image", &RendererAgg::draw_text_image, Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-08 12:45:23 UTC (rev 3927) +++ branches/transforms/src/_backend_agg.h 2007-10-08 18:10:11 UTC (rev 3928) @@ -244,6 +244,11 @@ "point_on_path(x, y, r, path, trans)"); add_varargs_method("get_path_extents", &_backend_agg_module::get_path_extents, "get_path_extents(path, trans)"); + add_varargs_method("get_path_collection_extents", &_backend_agg_module::get_path_collection_extents, + "get_path_collection_extents(trans, paths, transforms, offsets, offsetTrans)"); + add_varargs_method("point_in_path_collection", &_backend_agg_module::point_in_path_collection, + "point_in_path_collection(x, y, r, trans, paths, transforms, offsets, offsetTrans, colors)"); + initialize( "The agg rendering backend" ); } @@ -255,6 +260,8 @@ Py::Object point_in_path(const Py::Tuple& args); Py::Object point_on_path(const Py::Tuple& args); Py::Object get_path_extents(const Py::Tuple& args); + Py::Object get_path_collection_extents(const Py::Tuple& args); + Py::Object point_in_path_collection(const Py::Tuple& args); }; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-08 18:15:08
|
Revision: 3929 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3929&view=rev Author: mdboom Date: 2007-10-08 11:15:05 -0700 (Mon, 08 Oct 2007) Log Message: ----------- Merged revisions 3925-3928 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3926 | efiring | 2007-10-05 18:11:32 -0400 (Fri, 05 Oct 2007) | 2 lines Fixed numpification bug in pcolor argument handling ........ r3927 | mdboom | 2007-10-08 08:45:23 -0400 (Mon, 08 Oct 2007) | 2 lines Save image resolution in the PNG file. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_gtkagg.py branches/transforms/src/_backend_agg.cpp Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3924 + /trunk/matplotlib:1-3928 Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-08 18:10:11 UTC (rev 3928) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-08 18:15:05 UTC (rev 3929) @@ -4390,7 +4390,30 @@ return im + def _pcolorargs(self, funcname, *args): + if len(args)==1: + C = args[0] + numRows, numCols = C.shape + X, Y = npy.meshgrid(npy.arange(numCols+1), npy.arange(numRows+1) ) + elif len(args)==3: + X, Y, C = args + else: + raise TypeError( + 'Illegal arguments to %s; see help(%s)' % (funcname, funcname)) + Nx = X.shape[-1] + Ny = Y.shape[0] + if len(X.shape) <> 2 or X.shape[0] == 1: + x = X.reshape(1,Nx) + X = x.repeat(Ny, axis=0) + if len(Y.shape) <> 2 or Y.shape[1] == 1: + y = Y.reshape(Ny, 1) + Y = y.repeat(Nx, axis=1) + if X.shape != Y.shape: + raise TypeError( + 'Incompatible X, Y inputs to %s; see help(%s)' % (funcname, funcname)) + return X, Y, C + def pcolor(self, *args, **kwargs): """ pcolor(*args, **kwargs): pseudocolor plot of a 2-D array @@ -4502,25 +4525,9 @@ vmax = kwargs.pop('vmax', None) shading = kwargs.pop('shading', 'flat') - if len(args)==1: - C = args[0] - numRows, numCols = C.shape - X, Y = npy.meshgrid(npy.arange(numCols+1), npy.arange(numRows+1) ) - elif len(args)==3: - X, Y, C = args - numRows, numCols = C.shape - else: - raise TypeError, 'Illegal arguments to pcolor; see help(pcolor)' + X, Y, C = self._pcolorargs('pcolor', *args) + Ny, Nx = X.shape - Nx = X.shape[-1] - Ny = Y.shape[0] - if len(X.shape) <> 2 or X.shape[0] == 1: - X = X.ravel().resize((Ny, Nx)) - if len(Y.shape) <> 2 or Y.shape[1] == 1: - Y = Y.ravel().resize((Nx, Ny)).T - - - # convert to MA, if necessary. C = ma.asarray(C) X = ma.asarray(X) @@ -4655,23 +4662,9 @@ shading = kwargs.pop('shading', 'flat') edgecolors = kwargs.pop('edgecolors', 'None') - if len(args)==1: - C = args[0] - numRows, numCols = C.shape - X, Y = npy.meshgrid(npy.arange(numCols+1), npy.arange(numRows+1) ) - elif len(args)==3: - X, Y, C = args - numRows, numCols = C.shape - else: - raise TypeError, 'Illegal arguments to pcolormesh; see help(pcolormesh)' + X, Y, C = self._pcolorargs('pcolormesh', *args) + Ny, Nx = X.shape - Nx = X.shape[-1] - Ny = Y.shape[0] - if len(X.shape) <> 2 or X.shape[0] == 1: - X = X.ravel().resize((Ny, Nx)) - if len(Y.shape) <> 2 or Y.shape[1] == 1: - Y = Y.ravel().resize((Nx, Ny)).T - # convert to one dimensional arrays C = ma.ravel(C[0:Ny-1, 0:Nx-1]) # data point in each cell is value at lower left corner X = X.ravel() Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-08 18:10:11 UTC (rev 3928) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-08 18:15:05 UTC (rev 3929) @@ -387,5 +387,5 @@ def print_png(self, filename, *args, **kwargs): self.draw() - self.get_renderer()._renderer.write_png(str(filename)) + self.get_renderer()._renderer.write_png(str(filename), self.figure.dpi.get()) Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-10-08 18:10:11 UTC (rev 3928) +++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-10-08 18:15:05 UTC (rev 3929) @@ -97,6 +97,8 @@ 0, 0, 0, 0, w, h) if DEBUG: print 'FigureCanvasGTKAgg.done' + def print_png(self, filename, *args, **kwargs): + return FigureCanvasAgg.print_png(self, filename, *args, **kwargs) """\ Traceback (most recent call last): Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-08 18:10:11 UTC (rev 3928) +++ branches/transforms/src/_backend_agg.cpp 2007-10-08 18:15:05 UTC (rev 3929) @@ -1072,7 +1072,7 @@ { _VERBOSE("RendererAgg::write_png"); - args.verify_length(1); + args.verify_length(1, 2); FILE *fp; Py::Object o = Py::Object(args[0]); @@ -1133,6 +1133,13 @@ width, height, 8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + // Save the dpi of the image in the file + if (args.size() == 2) { + double dpi = Py::Float(args[1]); + size_t dots_per_meter = (size_t)(dpi / (2.54 / 100.0)); + png_set_pHYs(png_ptr, info_ptr, dots_per_meter, dots_per_meter, PNG_RESOLUTION_METER); + } // this a a color image! sig_bit.gray = 0; @@ -1718,7 +1725,7 @@ add_varargs_method("write_rgba", &RendererAgg::write_rgba, "write_rgba(fname)"); add_varargs_method("write_png", &RendererAgg::write_png, - "write_png(fname)"); + "write_png(fname, dpi=None)"); add_varargs_method("tostring_rgb", &RendererAgg::tostring_rgb, "s = tostring_rgb()"); add_varargs_method("tostring_argb", &RendererAgg::tostring_argb, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-10 13:37:31
|
Revision: 3932 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3932&view=rev Author: mdboom Date: 2007-10-10 06:37:28 -0700 (Wed, 10 Oct 2007) Log Message: ----------- Lots more work on making examples work. Details, details, details... 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/cbook.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/colorbar.py branches/transforms/lib/matplotlib/dates.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.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-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -477,7 +477,11 @@ """ % {'scale': ' | '.join([repr(x) for x in mscale.get_scale_names()])} martist.Artist.__init__(self) - self._position = mtransforms.Bbox.from_lbwh(*rect) + if isinstance(rect, mtransforms.Bbox): + self._position = rect + else: + warnings.warn("Passing non-bbox as rect to Axes") + mtransforms.Bbox.from_lbwh(*rect) self._originalPosition = self._position.frozen() self.set_axes(self) self.set_aspect('auto') @@ -564,16 +568,16 @@ # It is assumed that this part will have non-linear components self.transScale = mtransforms.TransformWrapper(mtransforms.IdentityTransform()) - # A (possibly non-linear) projection on the (already scaled) data - self.transProjection = mtransforms.IdentityTransform() - # An affine transformation on the data, generally to limit the # range of the axes self.transLimits = mtransforms.BboxTransform( mtransforms.TransformedBbox(self.viewLim, self.transScale), mtransforms.Bbox.unit()) - - self.transData = self.transScale + self.transProjection + self.transLimits + self.transAxes + # The parentheses are important for efficiency here -- they + # group the last two (which are usually affines) separately + # from the first (which, with log-scaling can be non-affine). + self.transData = self.transScale + (self.transLimits + self.transAxes) + self._xaxis_transform = mtransforms.blended_transform_factory( self.axes.transData, self.axes.transAxes) self._yaxis_transform = mtransforms.blended_transform_factory( @@ -807,9 +811,9 @@ ', '.join(mtransforms.BBox.coefs.keys())) def get_data_ratio(self): - xmin,xmax = self.get_xlim() + xmin,xmax = self.get_xbound() xsize = max(math.fabs(xmax-xmin), 1e-30) - ymin,ymax = self.get_ylim() + ymin,ymax = self.get_ybound() ysize = max(math.fabs(ymax-ymin), 1e-30) return ysize/xsize @@ -819,7 +823,7 @@ axes box or the view limits. ''' #MGDTODO: Numpify - + if self._aspect == 'auto': self.set_position( self._originalPosition , 'active') return @@ -843,7 +847,6 @@ self.set_position(pb1.anchored(self._anchor, pb), 'active') return - xmin,xmax = self.get_xbound() xsize = max(math.fabs(xmax-xmin), 1e-30) ymin,ymax = self.get_ybound() @@ -1519,7 +1522,9 @@ if xmin is None: xmin = old_xmin if xmax is None: xmax = old_xmax - xmax, xmin = mtransforms.nonsingular(xmax, xmin, increasing=False) + xmin, xmax = mtransforms.nonsingular(xmin, xmax) + xmin, xmax = self.xaxis.limit_range_for_scale(xmin, xmax) + self.viewLim.intervalx = (xmin, xmax) if emit: @@ -1678,6 +1683,7 @@ if ymax is None: ymax = old_ymax ymin, ymax = mtransforms.nonsingular(ymin, ymax, increasing=False) + ymin, ymax = self.yaxis.limit_range_for_scale(ymin, ymax) self.viewLim.intervaly = (ymin, ymax) if emit: @@ -1884,10 +1890,12 @@ .transformed(p.trans_inverse) elif button == 3: try: - # MGDTODO: This is broken with log scales - dx, dy = format_deltas(key, dx, dy) dx = -dx / float(self.bbox.width) dy = -dy / float(self.bbox.height) + dx, dy = format_deltas(key, dx, dy) + if self.get_aspect() != 'auto': + dx = 0.5 * (dx + dy) + dy = dx xmin, ymin, xmax, ymax = p.lim.lbrt alpha = npy.power(10.0, (dx, dy)) @@ -2375,7 +2383,7 @@ axvspan.__doc__ = cbook.dedent(axvspan.__doc__) % martist.kwdocd - def hlines(self, y, xmin, xmax, colors='k', linestyle='solid', + def hlines(self, y, xmin, xmax, colors='k', linestyles='solid', label='', **kwargs): """ HLINES(y, xmin, xmax, colors='k', linestyle='solid', **kwargs) @@ -2417,7 +2425,7 @@ verts = [ ((thisxmin, thisy), (thisxmax, thisy)) for thisxmin, thisxmax, thisy in zip(xmin, xmax, y)] coll = mcoll.LineCollection(verts, colors=colors, - linestyle=linestyle, label=label) + linestyles=linestyles, label=label) self.add_collection(coll) coll.update(kwargs) @@ -4896,7 +4904,7 @@ self.set_xlabel('Frequency') self.set_ylabel('Cross Spectrum Magnitude (dB)') self.grid(True) - vmin, vmax = self.viewLim.intervaly().get_bounds() + vmin, vmax = self.viewLim.intervaly intv = vmax-vmin step = 10*int(npy.log10(intv)) @@ -5177,8 +5185,7 @@ self.update_params() # _axes_class is set in the subplot_class_factory - self._axes_class.__init__(self, fig, [self.figLeft, self.figBottom, - self.figW, self.figH], **kwargs) + self._axes_class.__init__(self, fig, self.figbox, **kwargs) def get_geometry(self): 'get the subplot geometry, eg 2,2,3' @@ -5190,7 +5197,7 @@ self._cols = numcols self._num = num-1 self.update_params() - self.set_position([self.figLeft, self.figBottom, self.figW, self.figH]) + self.set_position(self.figbox) def update_params(self): 'update the subplot position from fig.subplotpars' @@ -5220,10 +5227,7 @@ figBottom = top - (rowNum+1)*figH - rowNum*sepH figLeft = left + colNum*(figW + sepW) - self.figBottom = figBottom - self.figLeft = figLeft - self.figW = figW - self.figH = figH + self.figbox = mtransforms.Bbox.from_lbwh(figLeft, figBottom, figW, figH) self.rowNum = rowNum self.colNum = colNum self.numRows = rows Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -524,7 +524,10 @@ def set_scale(self, value, **kwargs): self._scale = scale_factory(value, self, **kwargs) self._scale.set_default_locators_and_formatters(self) - + + def limit_range_for_scale(self, vmin, vmax): + return self._scale.limit_range_for_scale(vmin, vmax, self.get_minpos()) + def get_children(self): children = [self.label] majorticks = self.get_major_ticks() @@ -580,6 +583,10 @@ 'return the Interval instance for this axis data limits' raise NotImplementedError('Derived must override') + def set_data_interval(self): + 'Set the axis data limits' + raise NotImplementedError('Derived must override') + def _set_artist_props(self, a): if a is None: return a.set_figure(self.figure) @@ -887,7 +894,7 @@ ACCEPTS: A Formatter instance """ self.major.formatter = formatter - self.major.formatter.set_axis(self) + formatter.set_axis(self) def set_minor_formatter(self, formatter): @@ -897,7 +904,7 @@ ACCEPTS: A Formatter instance """ self.minor.formatter = formatter - self.minor.formatter.set_axis(self) + formatter.set_axis(self) def set_major_locator(self, locator): @@ -907,7 +914,7 @@ ACCEPTS: a Locator instance """ self.major.locator = locator - self.major.locator.set_axis(self) + locator.set_axis(self) def set_minor_locator(self, locator): @@ -917,7 +924,7 @@ ACCEPTS: a Locator instance """ self.minor.locator = locator - self.minor.locator.set_axis(self) + locator.set_axis(self) def set_pickradius(self, pickradius): """ @@ -1180,7 +1187,15 @@ 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervalx + def set_data_interval(self, vmin, vmax, ignore=False): + 'return the Interval instance for this axis data limits' + if ignore: + self.axes.dataLim.intervalx = vmin, vmax + else: + Vmin, Vmax = self.get_data_interval() + self.axes.dataLim.intervalx = min(vmin, Vmin), max(vmax, Vmax) + class YAxis(Axis): __name__ = 'yaxis' axis_name = 'y' @@ -1395,5 +1410,12 @@ 'return the Interval instance for this axis data limits' return self.axes.dataLim.intervaly + def set_data_interval(self, vmin, vmax, ignore=False): + 'return the Interval instance for this axis data limits' + if ignore: + self.axes.dataLim.intervaly = vmin, vmax + else: + Vmin, Vmax = self.get_data_interval() + self.axes.dataLim.intervaly = min(vmin, Vmin), max(vmax, Vmax) Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -1598,7 +1598,7 @@ for a, ind in self._xypress: a.end_pan() if not self._xypress: return - self._xypress = None + self._xypress = [] self._button_pressed=None self.push_current() self.release(event) Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -381,11 +381,11 @@ return 'png' def print_raw(self, filename, *args, **kwargs): - self.draw() + FigureCanvasAgg.draw(self) self.get_renderer()._renderer.write_rgba(str(filename)) print_rgba = print_raw def print_png(self, filename, *args, **kwargs): - self.draw() - self.get_renderer()._renderer.write_png(str(filename), self.figure.dpi.get()) + FigureCanvasAgg.draw(self) + self.get_renderer()._renderer.write_png(str(filename), self.figure.dpi) Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -1051,7 +1051,6 @@ a1 = a[1: ] delta = ((a1 - a0) / steps) - # MGDTODO: Could use linspace here? for i in range(1, int(steps)): result[i::steps] = delta * i + a0 result[steps::steps] = a1 Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -59,12 +59,6 @@ _offsets = npy.zeros((1, 2)) _transOffset = transforms.IdentityTransform() - _facecolors = [None] - _edgecolors = [None] - _lw = [1.0] - _ls = [None] - _aa = [True] - _pickradius = 5.0 _transforms = [None] zorder = 1 @@ -107,9 +101,8 @@ self._uniform_offsets = None self._offsets = npy.zeros((1, 2)) if offsets is not None: - offsets = npy.asarray(offsets) - if len(offsets.shape) == 1: - offsets = offsets[npy.newaxis,:] # Make it Nx2. +# if len(offsets.shape) == 1: +# offsets = offsets[npy.newaxis,:] # Make it Nx2. if transOffset is not None: Affine2D = transforms.Affine2D self._offsets = offsets @@ -152,29 +145,37 @@ transform = self.get_transform() transOffset = self._transOffset offsets = self._offsets + paths = self.get_paths() - # MGDTODO: Transform the paths (since we don't keep track of segments anymore + # MGDTODO: Test me if self.have_units(): - segments = [] - for segment in self._segments: + paths = [] + for path in self._paths: + vertices = path.vertices xs, ys = zip(*segment) xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) - segments.append(zip(xs, ys)) -# if self._offsets is not None: -# xs = self.convert_xunits(self._offsets[:0]) -# ys = self.convert_yunits(self._offsets[:1]) -# offsets = zip(xs, ys) + paths.append(path.Path(zip(xs, ys), path.codes)) + if self._offsets is not None: + xs = self.convert_xunits(self._offsets[:0]) + ys = self.convert_yunits(self._offsets[:1]) + offsets = zip(xs, ys) self.update_scalarmappable() #print 'calling renderer draw line collection' clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + if not transform.is_affine: + paths = [transform.transform_path_non_affine(path) for path in paths] + transform = transform.get_affine() + renderer.draw_path_collection( transform, self.clipbox, clippath, clippath_trans, - self.get_paths(), self.get_transforms(), offsets, transOffset, - self._facecolors, self._edgecolors, self._lw, self._ls, self._aa) + paths, self.get_transforms(), + npy.asarray(offsets, npy.float_), transOffset, + self._facecolors, self._edgecolors, self._linewidths, + self._linestyles, self._antialiaseds) renderer.close_group(self.__class__.__name__) def contains(self, mouseevent): @@ -190,7 +191,7 @@ self._offsetTrans, self._facecolors) return len(ind)>0,dict(ind=ind) - # MGDTODO + # MGDTODO: Update def get_transformed_patches(self): """ get a sequence of the polygons in the collection in display (transformed) space @@ -272,7 +273,7 @@ except ValueError: raise ValueError('Do not know how to convert %s to dashes'%ls) - self._ls = dashes + self._linestyles = dashes def set_color(self, c): """ @@ -328,13 +329,13 @@ self._edgecolors = [(r,g,b,alpha) for r,g,b,a in self._edgecolors] def get_linewidth(self): - return self._lw - + return self._linewidths + def get_linestyle(self): - return self._ls + return self._linestyles def get_dashes(self): - return self._ls + return self._linestyles def update_scalarmappable(self): """ @@ -509,14 +510,20 @@ self._sizes = sizes self._dpi = dpi self._paths = [path.Path.unit_regular_polygon(numsides)] - self._transforms = [transforms.Affine2D().scale(x) for x in sizes] + # sizes is the area of the circle circumscribing the polygon + # in points^2 + self._transforms = [ + transforms.Affine2D().rotate(rotation).scale( + (math.sqrt(x) * self._dpi / 72.0) * (1.0 / math.sqrt(math.pi))) + for x in sizes] + self.set_transform(transforms.IdentityTransform()) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_paths(self): return self._paths - # MGDTODO + # MGDTODO: Update def get_transformed_patches(self): # Shouldn't need all these calls to asarray; # the variables should be converted when stored. Modified: branches/transforms/lib/matplotlib/colorbar.py =================================================================== --- branches/transforms/lib/matplotlib/colorbar.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/colorbar.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -317,12 +317,13 @@ intv = transforms.Interval(transforms.Value(self._values[0]), transforms.Value(self._values[-1])) else: - intv = transforms.Interval(transforms.Value(self.vmin), - transforms.Value(self.vmax)) - locator.set_view_interval(intv) - locator.set_data_interval(intv) - formatter.set_view_interval(intv) - formatter.set_data_interval(intv) + intv = self.vmin, self.vmax + locator.create_dummy_axis() + locator.set_view_interval(*intv) + locator.set_data_interval(*intv) + formatter.create_dummy_axis() + formatter.set_view_interval(*intv) + formatter.set_data_interval(*intv) b = npy.array(locator()) b, ticks = self._locate(b) formatter.set_locs(b) Modified: branches/transforms/lib/matplotlib/dates.py =================================================================== --- branches/transforms/lib/matplotlib/dates.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/dates.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -429,13 +429,11 @@ self.tz = tz def datalim_to_dt(self): - self.verify_intervals() - dmin, dmax = self.dataInterval.get_bounds() + dmin, dmax = self.axis.get_data_interval() return num2date(dmin, self.tz), num2date(dmax, self.tz) def viewlim_to_dt(self): - self.verify_intervals() - vmin, vmax = self.viewInterval.get_bounds() + vmin, vmax = self.axis.get_view_interval() return num2date(vmin, self.tz), num2date(vmax, self.tz) def _get_unit(self): @@ -459,8 +457,6 @@ self.rule = o def __call__(self): - self.verify_intervals() - # if no data have been set, this will tank with a ValueError try: dmin, dmax = self.viewlim_to_dt() except ValueError: return [] @@ -500,7 +496,6 @@ """ Set the view limits to include the data range """ - self.verify_intervals() dmin, dmax = self.datalim_to_dt() if dmin>dmax: dmax, dmin = dmin, dmax @@ -537,6 +532,10 @@ self.refresh() return self._locator() + def set_axis(self, axis): + DateLocator.set_axis(self, axis) + self._locator.set_axis(axis) + def refresh(self): 'refresh internal information based on current lim' dmin, dmax = self.viewlim_to_dt() @@ -563,8 +562,6 @@ def autoscale(self): 'Try to choose the view limits intelligently' - - self.verify_intervals() dmin, dmax = self.datalim_to_dt() self._locator = self.get_locator(dmin, dmax) return self._locator.autoscale() @@ -667,9 +664,10 @@ bysecond=bysecond ) locator = RRuleLocator(rrule, self.tz) - - locator.set_view_interval(self.viewInterval) - locator.set_data_interval(self.dataInterval) + locator.set_axis(self.axis) + + locator.set_view_interval(*self.axis.get_view_interval()) + locator.set_data_interval(*self.axis.get_data_interval()) return locator @@ -710,8 +708,6 @@ return 365 def __call__(self): - self.verify_intervals() - dmin, dmax = self.viewlim_to_dt() ymin = self.base.le(dmin.year) ymax = self.base.ge(dmax.year) @@ -728,7 +724,6 @@ """ Set the view limits to include the data range """ - self.verify_intervals() dmin, dmax = self.datalim_to_dt() ymin = self.base.le(dmin.year) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -818,17 +818,17 @@ self.subplotpars.update(*args, **kwargs) import matplotlib.axes for ax in self.axes: - if not isinstance(ax, matplotlib.axes.Subplot): + if not isinstance(ax, matplotlib.axes.SubplotBase): # Check if sharing a subplots axis - if ax._sharex is not None and isinstance(ax._sharex, matplotlib.axes.Subplot): + if ax._sharex is not None and isinstance(ax._sharex, matplotlib.axes.SubplotBase): ax._sharex.update_params() - ax.set_position([ax._sharex.figLeft, ax._sharex.figBottom, ax._sharex.figW, ax._sharex.figH]) - elif ax._sharey is not None and isinstance(ax._sharey, matplotlib.axes.Subplot): + ax.set_position(ax._sharex.figbox) + elif ax._sharey is not None and isinstance(ax._sharey, matplotlib.axes.SubplotBase): ax._sharey.update_params() - ax.set_position([ax._sharey.figLeft, ax._sharey.figBottom, ax._sharey.figW, ax._sharey.figH]) + ax.set_position(ax._sharey.figbox) else: ax.update_params() - ax.set_position([ax.figLeft, ax.figBottom, ax.figW, ax.figH]) + ax.set_position(ax.figbox) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -300,18 +300,19 @@ raise ValueError,"pick radius should be a distance" # transform in backend - x = self._x - y = self._y - if len(x)==0: return False,{} + if len(self._xy)==0: return False,{} - xt, yt = self.get_transform().numerix_x_y(x, y) - + xyt = self.get_transform().transform(self._xy) + xt = xyt[:, 0] + yt = xyt[:, 1] + if self.figure == None: print str(self),' has no figure set' pixels = self.pickradius else: - pixels = self.figure.dpi.get()/72. * self.pickradius - + pixels = self.figure.dpi/72. * self.pickradius + + path, transform = self._transformed_path.get_transformed_path_and_affine() if self._linestyle == 'None': # If no line, return the nearby point(s) d = npy.sqrt((xt-mouseevent.x)**2 + (yt-mouseevent.y)**2) @@ -384,11 +385,17 @@ def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units - x = ma.asarray(self.convert_xunits(self._xorig), float) - y = ma.asarray(self.convert_yunits(self._yorig), float) - - x = ma.ravel(x) - y = ma.ravel(y) + if ma.isMaskedArray(self._xorig) or ma.isMaskedArray(self._yorig): + x = ma.asarray(self.convert_xunits(self._xorig), float) + y = ma.asarray(self.convert_yunits(self._yorig), float) + x = ma.ravel(x) + y = ma.ravel(y) + else: + x = npy.asarray(self.convert_xunits(self._xorig), float) + y = npy.asarray(self.convert_yunits(self._yorig), float) + x = npy.ravel(x) + y = npy.ravel(y) + if len(x)==1 and len(y)>1: x = x * npy.ones(y.shape, float) if len(y)==1 and len(x)>1: @@ -399,8 +406,11 @@ x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) - - self._xy = ma.concatenate((x, y), 1) + + if ma.isMaskedArray(x) or ma.isMaskedArray(y): + self._xy = ma.concatenate((x, y), 1) + else: + self._xy = npy.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view self._logcache = None Modified: branches/transforms/lib/matplotlib/scale.py =================================================================== --- branches/transforms/lib/matplotlib/scale.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/scale.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -14,7 +14,10 @@ class ScaleBase(object): def set_default_locators_and_formatters(self, axis): raise NotImplementedError - + + def limit_range_for_scale(self, vmin, vmax, minpos): + return vmin, vmax + class LinearScale(ScaleBase): name = 'linear' @@ -39,6 +42,9 @@ is_separable = True def transform(self, a): + # MGDTODO: Remove me + if len(a) > 10: + print "log transforming" return ma.log10(ma.masked_where(a <= 0.0, a * 10.0)) def inverted(self): @@ -159,6 +165,9 @@ def get_transform(self): return self._transform + def limit_range_for_scale(self, vmin, vmax, minpos): + return (vmin <= 0.0 and minpos or vmin, + vmax <= 0.0 and minpos or vmax) _scale_mapping = { 'linear' : LinearScale, Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/text.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -179,14 +179,17 @@ key = self.get_prop_tup() if self.cached.has_key(key): return self.cached[key] horizLayout = [] - thisx, thisy = self._get_xy_display() + transform = self.get_transform() + x, y = self.get_position() + thisx, thisy = transform.transform_point((x, y)) + tx, ty = thisx, thisy + width = 0 height = 0 xmin, ymin = thisx, thisy lines = self._text.split('\n') - # MGDTODO: whs could be a numpy.array whs = [] # Find full vertical extent of font, # including ascenders and descenders: @@ -267,11 +270,10 @@ # now rotate the positions around the first x,y position xys = M.transform(offsetLayout) - xys[:, 0] += offsetx - xys[:, 1] += offsety + xys += (offsetx, offsety) # now inverse transform back to data coords - inverse_transform = self.get_transform().inverted() + inverse_transform = transform.inverted() xys = inverse_transform.transform(xys) xs, ys = xys[:, 0], xys[:, 1] @@ -781,13 +783,14 @@ # Compute the dash end points # The 'c' prefix is for canvas coordinates - cxy = npy.array(transform.xy_tup((dashx, dashy))) + cxy = transform.transform_point((dashx, dashy)) cd = npy.array([cos_theta, sin_theta]) c1 = cxy+dashpush*cd c2 = cxy+(dashpush+dashlength)*cd - (x1, y1) = transform.inverse_xy_tup(tuple(c1)) - (x2, y2) = transform.inverse_xy_tup(tuple(c2)) + inverse = transform.inverted() + (x1, y1) = inverse.transform_point(tuple(c1)) + (x2, y2) = inverse.transform_point(tuple(c2)) self.dashline.set_data((x1, x2), (y1, y2)) # We now need to extend this vector out to @@ -805,7 +808,7 @@ # but I don't grok the transformation stuff # well enough yet. we = Text.get_window_extent(self, renderer=renderer) - w, h = we.width(), we.height() + w, h = we.width, we.height # Watch for zeros if sin_theta == 0.0: dx = w @@ -824,13 +827,13 @@ cwd *= 1+dashpad/npy.sqrt(npy.dot(cwd,cwd)) cw = c2+(dashdirection*2-1)*cwd - self._x, self._y = transform.inverse_xy_tup(tuple(cw)) + self._x, self._y = inverse.transform_point(tuple(cw)) # Now set the window extent # I'm not at all sure this is the right way to do this. we = Text.get_window_extent(self, renderer=renderer) - self._twd_window_extent = we.deepcopy() - self._twd_window_extent.update(((c1[0], c1[1]),), False) + self._twd_window_extent = we.frozen() + self._twd_window_extent.update_from_data_xy(npy.array([c1]), False) # Finally, make text align center Text.set_horizontalalignment(self, 'center') Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/ticker.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -116,10 +116,35 @@ class TickHelper: axis = None + class DummyAxis: + def __init__(self): + self.dataLim = mtransforms.Bbox + self.viewLim = mtransforms.Bbox + + def get_view_interval(self): + return self.viewLim.intervalx + + def set_view_interval(self, vmin, vmax): + self.viewLim.intervalx = vmin, vmax + + def get_data_interval(self): + return self.dataLim.intervalx + + def set_data_interval(self, vmin, vmax): + self.dataLim.intervalx = vmin, vmax + def set_axis(self, axis): self.axis = axis + def create_dummy_axis(self): + self.axis = self.DummyAxis() + + def set_view_interval(self, vmin, vmax): + self.axis.set_view_interval(vmin, vmax) + def set_data_interval(self, vmin, vmax): + self.axis.set_data_interval(vmin, vmax) + class Formatter(TickHelper): """ Convert the tick location to a string @@ -900,6 +925,9 @@ vmin, vmax = self.axis.get_view_interval() if vmin <= 0.0: vmin = self.axis.get_minpos() + if vmin <= 0.0: + raise ValueError( + "Data has no positive values, and therefore can not be log-scaled.") vmin = math.log(vmin)/math.log(b) vmax = math.log(vmax)/math.log(b) @@ -936,7 +964,8 @@ minpos = self.axis.get_minpos() if minpos<=0: - raise RuntimeError('No positive data to plot') + raise ValueError( + "Data has no positive values, and therefore can not be log-scaled.") if vmin <= minpos: vmin = minpos Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-10 13:37:28 UTC (rev 3932) @@ -32,7 +32,7 @@ import cbook from path import Path -DEBUG = False +DEBUG = True class TransformNode(object): """ @@ -403,7 +403,6 @@ if len(x) == 0 or len(y) == 0: return - # MGDTODO: All getters of minpos should be aware that is is sometimes -inf if ma.isMaskedArray(x) or ma.isMaskedArray(y): xpos = ma.where(x > 0.0, x, npy.inf) ypos = ma.where(y > 0.0, y, npy.inf) @@ -616,26 +615,28 @@ #@staticmethod def union(bboxes): """ - Return a Bbox that bounds all the given bboxes. + Return a Bbox that contains all of the given bboxes. """ - # MGDTODO: There's got to be a way to utilize numpy here - # to make this faster... assert(len(bboxes)) if len(bboxes) == 1: return bboxes[0] - - bbox = bboxes[0] - xmin0, ymin0, xmax0, ymax0 = bbox.lbrt - for bbox in bboxes[1:]: - xmin, ymin, xmax, ymax = bbox.lbrt - xmin0 = min(xmin0, xmin) - ymin0 = min(ymin0, ymin) - xmax0 = max(xmax0, xmax) - ymax0 = max(ymax0, ymax) + xmin = npy.inf + ymin = npy.inf + xmax = -npy.inf + ymax = -npy.inf - return Bbox.from_lbrt(xmin0, ymin0, xmax0, ymax0) + for bbox in bboxes: + points = bbox.get_points() + xs = points[:, 0] + ys = points[:, 1] + xmin = min(xmin, npy.min(xs)) + ymin = min(ymin, npy.min(ys)) + xmax = max(xmax, npy.max(xs)) + ymax = max(ymax, npy.max(ys)) + + return Bbox.from_lbrt(xmin, ymin, xmax, ymax) union = staticmethod(union) @@ -1243,22 +1244,18 @@ # 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 DEBUG and not isinstance(values, npy.ndarray): + if DEBUG and not ma.isMaskedArray(points) and not isinstance(points, npy.ndarray): import traceback print '-' * 60 - print 'A non-numpy array of type %s was passed in for transformation.' % type(values) + print 'A non-numpy array of type %s was passed in for transformation.' % type(points) print 'Please correct this.' print "".join(traceback.format_stack()) mtx = self.get_matrix() if ma.isMaskedArray(points): - points = points.transpose() - points = ma.dot(mtx[0:2, 0:2], points) - points = points + mtx[0:2, 2:] + points = ma.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:] else: - points = npy.asarray(points, npy.float_) - points = points.transpose() - points = npy.dot(mtx[0:2, 0:2], points) - points = points + mtx[0:2, 2:] + # points = npy.asarray(points, npy.float_) + points = npy.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:] return points.transpose() transform.__doc__ = AffineBase.transform.__doc__ @@ -1558,7 +1555,10 @@ y_points = y.transform(points[:, 1]) y_points = y_points.reshape((len(y_points), 1)) - return ma.concatenate((x_points, y_points), 1) + if ma.isMaskedArray(x_points) or ma.isMaskedArray(y_points): + return ma.concatenate((x_points, y_points), 1) + else: + return npy.concatenate((x_points, y_points), 1) transform.__doc__ = Transform.transform.__doc__ transform_non_affine = transform @@ -1741,14 +1741,6 @@ return "CompositeGenericTransform(%s, %s)" % (self._a, self._b) __str__ = __repr__ - # MGDTODO: Remove -# def get_matrix(self): -# if self._invalid: -# assert self._a.is_affine and self._b.is_affine -# self._mtx = npy.dot(self._b.get_matrix(), self._a.get_matrix()) -# self._invalid = 0 -# return self._mtx - def transform(self, points): return self._b.transform( self._a.transform(points)) @@ -1927,18 +1919,18 @@ the transform already applied, along with the affine part of the path necessary to complete the transformation. """ - if (self._invalid != self.INVALID_AFFINE or + if (self._invalid & self.INVALID_NON_AFFINE or self._transformed_path is None): self._transformed_path = \ self._transform.transform_path_non_affine(self._path) - self._invalid = 0 + self._invalid = 0 return self._transformed_path, self._transform.get_affine() def get_fully_transformed_path(self): """ Return a fully-transformed copy of the child path. """ - if (self._invalid != self.INVALID_AFFINE + if (self._invalid & self.INVALID_NON_AFFINE or self._transformed_path is None): self._transformed_path = \ self._transform.transform_path_non_affine(self._path) Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-09 15:58:36 UTC (rev 3931) +++ branches/transforms/src/_backend_agg.cpp 2007-10-10 13:37:28 UTC (rev 3932) @@ -527,10 +527,8 @@ RendererAgg::draw_markers(const Py::Tuple& args) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef conv_quantize<transformed_path_t> quantize_t; - typedef agg::conv_curve<transformed_path_t> curve_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; 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; @@ -836,16 +834,30 @@ // Render face 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(face.second); - agg::render_scanlines(*theRasterizer, *slineP8, ren); + 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(face.second); + agg::render_scanlines(*theRasterizer, *slineP8, ren); + } else { + rendererAA->color(face.second); + theRasterizer->add_path(curve); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + } } else { - rendererAA->color(face.second); - theRasterizer->add_path(curve); - agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); + if (has_clippath) { + pixfmt_amask_type pfa(*pixFmt, *alphaMask); + amask_ren_type r(pfa); + amask_bin_renderer_type ren(r); + ren.color(face.second); + agg::render_scanlines(*theRasterizer, *slineP8, ren); + } else { + rendererBin->color(face.second); + theRasterizer->add_path(curve); + agg::render_scanlines(*theRasterizer, *slineP8, *rendererBin); + } } } @@ -959,7 +971,7 @@ size_t Naa = antialiaseds.length(); size_t i = 0; - + // Convert all of the transforms up front typedef std::vector<agg::trans_affine> transforms_t; transforms_t transforms; @@ -1028,6 +1040,8 @@ bool has_clippath = render_clippath(clippath, clippath_trans); for (i = 0; i < N; ++i) { + PathIterator path(paths[i % Npaths]); + bool snap = (path.total_vertices() == 2); double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); offset_trans.transform(&xo, &yo); @@ -1039,8 +1053,6 @@ gc.dashes = dashes[i % Nlinestyles].second; gc.dashOffset = dashes[i % Nlinestyles].first; gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - PathIterator path(paths[i % Npaths]); - bool snap = (path.total_vertices() == 2); _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-10 13:38:38
|
Revision: 3933 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3933&view=rev Author: mdboom Date: 2007-10-10 06:38:32 -0700 (Wed, 10 Oct 2007) Log Message: ----------- Merged revisions 3929-3932 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3930 | mdboom | 2007-10-09 11:58:09 -0400 (Tue, 09 Oct 2007) | 2 lines Fix bug saving PNG files in GtkAgg backend. ........ r3931 | mdboom | 2007-10-09 11:58:36 -0400 (Tue, 09 Oct 2007) | 3 lines Raw files should be saved (optionally) with rgba extension, which is what ImageMagick understands. ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_gtkagg.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3928 + /trunk/matplotlib:1-3932 Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-10 13:37:28 UTC (rev 3932) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-10 13:38:32 UTC (rev 3933) @@ -1083,7 +1083,7 @@ 'png': 'Portable Network Graphics', 'ps' : 'Postscript', 'raw': 'Raw RGBA bitmap', - 'rgb': 'Raw RGBA bitmap', + 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics' } Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-10-10 13:37:28 UTC (rev 3932) +++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-10-10 13:38:32 UTC (rev 3933) @@ -98,7 +98,9 @@ if DEBUG: print 'FigureCanvasGTKAgg.done' def print_png(self, filename, *args, **kwargs): - return FigureCanvasAgg.print_png(self, filename, *args, **kwargs) + # Do this so we can save the resolution of figure in the PNG file + agg = self.switch_backends(FigureCanvasAgg) + return agg.print_png(filename, *args, **kwargs) """\ Traceback (most recent call last): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-11 15:42:55
|
Revision: 3934 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3934&view=rev Author: mdboom Date: 2007-10-11 08:42:53 -0700 (Thu, 11 Oct 2007) Log Message: ----------- Continued progress getting more examples to work. Working examples (with TkAgg backend only) are marked in PASSED_DEMOS for the curious. Modified Paths: -------------- branches/transforms/examples/histogram_demo_canvasagg.py branches/transforms/examples/line_collection2.py branches/transforms/examples/pick_event_demo.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/colorbar.py branches/transforms/lib/matplotlib/colors.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/image.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/mathtext.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h Added Paths: ----------- branches/transforms/PASSED_DEMOS Added: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS (rev 0) +++ branches/transforms/PASSED_DEMOS 2007-10-11 15:42:53 UTC (rev 3934) @@ -0,0 +1,210 @@ +accented_text.py O +agg_buffer_to_array.py O +agg_oo.py O +agg_resize.py [BROKEN IN TRUNK] +agg_test.py +alignment_test.py O +animation_blit_fltk.py +animation_blit.py +animation_blit_qt4.py +animation_blit_qt.py +animation_blit_tk.py +animation_blit_wx.py +anim.py O [BUT SLOWER] +annotation_demo.py O +anscombe.py O +arctest.py O +arrow_demo.py O +axes_demo.py O +axes_props.py [SOMETHING FUNNY ABOUT DASHED LINES] +axhspan_demo.py O +axis_equal_demo.py O +backend_driver.py +barchart_demo.py O +barcode_demo.py O +barh_demo.py [BROKEN IN TRUNK] +bar_stacked.py O +boxplot_demo.py O +break.py O +broken_barh.py O +clippath_test.py O +clippedline.py O +collections_demo.py -- [NEEDS ADDITIONAL WORK] +colorbar_only.py O +color_by_yvalue.py O +color_demo.py O +colours.py [???] +contour_demo.py +contourf_demo.py +contour_image.py +coords_demo.py O +coords_report.py O +csd_demo.py O +cursor_demo.py O +custom_figure_class.py [EXCEPT FOR PS OUTPUT] +customize_rc.py +custom_ticker1.py O +dannys_example.py [REQUIRES NUMERIC] +dash_control.py O +dashpointlabel.py O +dashtick.py +data_browser.py O +data_helper.py [N/A] +date_demo1.py O +date_demo2.py O +date_demo_convert.py O [PASSES] +date_demo_rrule.py O [PASSES] +date_index_formatter.py O [PASSES] +dynamic_collection.py O +dynamic_demo.py [GTK] +dynamic_demo_wx.py [WX] +dynamic_image_gtkagg.py +dynamic_image_wxagg2.py +dynamic_image_wxagg.py +ellipse_demo.py O +ellipse_rotated.py O +embedding_in_gtk2.py +embedding_in_gtk3.py +embedding_in_gtk.py +embedding_in_qt4.py +embedding_in_qt.py +embedding_in_tk2.py +embedding_in_tk.py +embedding_in_wx2.py +embedding_in_wx3.py +embedding_in_wx4.py +embedding_in_wx.py +errorbar_demo.py O +errorbar_limits.py O +figimage_demo.py O +figlegend_demo.py [HORRIBLY BROKEN] +figtext.py O +fill_between_posneg.py O +fill_between.py O +fill_demo2.py O +fill_demo.py O +fill_spiral.py O +finance_demo.py O +font_indexing.py O +fonts_demo_kw.py O +fonts_demo.py O +font_table_ttf.py [N/A] +ftface_props.py [N/A] +ganged_plots.py O +glyph_to_path.py [Requires PIL] +gradient_bar.py O +gtk_spreadsheet.py +hatch_demo.py [Requires PS] +histogram_demo_canvasagg.py [???] +histogram_demo.py O +image_demo2.py O +image_demo3.py [Requires PIL] +image_demo.py O +image_interp.py O +image_masked.py O [Whew!] +image_origin.py O +image_slices_viewer.py [BROKEN ON TRUNK] +__init__.py +integral_demo.py O +interactive2.py [N/A] +interactive.py [N/A] +interp_demo.py O +invert_axes.py O +keypress_demo.py [BROKEN IN TRUNK] +lasso_demo.py O +layer_images.py O +legend_auto.py [WEIRD z-order problem in figure 10] +legend_demo2.py O +legend_demo.py O +legend_scatter.py O +line_collection2.py O +line_collection.py O +lineprops_dialog_gtk.py +line_styles.py O +load_converter.py O +loadrec.py O +log_bar.py O +log_demo.py O +logo.py O +log_test.py O +major_minor_demo1.py O +major_minor_demo2.py O +masked_demo.py O +mathtext_demo.py O +mathtext_examples.py O +mathtext_wx.py +matplotlib_icon.py [N/A] +matshow.py O +movie_demo.py O +mpl_with_glade.py [N/A] +mri_demo.py O +mri_with_eeg.py +multi_image.py O +multiline.py O +multiple_figs_demo.py O +newscalarformatter_demo.py O +pcolor_demo2.py O +pcolor_demo.py O +pcolor_log.py O +pcolor_nonuniform.py O +pcolor_small.py O +pick_event_demo2.py +pick_event_demo.py +pie_demo.py +plotfile_demo.py +polar_bar.py +polar_demo.py +polar_legend.py +polar_scatter.py +poly_editor.py +poormans_contour.py +printing_in_wx.py +print_stdout.py +psd_demo.py +pstest.py +pylab_with_gtk.py +pythonic_matplotlib.py +quadmesh_demo.py +quiver_demo.py +rc_traits.py +scatter_custom_symbol.py +scatter_demo2.py +scatter_demo.py +scatter_masked.py +scatter_profile.py +scatter_star_poly.py +set_and_get.py +shared_axis_across_figures.py +shared_axis_demo.py +simple3d_oo.py +simple3d.py +simple_plot_fps.py +simple_plot.py +specgram_demo.py +spy_demos.py +stem_plot.py +step_demo.py +stock_demo.py +strip_chart_demo.py +subplot_demo.py +subplots_adjust.py +subplot_toolbar.py +system_monitor.py +table_demo.py +tex_demo.py +text_handles.py +text_rotation.py +text_themes.py +tex_unicode_demo.py +toggle_images.py +to_numeric.py +transoffset.py +two_scales.py +unicode_demo.py +vertical_ticklabels.py +vline_demo.py +webapp_demo.py +wxcursor_demo.py +xcorr_demo.py +zoom_window.py +zorder_demo.py Modified: branches/transforms/examples/histogram_demo_canvasagg.py =================================================================== --- branches/transforms/examples/histogram_demo_canvasagg.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/examples/histogram_demo_canvasagg.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -11,7 +11,6 @@ """ from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.figure import Figure -from matplotlib.axes import Subplot from matplotlib.mlab import normpdf from numpy.random import randn import numpy @@ -45,7 +44,7 @@ # get the figure dimensions for creating bitmaps or numpy arrays, # etc. -l,b,w,h = fig.bbox.get_bounds() +l,b,w,h = fig.bbox.bounds w, h = int(w), int(h) if 0: Modified: branches/transforms/examples/line_collection2.py =================================================================== --- branches/transforms/examples/line_collection2.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/examples/line_collection2.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -23,7 +23,7 @@ # See matplotlib.collections.LineCollection for more information line_segments = LineCollection([zip(x,y) for y in ys], # Make a sequence of x,y pairs linewidths = (0.5,1,1.5,2), - linestyle = 'solid') + linestyles = 'solid') line_segments.set_array(x) ax.add_collection(line_segments) fig = gcf() Modified: branches/transforms/examples/pick_event_demo.py =================================================================== --- branches/transforms/examples/pick_event_demo.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/examples/pick_event_demo.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -93,7 +93,7 @@ print 'onpick1 line:', zip(nx.take(xdata, ind), nx.take(ydata, ind)) elif isinstance(event.artist, Rectangle): patch = event.artist - print 'onpick1 patch:', patch.get_verts() + print 'onpick1 patch:', patch.get_path() elif isinstance(event.artist, Text): text = event.artist print 'onpick1 text:', text.get_text() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -480,8 +480,7 @@ if isinstance(rect, mtransforms.Bbox): self._position = rect else: - warnings.warn("Passing non-bbox as rect to Axes") - mtransforms.Bbox.from_lbwh(*rect) + self._position = mtransforms.Bbox.from_lbwh(*rect) self._originalPosition = self._position.frozen() self.set_axes(self) self.set_aspect('auto') @@ -596,7 +595,7 @@ def get_xaxis_text2_transform(self, pad_pixels): return (self._xaxis_transform + mtransforms.Affine2D().translate(0, pad_pixels), - "top", "center") + "bottom", "center") def get_yaxis_transform(self): return self._yaxis_transform @@ -609,7 +608,7 @@ def get_yaxis_text2_transform(self, pad_pixels): return (self._yaxis_transform + mtransforms.Affine2D().translate(pad_pixels, 0), - "center", "right") + "center", "left") def _update_transScale(self): self.transScale.set( @@ -643,8 +642,8 @@ self._position.set(pos) if which in ('both', 'original'): self._originalPosition.set(pos) + - def _set_artist_props(self, a): 'set the boilerplate props for artists added to axes' a.set_figure(self.figure) @@ -1083,7 +1082,8 @@ def _update_patch_limits(self, p): 'update the datalimits for patch p' xys = self._get_verts_in_data_coords( - p.get_transform(), p.get_path().vertices) + p.get_data_transform(), + p.get_patch_transform().transform(p.get_path().vertices)) self.update_datalim(xys) @@ -1240,11 +1240,11 @@ for im in self.images if im.get_visible()] - im = mimage.from_images(self.bbox.height()*mag, - self.bbox.width()*mag, + im = mimage.from_images(self.bbox.height*mag, + self.bbox.width*mag, ims) im.is_grayscale = False - l, b, w, h = self.bbox.get_bounds() + l, b, w, h = self.bbox.bounds # composite images need special args so they will not # respect z-order for now renderer.draw_image(l, b, im, self.bbox) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -1290,14 +1290,13 @@ else: if not len(bboxes2): - right = self.axes.bbox.xmax() + right = self.axes.bbox.xmax else: + bbox = Bbox.union(bboxes2) + right = bbox.xmax - bbox = bbox_union(bboxes2) - right = bbox.xmax() + self.label.set_position( (right+self.LABELPAD*self.figure.dpi/72.0, y)) - self.label.set_position( (right+self.LABELPAD*self.figure.dpi.get()/72.0, y)) - def _update_offset_text_position(self, bboxes, bboxes2): """ Update the offset_text position based on the sequence of bounding Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -23,6 +23,9 @@ from matplotlib.backends._backend_agg import get_path_collection_extents, \ point_in_path_collection +# MGDTODO: Treat facecolors and edgecolors as numpy arrays always +# and then update draw_path_collection to use the array interface + class Collection(artist.Artist, cm.ScalarMappable): """ Base class for Collections. Must be subclassed to be usable. @@ -58,7 +61,6 @@ """ _offsets = npy.zeros((1, 2)) _transOffset = transforms.IdentityTransform() - _transforms = [None] zorder = 1 @@ -163,9 +165,9 @@ self.update_scalarmappable() - #print 'calling renderer draw line collection' clippath, clippath_trans = self.get_transformed_clip_path_and_affine() + # MGDTODO: This may benefit from using TransformedPath if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() @@ -185,10 +187,19 @@ Returns T/F, dict(ind=itemlist), where every item in itemlist contains the event. """ if callable(self._contains): return self._contains(self,mouseevent) + + transform = self.get_transform() + paths = self.get_paths() + if not transform.is_affine: + paths = [transform.transform_path_non_affine(path) for path in paths] + transform = transform.get_affine() + + # MGDTODO: Don't pick when outside of clip path / clip box ind = point_in_path_collection( mouseevent.x, mouseevent.y, self._pickradius, - self.get_transform(), self._paths, self._transforms, self._offsets, - self._offsetTrans, self._facecolors) + transform.frozen(), paths, self.get_transforms(), + npy.asarray(self._offsets, npy.float_), + self._transOffset.frozen(), len(self._facecolors)) return len(ind)>0,dict(ind=ind) # MGDTODO: Update @@ -233,7 +244,7 @@ def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius - def set_linewidth(self, lw): + def set_linewidths(self, lw): """ Set the linewidth(s) for the collection. lw can be a scalar or a sequence; if it is a sequence the patches will cycle through the @@ -242,9 +253,8 @@ ACCEPTS: float or sequence of floats """ self._linewidths = self._get_value(lw) - def set_linewidths(self, lw): - self.set_linewidth(lw) - + set_linewidth = set_linewidths + def set_linestyles(self, ls): """ Set the linestyles(s) for the collection. @@ -274,6 +284,7 @@ raise ValueError('Do not know how to convert %s to dashes'%ls) self._linestyles = dashes + set_dashes = set_linestyle = set_linestyles def set_color(self, c): """ @@ -295,8 +306,7 @@ ACCEPTS: matplotlib color arg or sequence of rgba tuples """ self._facecolors = _colors.colorConverter.to_rgba_list(c) - def set_facecolors(self, c): - self.set_facecolor(c) + set_facecolors = set_facecolor def set_edgecolor(self, c): """ @@ -308,10 +318,10 @@ """ if c == 'None': self._linewidths = (0.0,) + self._edgecolors = npy.array([]) else: self._edgecolors = _colors.colorConverter.to_rgba_list(c) - def set_edgecolors(self, c): - self.set_edgecolor(c) + set_edgecolors = set_edgecolor def set_alpha(self, alpha): """ @@ -324,29 +334,30 @@ except TypeError: raise TypeError('alpha must be a float') else: artist.Artist.set_alpha(self, alpha) - self._facecolors = [(r,g,b,alpha) for r,g,b,a in self._facecolors] - if cbook.is_string_like(self._edgecolors) and self._edgecolors != 'None': - self._edgecolors = [(r,g,b,alpha) for r,g,b,a in self._edgecolors] + self._facecolors[:, 3] = alpha + self._edgecolors[:, 3] = alpha - def get_linewidth(self): + def get_linewidths(self): return self._linewidths + get_linewidth = get_linewidths - def get_linestyle(self): + def get_linestyles(self): return self._linestyles - - def get_dashes(self): - return self._linestyles + get_dashes = get_linestyle = get_linestyles def update_scalarmappable(self): """ - If the scalar mappable array is not none, update facecolors + If the scalar mappable array is not none, update colors from scalar data """ #print 'update_scalarmappable: self._A', self._A if self._A is None: return if len(self._A.shape)>1: raise ValueError('PatchCollections can only map rank 1 arrays') - self._facecolors = self.to_rgba(self._A, self._alpha) + if len(self._facecolors): + self._facecolors = self.to_rgba(self._A, self._alpha) + else: + self._edgecolors = self.to_rgba(self._A, self._alpha) #print self._facecolors @@ -673,6 +684,8 @@ if antialiaseds is None: antialiaseds = (mpl.rcParams['lines.antialiased'],) self.set_linestyles(linestyles) + colors = _colors.colorConverter.to_rgba_list(colors) + Collection.__init__( self, edgecolors=colors, @@ -686,7 +699,7 @@ pickradius=pickradius, **kwargs) - self._facecolors = [None] + self._facecolors = npy.array([]) self.set_segments(segments) def get_paths(self): Modified: branches/transforms/lib/matplotlib/colorbar.py =================================================================== --- branches/transforms/lib/matplotlib/colorbar.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/colorbar.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -319,9 +319,9 @@ else: intv = self.vmin, self.vmax locator.create_dummy_axis() + formatter.create_dummy_axis() locator.set_view_interval(*intv) locator.set_data_interval(*intv) - formatter.create_dummy_axis() formatter.set_view_interval(*intv) formatter.set_data_interval(*intv) b = npy.array(locator()) @@ -580,18 +580,18 @@ shrink = kw.pop('shrink', 1.0) aspect = kw.pop('aspect', 20) #pb = transforms.PBox(parent.get_position()) - pb = transforms.PBox(parent.get_position(original=True)) + pb = parent.get_position(original=True).frozen() if orientation == 'vertical': pad = kw.pop('pad', 0.05) x1 = 1.0-fraction pb1, pbx, pbcb = pb.splitx(x1-pad, x1) - pbcb.shrink(1.0, shrink).anchor('C') + pbcb = pbcb.shrunk(1.0, shrink).anchored('C', pbcb) anchor = (0.0, 0.5) panchor = (1.0, 0.5) else: pad = kw.pop('pad', 0.15) pbcb, pbx, pb1 = pb.splity(fraction, fraction+pad) - pbcb.shrink(shrink, 1.0).anchor('C') + pbcb = pbcb.shrunk(shrink, 1.0).anchored('C', pbcb) aspect = 1.0/aspect anchor = (0.5, 1.0) panchor = (0.5, 0.0) Modified: branches/transforms/lib/matplotlib/colors.py =================================================================== --- branches/transforms/lib/matplotlib/colors.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/colors.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -316,7 +316,7 @@ If the sequence is a list, the list items are changed in place. """ try: - return [self.to_rgba(c, alpha)] + result = [self.to_rgba(c, alpha)] except ValueError: # If c is a list it must be maintained as the same list # with modified items so that items can be appended to @@ -325,7 +325,8 @@ c = list(c) for i, cc in enumerate(c): c[i] = self.to_rgba(cc, alpha) # change in place - return c + result = c + return npy.asarray(result, npy.float_) colorConverter = ColorConverter() Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -623,11 +623,11 @@ mag = renderer.get_image_magnification() ims = [(im.make_image(mag), im.ox*mag, im.oy*mag) for im in self.images] - im = _image.from_images(self.bbox.height()*mag, - self.bbox.width()*mag, + im = _image.from_images(self.bbox.height * mag, + self.bbox.width * mag, ims) im.is_grayscale = False - l, b, w, h = self.bbox.get_bounds() + l, b, w, h = self.bbox.bounds renderer.draw_image(l, b, im, self.bbox) Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/image.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -332,8 +332,8 @@ if self._A is None: raise RuntimeError('You must first set the image array') - x0, y0, v_width, v_height = self.axes.viewLim.get_bounds() - l, b, width, height = self.axes.bbox.get_bounds() + x0, y0, v_width, v_height = self.axes.viewLim.bounds + l, b, width, height = self.axes.bbox.bounds width *= magnification height *= magnification im = _image.pcolor(self._Ax, self._Ay, self._A, Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -38,7 +38,7 @@ def line_cuts_bbox(line, bbox): """ Return True if and only if line cuts bbox. """ - minx, miny, width, height = bbox.get_bounds() + minx, miny, width, height = bbox.bounds maxx = minx + width maxy = miny + height @@ -343,31 +343,27 @@ bboxes = [] lines = [] - inv = ax.transAxes.inverse_xy_tup + inv = ax.transAxes.inverted().transform for handle in ax.lines: assert isinstance(handle, Line2D) - - xdata = handle.get_xdata(orig=False) - ydata = handle.get_ydata(orig=False) + data = handle.get_xydata() trans = handle.get_transform() - xt, yt = trans.numerix_x_y(xdata, ydata) - - # XXX need a special method in transform to do a list of verts - averts = [inv(v) for v in zip(xt, yt)] + tdata = trans.transform(data) + averts = inv(tdata) lines.append(averts) for handle in ax.patches: assert isinstance(handle, Patch) - verts = handle.get_verts() + path = handle.get_path() trans = handle.get_transform() - tverts = trans.seq_xy_tups(verts) + tpath = trans.transform_path(path) + tverts = tpath.vertices + averts = inv(tverts) - averts = [inv(v) for v in tverts] - - bbox = unit_bbox() - bbox.update(averts, True) + bbox = Bbox.unit() + bbox.update_from_data_xy(averts, True) bboxes.append(bbox) for handle in ax.collections: @@ -445,22 +441,19 @@ consider = [self._loc_to_axes_coords(x, width, height) for x in range(1, len(self.codes))] - tx, ty = self.legendPatch.xy + tx, ty = self.legendPatch.get_x(), self.legendPatch.get_y() candidates = [] for l, b in consider: legendBox = Bbox.from_lbwh(l, b, width, height) badness = 0 badness = legendBox.count_contains(verts) - ox, oy = l-tx, b-ty - for bbox in bboxes: - if legendBox.overlaps(bbox): - badness += 1 - + badness += legendBox.count_overlaps(bboxes) for line in lines: if line_cuts_bbox(line, legendBox): badness += 1 + ox, oy = l-tx, b-ty if badness == 0: return ox, oy @@ -564,6 +557,4 @@ self._offset(ox, oy) - - #artist.kwdocd['Legend'] = kwdoc(Legend) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -350,16 +350,15 @@ self._picker = p def get_window_extent(self, renderer): - bbox = Bbox() - bbox.update_from_data(self.get_transform().transform(self._xy)) - + bbox = Bbox.unit() + bbox.update_from_data_xy(self.get_transform().transform(self._xy), + ignore=True) # correct for marker size, if any if self._marker is not None: - ms = self._markersize / 72.0 * self.figure.dpi - bbox = Bbox(bbox.get_points() + [[-ms/2.0, ms/2.0]]) + ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 + bbox = Bbox(bbox.get_points() + [[-ms, -ms], [ms, ms]]) return bbox - def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: Modified: branches/transforms/lib/matplotlib/mathtext.py =================================================================== --- branches/transforms/lib/matplotlib/mathtext.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/mathtext.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -672,7 +672,8 @@ _slanted_symbols = Set(r"\int \oint".split()) def _get_glyph(self, fontname, sym, fontsize): - if fontname in self.fontmap and latex_to_bakoma.has_key(sym): + use_default = fontname == 'default' and len(sym) == 1 + if latex_to_bakoma.has_key(sym) and not use_default: basename, num = latex_to_bakoma[sym] slanted = (basename == "cmmi10") or sym in self._slanted_symbols cached_font = self._get_font(basename) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -114,6 +114,9 @@ self._combined_transform = self.get_patch_transform() + \ artist.Artist.get_transform(self) + def get_data_transform(self): + return artist.Artist.get_transform(self) + def get_patch_transform(self): return transforms.IdentityTransform() @@ -307,8 +310,8 @@ g = rho*g b = rho*b - self.set_facecolor((r,g,b)) - self.set_edgecolor((r,g,b)) + self.set_facecolor((r,g,b,0.5)) + self.set_edgecolor((r,g,b,0.5)) def get_path(self): return self.patch.get_path() @@ -960,7 +963,7 @@ pad = props.pop('pad', 4) pad = renderer.points_to_pixels(pad) bbox = artist.get_window_extent(renderer) - l,b,w,h = bbox.get_bounds() + l,b,w,h = bbox.bounds l-=pad/2. b-=pad/2. w+=pad Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/ticker.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -118,8 +118,8 @@ axis = None class DummyAxis: def __init__(self): - self.dataLim = mtransforms.Bbox - self.viewLim = mtransforms.Bbox + self.dataLim = mtransforms.Bbox.unit() + self.viewLim = mtransforms.Bbox.unit() def get_view_interval(self): return self.viewLim.intervalx @@ -137,7 +137,8 @@ self.axis = axis def create_dummy_axis(self): - self.axis = self.DummyAxis() + if self.axis is None: + self.axis = self.DummyAxis() def set_view_interval(self, vmin, vmax): self.axis.set_view_interval(vmin, vmax) @@ -229,8 +230,8 @@ def __call__(self, x, pos=None): 'Return the format for tick val x at position pos' - self.verify_intervals() - d = abs(self.viewInterval.span()) + xmin, xmax = self.axis.get_view_interval() + d = abs(xmax - xmin) return self.pprint_val(x,d) @@ -322,7 +323,7 @@ if self.offset > 0: offsetStr = '+' + offsetStr if self.orderOfMagnitude: if self._usetex or self._useMathText: - sciNotStr = r'{\times}'+self.format_data(10**self.orderOfMagnitude) + sciNotStr = r'\times'+self.format_data(10**self.orderOfMagnitude) else: sciNotStr = u'\xd7'+'1e%d'% self.orderOfMagnitude if self._useMathText: @@ -451,8 +452,8 @@ def __call__(self, x, pos=None): 'Return the format for tick val x at position pos' - self.verify_intervals() - d = abs(self.viewInterval.span()) + vmin, vmax = self.axis.get_view_interval() + d = abs(vmax - vmin) b=self._base # only label the decades fx = math.log(x)/math.log(b) @@ -769,10 +770,7 @@ def __call__(self): 'Return the locations of the ticks' - - self.verify_intervals() - - vmin, vmax = self.viewInterval.get_bounds() + vmin, vmax = self.axis.get_view_interval() if vmax<vmin: vmin, vmax = vmax, vmin vmin = self._base.ge(vmin) @@ -786,10 +784,8 @@ Set the view limits to the nearest multiples of base that contain the data """ + dmin, dmax = self.axis.get_data_interval() - self.verify_intervals() - dmin, dmax = self.dataInterval.get_bounds() - vmin = self._base.le(dmin) vmax = self._base.ge(dmax) if vmin==vmax: Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-11 15:42:53 UTC (rev 3934) @@ -268,20 +268,24 @@ def contains(self, x, y): return self.containsx(x) and self.containsy(y) - def overlapsx(self, other): - xmin, xmax = other.intervalx - return self.containsx(xmin) \ - or self.containsx(xmax) + def overlaps(self, other): + ax1, ay1, ax2, ay2 = self._get_lbrt() + bx1, by1, bx2, by2 = other._get_lbrt() - def overlapsy(self, other): - ymin, ymax = other.intervaly - return self.containsy(ymin) \ - or self.containsy(ymax) + if ax2 < ax1: + ax2, ax1 = ax1, ax2 + if ay2 < ay1: + ay2, ay1 = ay1, ay2 + if bx2 < bx1: + bx2, bx1 = bx1, bx2 + if by2 < by1: + by2, by1 = by1, by2 + + return not ((bx2 < ax1) or + (by2 < ay1) or + (bx1 > ax2) or + (by1 > ay2)) - def overlaps(self, other): - return self.overlapsx(other) \ - and self.overlapsy(other) - def fully_containsx(self, x): xmin, xmax = self.intervalx return ((xmin < xmax @@ -298,20 +302,24 @@ return self.fully_containsx(x) \ and self.fully_containsy(y) - def fully_overlapsx(self, other): - xmin, xmax = other.intervalx - return self.fully_containsx(xmin) \ - or self.fully_containsx(xmax) - - def fully_overlapsy(self, other): - ymin, ymax = other.intervaly - return self.fully_containsy(ymin) \ - or self.fully_containsy(ymax) - def fully_overlaps(self, other): - return self.fully_overlapsx(other) and \ - self.fully_overlapsy(other) + ax1, ay1, ax2, ay2 = self._get_lbrt() + bx1, by1, bx2, by2 = other._get_lbrt() + if ax2 < ax1: + ax2, ax1 = ax1, ax2 + if ay2 < ay1: + ay2, ay1 = ay1, ay2 + if bx2 < bx1: + bx2, bx1 = bx1, bx2 + if by2 < by1: + by2, by1 = by1, by2 + + return not ((bx2 <= ax1) or + (by2 <= ay1) or + (bx1 >= ax2) or + (by1 >= ay2)) + def transformed(self, transform): """ Return a new Bbox object, transformed by the given transform. @@ -324,8 +332,139 @@ given transform. """ return Bbox(transform.inverted().transform(self.get_points())) - - + + 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 anchored(self, c, container = None): + """ + Return a copy of the Bbox, shifted to position c within a + container. + + c: may be either a) a sequence (cx, cy) where cx, cy range + from 0 to 1, where 0 is left or bottom and 1 is right or top; + or b) 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 BBox + is positioned; it defaults to the initial BBox. + """ + if container is None: + container = self + l, b, w, h = container.bounds + if isinstance(c, str): + cx, cy = self.coefs[c] + else: + cx, cy = c + L, B, W, H = self.bounds + return Bbox(self._points + + [(l + cx * (w-W)) - L, + (b + cy * (h-H)) - B]) + + def shrunk(self, mx, my): + """ + Return a copy of the Bbox, shurnk by the factor mx in the x + direction and the factor 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. + """ + w, h = self.size + return Bbox([self._points[0], + self._points[0] + [mx * w, my * h]]) + + def shrunk_to_aspect(self, box_aspect, container = None, fig_aspect = 1.0): + """ + Return a copy of the Bbox, shrunk 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 + if container is None: + container = self + w, h = container.size + H = w * box_aspect/fig_aspect + if H <= h: + W = w + else: + W = h * fig_aspect/box_aspect + H = h + return Bbox([self._points[0], + self._points[0] + (W, H)]) + + def splitx(self, *args): + ''' + e.g., bbox.splitx(f1, f2, ...) + + Returns a list of new BBoxes formed by + splitting the original one with vertical lines + at fractional positions f1, f2, ... + ''' + boxes = [] + xf = [0] + list(args) + [1] + l, b, r, t = self.lbrt + w = r - l + for xf0, xf1 in zip(xf[:-1], xf[1:]): + boxes.append(Bbox([[l + xf0 * w, b], [l + xf1 * w, t]])) + return boxes + + def splity(self, *args): + ''' + e.g., bbox.splitx(f1, f2, ...) + + Returns a list of new PBoxes formed by + splitting the original one with horizontal lines + at fractional positions f1, f2, ... + ''' + boxes = [] + yf = [0] + list(args) + [1] + l, b, r, t = self.lbrt + h = t - b + for yf0, yf1 in zip(yf[:-1], yf[1:]): + boxes.append(Bbox([[l, b + yf0 * h], [r, b + yf1 * h]])) + return boxes + + def count_contains(self, vertices): + if len(vertices) == 0: + return 0 + vertices = npy.asarray(vertices) + xmin, ymin, xmax, ymax = self._get_lbrt() + dxmin = npy.sign(vertices[:, 0] - xmin) + dymin = npy.sign(vertices[:, 1] - ymin) + dxmax = npy.sign(vertices[:, 0] - xmax) + dymax = npy.sign(vertices[:, 1] - ymax) + inside = (abs(dxmin + dxmax) + abs(dymin + dymax)) <= 2 + return N.sum(inside) + + def count_overlaps(self, bboxes): + ax1, ay1, ax2, ay2 = self._get_lbrt() + if ax2 < ax1: + ax2, ax1 = ax1, ax2 + if ay2 < ay1: + ay2, ay1 = ay1, ay2 + + count = 0 + for bbox in bboxes: + bx1, by1, bx2, by2 = bbox._get_lbrt() + if bx2 < bx1: + bx2, bx1 = bx1, bx2 + if by2 < by1: + by2, by1 = by1, by2 + count += (not ((bx2 <= ax1) or + (by2 <= ay1) or + (bx1 >= ax2) or + (by1 >= ay2))) + return count + class Bbox(BboxBase): def __init__(self, points): """ @@ -402,7 +541,7 @@ if len(x) == 0 or len(y) == 0: return - + if ma.isMaskedArray(x) or ma.isMaskedArray(y): xpos = ma.where(x > 0.0, x, npy.inf) ypos = ma.where(y > 0.0, y, npy.inf) @@ -430,6 +569,7 @@ max(y.max(), self.ymax)]], npy.float_) self._minpos = npy.minimum(minpos, self._minpos) + self.invalidate() def update_from_data_xy(self, xy, ignore=None): @@ -544,74 +684,6 @@ """ return Bbox(self._points + (tx, ty)) - 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 anchored(self, c, container = None): - """ - Return a copy of the Bbox, shifted to position c within a - container. - - c: may be either a) a sequence (cx, cy) where cx, cy range - from 0 to 1, where 0 is left or bottom and 1 is right or top; - or b) 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 BBox - is positioned; it defaults to the initial BBox. - """ - if container is None: - container = self - l, b, w, h = container.bounds - if isinstance(c, str): - cx, cy = self.coefs[c] - else: - cx, cy = c - L, B, W, H = self.bounds - return Bbox(self._points + - [(l + cx * (w-W)) - L, - (b + cy * (h-H)) - B]) - - def shrunk(self, mx, my): - """ - Return a copy of the Bbox, shurnk by the factor mx in the x - direction and the factor 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. - """ - w, h = self.size - return Bbox([self._points[0], - self._points[1] - [w - (mx * w), h - (my * h)]]) - - def shrunk_to_aspect(self, box_aspect, container = None, fig_aspect = 1.0): - """ - Return a copy of the Bbox, shrunk 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 - if container is None: - container = self - w, h = container.size - H = w * box_aspect/fig_aspect - if H <= h: - W = w - else: - W = h * fig_aspect/box_aspect - H = h - return Bbox([self._points[0], - self._points[0] + (W, H)]) - #@staticmethod def union(bboxes): """ @@ -1444,6 +1516,7 @@ return mtx[0, 1] == 0.0 and mtx[1, 0] == 0.0 is_separable = property(_get_is_separable) + class IdentityTransform(Affine2DBase): """ A special class that does on thing, the identity transform, in a @@ -1478,10 +1551,10 @@ transform_path.__doc__ = Affine2DBase.transform_path.__doc__ transform_path_affine = transform_path - transform_path_affine = Affine2DBase.transform_path_affine.__doc__ + transform_path_affine.__doc__ = Affine2DBase.transform_path_affine.__doc__ transform_path_non_affine = transform_path - transform_path_non_affine = Affine2DBase.transform_path_non_affine.__doc__ + transform_path_non_affine.__doc__ = Affine2DBase.transform_path_non_affine.__doc__ def get_affine(self): return self Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/src/_backend_agg.cpp 2007-10-11 15:42:53 UTC (rev 3934) @@ -605,8 +605,6 @@ agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl; while (path_quantized.vertex(&x, &y) != agg::path_cmd_stop) { - x += 0.5; - y += 0.5; //render the fill if (face.first) { if (has_clippath) { @@ -948,8 +946,8 @@ Py::SeqBase<Py::Object> transforms_obj = args[5]; Py::Object offsets_obj = args[6]; agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7], false); - Py::SeqBase<Py::Object> facecolors_obj = args[8]; - Py::SeqBase<Py::Object> edgecolors_obj = args[9]; + Py::Object facecolors_obj = args[8]; + Py::Object edgecolors_obj = args[9]; Py::SeqBase<Py::Float> linewidths = args[10]; Py::SeqBase<Py::Object> linestyles_obj = args[11]; Py::SeqBase<Py::Int> antialiaseds = args[12]; @@ -960,16 +958,31 @@ if (!offsets || offsets->dimensions[1] != 2) throw Py::ValueError("Offsets array must be Nx2"); + PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + if (!facecolors || + (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || + (facecolors->nd == 2 && facecolors->dimensions[1] != 4)) + throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty"); + + PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + if (!edgecolors || + (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || + (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) + throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); + size_t Npaths = paths.length(); size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t Nfacecolors = std::min(facecolors_obj.length(), N); - size_t Nedgecolors = std::min(edgecolors_obj.length(), N); + size_t Nfacecolors = facecolors->dimensions[0]; + size_t Nedgecolors = edgecolors->dimensions[0]; size_t Nlinewidths = linewidths.length(); size_t Nlinestyles = std::min(linestyles_obj.length(), N); size_t Naa = antialiaseds.length(); + if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0) + return Py::Object(); + size_t i = 0; // Convert all of the transforms up front @@ -983,46 +996,6 @@ transforms.push_back(trans); } - // Convert all of the facecolors up front - typedef std::vector<facepair_t> facecolors_t; - facecolors_t facecolors; - facecolors.resize(Nfacecolors); - i = 0; - for (facecolors_t::iterator f = facecolors.begin(); - f != facecolors.end(); ++f, ++i) { - double r, g, b, a; - const Py::Object& facecolor_obj = facecolors_obj[i]; - if (facecolor_obj.ptr() == Py_None) - f->first = false; - else { - Py::SeqBase<Py::Float> facergba = facecolor_obj; - r = Py::Float(facergba[0]); - g = Py::Float(facergba[1]); - b = Py::Float(facergba[2]); - a = 1.0; - if (facergba.size() == 4) - a = Py::Float(facergba[3]); - f->first = true; - f->second = agg::rgba(r, g, b, a); - } - } - - // Convert all of the edgecolors up front - typedef std::vector<agg::rgba> edgecolors_t; - edgecolors_t edgecolors; - edgecolors.reserve(Nedgecolors); - for (i = 0; i < Nedgecolors; ++i) { - double r, g, b, a; - Py::SeqBase<Py::Float> edgergba(edgecolors_obj[i]); - r = Py::Float(edgergba[0]); - g = Py::Float(edgergba[1]); - b = Py::Float(edgergba[2]); - a = 1.0; - if (edgergba.size() == 4) - a = Py::Float(edgergba[3]); - edgecolors.push_back(agg::rgba(r, g, b, a)); - } - // Convert all the dashes up front typedef std::vector<std::pair<double, GCAgg::dash_t> > dashes_t; dashes_t dashes; @@ -1039,6 +1012,11 @@ set_clipbox(cliprect, theRasterizer); bool has_clippath = render_clippath(clippath, clippath_trans); + // Set some defaults, assuming no face or edge + gc.linewidth = 0.0; + facepair_t face; + face.first = Nfacecolors != 0; + for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); bool snap = (path.total_vertices() == 2); @@ -1047,11 +1025,26 @@ offset_trans.transform(&xo, &yo); agg::trans_affine_translation transOffset(xo, yo); agg::trans_affine& trans = transforms[i % Ntransforms]; - facepair_t& face = facecolors[i % Nfacecolors]; - gc.color = edgecolors[i % Nedgecolors]; - gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; - gc.dashes = dashes[i % Nlinestyles].second; - gc.dashOffset = dashes[i % Nlinestyles].first; + + if (Nfacecolors) { + size_t fi = i % Nfacecolors; + face.second = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0), + *(double*)PyArray_GETPTR2(facecolors, fi, 1), + *(double*)PyArray_GETPTR2(facecolors, fi, 2), + *(double*)PyArray_GETPTR2(facecolors, fi, 3)); + } + + if (Nedgecolors) { + size_t ei = i % Nedgecolors; + gc.color = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0), + *(double*)PyArray_GETPTR2(edgecolors, ei, 1), + *(double*)PyArray_GETPTR2(edgecolors, ei, 2), + *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; + } + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); } @@ -1400,16 +1393,17 @@ template<class T> bool point_in_path_impl(double tx, double ty, T& path) { int yflag0, yflag1, inside_flag; - double vtx0, vty0, vtx1, vty1; + double vtx0, vty0, vtx1, vty1, sx, sy; double x, y; path.rewind(0); - if (path.vertex(&x, &y) == agg::path_cmd_stop) + unsigned code = path.vertex(&x, &y); + if (code == agg::path_cmd_stop) return false; while (true) { - vtx0 = x; - vty0 = y; + sx = vtx0 = x; + sy = vty0 = y; // get test bit for above/below X axis yflag0 = (vty0 >= ty); @@ -1419,14 +1413,13 @@ inside_flag = 0; while (true) { - unsigned code = path.vertex(&x, &y); - if (code == agg::path_cmd_stop) - return false; + code = path.vertex(&x, &y); + // The following cases denote the beginning on a new subpath - if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) + if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { + x = sx; y = sy; + } else if (code == agg::path_cmd_move_to) break; - if (code == agg::path_cmd_move_to) - break; yflag1 = (vty1 >= ty); // Check if endpoints straddle (are on opposite sides) of X axis @@ -1459,10 +1452,17 @@ vtx1 = x; vty1 = y; + + if (code == agg::path_cmd_stop || + (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) + break; } if (inside_flag != 0) return true; + + if (code == agg::path_cmd_stop) + return false; } return false; @@ -1641,15 +1641,18 @@ agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[3]); Py::SeqBase<Py::Object> paths = args[4]; Py::SeqBase<Py::Object> transforms_obj = args[5]; - Py::SeqBase<Py::Object> offsets = args[6]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7], false); - Py::SeqBase<Py::Object> facecolors = args[8]; + Py::SeqBase<Py::Object> offsets_obj = args[6]; + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); + bool filled = Py::Int(args[8]); + PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!offsets || offsets->dimensions[1] != 2) + throw Py::ValueError("Offsets array must be Nx2"); + size_t Npaths = paths.length(); - size_t Noffsets = offsets.length(); + size_t Noffsets = offsets->dimensions[0]; size_t N = std::max(Npaths, Noffsets); size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t Ncolors = facecolors.length(); size_t i; // Convert all of the transforms up front @@ -1668,19 +1671,18 @@ for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); - Py::SeqBase<Py::Float> offset = Py::SeqBase<Py::Float>(offsets[i % Noffsets]); - double xo = Py::Float(offset[0]); - double yo = Py::Float(offset[1]); + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); offset_trans.transform(&xo, &yo); agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine trans = transforms[i % Ntransforms] * transOffset; + agg::trans_affine trans = transforms[i % Ntransforms]; + trans *= transOffset; - const Py::Object& facecolor_obj = facecolors[i & Ncolors]; - if (facecolor_obj.ptr() == Py_None) { - if (::point_on_path(x, y, radius, path, trans)) + if (filled) { + if (::point_in_path(x, y, path, trans)) result.append(Py::Int((int)i)); } else { - if (::point_in_path(x, y, path, trans)) + if (::point_on_path(x, y, radius, path, trans)) result.append(Py::Int((int)i)); } } Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-10 13:38:32 UTC (rev 3933) +++ branches/transforms/src/_backend_agg.h 2007-10-11 15:42:53 UTC (rev 3934) @@ -247,7 +247,7 @@ add_varargs_method("get_path_collection_extents", &_backend_agg_module::get_path_collection_extents, "get_path_collection_extents(trans, paths, transforms, offsets, offsetTrans)"); add_varargs_method("point_in_path_collection", &_backend_agg_module::point_in_path_collection, - "point_in_path_collection(x, y, r, trans, paths, transforms, offsets, offsetTrans, colors)"); + "point_in_path_collection(x, y, r, trans, paths, transforms, offsets, offsetTrans, filled)"); initialize( "The agg rendering backend" ); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-12 12:27:49
|
Revision: 3937 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3937&view=rev Author: mdboom Date: 2007-10-12 05:27:25 -0700 (Fri, 12 Oct 2007) Log Message: ----------- First pass through all of the examples -- not all working yet, though. (See PASSED_DEMOS). Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/to_numeric.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/pyplot.py branches/transforms/lib/matplotlib/quiver.py branches/transforms/lib/matplotlib/table.py branches/transforms/lib/matplotlib/widgets.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/PASSED_DEMOS 2007-10-12 12:27:25 UTC (rev 3937) @@ -148,63 +148,63 @@ pcolor_log.py O pcolor_nonuniform.py O pcolor_small.py O -pick_event_demo2.py -pick_event_demo.py -pie_demo.py -plotfile_demo.py -polar_bar.py -polar_demo.py -polar_legend.py -polar_scatter.py -poly_editor.py -poormans_contour.py +pick_event_demo2.py O +pick_event_demo.py O +pie_demo.py O +plotfile_demo.py O +polar_bar.py O +polar_demo.py O +polar_legend.py O +polar_scatter.py O +poly_editor.py [NEEDS OVERHAUL] +poormans_contour.py O printing_in_wx.py -print_stdout.py -psd_demo.py +print_stdout.py [BROKEN?] +psd_demo.py O pstest.py pylab_with_gtk.py -pythonic_matplotlib.py -quadmesh_demo.py -quiver_demo.py -rc_traits.py -scatter_custom_symbol.py -scatter_demo2.py -scatter_demo.py -scatter_masked.py -scatter_profile.py -scatter_star_poly.py -set_and_get.py -shared_axis_across_figures.py -shared_axis_demo.py -simple3d_oo.py -simple3d.py -simple_plot_fps.py -simple_plot.py -specgram_demo.py -spy_demos.py -stem_plot.py -step_demo.py -stock_demo.py -strip_chart_demo.py -subplot_demo.py -subplots_adjust.py -subplot_toolbar.py -system_monitor.py -table_demo.py -tex_demo.py -text_handles.py -text_rotation.py -text_themes.py -tex_unicode_demo.py -toggle_images.py -to_numeric.py +pythonic_matplotlib.py O +quadmesh_demo.py [MASKED VALUES NOT QUITE RIGHT] +quiver_demo.py [SEGFAULTS] +rc_traits.py [N/A] +scatter_custom_symbol.py O +scatter_demo2.py O +scatter_demo.py O +scatter_masked.py O +scatter_profile.py O +scatter_star_poly.py O [SOME BUGS IN TRUNK -- FIXED ON BRANCH] +set_and_get.py O +shared_axis_across_figures.py O +shared_axis_demo.py O +simple3d_oo.py [PUNTING ON 3D FOR NOW] +simple3d.py [PUNTING ON 3D FOR NOW] +simple_plot_fps.py O +simple_plot.py O +specgram_demo.py O +spy_demos.py O +stem_plot.py O +step_demo.py O +stock_demo.py O +strip_chart_demo.py [REQUIRES GTK] +subplot_demo.py O +subplots_adjust.py O +subplot_toolbar.py O +system_monitor.py O +table_demo.py +tex_demo.py O +text_handles.py O +text_rotation.py O +text_themes.py O +tex_unicode_demo.py O +toggle_images.py [???] +to_numeric.py [REQUIRES PIL] transoffset.py -two_scales.py -unicode_demo.py -vertical_ticklabels.py -vline_demo.py -webapp_demo.py -wxcursor_demo.py -xcorr_demo.py -zoom_window.py -zorder_demo.py +two_scales.py O +unicode_demo.py O +vertical_ticklabels.py O +vline_demo.py O +webapp_demo.py +wxcursor_demo.py +xcorr_demo.py O +zoom_window.py O +zorder_demo.py O Modified: branches/transforms/examples/to_numeric.py =================================================================== --- branches/transforms/examples/to_numeric.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/examples/to_numeric.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -17,7 +17,7 @@ s = agg.tostring_rgb() # get the width and the height to resize the matrix -l,b,w,h = agg.figure.bbox.get_bounds() +l,b,w,h = agg.figure.bbox.bounds w, h = int(w), int(h) Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -1196,9 +1196,9 @@ len(self.lines)==0 and len(self.patches)==0)): - if scalex: self.set_xbound(self.dataLim.intervalx().get_bounds()) + if scalex: self.set_xbound(self.dataLim.intervalx) - if scaley: self.set_ybound(self.dataLim.intervaly().get_bounds()) + if scaley: self.set_ybound(self.dataLim.intervaly) return if scalex: @@ -4107,7 +4107,6 @@ if sym is not None: if symstyle==0: - collection = mcoll.RegularPolyCollection( self.figure.dpi, numsides, rotation, scales, @@ -4143,7 +4142,7 @@ verts /= rescale scales = npy.asarray(scales) - scales = npy.sqrt(scales * self.figure.dpi.get() / 72.) + scales = npy.sqrt(scales * self.figure.dpi / 72.) if len(scales)==1: verts = [scales[0]*verts] else: @@ -4858,7 +4857,7 @@ self.set_xlabel('Frequency') self.set_ylabel('Power Spectrum (dB)') self.grid(True) - vmin, vmax = self.viewLim.intervaly().get_bounds() + vmin, vmax = self.viewLim.intervaly intv = vmax-vmin logi = int(npy.log10(intv)) if logi==0: logi=.1 Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -78,9 +78,9 @@ **kwargs ): """ - Create a PatchCollection + Create a Collection - %(PatchCollection)s + %(Collection)s """ artist.Artist.__init__(self) cm.ScalarMappable.__init__(self, norm, cmap) @@ -103,8 +103,9 @@ self._uniform_offsets = None self._offsets = npy.zeros((1, 2)) if offsets is not None: -# if len(offsets.shape) == 1: -# offsets = offsets[npy.newaxis,:] # Make it Nx2. + offsets = npy.asarray(offsets, npy.float_) + if len(offsets.shape) == 1: + offsets = offsets[npy.newaxis,:] # Make it Nx2. if transOffset is not None: Affine2D = transforms.Affine2D self._offsets = offsets @@ -171,7 +172,10 @@ if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() - + if not transOffset.is_affine: + offsets = transOffset.transform_non_affine(offsets) + transOffset = transOffset.get_affine() + renderer.draw_path_collection( transform, self.clipbox, clippath, clippath_trans, paths, self.get_transforms(), @@ -353,7 +357,7 @@ #print 'update_scalarmappable: self._A', self._A if self._A is None: return if len(self._A.shape)>1: - raise ValueError('PatchCollections can only map rank 1 arrays') + raise ValueError('Collections can only map rank 1 arrays') if len(self._facecolors): self._facecolors = self.to_rgba(self._A, self._alpha) else: @@ -410,33 +414,45 @@ (0, 2) .. (0, meshWidth), (1, 0), (1, 1), and so on. """ def __init__(self, meshWidth, meshHeight, coordinates, showedges): + Path = path.Path + Collection.__init__(self) self._meshWidth = meshWidth self._meshHeight = meshHeight self._coordinates = coordinates self._showedges = showedges + + # MGDTODO: Numpify + coordinates = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) + c = coordinates + paths = [] + # We could let the Path constructor generate the codes for us, + # but this is faster, since we know they'll always be the same + codes = npy.array([Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO]) + for m in xrange(meshHeight): + for n in xrange(meshWidth): + paths.append(Path( + [c[m , n], + c[m , n+1], + c[m+1, n+1], + c[m+1, n]], + codes)) + self._paths = paths + + def get_paths(self, dataTrans=None): + return self._paths - def get_verts(self, dataTrans=None): - return self._coordinates; - def draw(self, renderer): - # does not call update_scalarmappable, need to update it - # when creating/changing ****** Why not? speed? - if not self.get_visible(): return - transform = self.get_transform() - transoffset = self._transOffset - transform.freeze() - transoffset.freeze() - #print 'QuadMesh draw' self.update_scalarmappable() ####################### - renderer.draw_quad_mesh( self._meshWidth, self._meshHeight, - self._facecolors, self._coordinates[:,0], - self._coordinates[:, 1], self.clipbox, transform, - self._offsets, transoffset, self._showedges) - transform.thaw() - transoffset.thaw() + self._linewidths = (1,) + if self._showedges: + self._edgecolors = npy.array([[0.0, 0.0, 0.0, 1.0]], npy.float_) + else: + self._edgecolors = self._facecolors + Collection.draw(self, renderer) + class PolyCollection(Collection): def __init__(self, verts, **kwargs): """ @@ -476,6 +492,8 @@ __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd class RegularPolyCollection(Collection): + _path_generator = path.Path.unit_regular_polygon + def __init__(self, dpi, numsides, @@ -514,18 +532,16 @@ offsets = offsets, transOffset = ax.transData, ) - - """ Collection.__init__(self,**kwargs) self._sizes = sizes self._dpi = dpi - self._paths = [path.Path.unit_regular_polygon(numsides)] + self._paths = [self._path_generator(numsides)] # sizes is the area of the circle circumscribing the polygon # in points^2 self._transforms = [ - transforms.Affine2D().rotate(rotation).scale( - (math.sqrt(x) * self._dpi / 72.0) * (1.0 / math.sqrt(math.pi))) + transforms.Affine2D().rotate(-rotation).scale( + (math.sqrt(x) * self._dpi / 72.0) / math.sqrt(math.pi)) for x in sizes] self.set_transform(transforms.IdentityTransform()) @@ -554,72 +570,13 @@ class StarPolygonCollection(RegularPolyCollection): - def __init__(self, - dpi, - numsides, - rotation = 0 , - sizes = (1,), - **kwargs): - """ - Draw a regular star like Polygone with numsides. - - * dpi is the figure dpi instance, and is required to do the - area scaling. - - * numsides: the number of sides of the polygon - - * sizes gives the area of the circle circumscribing the - regular polygon in points^2 - - * rotation is the rotation of the polygon in radians - - %(Collection)s - """ - - RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - def _update_verts(self): - scale = 1.0/math.sqrt(math.pi) - ns2 = self.numsides*2 - r = scale*npy.ones(ns2) - r[1::2] *= 0.5 - theta = (math.pi/self.numsides)*npy.arange(ns2) + self.rotation - self._verts = zip( r*npy.sin(theta), r*npy.cos(theta) ) - + _path_generator = path.Path.unit_regular_star + + class AsteriskPolygonCollection(RegularPolyCollection): - def __init__(self, - dpi, - numsides, - rotation = 0 , - sizes = (1,), - **kwargs): - """ - Draw a regular asterisk Polygone with numsides spikes. - - * dpi is the figure dpi instance, and is required to do the - area scaling. - - * numsides: the number of spikes of the polygon - - * sizes gives the area of the circle circumscribing the - regular polygon in points^2 - - * rotation is the rotation of the polygon in radians - - %(Collection)s - """ - - RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) - __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd - - def _update_verts(self): - scale = 1.0/math.sqrt(math.pi) - r = scale*npy.ones(self.numsides*2) - r[1::2] = 0 - theta = (math.pi/self.numsides)*npy.arange(2*self.numsides) + self.rotation - self._verts = zip( r*npy.sin(theta), r*npy.cos(theta) ) - + _path_generator = path.Path.unit_regular_asterisk + + class LineCollection(Collection, cm.ScalarMappable): """ All parameters must be sequences or scalars; if scalars, they will Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -106,8 +106,7 @@ class Figure(Artist): def __str__(self): - return "Figure(%gx%g)"%(self.bbox.max) - # return "Figure(%gx%g)"%(self.figwidth.get(),self.figheight.get()) + return "Figure(%gx%g)" % tuple(self.bbox.size) def __init__(self, figsize = None, # defaults to rc figure.figsize Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -495,7 +495,7 @@ A general polygon patch. """ def __str__(self): - return "Poly(%g,%g)"%self.xy[0] + return "Poly(%g, %g)" % tuple(self._path.vertices[0]) def __init__(self, xy, **kwargs): """ @@ -506,11 +506,15 @@ See Patch documentation for additional kwargs """ Patch.__init__(self, **kwargs) + self.xy = xy self._path = Path(xy, closed=True) __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): return self._path + + def update(self): + self._path = Path(self.xy, closed=True) class Wedge(Patch): def __str__(self): Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/path.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -93,7 +93,7 @@ codes = self.LINETO * npy.ones( vertices.shape[0] + 1, self.code_type) codes[0] = self.MOVETO - codes[-1] = self.LINETO + codes[-1] = self.CLOSEPOLY vertices = npy.concatenate((vertices, [vertices[0]])) else: codes = self.LINETO * npy.ones( @@ -214,7 +214,7 @@ 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 + return cls._unit_rectangle unit_rectangle = classmethod(unit_rectangle) _unit_regular_polygons = {} @@ -237,6 +237,37 @@ return path unit_regular_polygon = classmethod(unit_regular_polygon) + _unit_regular_stars = {} + #@classmethod + def unit_regular_star(cls, numVertices, innerCircle=0.5): + """ + Returns a Path for a unit regular star with the given + numVertices and radius of 1.0, centered at (0, 0). + """ + path = cls._unit_regular_stars.get((numVertices, innerCircle)) + if path is None: + ns2 = numVertices * 2 + theta = (2*npy.pi/ns2 * npy.arange(ns2)) + # This initial rotation is to make sure the polygon always + # "points-up" + theta += npy.pi / 2.0 + r = npy.ones(ns2) + r[1::2] = innerCircle + verts = npy.vstack((r*npy.cos(theta), r*npy.sin(theta))).transpose() + path = Path(verts) + cls._unit_regular_polygons[(numVertices, innerCircle)] = path + return path + unit_regular_star = classmethod(unit_regular_star) + + #@classmethod + def unit_regular_asterisk(cls, numVertices): + """ + Returns a Path for a unit regular asterisk with the given + numVertices and radius of 1.0, centered at (0, 0). + """ + return cls.unit_regular_star(numVertices, 0.0) + unit_regular_asterisk = classmethod(unit_regular_asterisk) + _unit_circle = None #@classmethod def unit_circle(cls): Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -55,8 +55,7 @@ transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ def transform_path(self, path): - if len(path.vertices) == 2: - path = path.interpolated(self._resolution) + path = path.interpolated(self._resolution) return Path(self.transform(path.vertices), path.codes) transform_path.__doc__ = Transform.transform_path.__doc__ Modified: branches/transforms/lib/matplotlib/pyplot.py =================================================================== --- branches/transforms/lib/matplotlib/pyplot.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/pyplot.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -2,7 +2,7 @@ import matplotlib from matplotlib import _pylab_helpers -from matplotlib.cbook import dedent, silent_list +from matplotlib.cbook import dedent, silent_list, is_string_like, is_numlike from matplotlib.figure import Figure, figaspect from matplotlib.backend_bases import FigureCanvasBase from matplotlib.image import imread as _imread @@ -1232,9 +1232,9 @@ def getname_val(identifier): 'return the name and column data for identifier' - if cbook.is_string_like(identifier): + if is_string_like(identifier): return identifier, r[identifier] - elif cbook.is_numlike(identifier): + elif is_numlike(identifier): name = r.dtype.names[int(identifier)] return name, r[name] else: Modified: branches/transforms/lib/matplotlib/quiver.py =================================================================== --- branches/transforms/lib/matplotlib/quiver.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/quiver.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -168,8 +168,7 @@ self.coord = kw.pop('coordinates', 'axes') self.color = kw.pop('color', None) self.label = label - self.labelsep = (transforms.Value(kw.pop('labelsep', 0.1)) - * Q.ax.figure.dpi) + self.labelsep = (kw.pop('labelsep', 0.1) * Q.ax.figure.dpi) self.labelpos = kw.pop('labelpos', 'N') self.labelcolor = kw.pop('labelcolor', None) self.fontproperties = kw.pop('fontproperties', dict()) @@ -281,8 +280,8 @@ self.pivot = kw.pop('pivot', 'tail') kw.setdefault('facecolors', self.color) kw.setdefault('linewidths', (0,)) - collections.PolyCollection.__init__(self, None, offsets=zip(X, Y), - transOffset=ax.transData, **kw) + collections.PolyCollection.__init__(self, [], offsets=zip(X, Y), + transOffset=ax.transData, **kw) self.polykw = kw self.set_UVC(U, V, C) self._initialized = False @@ -324,7 +323,7 @@ if not self._initialized: trans = self._set_transform() ax = self.ax - sx, sy = trans.inverse_xy_tup((ax.bbox.width(), ax.bbox.height())) + sx, sy = trans.transform_point((ax.bbox.width, ax.bbox.height)) self.span = sx sn = max(8, min(25, math.sqrt(self.N))) if self.width is None: @@ -362,17 +361,17 @@ dx = dx1/dx0 else: if self.units == 'width': - dx = ax.bbox.ur().x() - ax.bbox.ll().x() + dx = ax.bbox.width elif self.units == 'height': - dx = ax.bbox.ur().y() - ax.bbox.ll().y() + dx = ax.bbox.height elif self.units == 'dots': dx = transforms.Value(1) elif self.units == 'inches': dx = ax.figure.dpi else: raise ValueError('unrecognized units') - bb = transforms.Bbox(transforms.origin(), transforms.Point(dx, dx)) - trans = transforms.get_bbox_transform(transforms.unit_bbox(), bb) + bb = transforms.Bbox.from_lbrt(0, 0, dx, dx) + trans = transforms.BboxTransform(transforms.Bbox.unit(), bb) self.set_transform(trans) return trans Modified: branches/transforms/lib/matplotlib/table.py =================================================================== --- branches/transforms/lib/matplotlib/table.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/table.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -216,7 +216,7 @@ self._cells[(row, col)] = cell def _approx_text_height(self): - return self.FONTSIZE/72.0*self.figure.dpi.get()/self._axes.bbox.height() * 1.2 + return self.FONTSIZE/72.0*self.figure.dpi/self._axes.bbox.height * 1.2 def draw(self, renderer): # Need a renderer to do hit tests on mouseevent; assume the last one will do Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/lib/matplotlib/widgets.py 2007-10-12 12:27:25 UTC (rev 3937) @@ -242,6 +242,7 @@ def set_val(self, val): self.poly.xy[-1] = val, 0 self.poly.xy[-2] = val, 1 + self.poly.update() self.valtext.set_text(self.valfmt%val) if self.drawon: self.ax.figure.canvas.draw() self.val = val Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-11 22:09:18 UTC (rev 3936) +++ branches/transforms/src/_backend_agg.cpp 2007-10-12 12:27:25 UTC (rev 3937) @@ -832,6 +832,8 @@ // Render face if (face.first) { + theRasterizer->add_path(curve); + if (gc.isaa) { if (has_clippath) { pixfmt_amask_type pfa(*pixFmt, *alphaMask); @@ -841,7 +843,6 @@ agg::render_scanlines(*theRasterizer, *slineP8, ren); } else { rendererAA->color(face.second); - theRasterizer->add_path(curve); agg::render_scanlines(*theRasterizer, *slineP8, *rendererAA); } } else { @@ -853,7 +854,6 @@ agg::render_scanlines(*theRasterizer, *slineP8, ren); } else { rendererBin->color(face.second); - theRasterizer->add_path(curve); agg::render_scanlines(*theRasterizer, *slineP8, *rendererBin); } } @@ -945,7 +945,7 @@ Py::SeqBase<Py::Object> paths = args[4]; Py::SeqBase<Py::Object> transforms_obj = args[5]; Py::Object offsets_obj = args[6]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7], false); + agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); Py::Object facecolors_obj = args[8]; Py::Object edgecolors_obj = args[9]; Py::SeqBase<Py::Float> linewidths = args[10]; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-12 17:30:22
|
Revision: 3939 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3939&view=rev Author: mdboom Date: 2007-10-12 10:30:17 -0700 (Fri, 12 Oct 2007) Log Message: ----------- More progress on examples. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/collections_demo.py branches/transforms/examples/simple_plot_fps.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/colorbar.py branches/transforms/lib/matplotlib/contour.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/ticker.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/PASSED_DEMOS 2007-10-12 17:30:17 UTC (rev 3939) @@ -16,10 +16,10 @@ arctest.py O arrow_demo.py O axes_demo.py O -axes_props.py [SOMETHING FUNNY ABOUT DASHED LINES] +axes_props.py O axhspan_demo.py O axis_equal_demo.py O -backend_driver.py +backend_driver.py [N/A] barchart_demo.py O barcode_demo.py O barh_demo.py [BROKEN IN TRUNK] @@ -29,14 +29,14 @@ broken_barh.py O clippath_test.py O clippedline.py O -collections_demo.py -- [NEEDS ADDITIONAL WORK] +collections_demo.py O colorbar_only.py O color_by_yvalue.py O color_demo.py O colours.py [???] -contour_demo.py -contourf_demo.py -contour_image.py +contour_demo.py O +contourf_demo.py [FLOATING POINT EXCEPTION] +contour_image.py [FLOATING POINT EXCEPTION] coords_demo.py O coords_report.py O csd_demo.py O Modified: branches/transforms/examples/collections_demo.py =================================================================== --- branches/transforms/examples/collections_demo.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/examples/collections_demo.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -87,7 +87,7 @@ a = fig.add_subplot(2,2,3) col = collections.RegularPolyCollection(fig.dpi, 7, - sizes = N.fabs(xx) / 10.0, offsets=xyo, + sizes = N.fabs(xx)*10.0, offsets=xyo, transOffset=a.transData) trans = transforms.Affine2D().scale(fig.dpi/72.0) col.set_transform(trans) # the points to pixels transform Modified: branches/transforms/examples/simple_plot_fps.py =================================================================== --- branches/transforms/examples/simple_plot_fps.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/examples/simple_plot_fps.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -21,11 +21,13 @@ #savefig('simple_plot') import time - +from matplotlib import transforms + frames = 100.0 t = time.clock() ion() for i in xrange(int(frames)): + transforms.CATCH = True part = i / frames axis([0.0, 1.0 - part, -1.0 + part, 1.0 - part]) show() Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -1110,7 +1110,6 @@ # and the data in xydata # MGDTODO: This isn't always the most efficient way to do this... in # some cases things should use update_datalim_bounds - if not ma.isMaskedArray(xys): xys = npy.asarray(xys) self.update_datalim_numerix(xys[:, 0], xys[:, 1]) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -91,16 +91,18 @@ self._size = size self._padPixels = self.figure.dpi * self._pad * (1/72.0) + self._locTransform = Affine2D() + + self.tick1line = self._get_tick1line() + self.tick2line = self._get_tick2line() + self.gridline = self._get_gridline() - - self.tick1line = self._get_tick1line(loc) - self.tick2line = self._get_tick2line(loc) - self.gridline = self._get_gridline(loc) - - self.label1 = self._get_text1(loc) + self.label1 = self._get_text1() self.label = self.label1 # legacy name - self.label2 = self._get_text2(loc) + self.label2 = self._get_text2() + self.update_position(loc) + self.gridOn = gridOn self.tick1On = tick1On self.tick2On = tick2On @@ -138,23 +140,23 @@ 'Get the value of the tick label pad in points' return self._pad.get() - def _get_text1(self, loc): + def _get_text1(self): 'Get the default Text 1 instance' pass - def _get_text2(self, loc): + def _get_text2(self): 'Get the default Text 2 instance' pass - def _get_tick1line(self, loc): + def _get_tick1line(self): 'Get the default line2D instance for tick1' pass - def _get_tick2line(self, loc): + def _get_tick2line(self): 'Get the default line2D instance for tick2' pass - def _get_gridline(self, loc): + def _get_gridline(self): 'Get the default grid Line2d instance for this tick' pass @@ -183,22 +185,6 @@ renderer.close_group(self.__name__) - def set_xy(self, loc): - """ - Set the location of tick in data coords with scalar loc - - ACCEPTS: float - """ - raise NotImplementedError('Derived must override') - - def set_label(self, s): # legacy name - """ - Set the text of ticklabel - - ACCEPTS: str - """ - self.label1.set_text(s) - def set_label1(self, s): """ Set the text of ticklabel @@ -206,7 +192,8 @@ ACCEPTS: str """ self.label1.set_text(s) - + set_label = set_label1 + def set_label2(self, s): """ Set the text of ticklabel2 @@ -233,7 +220,7 @@ the label text and the grid line """ __name__ = 'xtick' - def _get_text1(self, loc): + def _get_text1(self): 'Get the default Text instance' # the y loc is 3 points below the min of y axis # get the affine as an a,b,c,d,tx,ty list @@ -242,7 +229,7 @@ trans, vert, horiz = self.axes.get_xaxis_text1_transform(self._padPixels) t = TextWithDash( - x=loc, y=0, + x=0, y=0, fontproperties=FontProperties(size=rcParams['xtick.labelsize']), color=rcParams['xtick.color'], verticalalignment=vert, @@ -256,15 +243,15 @@ return t - def _get_text2(self, loc): + def _get_text2(self): 'Get the default Text 2 instance' # x in data coords, y in axes coords #t = Text( trans, vert, horiz = self.axes.get_xaxis_text2_transform(self._padPixels) - t = TextWithDash( - x=loc, y=1, + t = TextWithDash( + x=0, y=1, fontproperties=FontProperties(size=rcParams['xtick.labelsize']), color=rcParams['xtick.color'], verticalalignment=vert, @@ -272,60 +259,55 @@ xaxis=True, horizontalalignment=horiz, ) - t.set_transform(trans) self._set_artist_props(t) return t - def _get_tick1line(self, loc): + def _get_tick1line(self): 'Get the default line2D instance' # x in data coords, y in axes coords - l = Line2D( xdata=(loc,), ydata=(0,), - color='k', - linestyle = 'None', - marker = self._xtickmarkers[0], - markersize=self._size, - ) + l = Line2D(xdata=(0,), ydata=(0,), + color='k', + linestyle = 'None', + marker = self._xtickmarkers[0], + markersize=self._size, + ) l.set_transform(self.axes.get_xaxis_transform()) self._set_artist_props(l) return l - def _get_tick2line(self, loc): + def _get_tick2line(self): 'Get the default line2D instance' # x in data coords, y in axes coords - l = Line2D( xdata=(loc,), ydata=(1,), + l = Line2D( xdata=(0,), ydata=(1,), color='k', linestyle = 'None', marker = self._xtickmarkers[1], markersize=self._size, ) - l.set_transform(self.axes.get_xaxis_transform()) + l.set_transform(self._locTransform + self.axes.get_xaxis_transform()) self._set_artist_props(l) return l - def _get_gridline(self, loc): + def _get_gridline(self): 'Get the default line2D instance' # x in data coords, y in axes coords - l = Line2D(xdata=(loc, loc), ydata=(0, 1.0), + l = Line2D(xdata=(0.0, 0.0), ydata=(0, 1.0), color=rcParams['grid.color'], linestyle=rcParams['grid.linestyle'], linewidth=rcParams['grid.linewidth'], ) - l.set_transform(self.axes.get_xaxis_transform()) + l.set_transform(self._locTransform + self.axes.get_xaxis_transform()) self._set_artist_props(l) return l def update_position(self, loc): 'Set the location of tick in data coords with scalar loc' - x = loc - - self.tick1line.set_xdata((x,)) - self.tick2line.set_xdata((x,)) - self.gridline.set_xdata((x, )) - self.label1.set_x(x) - self.label2.set_x(x) + self._locTransform.clear().translate(loc, 0.0) + self.label1.set_x(loc) + self.label2.set_x(loc) self._loc = loc def get_view_interval(self): @@ -355,14 +337,14 @@ __name__ = 'ytick' # how far from the y axis line the right of the ticklabel are - def _get_text1(self, loc): + def _get_text1(self): 'Get the default Text instance' # x in axes coords, y in data coords #t = Text( trans, vert, horiz = self.axes.get_yaxis_text1_transform(self._padPixels) t = TextWithDash( - x=0, y=loc, + x=0, y=0, fontproperties=FontProperties(size=rcParams['ytick.labelsize']), color=rcParams['ytick.color'], verticalalignment=vert, @@ -375,14 +357,14 @@ self._set_artist_props(t) return t - def _get_text2(self, loc): + def _get_text2(self): 'Get the default Text instance' # x in axes coords, y in data coords #t = Text( trans, vert, horiz = self.axes.get_yaxis_text2_transform(self._padPixels) - t = TextWithDash( - x=1, y=loc, + t = TextWithDash( + x=1, y=0, fontproperties=FontProperties(size=rcParams['ytick.labelsize']), color=rcParams['ytick.color'], verticalalignment=vert, @@ -394,20 +376,20 @@ self._set_artist_props(t) return t - def _get_tick1line(self, loc): + def _get_tick1line(self): 'Get the default line2D instance' # x in axes coords, y in data coords - l = Line2D( (0,), (loc,), color='k', + l = Line2D( (0,), (0,), color='k', marker = self._ytickmarkers[0], linestyle = 'None', markersize=self._size, ) - l.set_transform(self.axes.get_yaxis_transform()) + l.set_transform(self._locTransform + self.axes.get_yaxis_transform()) self._set_artist_props(l) return l - def _get_tick2line(self, loc): + def _get_tick2line(self): 'Get the default line2D instance' # x in axes coords, y in data coords l = Line2D( (1,), (0,), color='k', @@ -416,34 +398,29 @@ markersize=self._size, ) - l.set_transform(self.axes.get_yaxis_transform()) + l.set_transform(self._locTransform + self.axes.get_yaxis_transform()) self._set_artist_props(l) return l - def _get_gridline(self, loc): + def _get_gridline(self): 'Get the default line2D instance' # x in axes coords, y in data coords - l = Line2D( xdata=(0,1), ydata=(loc,loc), + l = Line2D( xdata=(0,1), ydata=(0, 0), color=rcParams['grid.color'], linestyle=rcParams['grid.linestyle'], linewidth=rcParams['grid.linewidth'], ) - l.set_transform(self.axes.get_yaxis_transform()) + l.set_transform(self._locTransform + self.axes.get_yaxis_transform()) self._set_artist_props(l) return l def update_position(self, loc): 'Set the location of tick in data coords with scalar loc' - y = loc - self.tick1line.set_ydata((y,)) - self.tick2line.set_ydata((y,)) - self.gridline.set_ydata((y, )) - - self.label1.set_y( y ) - self.label2.set_y( y ) - + self._locTransform.clear().translate(0.0, loc) + self.label1.set_y(loc) + self.label2.set_y(loc) self._loc = loc @@ -558,9 +535,11 @@ popall(self.majorTicks) popall(self.minorTicks) - self.majorTicks.extend([self._get_tick(major=True) for i in range(1)]) - self.minorTicks.extend([self._get_tick(major=False) for i in range(1)]) - + self.majorTicks.extend([self._get_tick(major=True)]) + self.minorTicks.extend([self._get_tick(major=False)]) + self._lastNumMajorTicks = 1 + self._lastNumMinorTicks = 1 + self.converter = None self.units = None self.set_units(None) @@ -744,16 +723,21 @@ 'get the tick instances; grow as necessary' if numticks is None: numticks = len(self.get_major_locator()()) - - if len(self.majorTicks)<numticks: + + if len(self.majorTicks) < numticks: # update the new tick label properties from the old - protoTick = self.majorTicks[0] - for i in range(numticks-len(self.majorTicks)): + for i in range(numticks - len(self.majorTicks)): tick = self._get_tick(major=True) - #tick = protoTick + self.majorTicks.append(tick) + + if self._lastNumMajorTicks < numticks: + protoTick = self.majorTicks[0] + for i in range(self._lastNumMajorTicks, len(self.majorTicks)): + tick = self.majorTicks[i] if self._gridOnMajor: tick.gridOn = True self._copy_tick_props(protoTick, tick) - self.majorTicks.append(tick) + + self._lastNumMajorTicks = numticks ticks = self.majorTicks[:numticks] return ticks @@ -764,13 +748,20 @@ if numticks is None: numticks = len(self.get_minor_locator()()) - if len(self.minorTicks)<numticks: + if len(self.minorTicks) < numticks: + # update the new tick label properties from the old + for i in range(numticks - len(self.minorTicks)): + tick = self._get_tick(minor=True) + self.minorTicks.append(tick) + + if self._lastNumMinorTicks < numticks: protoTick = self.minorTicks[0] - for i in range(numticks-len(self.minorTicks)): - tick = self._get_tick(major=False) + for i in range(self._lastNumMinorTicks, len(self.minorTicks)): + tick = self.minorTicks[i] if self._gridOnMinor: tick.gridOn = True self._copy_tick_props(protoTick, tick) - self.minorTicks.append(tick) + + self._lastNumMinorTicks = numticks ticks = self.minorTicks[:numticks] return ticks @@ -946,7 +937,6 @@ self.set_major_formatter( FixedFormatter(ticklabels) ) - ret = [] for i, tick in enumerate(self.get_major_ticks()): if i<len(ticklabels): Modified: branches/transforms/lib/matplotlib/colorbar.py =================================================================== --- branches/transforms/lib/matplotlib/colorbar.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/colorbar.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -314,8 +314,7 @@ b = self._boundaries[self._inside] locator = ticker.FixedLocator(b, nbins=10) if isinstance(self.norm, colors.NoNorm): - intv = transforms.Interval(transforms.Value(self._values[0]), - transforms.Value(self._values[-1])) + intv = self._values[0], self._values[-1] else: intv = self.vmin, self.vmax locator.create_dummy_axis() Modified: branches/transforms/lib/matplotlib/contour.py =================================================================== --- branches/transforms/lib/matplotlib/contour.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/contour.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -8,6 +8,7 @@ import numpy as npy import matplotlib.numerix.npyma as ma import matplotlib._cntr as _cntr +import matplotlib.path as path import matplotlib.ticker as ticker import matplotlib.transforms as transforms import matplotlib.cm as cm @@ -210,7 +211,7 @@ trans = self.ax.transData - slc = trans.seq_xy_tups(linecontour) + slc = trans.transform(linecontour) x,y = slc[ind] xx= npy.asarray(slc)[:,0].copy() yy=npy.asarray(slc)[:,1].copy() @@ -247,8 +248,9 @@ new_x1, new_y1 = x-xlabel, y-ylabel new_x2, new_y2 = x+xlabel, y+ylabel - new_x1d, new_y1d = trans.inverse_xy_tup((new_x1, new_y1)) - new_x2d, new_y2d = trans.inverse_xy_tup((new_x2, new_y2)) + inverse = trans.inverted() + new_x1d, new_y1d = inverse.transform_point((new_x1, new_y1)) + new_x2d, new_y2d = inverse.transform_point((new_x2, new_y2)) new_xy1 = npy.array(((new_x1d, new_y1d),)) new_xy2 = npy.array(((new_x2d, new_y2d),)) @@ -333,20 +335,22 @@ con = self.collections[icon] lw = self.get_label_width(lev, fmt, fsize) additions = [] - for segNum, linecontour in enumerate(con._segments): + paths = con.get_paths() + for segNum, linepath in enumerate(paths): + linecontour = linepath.vertices # for closed contours add one more point to # avoid division by zero if npy.all(linecontour[0] == linecontour[-1]): linecontour = npy.concatenate((linecontour, - linecontour[1][npy.newaxis,:])) + linecontour[1][npy.newaxis,:])) #linecontour.append(linecontour[1]) # transfer all data points to screen coordinates - slc = trans.seq_xy_tups(linecontour) + slc = trans.transform(linecontour) if self.print_label(slc,lw): x,y, rotation, ind = self.locate_label(slc, lw) # transfer the location of the label back to # data coordinates - dx,dy = trans.inverse_xy_tup((x,y)) + dx,dy = trans.inverted().transform_point((x,y)) t = text.Text(dx, dy, rotation = rotation, horizontalalignment='center', verticalalignment='center') @@ -355,12 +359,14 @@ self.cl.append(t) self.cl_cvalues.append(cvalue) if inline: - new = self.break_linecontour(linecontour, rotation, - lw, ind) - con._segments[segNum] = new[0] - additions.append(new[1]) - con._segments.extend(additions) + new = self.break_linecontour(linecontour, rotation, lw, ind) + if len(new[0]): + paths[segNum] = path.Path(new[0], closed=False) + if len(new[1]): + additions.append(path.Path(new[1], closed=False)) + paths.extend(additions) + class ContourSet(cm.ScalarMappable, ContourLabeler): """ Create and store a set of contour lines or filled regions. @@ -494,6 +500,7 @@ ''' if self.locator is None: self.locator = ticker.MaxNLocator(N+1) + self.locator.create_dummy_axis() locator = self.locator zmax = self.zmax zmin = self.zmin Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/text.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -172,7 +172,6 @@ self._linespacing = other._linespacing def _get_layout(self, renderer): - # layout the xylocs in display coords as if angle = zero and # then rotate them around self._x, self._y #return _unit_box @@ -327,11 +326,10 @@ self._fontproperties, angle) return + canvasw, canvash = renderer.get_canvas_width_height() for line, wh, x, y in info: x, y = trans.transform_point((x, y)) - if renderer.flipy(): - canvasw, canvash = renderer.get_canvas_width_height() y = canvash-y renderer.draw_text(gc, x, y, line, Modified: branches/transforms/lib/matplotlib/ticker.py =================================================================== --- branches/transforms/lib/matplotlib/ticker.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/ticker.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -145,6 +145,11 @@ def set_data_interval(self, vmin, vmax): self.axis.set_data_interval(vmin, vmax) + + def set_bounds(self, vmin, vmax): + self.set_view_interval(vmin, vmax) + self.set_data_interval(vmin, vmax) + class Formatter(TickHelper): """ Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-12 17:30:17 UTC (rev 3939) @@ -32,8 +32,10 @@ import cbook from path import Path -DEBUG = True +DEBUG = False +# MGDTODO: Cache get_affine??? + class TransformNode(object): """ TransformNode is the base class for anything that participates in @@ -81,7 +83,7 @@ # A list of the children is kept around for debugging purposes # only. self._children = [] - + def __copy__(self, *args): raise NotImplementedError( "TransformNode instances can not be copied. " + @@ -402,13 +404,13 @@ self._points[0] + (W, H)]) def splitx(self, *args): - ''' + """ e.g., bbox.splitx(f1, f2, ...) Returns a list of new BBoxes formed by splitting the original one with vertical lines at fractional positions f1, f2, ... - ''' + """ boxes = [] xf = [0] + list(args) + [1] l, b, r, t = self.lbrt @@ -418,13 +420,13 @@ return boxes def splity(self, *args): - ''' + """ e.g., bbox.splitx(f1, f2, ...) Returns a list of new PBoxes formed by splitting the original one with horizontal lines at fractional positions f1, f2, ... - ''' + """ boxes = [] yf = [0] + list(args) + [1] l, b, r, t = self.lbrt @@ -434,6 +436,11 @@ return boxes def count_contains(self, vertices): + """ + Count the number of vertices contained in the Bbox. + + vertices is a Nx2 numpy array. + """ if len(vertices) == 0: return 0 vertices = npy.asarray(vertices) @@ -446,6 +453,11 @@ return N.sum(inside) def count_overlaps(self, bboxes): + """ + Count the number of bounding boxes that overlap this one. + + bboxes is a sequence of Bbox objects + """ ax1, ay1, ax2, ay2 = self._get_lbrt() if ax2 < ax1: ax2, ax1 = ax1, ax2 @@ -454,7 +466,9 @@ count = 0 for bbox in bboxes: - bx1, by1, bx2, by2 = bbox._get_lbrt() + # bx1, by1, bx2, by2 = bbox._get_lbrt() + # The above, inlined... + bx1, by1, bx2, by2 = bbox.get_points().flatten() if bx2 < bx1: bx2, bx1 = bx1, bx2 if by2 < by1: @@ -464,7 +478,53 @@ (bx1 >= ax2) or (by1 >= ay2))) return count - + + def expanded(self, sw, sh): + """ + Return a new Bbox which is this Bbox expanded around its + center by the given factors sw and 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) + + def translated(self, tx, ty): + """ + Return a copy of the Bbox, translated by tx and ty. + """ + return Bbox(self._points + (tx, ty)) + + #@staticmethod + def union(bboxes): + """ + Return a Bbox that contains all of the given bboxes. + """ + assert(len(bboxes)) + + if len(bboxes) == 1: + return bboxes[0] + + xmin = npy.inf + ymin = npy.inf + xmax = -npy.inf + ymax = -npy.inf + + for bbox in bboxes: + points = bbox.get_points() + xs = points[:, 0] + ys = points[:, 1] + xmin = min(xmin, npy.min(xs)) + ymin = min(ymin, npy.min(ys)) + xmax = max(xmax, npy.max(xs)) + ymax = max(ymax, npy.max(ys)) + + return Bbox.from_lbrt(xmin, ymin, xmax, ymax) + union = staticmethod(union) + + class Bbox(BboxBase): def __init__(self, points): """ @@ -535,7 +595,6 @@ when None, use the last value passed to Bbox.ignore(). """ # MGDTODO: It may be more efficient for some callers to use update_from_data_xy instead - if ignore is None: ignore = self._ignore @@ -569,7 +628,6 @@ max(y.max(), self.ymax)]], npy.float_) self._minpos = npy.minimum(minpos, self._minpos) - self.invalidate() def update_from_data_xy(self, xy, ignore=None): @@ -665,52 +723,7 @@ """ self._points = other.get_points() self.invalidate() - - def expanded(self, sw, sh): - """ - Return a new Bbox which is this Bbox expanded around its - center by the given factors sw and 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) - def translated(self, tx, ty): - """ - Return a copy of the Bbox, translated by tx and ty. - """ - return Bbox(self._points + (tx, ty)) - - #@staticmethod - def union(bboxes): - """ - Return a Bbox that contains all of the given bboxes. - """ - assert(len(bboxes)) - - if len(bboxes) == 1: - return bboxes[0] - - xmin = npy.inf - ymin = npy.inf - xmax = -npy.inf - ymax = -npy.inf - - for bbox in bboxes: - points = bbox.get_points() - xs = points[:, 0] - ys = points[:, 1] - xmin = min(xmin, npy.min(xs)) - ymin = min(ymin, npy.min(ys)) - xmax = max(xmax, npy.max(xs)) - ymax = max(ymax, npy.max(ys)) - - return Bbox.from_lbrt(xmin, ymin, xmax, ymax) - union = staticmethod(union) - class TransformedBbox(BboxBase): """ @@ -1633,15 +1646,39 @@ else: return npy.concatenate((x_points, y_points), 1) transform.__doc__ = Transform.transform.__doc__ - - transform_non_affine = transform + + def transform_affine(self, points): + if self._x.is_affine and self._y.is_affine: + return self.transform(points) + return points + transform_affine.__doc__ = Transform.transform_affine.__doc__ + + def transform_non_affine(self, points): + if self._x.is_affine and self._y.is_affine: + return points + return self.transform(points) transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ def inverted(self): return BlendedGenericTransform(self._x.inverted(), self._y.inverted()) inverted.__doc__ = Transform.inverted.__doc__ - + def get_affine(self): + if self._x.is_affine and self._y.is_affine: + if self._x == self._y: + return self._x.get_affine() + else: + x_mtx = self._x.get_affine().get_matrix() + y_mtx = self._y.get_affine().get_matrix() + # This works because we already know the transforms are + # separable, though normally one would want to set b and + # c to zero. + mtx = npy.vstack((x_mtx[0], y_mtx[1], [0.0, 0.0, 1.0])) + return Affine2D(mtx) + return IdentityTransform() + get_affine.__doc__ = Transform.get_affine.__doc__ + + class BlendedAffine1D(Affine2DBase): """ A "blended" transform uses one transform for the x-direction, and @@ -1807,7 +1844,7 @@ is_affine = property(_get_is_affine) def _get_is_separable(self): - return self._a.is_separable() and self._b.is_separable() + return self._a.is_separable and self._b.is_separable is_separable = property(_get_is_separable) def __repr__(self): @@ -1838,7 +1875,7 @@ def transform_path_affine(self, path): return self._b.transform_path_affine( - self._a.transform(path)) + self._a.transform_path(path)) transform_path_affine.__doc__ = Transform.transform_path_affine.__doc__ def transform_path_non_affine(self, path): @@ -1850,7 +1887,8 @@ def get_affine(self): if self._a.is_affine and self._b.is_affine: - return CompositeAffine2D(self._a.get_affine(), self._b.get_affine()) + return Affine2D(npy.dot(self._b.get_affine().get_matrix(), + self._a.get_affine().get_matrix())) return self._b.get_affine() get_affine.__doc__ = Transform.get_affine.__doc__ Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-12 14:29:57 UTC (rev 3938) +++ branches/transforms/src/_backend_agg.cpp 2007-10-12 17:30:17 UTC (rev 3939) @@ -82,7 +82,10 @@ return agg::trans_affine(a, b, c, d, e, f); } } catch (...) { - + if (errors) { + Py_XDECREF(matrix); + throw; + } } Py_XDECREF(matrix); @@ -333,8 +336,10 @@ bool RendererAgg::bbox_to_rect(const Py::Object& bbox_obj, double* l, double* b, double* r, double* t) { + PyArrayObject* bbox = NULL; + if (bbox_obj.ptr() != Py_None) { - PyArrayObject* bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), PyArray_DOUBLE, 2, 2); + bbox = (PyArrayObject*) PyArray_FromObject(bbox_obj.ptr(), PyArray_DOUBLE, 2, 2); if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { Py_XDECREF(bbox); @@ -559,9 +564,9 @@ PathIterator path(path_obj); transformed_path_t path_transformed(path, trans); - bool snap = should_snap(path, trans); - GCAgg gc = GCAgg(gc_obj, dpi, snap); - quantize_t path_quantized(path_transformed, snap); + // bool snap = should_snap(path, trans); + GCAgg gc = GCAgg(gc_obj, dpi, true); + quantize_t path_quantized(path_transformed, true); path_quantized.rewind(0); facepair_t face = _get_rgba_face(face_obj, gc.alpha); @@ -638,6 +643,7 @@ } catch(...) { delete[] fillCache; delete[] strokeCache; + throw; } delete [] fillCache; @@ -879,7 +885,7 @@ theRasterizer->add_path(stroke); } - if (gc.isaa && !(snap && gc.dashes.size())) { + if (gc.isaa && !(snap && gc.linewidth < 1.5)) { if (has_clippath) { pixfmt_amask_type pfa(*pixFmt, *alphaMask); amask_ren_type r(pfa); @@ -954,99 +960,110 @@ GCAgg gc(dpi, false); - PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) - throw Py::ValueError("Offsets array must be Nx2"); + PyArrayObject* offsets = NULL; + PyArrayObject* facecolors = NULL; + PyArrayObject* edgecolors = NULL; - PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); - if (!facecolors || - (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || - (facecolors->nd == 2 && facecolors->dimensions[1] != 4)) - throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty"); + try { + offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!offsets || offsets->dimensions[1] != 2) + throw Py::ValueError("Offsets array must be Nx2"); - PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); - if (!edgecolors || - (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || - (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) - throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); + PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + if (!facecolors || + (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || + (facecolors->nd == 2 && facecolors->dimensions[1] != 4)) + throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty"); - size_t Npaths = paths.length(); - size_t Noffsets = offsets->dimensions[0]; - size_t N = std::max(Npaths, Noffsets); - size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t Nfacecolors = facecolors->dimensions[0]; - size_t Nedgecolors = edgecolors->dimensions[0]; - size_t Nlinewidths = linewidths.length(); - size_t Nlinestyles = std::min(linestyles_obj.length(), N); - size_t Naa = antialiaseds.length(); + PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + if (!edgecolors || + (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || + (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) + throw Py::ValueError("Edgecolors must be a Nx4 numpy array"); + + size_t Npaths = paths.length(); + size_t Noffsets = offsets->dimensions[0]; + size_t N = std::max(Npaths, Noffsets); + size_t Ntransforms = std::min(transforms_obj.length(), N); + size_t Nfacecolors = facecolors->dimensions[0]; + size_t Nedgecolors = edgecolors->dimensions[0]; + size_t Nlinewidths = linewidths.length(); + size_t Nlinestyles = std::min(linestyles_obj.length(), N); + size_t Naa = antialiaseds.length(); - if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0) - return Py::Object(); - - size_t i = 0; - - // Convert all of the transforms up front - typedef std::vector<agg::trans_affine> transforms_t; - transforms_t transforms; - transforms.reserve(Ntransforms); - for (i = 0; i < Ntransforms; ++i) { - agg::trans_affine trans = py_to_agg_transformation_matrix - (transforms_obj[i], false); - trans *= master_transform; - transforms.push_back(trans); - } - - // Convert all the dashes up front - typedef std::vector<std::pair<double, GCAgg::dash_t> > dashes_t; - dashes_t dashes; - dashes.resize(Nlinestyles); - i = 0; - for (dashes_t::iterator d = dashes.begin(); - d != dashes.end(); ++d, ++i) { - convert_dashes(Py::Tuple(linestyles_obj[i]), false, dpi, d->second, d->first); - } - - // Handle any clipping globally - theRasterizer->reset_clipping(); - rendererBase->reset_clipping(true); - set_clipbox(cliprect, theRasterizer); - bool has_clippath = render_clippath(clippath, clippath_trans); - - // Set some defaults, assuming no face or edge - gc.linewidth = 0.0; - facepair_t face; - face.first = Nfacecolors != 0; - - for (i = 0; i < N; ++i) { - PathIterator path(paths[i % Npaths]); - bool snap = (path.total_vertices() == 2); - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine& trans = transforms[i % Ntransforms]; - - if (Nfacecolors) { - size_t fi = i % Nfacecolors; - face.second = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0), - *(double*)PyArray_GETPTR2(facecolors, fi, 1), - *(double*)PyArray_GETPTR2(facecolors, fi, 2), - *(double*)PyArray_GETPTR2(facecolors, fi, 3)); + if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0) + return Py::Object(); + + size_t i = 0; + + // Convert all of the transforms up front + typedef std::vector<agg::trans_affine> transforms_t; + transforms_t transforms; + transforms.reserve(Ntransforms); + for (i = 0; i < Ntransforms; ++i) { + agg::trans_affine trans = py_to_agg_transformation_matrix + (transforms_obj[i], false); + trans *= master_transform; + transforms.push_back(trans); } - - if (Nedgecolors) { - size_t ei = i % Nedgecolors; - gc.color = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0), - *(double*)PyArray_GETPTR2(edgecolors, ei, 1), - *(double*)PyArray_GETPTR2(edgecolors, ei, 2), - *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); - gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; - gc.dashes = dashes[i % Nlinestyles].second; - gc.dashOffset = dashes[i % Nlinestyles].first; + + // Convert all the dashes up front + typedef std::vector<std::pair<double, GCAgg::dash_t> > dashes_t; + dashes_t dashes; + dashes.resize(Nlinestyles); + i = 0; + for (dashes_t::iterator d = dashes.begin(); + d != dashes.end(); ++d, ++i) { + convert_dashes(Py::Tuple(linestyles_obj[i]), false, dpi, d->second, d->first); } - - gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); + + // Handle any clipping globally + theRasterizer->reset_clipping(); + rendererBase->reset_clipping(true); + set_clipbox(cliprect, theRasterizer); + bool has_clippath = render_clippath(clippath, clippath_trans); + + // Set some defaults, assuming no face or edge + gc.linewidth = 0.0; + facepair_t face; + face.first = Nfacecolors != 0; + + for (i = 0; i < N; ++i) { + PathIterator path(paths[i % Npaths]); + bool snap = (path.total_vertices() == 2); + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + agg::trans_affine_translation transOffset(xo, yo); + agg::trans_affine& trans = transforms[i % Ntransforms]; + + if (Nfacecolors) { + size_t fi = i % Nfacecolors; + face.second = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0), + *(double*)PyArray_GETPTR2(facecolors, fi, 1), + *(double*)PyArray_GETPTR2(facecolors, fi, 2), + *(double*)PyArray_GETPTR2(facecolors, fi, 3)); + } + + if (Nedgecolors) { + size_t ei = i % Nedgecolors; + gc.color = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0), + *(double*)PyArray_GETPTR2(edgecolors, ei, 1), + *(double*)PyArray_GETPTR2(edgecolors, ei, 2), + *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; + } + + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); + } + } catch (...) { + Py_XDECREF(offsets); + Py_XDECREF(facecolors); + Py_XDECREF(edgecolors); + throw; } Py_XDECREF(offsets); @@ -1518,18 +1535,15 @@ void get_path_extents(PathIterator& path, agg::trans_affine& trans, double* x0, double* y0, double* x1, double* y1) { - typedef agg::conv_curve<PathIterator> curve_t; - - curve_t curved_path(path); + typedef agg::conv_transform<PathIterator> transformed_path_t; + typedef agg::conv_curve<transformed_path_t> curve_t; double x, y; - curved_path.rewind(0); + unsigned code; - unsigned code = curved_path.vertex(&x, &y); + transformed_path_t tpath(path, trans); + curve_t curved_path(tpath); - *x0 = x; - *y0 = y; - *x1 = x; - *y1 = y; + curved_path.rewind(0); while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) { if (code & agg::path_cmd_end_poly == agg::path_cmd_end_poly) @@ -1539,9 +1553,6 @@ if (x > *x1) *x1 = x; if (y > *y1) *y1 = y; } - - trans.transform(x0, y0); - trans.transform(x1, y1); } Py::Object _backend_agg_module::get_path_extents(const Py::Tuple& args) { @@ -1550,7 +1561,11 @@ PathIterator path(args[0]); agg::trans_affine trans = py_to_agg_transformation_matrix(args[1]); - double x0, y0, x1, y1; + double x0 = std::numeric_limits<double>::infinity(); + double y0 = std::numeric_limits<double>::infinity(); + double x1 = -std::numeric_limits<double>::infinity(); + double y1 = -std::numeric_limits<double>::infinity(); + ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); Py::Tuple result(4); @@ -1561,10 +1576,6 @@ return result; } -struct PathCollectionExtents { - double x0, y0, x1, y1; -}; - Py::Object _backend_agg_module::get_path_collection_extents(const Py::Tuple& args) { args.verify_length(5); @@ -1572,57 +1583,58 @@ agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); Py::SeqBase<Py::Object> paths = args[1]; Py::SeqBase<Py::Object> transforms_obj = args[2]; - Py::SeqBase<Py::Object> offsets = args[3]; + Py::Object offsets_obj = args[3]; agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[4], false); - size_t Npaths = paths.length(); - size_t Noffsets = offsets.length(); - size_t N = std::max(Npaths, Noffsets); - size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t i; + PyArrayObject* offsets = NULL; + double x0, y0, x1, y1; - // Convert all of the transforms up front - typedef std::vector<agg::trans_affine> transforms_t; - transforms_t transforms; - transforms.reserve(Ntransforms); - for (i = 0; i < Ntransforms; ++i) { - agg::trans_affine trans = py_to_agg_transformation_matrix - (transforms_obj[i], false); - trans *= master_transform; - transforms.push_back(trans); - } - - typedef std::vector<PathCollectionExtents> path_extents_t; - path_extents_t path_extents; - path_extents.resize(Npaths); + try { + offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); + if (!offsets || offsets->dimensions[1] != 2) + throw Py::ValueError("Offsets array must be Nx2"); - // Get each of the path extents first - i = 0; - for (path_extents_t::iterator p = path_extents.begin(); - p != path_extents.end(); ++p, ++i) { - PathIterator path(paths[i]); - agg::trans_affine& trans = transforms[i % Ntransforms]; - ::get_path_extents(path, trans, &p->x0, &p->y0, &p->x1, &p->y1); - } + size_t Npaths = paths.length(); + size_t Noffsets = offsets->dimensions[0]; + size_t N = std::max(Npaths, Noffsets); + size_t Ntransforms = std::min(transforms_obj.length(), N); + size_t i; - // The offset each of those and collect the mins/maxs - double x0 = std::numeric_limits<double>::infinity(); - double y0 = std::numeric_limits<double>::infinity(); - double x1 = -std::numeric_limits<double>::infinity(); - double y1 = -std::numeric_limits<double>::infinity(); - for (i = 0; i < N; ++i) { - Py::SeqBase<Py::Float> offset = Py::SeqBase<Py::Float>(offsets[i % Noffsets]); - double xo = Py::Float(offset[0]); - double yo = Py::Float(offset[1]); - offset_trans.transform(&xo, &yo); - PathCollectionExtents& ext = path_extents[i % Npaths]; + // Convert all of the transforms up front + typedef std::vector<agg::trans_affine> transforms_t; + transforms_t transforms; + transforms.reserve(Ntransforms); + for (i = 0; i < Ntransforms; ++i) { + agg::trans_affine trans = py_to_agg_transformation_matrix + (transforms_obj[i], false); + trans *= master_transform; + transforms.push_back(trans); + } + + // The offset each of those and collect the mins/maxs + x0 = std::numeric_limits<double>::infinity(); + y0 = std::numeric_limits<double>::infinity(); + x1 = -std::numeric_limits<double>::infinity(); + y1 = -std::numeric_limits<double>::infinity(); + for (i = 0; i < N; ++i) { + PathIterator path(paths[i % Npaths]); + + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + agg::trans_affine_translation transOffset(xo, yo); + agg::trans_affine trans = transforms[i % Ntransforms]; + trans *= transOffset; - x0 = std::min(x0, ext.x0 + xo); - y0 = std::min(y0, ext.y0 + yo); - x1 = std::max(x1, ext.x1 + xo); - y1 = std::max(y1, ext.y1 + yo); + ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); + } + } catch (...) { + Py_XDECREF(offsets); + throw; } + Py_XDECREF(offsets); + Py::Tuple result(4); result[0] = Py::Float(x0); result[1] = Py::Float(y0); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-15 14:03:49
|
Revision: 3948 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3948&view=rev Author: mdboom Date: 2007-10-15 07:03:19 -0700 (Mon, 15 Oct 2007) Log Message: ----------- Merged revisions 3933-3947 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3935 | mdboom | 2007-10-11 13:03:50 -0400 (Thu, 11 Oct 2007) | 1 line Fixed minor import bug ........ r3941 | jdh2358 | 2007-10-14 15:00:50 -0400 (Sun, 14 Oct 2007) | 1 line added ellipse compare script ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_ps.py Added Paths: ----------- branches/transforms/unit/ellipse_compare.py Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-15 13:49:25 UTC (rev 3947) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-10-15 14:03:19 UTC (rev 3948) @@ -109,8 +109,9 @@ debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', 'debug-annoying') - #self.draw_path = self._renderer.draw_path - #self.draw_markers = self._renderer.draw_markers + self.draw_path = self._renderer.draw_path + self.draw_markers = self._renderer.draw_markers + self.draw_path_collection = self._renderer.draw_path_collection self.draw_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region @@ -121,26 +122,6 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') - def draw_path(self, gc, path, trans, rgbFace=None): - assert trans.is_affine - self._renderer.draw_path(gc, path, trans.frozen(), rgbFace) - - def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): - assert marker_trans.is_affine - assert trans.is_affine - self._renderer.draw_markers(gc, marker_path, marker_trans.frozen(), path, trans.frozen(), rgbFace) - - def draw_path_collection(self, master_transform, clipbox, clippath, clippath_trans, - paths, transforms, offsets, transOffset, facecolors, edgecolors, - linewidths, linestyles, antialiaseds): - assert master_transform.is_affine - if transOffset is not None: - transOffset = transOffset.frozen() - self._renderer.draw_path_collection( - master_transform.frozen(), clipbox, clippath, clippath_trans, - paths, transforms, offsets, transOffset, facecolors, edgecolors, linewidths, - linestyles, antialiaseds) - def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext @@ -153,11 +134,6 @@ x = int(x) + ox y = int(y) - oy self._renderer.draw_text_image(font_image, x, y + 1, angle, gc) - if 0: - self._renderer.draw_rectangle(gc, None, - int(x), - self.height-int(y), - width, height) def draw_text(self, gc, x, y, s, prop, angle, ismath): """ @@ -173,13 +149,13 @@ if len(s) == 1 and ord(s) > 127: font.load_char(ord(s), flags=LOAD_DEFAULT) else: + # We pass '0' for angle here, since it will be rotated (in raster + # space) in the following call to draw_text_image). font.set_text(s, 0, flags=LOAD_DEFAULT) font.draw_glyphs_to_bitmap() #print x, y, int(x), int(y) - # We pass '0' for angle here, since is has already been rotated - # (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)): Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-15 13:49:25 UTC (rev 3947) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-15 14:03:19 UTC (rev 3948) @@ -882,7 +882,7 @@ """ # local variable eliminates all repeated attribute lookups write = self._pswriter.write - + write('gsave\n') if debugPS and command: write("% "+command+"\n") @@ -915,7 +915,7 @@ write("stroke\n") if cliprect: write("grestore\n") - + write('grestore\n') def push_gc(self, gc, store=1): """ Push the current onto stack, with the exception of the clip box, which Copied: branches/transforms/unit/ellipse_compare.py (from rev 3941, trunk/matplotlib/unit/ellipse_compare.py) =================================================================== --- branches/transforms/unit/ellipse_compare.py (rev 0) +++ branches/transforms/unit/ellipse_compare.py 2007-10-15 14:03:19 UTC (rev 3948) @@ -0,0 +1,53 @@ +""" +Compare the ellipse generated with arcs versus a polygonal approximation +""" +import numpy as npy +from matplotlib import patches +from pylab import figure, show + +xcenter, ycenter = 0.38, 0.52 +#xcenter, ycenter = 0., 0. +width, height = 1e-1, 3e-1 +angle = -30 + +theta = npy.arange(0.0, 360.0, 1.0)*npy.pi/180.0 +x = width/2. * npy.cos(theta) +y = height/2. * npy.sin(theta) + +rtheta = angle*npy.pi/180. +R = npy.array([ + [npy.cos(rtheta), -npy.sin(rtheta)], + [npy.sin(rtheta), npy.cos(rtheta)], + ]) + + +x, y = npy.dot(R, npy.array([x, y])) +x += xcenter +y += ycenter + +fig = figure() +ax = fig.add_subplot(211, aspect='auto') +ax.fill(x, y, alpha=0.2, facecolor='yellow') + +e1 = patches.Ellipse((xcenter, ycenter), width, height, + angle=angle, linewidth=2, fill=False) + +ax.add_artist(e1) + +ax = fig.add_subplot(212, aspect='equal') +ax.fill(x, y, alpha=0.2, facecolor='yellow') +e2 = patches.Ellipse((xcenter, ycenter), width, height, + angle=angle, linewidth=2, fill=False) + + +ax.add_artist(e2) +ax.autoscale_view() + + +ax.set_xlim(0.2, .5) +ax.set_ylim(0.3, 0.7) + +#fig.savefig('ellipse_compare.png') +#fig.savefig('ellipse_compare.ps') + +show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-16 14:35:18
|
Revision: 3956 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3956&view=rev Author: mdboom Date: 2007-10-16 07:35:12 -0700 (Tue, 16 Oct 2007) Log Message: ----------- Merged revisions 3933-3955 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3935 | mdboom | 2007-10-11 13:03:50 -0400 (Thu, 11 Oct 2007) | 1 line Fixed minor import bug ........ r3941 | jdh2358 | 2007-10-14 15:00:50 -0400 (Sun, 14 Oct 2007) | 1 line added ellipse compare script ........ r3949 | jdh2358 | 2007-10-15 16:00:54 -0400 (Mon, 15 Oct 2007) | 3 lines fixed an aspect=auto problem with bezier ellipse approx ........ r3950 | jdh2358 | 2007-10-15 16:52:32 -0400 (Mon, 15 Oct 2007) | 2 lines Fixed a texst clipping bug in backend agg ........ r3951 | jdh2358 | 2007-10-15 17:08:35 -0400 (Mon, 15 Oct 2007) | 2 lines Fixed an annotation unit bug ........ r3952 | jdh2358 | 2007-10-15 17:22:03 -0400 (Mon, 15 Oct 2007) | 2 lines fixed a unit problem with annotations ........ r3953 | mdboom | 2007-10-16 08:28:49 -0400 (Tue, 16 Oct 2007) | 1 line Fix build on Windows with MSVC .NET 2003 ........ r3954 | jdh2358 | 2007-10-16 09:45:59 -0400 (Tue, 16 Oct 2007) | 2 lines restored unit support for ellipses -- and added examples/units/ellipse_with_units.py ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/boilerplate.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/mlab.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/text.py branches/transforms/src/_backend_agg.cpp branches/transforms/ttconv/ttutil.cpp branches/transforms/unit/ellipse_compare.py Added Paths: ----------- branches/transforms/examples/units/annotate_with_units.py branches/transforms/examples/units/ellipse_with_units.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3932 + /trunk/matplotlib:1-3955 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/CHANGELOG 2007-10-16 14:35:12 UTC (rev 3956) @@ -1,3 +1,12 @@ +2007-10-15 Fixed a bug in patches.Ellipse that was broken for + aspect='auto'. Scale free ellipses now work properly for + equal and auto on Agg and PS, and they fall back on a + polygonal approximation for nonlinear transformations until + we convince oursleves that the spline approximation holds + for nonlinear transformations. Added + unit/ellipse_compare.py to compare spline with vertex + approx for both aspects. JDH + 2007-10-05 remove generator expressions from texmanager and mpltraits. generator expressions are not supported by python-2.3 - DSD Modified: branches/transforms/boilerplate.py =================================================================== --- branches/transforms/boilerplate.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/boilerplate.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -2,10 +2,9 @@ # file is pasted into pylab.py. We did try to do this the smart way, # with callable functions and new.function, but could never get the # docstrings right for python2.2. See -# http://groups-beta.google.com/group/comp.lang.python/messages/1b14640f3a4ad3dc,b3d7453af21e5f82,17739e70ac6f710c,9d5291fce29cbbb1,c5b578e4ffc6af28,056ff270daa2f414?thread_id=dcd63ec13096a0f6&mode=thread +# http://groups.google.com/group/comp.lang.python/browse_frm/thread/dcd63ec13096a0f6/1b14640f3a4ad3dc?#1b14640f3a4ad3dc - # note we check for __doc__ is not None since py2exe optimize removes # the docstrings Copied: branches/transforms/examples/units/annotate_with_units.py (from rev 3954, trunk/matplotlib/examples/units/annotate_with_units.py) =================================================================== --- branches/transforms/examples/units/annotate_with_units.py (rev 0) +++ branches/transforms/examples/units/annotate_with_units.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -0,0 +1,27 @@ + +import pylab +from basic_units import cm + +fig = pylab.figure() +ax = fig.add_subplot(111) + + +ax.annotate( "Note 01", [0.5*cm, 0.5*cm] ) + +# xy and text both unitized +ax.annotate('local max', xy=(3*cm, 1*cm), xycoords='data', + xytext=(0.8*cm, 0.95*cm), textcoords='data', + arrowprops=dict(facecolor='black', shrink=0.05), + horizontalalignment='right', verticalalignment='top') + +# mixing units w/ nonunits +ax.annotate('local max', xy=(3*cm, 1*cm), xycoords='data', + xytext=(0.8, 0.95), textcoords='axes fraction', + arrowprops=dict(facecolor='black', shrink=0.05), + horizontalalignment='right', verticalalignment='top') + + +ax.set_xlim(0*cm, 4*cm) +ax.set_ylim(0*cm, 4*cm) +pylab.show() + Copied: branches/transforms/examples/units/ellipse_with_units.py (from rev 3954, trunk/matplotlib/examples/units/ellipse_with_units.py) =================================================================== --- branches/transforms/examples/units/ellipse_with_units.py (rev 0) +++ branches/transforms/examples/units/ellipse_with_units.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -0,0 +1,49 @@ +""" +Compare the ellipse generated with arcs versus a polygonal approximation +""" +from basic_units import cm +import numpy as npy +from matplotlib import patches +from pylab import figure, show + +xcenter, ycenter = 0.38*cm, 0.52*cm +#xcenter, ycenter = 0., 0. +width, height = 1e-1*cm, 3e-1*cm +angle = -30 + +theta = npy.arange(0.0, 360.0, 1.0)*npy.pi/180.0 +x = 0.5 * width * npy.cos(theta) +y = 0.5 * height * npy.sin(theta) + +rtheta = angle*npy.pi/180. +R = npy.array([ + [npy.cos(rtheta), -npy.sin(rtheta)], + [npy.sin(rtheta), npy.cos(rtheta)], + ]) + + +x, y = npy.dot(R, npy.array([x, y])) +x += xcenter +y += ycenter + +fig = figure() +ax = fig.add_subplot(211, aspect='auto') +ax.fill(x, y, alpha=0.2, facecolor='yellow', edgecolor='yellow', linewidth=1, zorder=1) + +e1 = patches.Ellipse((xcenter, ycenter), width, height, + angle=angle, linewidth=2, fill=False, zorder=2) + +ax.add_patch(e1) + +ax = fig.add_subplot(212, aspect='equal') +ax.fill(x, y, alpha=0.2, facecolor='green', edgecolor='green', zorder=1) +e2 = patches.Ellipse((xcenter, ycenter), width, height, + angle=angle, linewidth=2, fill=False, zorder=2) + + +ax.add_patch(e2) + +#fig.savefig('ellipse_compare.png') +fig.savefig('ellipse_compare') + +show() Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -331,7 +331,7 @@ size = prop.get_size_in_points() font.set_size(size, 72.0) return font - + def _rgba(self, im): return im.as_rgba_str() @@ -398,7 +398,7 @@ #print 'values', origin, flipud, figh, h, y if bbox is not None: - clipx,clipy,clipw,cliph = bbox.get_bounds() + clipx,clipy,clipw,cliph = bbox.bounds clip = '%s clipbox' % _nums_to_str(clipw, cliph, clipx, clipy) #y = figh-(y+h) ps = """gsave @@ -1425,5 +1425,15 @@ box clip newpath - } bind def""" + } bind def""", + """/unitcircle { + newpath +-1. 0. moveto +-1.0 0.552284749831 -0.552284749831 1.0 0.0 1.0 curveto +0.552284749831 1.0 1.0 0.552284749831 1.0 0.0 curveto +1.0 -0.552284749831 0.552284749831 -1.0 0.0 -1.0 curveto +-0.552284749831 -1.0 -1.0 -0.552284749831 -1.0 0.0 curveto +closepath + } bind def""", + ] Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -232,17 +232,18 @@ except TypeError: return False else: return True -def to_filehandle(fname): +def to_filehandle(fname, flag='r'): """ fname can be a filename or a file handle. Support for gzipped - files is automatic, if the filename ends in .gz + files is automatic, if the filename ends in .gz. flag is a + read/write flag for file """ if is_string_like(fname): if fname.endswith('.gz'): import gzip - fh = gzip.open(fname) + fh = gzip.open(fname, flag) else: - fh = file(fname) + fh = file(fname, flag) elif hasattr(fname, 'seek'): fh = fname else: Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/lib/matplotlib/mlab.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -809,6 +809,8 @@ If p is a scalar, the largest value of x less than or equal to the p percentage point in the sequence is returned. """ + + x = npy.ravel(x) x.sort() Nx = len(x) @@ -1282,7 +1284,10 @@ converterd, if not None, is a dictionary mapping column number or munged column name to a converter function - See examples/loadrec.py + names, if not None, is a list of header names. In this case, no + header will be read from the file + + if no rows are found, None is returned See examples/loadrec.py """ if converterd is None: @@ -1291,9 +1296,42 @@ import dateutil.parser parsedate = dateutil.parser.parse + fh = cbook.to_filehandle(fname) - reader = csv.reader(fh, delimiter=delimiter) + + class FH: + """ + for space delimited files, we want different behavior than + comma or tab. Generally, we want multiple spaces to be + treated as a single separator, whereas with comma and tab we + want multiple commas to return multiple (empty) fields. The + join/strip trick below effects this + """ + def __init__(self, fh): + self.fh = fh + + def close(self): + self.fh.close() + + def seek(self, arg): + self.fh.seek(arg) + + def fix(self, s): + return ' '.join(s.split()) + + + def next(self): + return self.fix(self.fh.next()) + + def __iter__(self): + for line in self.fh: + yield self.fix(line) + + if delimiter==' ': + fh = FH(fh) + + reader = csv.reader(fh, delimiter=delimiter) def process_skiprows(reader): if skiprows: for i, row in enumerate(reader): @@ -1388,9 +1426,131 @@ rows.append([func(val) for func, val in zip(converters, row)]) fh.close() + if not len(rows): + return None r = npy.rec.fromrecords(rows, names=names) return r + +def rec2csv(r, fname, delimiter=','): + """ + Save the data from numpy record array r into a comma/space/tab + delimited file. The record array dtype names will be used for + column headers. + + + fname - can be a filename or a file handle. Support for gzipped + files is automatic, if the filename ends in .gz + """ + fh = cbook.to_filehandle(fname, 'w') + writer = csv.writer(fh, delimiter=delimiter) + header = r.dtype.names + writer.writerow(header) + for row in r: + writer.writerow(map(str, row)) + fh.close() + +# some record array helpers +def rec_append_field(rec, name, arr, dtype=None): + 'return a new record array with field name populated with data from array arr' + arr = npy.asarray(arr) + if dtype is None: + dtype = arr.dtype + newdtype = npy.dtype(rec.dtype.descr + [(name, dtype)]) + newrec = npy.empty(rec.shape, dtype=newdtype) + for field in rec.dtype.fields: + newrec[field] = rec[field] + newrec[name] = arr + return newrec.view(npy.recarray) + + +def rec_drop_fields(rec, names): + 'return a new numpy record array with fields in names dropped' + + names = set(names) + Nr = len(rec) + + newdtype = npy.dtype([(name, rec.dtype[name]) for name in rec.dtype.names + if name not in names]) + + newrec = npy.empty(Nr, dtype=newdtype) + for field in newdtype.names: + newrec[field] = rec[field] + + return newrec.view(npy.recarray) + + +def rec_join(key, r1, r2): + """ + join record arrays r1 and r2 on key; key is a tuple of field + names. if r1 and r2 have equal values on all the keys in the key + tuple, then their fields will be merged into a new record array + containing the union of the fields of r1 and r2 + """ + + for name in key: + if name not in r1.dtype.names: + raise ValueError('r1 does not have key field %s'%name) + if name not in r2.dtype.names: + raise ValueError('r2 does not have key field %s'%name) + + def makekey(row): + return tuple([row[name] for name in key]) + + + names = list(r1.dtype.names) + [name for name in r2.dtype.names if name not in set(r1.dtype.names)] + + + + r1d = dict([(makekey(row),i) for i,row in enumerate(r1)]) + r2d = dict([(makekey(row),i) for i,row in enumerate(r2)]) + + r1keys = set(r1d.keys()) + r2keys = set(r2d.keys()) + + keys = r1keys & r2keys + + r1ind = [r1d[k] for k in keys] + r2ind = [r2d[k] for k in keys] + + + r1 = r1[r1ind] + r2 = r2[r2ind] + + r2 = rec_drop_fields(r2, r1.dtype.names) + + + def key_desc(name): + 'if name is a string key, use the larger size of r1 or r2 before merging' + dt1 = r1.dtype[name] + if dt1.type != npy.string_: + return (name, dt1.descr[0][1]) + + dt2 = r1.dtype[name] + assert dt2==dt1 + if dt1.num>dt2.num: + return (name, dt1.descr[0][1]) + else: + return (name, dt2.descr[0][1]) + + + + keydesc = [key_desc(name) for name in key] + + newdtype = npy.dtype(keydesc + + [desc for desc in r1.dtype.descr if desc[0] not in key ] + + [desc for desc in r2.dtype.descr if desc[0] not in key ] ) + + + newrec = npy.empty(len(r1), dtype=newdtype) + for field in r1.dtype.names: + newrec[field] = r1[field] + + for field in r2.dtype.names: + newrec[field] = r2[field] + + return newrec.view(npy.recarray) + def slopes(x,y): """ SLOPES calculate the slope y'(x) Given data vectors X and Y SLOPES Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -771,6 +771,32 @@ """ A scale-free ellipse """ + offset = 4.0 * (npy.sqrt(2) - 1) / 3.0 + + circle = 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], + + [-1.0, 0.0] + ], + npy.float_) + + def __str__(self): return "Ellipse(%d,%d;%dx%d)"%(self.center[0],self.center[1],self.width,self.height) @@ -807,8 +833,8 @@ if ev.x is None or ev.y is None: return False,{} x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) return (x*x + y*y) <= 1.0, {} + - class Circle(Ellipse): """ A circle patch Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/lib/matplotlib/text.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -1041,6 +1041,8 @@ def _get_xy(self, x, y, s): if s=='data': trans = self.axes.transData + x = float(self.convert_xunits(x)) + y = float(self.convert_yunits(y)) return trans.transform_point((x, y)) elif s=='polar': theta, r = x, y Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/src/_backend_agg.cpp 2007-10-16 14:35:12 UTC (rev 3956) @@ -653,7 +653,6 @@ } - /** * This is a custom span generator that converts spans in the * 8-bit inverted greyscale font buffer to rgba that agg can use. @@ -776,11 +775,16 @@ srcbuf, 0, interpolator, filter); span_gen_type output_span_generator(&image_span_generator, gc.color); renderer_type ri(*rendererBase, output_span_generator); - agg::rasterizer_scanline_aa<> rasterizer; - agg::scanline_p8 scanline; - rasterizer.add_path(rect2); - agg::render_scanlines(rasterizer, scanline, ri); + //agg::rasterizer_scanline_aa<> rasterizer; + //agg::scanline_p8 scanline; + //rasterizer.add_path(rect2); + //agg::render_scanlines(rasterizer, scanline, ri); + + theRasterizer->add_path(rect2); + agg::render_scanlines(*theRasterizer, *slineP8, ri); + + return Py::Object(); } Modified: branches/transforms/ttconv/ttutil.cpp =================================================================== --- branches/transforms/ttconv/ttutil.cpp 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/ttconv/ttutil.cpp 2007-10-16 14:35:12 UTC (rev 3956) @@ -32,14 +32,14 @@ va_start(arg_list, format); char buffer[PRINTF_BUFFER_SIZE]; -#ifdef WIN32 +#if defined(WIN32) || defined(_MSC_VER) int size = _vsnprintf(buffer, PRINTF_BUFFER_SIZE, format, arg_list); #else int size = vsnprintf(buffer, PRINTF_BUFFER_SIZE, format, arg_list); #endif if (size >= PRINTF_BUFFER_SIZE) { char* buffer2 = (char*)malloc(size); -#ifdef WIN32 +#if defined(WIN32) || defined(_MSC_VER) _vsnprintf(buffer2, size, format, arg_list); #else vsnprintf(buffer2, size, format, arg_list); Modified: branches/transforms/unit/ellipse_compare.py =================================================================== --- branches/transforms/unit/ellipse_compare.py 2007-10-16 14:17:53 UTC (rev 3955) +++ branches/transforms/unit/ellipse_compare.py 2007-10-16 14:35:12 UTC (rev 3956) @@ -27,27 +27,22 @@ fig = figure() ax = fig.add_subplot(211, aspect='auto') -ax.fill(x, y, alpha=0.2, facecolor='yellow') +ax.fill(x, y, alpha=0.2, facecolor='yellow', edgecolor='yellow', linewidth=1, zorder=1) e1 = patches.Ellipse((xcenter, ycenter), width, height, - angle=angle, linewidth=2, fill=False) + angle=angle, linewidth=2, fill=False, zorder=2) -ax.add_artist(e1) +ax.add_patch(e1) ax = fig.add_subplot(212, aspect='equal') -ax.fill(x, y, alpha=0.2, facecolor='yellow') +ax.fill(x, y, alpha=0.2, facecolor='green', edgecolor='green', zorder=1) e2 = patches.Ellipse((xcenter, ycenter), width, height, - angle=angle, linewidth=2, fill=False) + angle=angle, linewidth=2, fill=False, zorder=2) -ax.add_artist(e2) -ax.autoscale_view() +ax.add_patch(e2) - -ax.set_xlim(0.2, .5) -ax.set_ylim(0.3, 0.7) - #fig.savefig('ellipse_compare.png') -#fig.savefig('ellipse_compare.ps') +fig.savefig('ellipse_compare') show() This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-16 19:40:09
|
Revision: 3958 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3958&view=rev Author: mdboom Date: 2007-10-16 12:39:57 -0700 (Tue, 16 Oct 2007) Log Message: ----------- figlegends work now. (Phew!) Rendering quality fixes drawing axis-aligned line segments in Agg. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/image.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 branches/transforms/src/_backend_agg.h Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/PASSED_DEMOS 2007-10-16 19:39:57 UTC (rev 3958) @@ -35,26 +35,26 @@ color_demo.py O colours.py [???] contour_demo.py O -contourf_demo.py [FLOATING POINT EXCEPTION] -contour_image.py [FLOATING POINT EXCEPTION] +contourf_demo.py O +contour_image.py O coords_demo.py O coords_report.py O csd_demo.py O cursor_demo.py O -custom_figure_class.py [EXCEPT FOR PS OUTPUT] +custom_figure_class.py O customize_rc.py custom_ticker1.py O dannys_example.py [REQUIRES NUMERIC] dash_control.py O dashpointlabel.py O -dashtick.py +dashtick.py O data_browser.py O data_helper.py [N/A] date_demo1.py O date_demo2.py O -date_demo_convert.py O [PASSES] -date_demo_rrule.py O [PASSES] -date_index_formatter.py O [PASSES] +date_demo_convert.py O +date_demo_rrule.py O +date_index_formatter.py O dynamic_collection.py O dynamic_demo.py [GTK] dynamic_demo_wx.py [WX] @@ -77,7 +77,7 @@ errorbar_demo.py O errorbar_limits.py O figimage_demo.py O -figlegend_demo.py [HORRIBLY BROKEN] +figlegend_demo.py O figtext.py O fill_between_posneg.py O fill_between.py O @@ -94,7 +94,7 @@ glyph_to_path.py [Requires PIL] gradient_bar.py O gtk_spreadsheet.py -hatch_demo.py [Requires PS] +hatch_demo.py O histogram_demo_canvasagg.py [???] histogram_demo.py O image_demo2.py O Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -1248,7 +1248,10 @@ l, b, w, h = self.bbox.bounds # composite images need special args so they will not # respect z-order for now - renderer.draw_image(l, b, im, self.bbox) + renderer.draw_image( + l, b, im, self.bbox, + self.axesPatch.get_path(), + self.axesPatch.get_transform()) artists.extend(self.collections) artists.extend(self.patches) @@ -4379,6 +4382,7 @@ im.set_data(X) im.set_alpha(alpha) self._set_artist_props(im) + im.set_clip_path(self.axesPatch) #if norm is None and shape is None: # im.set_clim(vmin, vmax) if vmin is not None or vmax is not None: Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -68,7 +68,7 @@ Nlinestyles = len(linestyles) Naa = len(antialiaseds) - if (Nfacecolors == 0 and Nedgecolors == 0) or N == 0: + if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return ttransforms = [] @@ -113,7 +113,7 @@ """ return 1.0 - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): """ Draw the Image instance into the current axes; x is the distance in pixels from the left hand side of the canvas. y is Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -371,7 +371,7 @@ """ return self.image_magnification - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): """ Draw the Image instance into the current axes; x is the distance in pixels from the left hand side of the canvas and y @@ -397,9 +397,16 @@ figh = self.height*72 #print 'values', origin, flipud, figh, h, y + clip = [] if bbox is not None: clipx,clipy,clipw,cliph = bbox.bounds - clip = '%s clipbox' % _nums_to_str(clipw, cliph, clipx, clipy) + clip.append('%s clipbox' % _nums_to_str(clipw, cliph, clipx, clipy)) + if clippath is not None: + print "clippath" + id = self._get_clip_path(clippath, clippath_trans) + clip.append('%s' % id) + clip = '\n'.join(clip) + #y = figh-(y+h) ps = """gsave %(clip)s @@ -507,7 +514,7 @@ Nlinestyles = len(linestyles) Naa = len(antialiaseds) - if (Nfacecolors == 0 and Nedgecolors == 0) or N == 0: + if (Nfacecolors == 0 and Nedgecolors == 0) or Npaths == 0: return for i in range(Ntpaths): Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -627,7 +627,8 @@ ims) im.is_grayscale = False l, b, w, h = self.bbox.bounds - renderer.draw_image(l, b, im, self.bbox) + renderer.draw_image(l, b, im, self.bbox, + *self.get_transformed_clip_path_and_affine()) # render the axes @@ -702,7 +703,6 @@ handles = flatten(handles) l = Legend(self, handles, labels, *args, **kwargs) - self._set_artist_props(l) self.legends.append(l) return l Modified: branches/transforms/lib/matplotlib/image.py =================================================================== --- branches/transforms/lib/matplotlib/image.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/image.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -181,7 +181,8 @@ if not self.get_visible(): return im = self.make_image(renderer.get_image_magnification()) l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds - renderer.draw_image(l, b, im, self.axes.bbox.frozen()) + renderer.draw_image(l, b, im, self.axes.bbox.frozen(), + *self.get_transformed_clip_path_and_affine()) def contains(self, mouseevent): """Test whether the mouse event occured within the image. @@ -481,7 +482,8 @@ def draw(self, renderer, *args, **kwargs): if not self.get_visible(): return im = self.make_image() - renderer.draw_image(self.ox, self.oy, im, self.figure.bbox) + renderer.draw_image(self.ox, self.oy, im, self.figure.bbox, + *self.get_transformed_clip_path_and_affine()) def write_png(self, fname): """Write the image to png file with fname""" Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/legend.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -165,7 +165,8 @@ raise TypeError("Legend needs either Axes or Figure as parent") self.parent = parent self._offsetTransform = Affine2D() - self.set_transform( self._offsetTransform + BboxTransform(Bbox.unit(), parent.bbox) ) + self._parentTransform = BboxTransform(Bbox.unit(), parent.bbox) + Artist.set_transform(self, self._offsetTransform + self._parentTransform) if loc is None: loc = rcParams["legend.loc"] @@ -192,6 +193,12 @@ self._loc = loc + self.legendPatch = Rectangle( + xy=(0.0, 0.0), width=0.5, height=0.5, + facecolor='w', edgecolor='k', + ) + self._set_artist_props(self.legendPatch) + # make a trial box in the middle of the axes. relocate it # based on it's bbox left, top = 0.5, 0.5 @@ -203,20 +210,6 @@ self.texts = self._get_texts(labels, textleft, top) self.legendHandles = self._get_handles(handles, self.texts) - - if len(self.texts): - left, top = self.texts[-1].get_position() - HEIGHT = self._approx_text_height()*len(self.texts) - else: - HEIGHT = 0.2 - - bottom = top-HEIGHT - left -= self.handlelen + self.handletextsep + self.pad - self.legendPatch = Rectangle( - xy=(left, bottom), width=0.5, height=HEIGHT, - facecolor='w', edgecolor='k', - ) - self._set_artist_props(self.legendPatch) self._drawFrame = True def _set_artist_props(self, a): @@ -282,6 +275,7 @@ legline.update_from(handle) self._set_artist_props(legline) # after update legline.set_clip_box(None) + legline.set_clip_path(self.legendPatch) legline.set_markersize(self.markerscale*legline.get_markersize()) ret.append(legline) @@ -293,12 +287,14 @@ p.update_from(handle) self._set_artist_props(p) p.set_clip_box(None) + p.set_clip_path(self.legendPatch) ret.append(p) elif isinstance(handle, LineCollection): ydata = (y-HEIGHT/2)*npy.ones(self._xdata.shape, float) legline = Line2D(self._xdata, ydata) self._set_artist_props(legline) legline.set_clip_box(None) + legline.set_clip_path(self.legendPatch) lw = handle.get_linewidth()[0] dashes = handle.get_dashes() color = handle.get_colors()[0] @@ -316,6 +312,7 @@ p.set_edgecolor(handle._edgecolors[0]) self._set_artist_props(p) p.set_clip_box(None) + p.set_clip_path(self.legendPatch) ret.append(p) else: @@ -536,7 +533,7 @@ handle.set_height(h/2) # Set the data for the legend patch - bbox = self._get_handle_text_bbox(renderer).frozen() + bbox = self._get_handle_text_bbox(renderer) bbox = bbox.expanded(1 + self.pad, 1 + self.pad) l, b, w, h = bbox.bounds Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -748,7 +748,7 @@ def _draw_diamond(self, renderer, gc, path, path_trans): side = renderer.points_to_pixels(self._markersize) - transform = Affine2D().translate(0.5, 0.5).rotate_deg(45).scale(side) + transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) @@ -756,8 +756,8 @@ def _draw_thin_diamond(self, renderer, gc, path, path_trans): 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.6, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-16 19:39:57 UTC (rev 3958) @@ -822,7 +822,7 @@ raise TypeError( "Can not add Transform to object of type '%s'" % type(other)) - def __array__(self): + def __array__(self, *args, **kwargs): """ Used by C/C++ -based backends to get at the array matrix data. """ Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/src/_backend_agg.cpp 2007-10-16 19:39:57 UTC (rev 3958) @@ -99,7 +99,7 @@ the C++ representation as a std::vector<std::pair<double, double> > (GCAgg::dash_t) */ -void convert_dashes(const Py::Tuple& dashes, bool snap, double dpi, GCAgg::dash_t& dashes_out, +void convert_dashes(const Py::Tuple& dashes, double dpi, GCAgg::dash_t& dashes_out, double& dashOffset_out) { if (dashes.length()!=2) throw Py::ValueError(Printf("Dash descriptor must be a length 2 tuple; found %d", dashes.length()).str()); @@ -124,10 +124,6 @@ for (size_t i = 0; i < Ndash; i += 2) { val0 = double(Py::Float(dashSeq[i])) * dpi/72.0; val1 = double(Py::Float(dashSeq[i+1])) * dpi/72.0; - if (snap) { - val0 = (int)val0 + 0.5; - val1 = (int)val1 + 0.5; - } dashes_out.push_back(std::make_pair(val0, val1)); } } @@ -143,8 +139,6 @@ conv_quantize(VertexSource& source, bool quantize) : m_source(&source), m_quantize(quantize) {} - void set_source(VertexSource& source) { m_source = &source; } - void rewind(unsigned path_id) { m_source->rewind(path_id); } @@ -158,18 +152,14 @@ return cmd; } - void activate(bool quantize) { - m_quantize = quantize; - } - private: VertexSource* m_source; bool m_quantize; }; -GCAgg::GCAgg(const Py::Object &gc, double dpi, bool snapto) : - dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), +GCAgg::GCAgg(const Py::Object &gc, double dpi) : + dpi(dpi), isaa(true), linewidth(1.0), alpha(1.0), dashOffset(0.0) { _VERBOSE("GCAgg::GCAgg"); @@ -184,8 +174,8 @@ _set_clip_path(gc); } -GCAgg::GCAgg(double dpi, bool snapto) : - dpi(dpi), snapto(snapto), isaa(true), linewidth(1.0), alpha(1.0), +GCAgg::GCAgg(double dpi) : + dpi(dpi), isaa(true), linewidth(1.0), alpha(1.0), dashOffset(0.0) { @@ -260,7 +250,7 @@ return; } - convert_dashes(dash_obj, snapto, dpi, dashes, dashOffset); + convert_dashes(dash_obj, dpi, dashes, dashOffset); } void @@ -435,17 +425,31 @@ bool should_snap(Path& path, const agg::trans_affine& trans) { // If this is a straight horizontal or vertical line, quantize to nearest // pixels - bool snap = false; - if (path.total_vertices() == 2) { - double x0, y0, x1, y1; - path.vertex(0, &x0, &y0); - trans.transform(&x0, &y0); - path.vertex(1, &x1, &y1); + double x0, y0, x1, y1; + unsigned code; + code = path.vertex(&x0, &y0); + trans.transform(&x0, &y0); + + while ((code = path.vertex(&x1, &y1)) != agg::path_cmd_stop) { + + switch (code) { + case agg::path_cmd_curve3: + case agg::path_cmd_curve4: + path.rewind(0); + return false; + } + trans.transform(&x1, &y1); - snap = (fabs(x0 - x1) < 1.0 || fabs(y0 - y1) < 1.0); + if (!(fabs(x0 - x1) < 0.1 || fabs(y0 - y1) < 0.1)) { + path.rewind(0); + return false; + } + x0 = x1; + y0 = y1; } - return snap; + path.rewind(0); + return true; } Py::Object @@ -563,10 +567,10 @@ curve_t marker_path_curve(marker_path_transformed); PathIterator path(path_obj); + bool snap = should_snap(path, trans); transformed_path_t path_transformed(path, trans); - // bool snap = should_snap(path, trans); - GCAgg gc = GCAgg(gc_obj, dpi, true); - quantize_t path_quantized(path_transformed, true); + GCAgg gc = GCAgg(gc_obj, dpi); + quantize_t path_quantized(path_transformed, snap); path_quantized.rewind(0); facepair_t face = _get_rgba_face(face_obj, gc.alpha); @@ -793,31 +797,37 @@ Py::Object RendererAgg::draw_image(const Py::Tuple& args) { _VERBOSE("RendererAgg::draw_image"); - args.verify_length(4); + args.verify_length(4, 6); float x = Py::Float(args[0]); float y = Py::Float(args[1]); Image *image = static_cast<Image*>(args[2].ptr()); Py::Object box_obj = args[3]; - + Py::Object clippath; + agg::trans_affine clippath_trans; + if (args.size() == 6) { + clippath = args[4]; + clippath_trans = py_to_agg_transformation_matrix(args[5]); + } + theRasterizer->reset_clipping(); rendererBase->reset_clipping(true); set_clipbox(box_obj, rendererBase); - + + Py::Tuple empty; pixfmt pixf(*(image->rbufOut)); - - - Py::Tuple empty; image->flipud_out(empty); + rendererBase->blend_from(pixf, 0, (int)x, (int)(height-(y+image->rowsOut))); + image->flipud_out(empty); return Py::Object(); } void RendererAgg::_draw_path(PathIterator& path, agg::trans_affine trans, - bool snap, bool has_clippath, - const facepair_t& face, const GCAgg& gc) { + bool has_clippath, const facepair_t& face, + const GCAgg& gc) { typedef agg::conv_transform<PathIterator> transformed_path_t; typedef conv_quantize<transformed_path_t> quantize_t; typedef agg::conv_curve<quantize_t> curve_t; @@ -833,6 +843,7 @@ trans *= agg::trans_affine_translation(0.0, (double)height); // Build the transform stack + bool snap = should_snap(path, trans); transformed_path_t tpath(path, trans); quantize_t quantized(tpath, snap); // Benchmarking shows that there is no noticable slowdown to always @@ -871,25 +882,36 @@ // Render stroke if (gc.linewidth != 0.0) { + double linewidth = gc.linewidth; + if (snap) + linewidth = round(linewidth); + if (gc.dashes.size() == 0) { stroke_t stroke(curve); - stroke.width(gc.linewidth); + stroke.width(linewidth); stroke.line_cap(gc.cap); stroke.line_join(gc.join); theRasterizer->add_path(stroke); } else { dash_t dash(curve); for (GCAgg::dash_t::const_iterator i = gc.dashes.begin(); - i != gc.dashes.end(); ++i) - dash.add_dash(i->first, i->second); + i != gc.dashes.end(); ++i) { + double val0 = i->first; + double val1 = i->second; + if (snap) { + val0 = (int)val0 + 0.5; + val1 = (int)val1 + 0.5; + } + dash.add_dash(val0, val1); + } stroke_dash_t stroke(dash); stroke.line_cap(gc.cap); stroke.line_join(gc.join); - stroke.width(gc.linewidth); + stroke.width(linewidth); theRasterizer->add_path(stroke); } - if (gc.isaa && !(snap && gc.linewidth < 1.5)) { + if (gc.isaa && !(snap)) { if (has_clippath) { pixfmt_amask_type pfa(*pixFmt, *alphaMask); amask_ren_type r(pfa); @@ -928,8 +950,7 @@ face_obj = args[3]; PathIterator path(path_obj); - bool snap = should_snap(path, trans); - GCAgg gc = GCAgg(gc_obj, dpi, snap); + GCAgg gc = GCAgg(gc_obj, dpi); facepair_t face = _get_rgba_face(face_obj, gc.alpha); theRasterizer->reset_clipping(); @@ -937,7 +958,7 @@ set_clipbox(gc.cliprect, theRasterizer); bool has_clippath = render_clippath(gc.clippath, gc.clippath_trans); - _draw_path(path, trans, snap, has_clippath, face, gc); + _draw_path(path, trans, has_clippath, face, gc); return Py::Object(); } @@ -962,7 +983,7 @@ Py::SeqBase<Py::Object> linestyles_obj = args[11]; Py::SeqBase<Py::Int> antialiaseds = args[12]; - GCAgg gc(dpi, false); + GCAgg gc(dpi); PyArrayObject* offsets = NULL; PyArrayObject* facecolors = NULL; @@ -973,13 +994,15 @@ if (!offsets || offsets->dimensions[1] != 2) throw Py::ValueError("Offsets array must be Nx2"); - PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject(facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + PyArrayObject* facecolors = (PyArrayObject*)PyArray_FromObject + (facecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); if (!facecolors || (facecolors->nd == 1 && facecolors->dimensions[0] != 0) || (facecolors->nd == 2 && facecolors->dimensions[1] != 4)) throw Py::ValueError("Facecolors must be a Nx4 numpy array or empty"); - PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject(edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); + PyArrayObject* edgecolors = (PyArrayObject*)PyArray_FromObject + (edgecolors_obj.ptr(), PyArray_DOUBLE, 1, 2); if (!edgecolors || (edgecolors->nd == 1 && edgecolors->dimensions[0] != 0) || (edgecolors->nd == 2 && edgecolors->dimensions[1] != 4)) @@ -995,10 +1018,10 @@ size_t Nlinestyles = std::min(linestyles_obj.length(), N); size_t Naa = antialiaseds.length(); - if ((Nfacecolors == 0 && Nedgecolors == 0) || N == 0) + if ((Nfacecolors == 0 && Nedgecolors == 0) || Npaths == 0) return Py::Object(); - size_t i = 0; + size_t i = 0; // Convert all of the transforms up front typedef std::vector<agg::trans_affine> transforms_t; @@ -1018,7 +1041,7 @@ i = 0; for (dashes_t::iterator d = dashes.begin(); d != dashes.end(); ++d, ++i) { - convert_dashes(Py::Tuple(linestyles_obj[i]), false, dpi, d->second, d->first); + convert_dashes(Py::Tuple(linestyles_obj[i]), dpi, d->second, d->first); } // Handle any clipping globally @@ -1034,34 +1057,34 @@ for (i = 0; i < N; ++i) { PathIterator path(paths[i % Npaths]); - bool snap = (path.total_vertices() == 2); - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); + double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); + double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); offset_trans.transform(&xo, &yo); agg::trans_affine_translation transOffset(xo, yo); agg::trans_affine& trans = transforms[i % Ntransforms]; if (Nfacecolors) { size_t fi = i % Nfacecolors; - face.second = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0), - *(double*)PyArray_GETPTR2(facecolors, fi, 1), - *(double*)PyArray_GETPTR2(facecolors, fi, 2), - *(double*)PyArray_GETPTR2(facecolors, fi, 3)); + face.second = agg::rgba(*(double*)PyArray_GETPTR2(facecolors, fi, 0), + *(double*)PyArray_GETPTR2(facecolors, fi, 1), + *(double*)PyArray_GETPTR2(facecolors, fi, 2), + *(double*)PyArray_GETPTR2(facecolors, fi, 3)); } if (Nedgecolors) { size_t ei = i % Nedgecolors; - gc.color = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0), - *(double*)PyArray_GETPTR2(edgecolors, ei, 1), - *(double*)PyArray_GETPTR2(edgecolors, ei, 2), - *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); - gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; - gc.dashes = dashes[i % Nlinestyles].second; - gc.dashOffset = dashes[i % Nlinestyles].first; + gc.color = agg::rgba(*(double*)PyArray_GETPTR2(edgecolors, ei, 0), + *(double*)PyArray_GETPTR2(edgecolors, ei, 1), + *(double*)PyArray_GETPTR2(edgecolors, ei, 2), + *(double*)PyArray_GETPTR2(edgecolors, ei, 3)); + gc.linewidth = double(Py::Float(linewidths[i % Nlinewidths])) * dpi/72.0; + gc.dashes = dashes[i % Nlinestyles].second; + gc.dashOffset = dashes[i % Nlinestyles].first; } - gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); - _draw_path(path, trans * transOffset, snap, has_clippath, face, gc); + gc.isaa = bool(Py::Int(antialiaseds[i % Naa])); + + _draw_path(path, trans * transOffset, has_clippath, face, gc); } } catch (...) { Py_XDECREF(offsets); Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-16 14:41:29 UTC (rev 3957) +++ branches/transforms/src/_backend_agg.h 2007-10-16 19:39:57 UTC (rev 3958) @@ -109,11 +109,10 @@ class GCAgg { public: - GCAgg(const Py::Object& gc, double dpi, bool snapto=false); - GCAgg(double dpi, bool snapto=false); + GCAgg(const Py::Object& gc, double dpi); + GCAgg(double dpi); double dpi; - bool snapto; bool isaa; agg::line_cap_e cap; @@ -219,8 +218,7 @@ void set_clipbox(Py::Object& cliprect, R rasterizer); bool render_clippath(const Py::Object& clippath, const agg::trans_affine& clippath_trans); void _draw_path(PathIterator& path, agg::trans_affine trans, - bool snap, bool has_clippath, - const facepair_t& face, const GCAgg& gc); + bool has_clippath, const facepair_t& face, const GCAgg& gc); private: Py::Object lastclippath; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-18 14:51:21
|
Revision: 3960 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3960&view=rev Author: mdboom Date: 2007-10-18 07:51:16 -0700 (Thu, 18 Oct 2007) Log Message: ----------- More examples working. Minor speedups. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/pyplot.py branches/transforms/lib/matplotlib/quiver.py branches/transforms/lib/matplotlib/transforms.py Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/PASSED_DEMOS 2007-10-18 14:51:16 UTC (rev 3960) @@ -164,8 +164,8 @@ pstest.py pylab_with_gtk.py pythonic_matplotlib.py O -quadmesh_demo.py [MASKED VALUES NOT QUITE RIGHT] -quiver_demo.py [SEGFAULTS] +quadmesh_demo.py O [MASKED VALUES ARE SHOWN DUE TO A BUG IN TRUNK] +quiver_demo.py O rc_traits.py [N/A] scatter_custom_symbol.py O scatter_demo2.py O Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-18 14:51:16 UTC (rev 3960) @@ -356,7 +356,6 @@ If the scalar mappable array is not none, update colors from scalar data """ - #print 'update_scalarmappable: self._A', self._A if self._A is None: return if len(self._A.shape)>1: raise ValueError('Collections can only map rank 1 arrays') @@ -364,7 +363,6 @@ self._facecolors = self.to_rgba(self._A, self._alpha) else: self._edgecolors = self.to_rgba(self._A, self._alpha) - #print self._facecolors # these are not available for the object inspector until after the @@ -445,7 +443,7 @@ return self._paths def draw(self, renderer): - self.update_scalarmappable() ####################### + self.update_scalarmappable() self._linewidths = (1,) if self._showedges: Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-18 14:51:16 UTC (rev 3960) @@ -281,6 +281,8 @@ if is_numlike(self._picker): self.pickradius = self._picker + self._xorig = npy.asarray([]) + self._yorig = npy.asarray([]) self.set_data(xdata, ydata) self._logcache = None @@ -377,9 +379,13 @@ else: x, y = args - self._xorig = x - self._yorig = y - self.recache() + x = npy.asarray(x) + y = npy.asarray(y) + if ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or + (y.shape != self._yorig.shape or npy.any(y != self._yorig))): + self._xorig = x + self._yorig = y + self.recache() def recache(self): #if self.axes is None: print 'recache no axes' @@ -625,8 +631,10 @@ ACCEPTS: npy.array """ - self._xorig = x - self.recache() + x = npy.asarray(x) + if x.shape != self._xorig.shape or npy.any(x != self._xorig): + self._xorig = x + self.recache() def set_ydata(self, y): """ @@ -634,10 +642,11 @@ ACCEPTS: npy.array """ + y = npy.asarray(y) + if y.shape != self._yorig.shape or npy.any(y != self._yorig): + self._yorig = y + self.recache() - self._yorig = y - self.recache() - def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in Modified: branches/transforms/lib/matplotlib/pyplot.py =================================================================== --- branches/transforms/lib/matplotlib/pyplot.py 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/lib/matplotlib/pyplot.py 2007-10-18 14:51:16 UTC (rev 3960) @@ -312,7 +312,7 @@ A matplotlib.legend.Legend instance is returned """ - l= gcf().legend(handles, labels, loc, **kwargs) + l = gcf().legend(handles, labels, loc, **kwargs) draw_if_interactive() return l Modified: branches/transforms/lib/matplotlib/quiver.py =================================================================== --- branches/transforms/lib/matplotlib/quiver.py 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/lib/matplotlib/quiver.py 2007-10-18 14:51:16 UTC (rev 3960) @@ -206,24 +206,24 @@ def _text_x(self, x): if self.labelpos == 'E': - return x + self.labelsep.get() + return x + self.labelsep elif self.labelpos == 'W': - return x - self.labelsep.get() + return x - self.labelsep else: return x def _text_y(self, y): if self.labelpos == 'N': - return y + self.labelsep.get() + return y + self.labelsep elif self.labelpos == 'S': - return y - self.labelsep.get() + return y - self.labelsep else: return y def draw(self, renderer): self._init() self.vector.draw(renderer) - x, y = self.get_transform().xy_tup((self.X, self.Y)) + x, y = self.get_transform().transform_point((self.X, self.Y)) self.text.set_x(self._text_x(x)) self.text.set_y(self._text_y(y)) self.text.draw(renderer) @@ -323,7 +323,7 @@ if not self._initialized: trans = self._set_transform() ax = self.ax - sx, sy = trans.transform_point((ax.bbox.width, ax.bbox.height)) + sx, sy = trans.inverted().transform_point((ax.bbox.width, ax.bbox.height)) self.span = sx sn = max(8, min(25, math.sqrt(self.N))) if self.width is None: @@ -333,12 +333,7 @@ self._init() if self._new_UV: verts = self._make_verts(self.U, self.V) - # Using nan internally here is the easiest - # way to support masked inputs; it doesn't - # require adding mask support to PolyCollection, - # and it keeps all array dimensions (X, Y, U, V, C) - # intact. - self.set_verts(verts.filled(npy.nan)) + self.set_verts(verts) self._new_UV = False collections.PolyCollection.draw(self, renderer) @@ -353,11 +348,11 @@ ax = self.ax if self.units in ('x', 'y'): if self.units == 'x': - dx0 = ax.viewLim.ur().x() - ax.viewLim.ll().x() - dx1 = ax.bbox.ur().x() - ax.bbox.ll().x() + dx0 = ax.viewLim.width + dx1 = ax.bbox.width else: - dx0 = ax.viewLim.ur().y() - ax.viewLim.ll().y() - dx1 = ax.bbox.ur().y() - ax.bbox.ll().y() + dx0 = ax.viewLim.height + dx1 = ax.bbox.height dx = dx1/dx0 else: if self.units == 'width': @@ -365,13 +360,12 @@ elif self.units == 'height': dx = ax.bbox.height elif self.units == 'dots': - dx = transforms.Value(1) + dx = 1.0 elif self.units == 'inches': dx = ax.figure.dpi else: raise ValueError('unrecognized units') - bb = transforms.Bbox.from_lbrt(0, 0, dx, dx) - trans = transforms.BboxTransform(transforms.Bbox.unit(), bb) + trans = transforms.Affine2D().scale(dx) self.set_transform(trans) return trans Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-17 01:15:48 UTC (rev 3959) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-18 14:51:16 UTC (rev 3960) @@ -90,7 +90,7 @@ """ # Shortcut: If self is already invalid, that means its parents # are as well, so we don't need to do anything. - if self._invalid: + if self._invalid or not len(self._parents): return # If we are an affine transform being changed, we can set the @@ -127,7 +127,7 @@ """ return self - def write_graphviz(self, fobj): + def write_graphviz(self, fobj, highlight=[]): """ For debugging purposes. @@ -146,14 +146,22 @@ if root in seen: return seen.add(root) - fobj.write('%s [label="%s"];\n' % - (hash(root), root.__class__.__name__)) + props = {} + label = root.__class__.__name__ + if root._invalid: + label = '[%s]' % label + if root in highlight: + props['style'] = 'bold' if root.is_affine: - fobj.write('%s [style=filled, color=".7 .7 .9"];\n' % - hash(root)) - elif root.is_bbox: - fobj.write('%s [style=filled, color=".9 .9 .7"];\n' % - hash(root)) + props['shape'] = 'parallelogram' + if root.is_bbox: + props['shape'] = 'box' + props['label'] = '"%s"' % label + props = ' '.join(['%s=%s' % (key, val) for key, val in props.items()]) + + fobj.write('%s [%s];\n' % + (hash(root), props)) + for child in root._children: name = '?' for key, val in root.__dict__.items(): @@ -627,20 +635,23 @@ minpos = npy.array([-npy.inf, -npy.inf], npy.float_) if ignore: - self._points = npy.array( + points = npy.array( [[x.min(), y.min()], [x.max(), y.max()]], npy.float_) self._minpos = minpos else: - self._points = npy.array( + 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._minpos = npy.minimum(minpos, self._minpos) - self.invalidate() + if npy.any(self._points != points): + self._points = points + self.invalidate() + def update_from_data_xy(self, xy, ignore=None): """ Update the bounds of the Bbox based on the passed in data. @@ -695,8 +706,10 @@ def _set_bounds(self, bounds): l, b, w, h = bounds - self._points = npy.array([[l, b], [l+w, b+h]], npy.float_) - self.invalidate() + points = npy.array([[l, b], [l+w, b+h]], npy.float_) + if npy.any(self._points != points): + self._points = points + self.invalidate() bounds = property(BboxBase._get_bounds, _set_bounds) def _get_minpos(self): @@ -725,15 +738,17 @@ of the form: [[xmin, ymin], [xmax, ymax]]. No error checking is performed, as this method is mainly for internal use. """ - self._points = points - self.invalidate() + if npy.any(self._points != points): + self._points = points + self.invalidate() def set(self, other): """ Set this bounding box from the "frozen" bounds of another Bbox. """ - self._points = other.get_points() - self.invalidate() + if npy.any(self._points != other.get_points()): + self._points = other.get_points() + self.invalidate() class TransformedBbox(BboxBase): @@ -1848,8 +1863,6 @@ self._a = a self._b = b self.set_children(a, b) - self._mtx = None - self._affine = None def frozen(self): self._invalid = 0 @@ -1905,14 +1918,11 @@ transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ def get_affine(self): - if self._invalid or self._affine is None: - if self._a.is_affine and self._b.is_affine: - self._affine = Affine2D(npy.dot(self._b.get_affine().get_matrix(), - self._a.get_affine().get_matrix())) - else: - self._affine = self._b.get_affine() - self._invalid = 0 - return self._affine + if self._a.is_affine and self._b.is_affine: + return Affine2D(npy.dot(self._b.get_affine().get_matrix(), + self._a.get_affine().get_matrix())) + else: + return self._b.get_affine() get_affine.__doc__ = Transform.get_affine.__doc__ def inverted(self): @@ -2046,7 +2056,6 @@ self._transform = transform self.set_children(transform) self._transformed_path = None - self.get_affine = self._transform.get_affine def get_transformed_path_and_affine(self): """ @@ -2071,8 +2080,10 @@ self._transform.transform_path_non_affine(self._path) self._invalid = 0 return self._transform.transform_path_affine(self._transformed_path) + + def get_affine(self): + return self._transform.get_affine() - 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-10-18 15:06:51
|
Revision: 3962 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3962&view=rev Author: mdboom Date: 2007-10-18 08:06:49 -0700 (Thu, 18 Oct 2007) Log Message: ----------- Merged revisions 3956-3961 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3961 | jdh2358 | 2007-10-18 11:02:13 -0400 (Thu, 18 Oct 2007) | 3 lines Fixed collection.set_facecolor to respect alpha ........ Modified Paths: -------------- branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/mlab.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3955 + /trunk/matplotlib:1-3961 Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-18 15:02:13 UTC (rev 3961) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-18 15:06:49 UTC (rev 3962) @@ -311,7 +311,8 @@ ACCEPTS: matplotlib color arg or sequence of rgba tuples """ - self._facecolors = _colors.colorConverter.to_rgba_list(c) + self._facecolors = _colors.colorConverter.to_rgba_list(c, self._alpha) + set_facecolors = set_facecolor def set_edgecolor(self, c): Modified: branches/transforms/lib/matplotlib/mlab.py =================================================================== --- branches/transforms/lib/matplotlib/mlab.py 2007-10-18 15:02:13 UTC (rev 3961) +++ branches/transforms/lib/matplotlib/mlab.py 2007-10-18 15:06:49 UTC (rev 3962) @@ -1342,9 +1342,15 @@ process_skiprows(reader) + def myfloat(x): + if x==missing: + return npy.nan + else: + return float(x) + def get_func(item, func): # promote functions in this order - funcmap = {int:float, float:dateutil.parser.parse, dateutil.parser.parse:str} + funcmap = {int:myfloat, myfloat:dateutil.parser.parse, dateutil.parser.parse:str} try: func(item) except: if func==str: This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-18 18:12:03
|
Revision: 3965 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3965&view=rev Author: mdboom Date: 2007-10-18 11:11:59 -0700 (Thu, 18 Oct 2007) Log Message: ----------- First pass at working PDF backend. Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-18 18:07:06 UTC (rev 3964) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-18 18:11:59 UTC (rev 3965) @@ -33,7 +33,10 @@ LOAD_NO_HINTING, KERNING_UNFITTED from matplotlib.mathtext import MathTextParser from matplotlib.transforms import Bbox +from matplotlib.path import Path from matplotlib import ttconv +# MGDTODO: Move this stuff +from matplotlib.backends._backend_agg import get_path_extents # Overview # @@ -90,22 +93,26 @@ """Make one string from sequence of strings, with whitespace in between. The whitespace is chosen to form lines of at most linelen characters, if possible.""" - - s, strings = [strings[0]], strings[1:] - while strings: - if len(s[-1]) + len(strings[0]) < linelen: - s[-1] += ' ' + strings[0] + currpos = 0 + lasti = 0 + result = [] + for i, s in enumerate(strings): + length = len(s) + if currpos + length < linelen: + currpos += length + 1 else: - s.append(strings[0]) - strings = strings[1:] - return '\n'.join(s) + result.append(' '.join(strings[lasti:i])) + lasti = i + currpos = length + result.append(' '.join(strings[lasti:])) + return '\n'.join(result) def pdfRepr(obj): """Map Python objects to PDF syntax.""" # Some objects defined later have their own pdfRepr method. - if 'pdfRepr' in dir(obj): + if hasattr(obj, 'pdfRepr'): return obj.pdfRepr() # Floats. PDF does not have exponential notation (1.0e-10) so we @@ -164,6 +171,13 @@ else: r += "-%02d'%02d'" % (z//3600, z%3600) return pdfRepr(r) + # A bounding box + elif isinstance(obj, Bbox): + r = ["["] + r.extend([pdfRepr(val) for val in obj.lbrt]) + r.append("]") + return fill(r) + else: raise TypeError, \ "Don't know a PDF representation for %s objects." \ @@ -379,7 +393,6 @@ self.markers = {} self.two_byte_charprocs = {} - self.nextMarker = 1 # The PDF spec recommends to include every procset procsets = [ Name(x) @@ -409,8 +422,8 @@ for val in self.alphaStates.values()])) self.writeHatches() xobjects = dict(self.images.values()) - for name, value in self.markers.items(): - xobjects[name] = value[0] + for tup in self.markers.values(): + xobjects[tup[0]] = tup[1] for name, value in self.two_byte_charprocs.items(): xobjects[name] = value self.writeObject(self.XObjectObject, xobjects) @@ -1009,71 +1022,64 @@ img.flipud_out() - def markerObject(self, path, fillp, lw): + def markerObject(self, path, trans, fillp, lw): """Return name of a marker XObject representing the given path.""" - - name = Name('M%d' % self.nextMarker) - ob = self.reserveObject('marker %d' % self.nextMarker) - self.nextMarker += 1 - self.markers[name] = (ob, path, fillp, lw) + key = (path, trans) + result = self.markers.get(key) + if result is None: + name = Name('M%d' % len(self.markers)) + ob = self.reserveObject('marker %d' % len(self.markers)) + self.markers[key] = (name, ob, path, trans, fillp, lw) + else: + name = result[0] return name - + def writeMarkers(self): - for name, tuple in self.markers.items(): - object, path, fillp, lw = tuple + for tup in self.markers.values(): + name, object, path, trans, fillp, lw = tup + a, b, c, d = get_path_extents(path, trans) + bbox = Bbox.from_lbrt(*get_path_extents(path, trans)) + bbox = bbox.padded(lw * 0.5) self.beginStream( object.id, None, {'Type': Name('XObject'), 'Subtype': Name('Form'), - 'BBox': self.pathBbox(path, lw) }) - self.writePath(path, fillp) + 'BBox': bbox }) + self.writePath(path, trans) + if fillp: + self.output(Op.fill_stroke) + else: + self.output(Op.stroke) self.endStream() #@staticmethod - def pathBbox(path, lw): - path.rewind(0) - x, y = [], [] - while True: - code, xp, yp = path.vertex() - if code & agg.path_cmd_mask in \ - (agg.path_cmd_move_to, agg.path_cmd_line_to): - x.append(xp) - y.append(yp) - elif code == agg.path_cmd_stop: - break - return min(x)-lw, min(y)-lw, max(x)+lw, max(y)+lw - pathBbox = staticmethod(pathBbox) - - #@staticmethod - def pathOperations(path): - path.rewind(0) - result = [] - while True: - code, x, y = path.vertex() - code = code & agg.path_cmd_mask - if code == agg.path_cmd_stop: - break - elif code == agg.path_cmd_move_to: - result += (x, y, Op.moveto) - elif code == agg.path_cmd_line_to: - result += (x, y, Op.lineto) - elif code == agg.path_cmd_curve3: - pass # TODO - elif code == agg.path_cmd_curve4: - pass # TODO - elif code == agg.path_cmd_end_poly: - result += (Op.closepath,) - else: - print >>sys.stderr, "pathOperations", code, xp, yp - return result + def pathOperations(path, transform): + tpath = transform.transform_path(path) + + cmds = [] + for points, code in tpath.iter_segments(): + if code == Path.MOVETO: + cmds.extend(points) + cmds.append(Op.moveto) + elif code == Path.LINETO: + cmds.extend(points) + cmds.append(Op.lineto) + elif code == Path.CURVE3: + cmds.extend([points[0], points[1], + points[0], points[1], + points[2], points[3], + Op.curveto]) + elif code == Path.CURVE4: + cmds.extend(points) + cmds.append(Op.curveto) + elif code == Path.CLOSEPOLY: + cmds.append(Op.closepath) + return cmds pathOperations = staticmethod(pathOperations) - - def writePath(self, path, fillp): - self.output(*self.pathOperations(path)) - if fillp: - self.output(Op.fill_stroke) - else: - self.output(Op.stroke) - + + def writePath(self, path, transform): + cmds = self.pathOperations(path, transform) + self.output(*cmds) + def reserveObject(self, name=''): """Reserve an ID for an indirect object. The name is used for debugging in case we forget to print out @@ -1177,59 +1183,6 @@ stat_key, (realpath, Set())) used_characters[1].update(set) - def draw_arc(self, gcEdge, rgbFace, x, y, width, height, - angle1, angle2, rotation): - """ - 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, rotated by `rotation` degrees - positive angles are anti-clockwise - - If the color rgbFace is not None, fill the arc with it. - """ - # source: agg_bezier_arc.cpp in agg23 - - def arc_to_bezier(cx, cy, rx, ry, angle1, sweep, rotation): - halfsweep = sweep / 2.0 - x0, y0 = cos(halfsweep), sin(halfsweep) - tx = (1.0 - x0) * 4.0/3.0; - ty = y0 - tx * x0 / y0; - px = x0, x0+tx, x0+tx, x0 - py = -y0, -ty, ty, y0 - sn, cs = sin(angle1 + halfsweep), cos(angle1 + halfsweep) - result = [ (rx * (pxi * cs - pyi * sn), - ry * (pxi * sn + pyi * cs)) - for pxi, pyi in zip(px, py) ] - result = [ (cx + cos(rotation)*x - sin(rotation)*y, - cy + sin(rotation)*x + cos(rotation)*y) - for x, y in result ] - return reduce(lambda x, y: x + y, result) - - epsilon = 0.01 - angle1 *= pi/180.0 - angle2 *= pi/180.0 - rotation *= pi/180.0 - sweep = angle2 - angle1 - angle1 = angle1 % (2*pi) - sweep = min(max(-2*pi, sweep), 2*pi) - - if sweep < 0.0: - sweep, angle1, angle2 = -sweep, angle2, angle1 - bp = [ pi/2.0 * i - for i in range(4) - if pi/2.0 * i < sweep-epsilon ] - bp.append(sweep) - subarcs = [ arc_to_bezier(x, y, width/2.0, height/2.0, - bp[i], bp[i+1]-bp[i], rotation) - for i in range(len(bp)-1) ] - - self.check_gc(gcEdge, rgbFace) - self.file.output(subarcs[0][0], subarcs[0][1], Op.moveto) - for arc in subarcs: - self.file.output(*(arc[2:] + (Op.curveto,))) - - self.file.output(self.gc.close_and_paint()) - def get_image_magnification(self): return self.image_magnification @@ -1246,82 +1199,29 @@ self.file.output(Op.gsave, w, 0, 0, h, x, y, Op.concat_matrix, imob, Op.use_xobject, Op.grestore) - def draw_line(self, gc, x1, y1, x2, y2): - if npy.isnan(x1) or npy.isnan(x2) or npy.isnan(y1) or npy.isnan(y2): - return - self.check_gc(gc) - self.file.output(x1, y1, Op.moveto, - x2, y2, Op.lineto, self.gc.paint()) - - def draw_lines(self, gc, x, y, transform=None): - self.check_gc(gc) - if transform is not None: - x, y = transform.seq_x_y(x, y) - nan_at = npy.isnan(x) | npy.isnan(y) - next_op = Op.moveto - for i in range(len(x)): - if nan_at[i]: - next_op = Op.moveto - else: - self.file.output(x[i], y[i], next_op) - next_op = Op.lineto + def draw_path(self, gc, path, transform, rgbFace=None): + self.check_gc(gc, rgbFace) + stream = self.file.writePath(path, transform) self.file.output(self.gc.paint()) - def draw_point(self, gc, x, y): - print >>sys.stderr, "draw_point called" - - self.check_gc(gc, gc._rgb) - self.file.output(x, y, 1, 1, - Op.rectangle, Op.fill_stroke) - - def draw_polygon(self, gcEdge, rgbFace, points): - # Optimization for axis-aligned rectangles - if len(points) == 4: - if points[0][0] == points[1][0] and points[1][1] == points[2][1] and \ - points[2][0] == points[3][0] and points[3][1] == points[0][1]: - self.draw_rectangle(gcEdge, rgbFace, - min(points[0][0], points[2][0]), - min(points[1][1], points[3][1]), - abs(points[2][0] - points[0][0]), - abs(points[3][1] - points[1][1])) - return - elif points[0][1] == points[1][1] and points[1][0] == points[2][0] and \ - points[2][1] == points[3][1] and points[3][0] == points[0][0]: - self.draw_rectangle(gcEdge, rgbFace, - min(points[1][0], points[3][0]), - min(points[2][1], points[0][1]), - abs(points[1][0] - points[3][0]), - abs(points[2][1] - points[0][1])) - return - - self.check_gc(gcEdge, rgbFace) - self.file.output(points[0][0], points[0][1], Op.moveto) - for x,y in points[1:]: - self.file.output(x, y, Op.lineto) - self.file.output(self.gc.close_and_paint()) - - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - self.check_gc(gcEdge, rgbFace) - self.file.output(x, y, width, height, Op.rectangle) - self.file.output(self.gc.paint()) - - def draw_markers(self, gc, path, rgbFace, x, y, trans): + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): self.check_gc(gc, rgbFace) fillp = rgbFace is not None - marker = self.file.markerObject(path, fillp, self.gc._linewidth) - x, y = trans.numerix_x_y(npy.asarray(x), npy.asarray(y)) - nan_at = npy.isnan(x) | npy.isnan(y) - self.file.output(Op.gsave) - ox, oy = 0, 0 - for i in range(len(x)): - if nan_at[i]: continue - dx, dy, ox, oy = x[i]-ox, y[i]-oy, x[i], y[i] - self.file.output(1, 0, 0, 1, dx, dy, - Op.concat_matrix, - marker, Op.use_xobject) - self.file.output(Op.grestore) + output = self.file.output + marker = self.file.markerObject( + marker_path, marker_trans, fillp, self.gc._linewidth) + tpath = trans.transform_path(path) + output(Op.gsave) + lastx, lasty = 0, 0 + for x, y in tpath.vertices: + dx, dy = x - lastx, y - lasty + output(1, 0, 0, 1, dx, dy, Op.concat_matrix, + marker, Op.use_xobject) + lastx, lasty = x, y + output(Op.grestore) + def _setup_textpos(self, x, y, angle, oldx=0, oldy=0, oldangle=0): if angle == oldangle == 0: self.file.output(x - oldx, y - oldy, Op.textpos) @@ -1735,7 +1635,7 @@ def hatch_cmd(self, hatch): if not hatch: - if self._fillcolor: + if self._fillcolor is not None: return self.fillcolor_cmd(self._fillcolor) else: return [Name('DeviceRGB'), Op.setcolorspace_nonstroke] @@ -1757,7 +1657,7 @@ if rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_stroke] else: - return list(rgb) + [Op.setrgb_stroke] + return list(rgb[:3]) + [Op.setrgb_stroke] def fillcolor_cmd(self, rgb): if rgb is None or rcParams['pdf.inheritcolor']: @@ -1765,7 +1665,7 @@ elif rgb[0] == rgb[1] == rgb[2]: return [rgb[0], Op.setgray_nonstroke] else: - return list(rgb) + [Op.setrgb_nonstroke] + return list(rgb[:3]) + [Op.setrgb_nonstroke] def push(self): parent = GraphicsContextPdf(self.file) @@ -1791,11 +1691,12 @@ if (self._cliprect, self._clippath) != (cliprect, clippath): cmds.extend(self.push()) if self._cliprect != cliprect: - cmds.extend([t for t in cliprect] + - [Op.rectangle, Op.clip, Op.endpath]) + cmds.extend([cliprect, Op.rectangle, Op.clip, Op.endpath]) if self._clippath != clippath: - cmds.extend(PdfFile.pathOperations(clippath) + - [Op.clip, Op.endpath]) + cmds.extend( + PdfFile.pathOperations( + *clippath.get_transformed_path_and_affine()) + + [Op.clip, Op.endpath]) return cmds commands = ( @@ -1821,7 +1722,11 @@ for params, cmd in self.commands: ours = [ getattr(self, p) for p in params ] theirs = [ getattr(other, p) for p in params ] - if ours != theirs: + try: + different = ours != theirs + except ValueError: + different = ours.shape != theirs.shape or npy.any(ours != theirs) + if ours is not theirs: cmds.extend(cmd(self, *theirs)) for p in params: setattr(self, p, getattr(other, p)) Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-18 18:07:06 UTC (rev 3964) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-18 18:11:59 UTC (rev 3965) @@ -1433,14 +1433,4 @@ clip newpath } bind def""", - """/unitcircle { - newpath --1. 0. moveto --1.0 0.552284749831 -0.552284749831 1.0 0.0 1.0 curveto -0.552284749831 1.0 1.0 0.552284749831 1.0 0.0 curveto -1.0 -0.552284749831 0.552284749831 -1.0 0.0 -1.0 curveto --0.552284749831 -1.0 -1.0 -0.552284749831 -1.0 0.0 curveto -closepath - } bind def""", - ] Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-10-18 18:07:06 UTC (rev 3964) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-10-18 18:11:59 UTC (rev 3965) @@ -41,13 +41,13 @@ self._resolution = resolution def transform(self, tr): - xy = npy.zeros(tr.shape, npy.float_) - t = tr[:, 0:1] - r = tr[:, 1:2] - x = xy[:, 0:1] - y = xy[:, 1:2] - x += r * npy.cos(t) - y += r * npy.sin(t) + xy = npy.zeros(tr.shape, npy.float_) + t = tr[:, 0:1] + r = tr[:, 1:2] + x = xy[:, 0:1] + y = xy[:, 1:2] + x[:] = r * npy.cos(t) + y[:] = r * npy.sin(t) return xy transform.__doc__ = Transform.transform.__doc__ Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-18 18:07:06 UTC (rev 3964) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-18 18:11:59 UTC (rev 3965) @@ -490,6 +490,14 @@ a = npy.array([[-deltaw, -deltah], [deltaw, deltah]]) return Bbox(self._points + a) + def padded(self, p): + """ + Return a new Bbox that is padded on all four sides by the + given value. + """ + points = self._points + return Bbox(points + [[-p, -p], [p, p]]) + def translated(self, tx, ty): """ Return a copy of the Bbox, translated by tx and ty. Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-18 18:07:06 UTC (rev 3964) +++ branches/transforms/src/_backend_agg.cpp 2007-10-18 18:11:59 UTC (rev 3965) @@ -1573,12 +1573,12 @@ curved_path.rewind(0); while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) { - if (code & agg::path_cmd_end_poly == agg::path_cmd_end_poly) - continue; if (x < *x0) *x0 = x; if (y < *y0) *y0 = y; if (x > *x1) *x1 = x; if (y > *y1) *y1 = y; + if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) + continue; } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-23 14:30:59
|
Revision: 3984 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3984&view=rev Author: mdboom Date: 2007-10-23 07:30:57 -0700 (Tue, 23 Oct 2007) Log Message: ----------- Merged revisions 3962-3983 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3963 | mdboom | 2007-10-18 13:40:30 -0400 (Thu, 18 Oct 2007) | 1 line Major speedup in PDF backend by using hasattr() rather than 'in dir()' ........ r3964 | mdboom | 2007-10-18 14:07:06 -0400 (Thu, 18 Oct 2007) | 1 line Faster version of fill() for PDF writing ........ r3966 | jdh2358 | 2007-10-19 10:23:48 -0400 (Fri, 19 Oct 2007) | 2 lines fixed a verbose report bug in patches ........ r3967 | dsdale | 2007-10-19 10:43:21 -0400 (Fri, 19 Oct 2007) | 2 lines removed a gsave/grestore pair surrounding _draw_ps ........ r3968 | dsdale | 2007-10-19 11:37:41 -0400 (Fri, 19 Oct 2007) | 3 lines changed dependency check for ghostscript, which was failing to identify svn versions ........ r3969 | dsdale | 2007-10-19 11:41:25 -0400 (Fri, 19 Oct 2007) | 2 lines whitespace cleanup ........ r3975 | jdh2358 | 2007-10-21 12:02:07 -0400 (Sun, 21 Oct 2007) | 1 line added a show method for gtk fig manager ........ Modified Paths: -------------- branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/__init__.py branches/transforms/lib/matplotlib/backends/backend_gtk.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/config/checkdep.py branches/transforms/setup.py branches/transforms/setupext.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3961 + /trunk/matplotlib:1-3983 Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/CHANGELOG 2007-10-23 14:30:57 UTC (rev 3984) @@ -1,3 +1,8 @@ +2007-10-19 Removed a gsave/grestore pair surrounding _draw_ps, which + was causing a loss graphics state info (see "EPS output + problem - scatter & edgecolors" on mpl-dev, 2007-10-29) + - DSD + 2007-10-15 Fixed a bug in patches.Ellipse that was broken for aspect='auto'. Scale free ellipses now work properly for equal and auto on Agg and PS, and they fall back on a Modified: branches/transforms/lib/matplotlib/__init__.py =================================================================== --- branches/transforms/lib/matplotlib/__init__.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/lib/matplotlib/__init__.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -149,13 +149,10 @@ # --verbose-silent or --verbose-helpful _commandLineVerbose = None - for arg in sys.argv[1:]: if not arg.startswith('--verbose-'): continue _commandLineVerbose = arg[10:] - - def __init__(self): self.set_level('silent') self.fileo = sys.stdout @@ -195,8 +192,6 @@ return True return False - - def wrap(self, fmt, func, level='helpful', always=True): """ return a callable function that wraps func and reports it @@ -225,6 +220,7 @@ verbose=Verbose() + def checkdep_dvipng(): try: stdin, stdout = os.popen4('dvipng -version') @@ -243,7 +239,7 @@ command = 'gs -v' stdin, stdout = os.popen4(command) line = stdout.readlines()[0] - v = line.split()[2] + v = line.split()[-2] vtest = '.'.join(v.split('.')[:2]) # deal with version numbers like '7.07.1' float(vtest) return vtest Modified: branches/transforms/lib/matplotlib/backends/backend_gtk.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -390,7 +390,7 @@ self.window = gtk.Window() self.window.set_title("Figure %d" % num) - + self.vbox = gtk.VBox() self.window.add(self.vbox) self.vbox.show() @@ -439,7 +439,10 @@ gtk.main_level() >= 1: gtk.main_quit() - + def show(self): + # show the figure window + self.window.show() + def full_screen_toggle (self): self._full_screen_flag = not self._full_screen_flag if self._full_screen_flag: Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -777,7 +777,6 @@ """ # local variable eliminates all repeated attribute lookups write = self._pswriter.write - # write('gsave\n') if debugPS and command: write("% "+command+"\n") @@ -818,7 +817,6 @@ write("grestore\n") if cliprect: write("grestore\n") - #write('grestore\n') class GraphicsContextPS(GraphicsContextBase): Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -288,7 +288,6 @@ raise ValueError() except ValueError: raise ValueError('Do not know how to convert %s to dashes'%ls) - self._linestyles = dashes set_dashes = set_linestyle = set_linestyles Modified: branches/transforms/lib/matplotlib/config/checkdep.py =================================================================== --- branches/transforms/lib/matplotlib/config/checkdep.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/lib/matplotlib/config/checkdep.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -1,4 +1,7 @@ -import os, re, sys +import os +import re +import sys +import warnings import distutils.version as version def dvipng(): @@ -19,7 +22,7 @@ command = 'gs -v' stdin, stdout = os.popen4(command) line = stdout.readlines()[0] - v = line.split()[2] + v = line.split()[-2] vtest = '.'.join(v.split('.')[:2]) # deal with version numbers like '7.07.1' float(vtest) return vtest @@ -130,4 +133,4 @@ 'unless ghostscript-%s or later is ' 'installed on your system') % gs_req) - return flag \ No newline at end of file + return flag Modified: branches/transforms/setup.py =================================================================== --- branches/transforms/setup.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/setup.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -24,8 +24,8 @@ # it. It makes very nice antialiased output and also supports alpha # blending BUILD_AGG = 1 -BUILD_GTKAGG = 'auto' -BUILD_GTK = 'auto' +BUILD_GTKAGG = 1 +BUILD_GTK = 1 # build TK GUI with Agg renderer ; requires Tkinter Python extension # and Tk includes @@ -271,7 +271,7 @@ # packagers: set rc['numerix'] and rc['backend'] here to override the auto # defaults, eg #rc['numerix'] = numpy -#rc['backend'] = GTKAgg +#rc['backend'] = 'GTKAgg' if sys.platform=='win32': rc = dict(backend='TkAgg', numerix='numpy') template = file('matplotlibrc.template').read() Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-10-23 14:25:49 UTC (rev 3983) +++ branches/transforms/setupext.py 2007-10-23 14:30:57 UTC (rev 3984) @@ -43,9 +43,10 @@ import os + basedir = { 'win32' : ['win32_static',], - 'linux2' : ['/usr/local', '/usr',], + 'linux2' : ['/usr/local', '/usr'], 'linux' : ['/usr/local', '/usr',], 'cygwin' : ['/usr/local', '/usr',], 'darwin' : ['/sw/lib/freetype2', '/sw/lib/freetype219', '/usr/local', @@ -170,6 +171,7 @@ if sys.platform == 'win32': has_pkgconfig.cache = False else: + #print 'environ', os.environ['PKG_CONFIG_PATH'] status, output = commands.getstatusoutput("pkg-config --help") has_pkgconfig.cache = (status == 0) return has_pkgconfig.cache @@ -192,6 +194,9 @@ status, output = commands.getstatusoutput( "%s %s %s" % (pkg_config_exec, flags, packages)) + #if packages.startswith('pygtk'): + # print 'status', status, output + # raise SystemExit if status == 0: for token in output.split(): attr = _flags.get(token[:2], None) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-24 16:17:52
|
Revision: 3992 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3992&view=rev Author: mdboom Date: 2007-10-24 09:03:49 -0700 (Wed, 24 Oct 2007) Log Message: ----------- Separated path utilities from backend_agg Modified Paths: -------------- branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/path.py branches/transforms/setup.py branches/transforms/setupext.py branches/transforms/src/_backend_agg.cpp branches/transforms/src/_backend_agg.h branches/transforms/src/agg_py_path_iterator.h Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-24 16:03:49 UTC (rev 3992) @@ -35,8 +35,6 @@ from matplotlib.transforms import Bbox, BboxBase from matplotlib.path import Path from matplotlib import ttconv -# MGDTODO: Move this stuff -from matplotlib.backends._backend_agg import get_path_extents # Overview # @@ -1034,8 +1032,7 @@ def writeMarkers(self): for tup in self.markers.values(): name, object, path, trans, fillp, lw = tup - a, b, c, d = get_path_extents(path, trans) - bbox = Bbox.from_lbrt(*get_path_extents(path, trans)) + bbox = Bbox.from_lbrt(*path.get_extents(trans)) bbox = bbox.padded(lw * 0.5) self.beginStream( object.id, None, Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-24 16:03:49 UTC (rev 3992) @@ -19,13 +19,6 @@ import matplotlib.nxutils as nxutils import matplotlib.path as path -# MGDTODO: Move this stuff -from matplotlib.backends._backend_agg import get_path_collection_extents, \ - point_in_path_collection - -# MGDTODO: Treat facecolors and edgecolors as numpy arrays always -# and then update draw_path_collection to use the array interface - class Collection(artist.Artist, cm.ScalarMappable): """ Base class for Collections. Must be subclassed to be usable. @@ -133,7 +126,7 @@ return self._transforms def get_datalim(self, transData): - result = transforms.Bbox.from_lbrt(*get_path_collection_extents( + result = transforms.Bbox.from_lbrt(*path.get_path_collection_extents( self.get_transform().frozen(), self.get_paths(), self.get_transforms(), @@ -201,7 +194,7 @@ transform = transform.get_affine() # MGDTODO: Don't pick when outside of clip path / clip box - ind = point_in_path_collection( + ind = path.point_in_path_collection( mouseevent.x, mouseevent.y, self._pickradius, transform.frozen(), paths, self.get_transforms(), npy.asarray(self._offsets, npy.float_), Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/lib/matplotlib/path.py 2007-10-24 16:03:49 UTC (rev 3992) @@ -9,7 +9,8 @@ import numpy as npy from numpy import ma as ma -from matplotlib.backends._backend_agg import point_in_path, get_path_extents +from matplotlib._path import point_in_path, get_path_extents, \ + get_path_collection_extents, point_in_path_collection from matplotlib.cbook import simple_linear_interpolation KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0 Modified: branches/transforms/setup.py =================================================================== --- branches/transforms/setup.py 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/setup.py 2007-10-24 16:03:49 UTC (rev 3992) @@ -19,6 +19,11 @@ # whatever array packages you have installed. BUILD_IMAGE = 1 +# Build the path utilities module. This module depends on some parts +# of Agg, but is separate from _backend_agg, since it is used even when +# the Agg renderer is not. +BUILD_PATH = 1 + # Build the antigrain geometry toolkit. Agg makes heavy use of # templates, so it probably requires a fairly recent compiler to build # it. It makes very nice antialiased output and also supports alpha @@ -77,7 +82,7 @@ import glob from distutils.core import setup from setupext import build_agg, build_gtkagg, build_tkagg, build_wxagg,\ - build_ft2font, build_image, build_windowing, \ + build_ft2font, build_image, build_windowing, build_path, \ build_contour, build_nxutils, build_enthought, build_swigagg, build_gdk, \ build_subprocess, build_ttconv, print_line, print_status, print_message, \ print_raw, check_for_freetype, check_for_libpng, check_for_gtk, check_for_tk, \ @@ -260,6 +265,9 @@ if BUILD_IMAGE: build_image(ext_modules, packages) +if BUILD_PATH: + build_path(ext_modules, packages) + for mod in ext_modules: if VERBOSE: mod.extra_compile_args.append('-DVERBOSE') Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/setupext.py 2007-10-24 16:03:49 UTC (rev 3992) @@ -90,6 +90,7 @@ BUILT_ENTHOUGHT = False BUILT_CONTOUR = False BUILT_GDK = False +BUILT_PATH = False AGG_VERSION = 'agg23' @@ -897,6 +898,37 @@ BUILT_AGG = True +def build_path(ext_modules, packages): + global BUILT_PATH + if BUILT_PATH: return # only build it if you you haven't already + + agg = ( + 'agg_curves.cpp', + 'agg_bezier_arc.cpp', + 'agg_path_storage.cpp', + 'agg_trans_affine.cpp', + 'agg_vcgen_stroke.cpp', + ) + + deps = ['%s/src/%s'%(AGG_VERSION, name) for name in agg] + deps.extend(glob.glob('CXX/*.cxx')) + deps.extend(glob.glob('CXX/*.c')) + + temp_copy('src/_path.cpp', 'src/path.cpp') + deps.extend(['src/path.cpp']) + module = Extension( + 'matplotlib._path', + deps, + include_dirs=numpy_inc_dirs, + ) + + add_numpy_flags(module) + + add_agg_flags(module) + ext_modules.append(module) + + BUILT_PATH = True + def build_image(ext_modules, packages): global BUILT_IMAGE if BUILT_IMAGE: return # only build it if you you haven't already Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/src/_backend_agg.cpp 2007-10-24 16:03:49 UTC (rev 3992) @@ -30,6 +30,7 @@ #define PY_ARRAY_TYPES_PREFIX NumPy #include "numpy/arrayobject.h" +#include "agg_py_transforms.h" #ifndef M_PI #define M_PI 3.14159265358979323846 @@ -41,53 +42,7 @@ #define M_PI_2 1.57079632679489661923 #endif -/** 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, bool errors=true) { - PyArrayObject* matrix = NULL; - - try { - if (obj.ptr() == Py_None) - throw Py::Exception(); - matrix = (PyArrayObject*) PyArray_FromObject(obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!matrix) - throw Py::Exception(); - if (matrix->nd == 2 || matrix->dimensions[0] == 3 || matrix->dimensions[1] == 3) { - size_t stride0 = matrix->strides[0]; - size_t stride1 = matrix->strides[1]; - char* row0 = matrix->data; - char* row1 = row0 + stride0; - - double a = *(double*)(row0); - row0 += stride1; - double c = *(double*)(row0); - row0 += stride1; - double e = *(double*)(row0); - - double b = *(double*)(row1); - row1 += stride1; - double d = *(double*)(row1); - row1 += stride1; - double f = *(double*)(row1); - - Py_XDECREF(matrix); - - return agg::trans_affine(a, b, c, d, e, f); - } - throw Py::Exception(); - } catch (...) { - if (errors) { - Py_XDECREF(matrix); - throw Py::TypeError("Invalid affine transformation matrix"); - } - } - - Py_XDECREF(matrix); - return agg::trans_affine(); -} - /* Convert dashes from the Python representation as nested sequences to the C++ representation as a std::vector<std::pair<double, double> > @@ -1392,338 +1347,6 @@ } -// -// The following code was found in the Agg 2.3 examples (interactive_polygon.cpp). -// It has been generalized to work on (possibly curved) polylines, rather than -// just polygons. The original comments have been kept intact. -// -- Michael Droettboom 2007-10-02 -// -//======= Crossings Multiply algorithm of InsideTest ======================== -// -// By Eric Haines, 3D/Eye Inc, er...@ey... -// -// This version is usually somewhat faster than the original published in -// Graphics Gems IV; by turning the division for testing the X axis crossing -// into a tricky multiplication test this part of the test became faster, -// which had the additional effect of making the test for "both to left or -// both to right" a bit slower for triangles than simply computing the -// intersection each time. The main increase is in triangle testing speed, -// which was about 15% faster; all other polygon complexities were pretty much -// the same as before. On machines where division is very expensive (not the -// case on the HP 9000 series on which I tested) this test should be much -// faster overall than the old code. Your mileage may (in fact, will) vary, -// depending on the machine and the test data, but in general I believe this -// code is both shorter and faster. This test was inspired by unpublished -// Graphics Gems submitted by Joseph Samosky and Mark Haigh-Hutchinson. -// Related work by Samosky is in: -// -// Samosky, Joseph, "SectionView: A system for interactively specifying and -// visualizing sections through three-dimensional medical image data", -// M.S. Thesis, Department of Electrical Engineering and Computer Science, -// Massachusetts Institute of Technology, 1993. -// -// Shoot a test ray along +X axis. The strategy is to compare vertex Y values -// to the testing point's Y and quickly discard edges which are entirely to one -// side of the test ray. Note that CONVEX and WINDING code can be added as -// for the CrossingsTest() code; it is left out here for clarity. -// -// Input 2D polygon _pgon_ with _numverts_ number of vertices and test point -// _point_, returns 1 if inside, 0 if outside. -template<class T> -bool point_in_path_impl(double tx, double ty, T& path) { - int yflag0, yflag1, inside_flag; - double vtx0, vty0, vtx1, vty1, sx, sy; - double x, y; - - path.rewind(0); - unsigned code = path.vertex(&x, &y); - if (code == agg::path_cmd_stop) - return false; - - while (true) { - sx = vtx0 = x; - sy = vty0 = y; - - // get test bit for above/below X axis - yflag0 = (vty0 >= ty); - - vtx1 = x; - vty1 = x; - - inside_flag = 0; - while (true) { - code = path.vertex(&x, &y); - - // The following cases denote the beginning on a new subpath - if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) { - x = sx; y = sy; - } else if (code == agg::path_cmd_move_to) - break; - - yflag1 = (vty1 >= ty); - // Check if endpoints straddle (are on opposite sides) of X axis - // (i.e. the Y's differ); if so, +X ray could intersect this edge. - // The old test also checked whether the endpoints are both to the - // right or to the left of the test point. However, given the faster - // intersection point computation used below, this test was found to - // be a break-even proposition for most polygons and a loser for - // triangles (where 50% or more of the edges which survive this test - // will cross quadrants and so have to have the X intersection computed - // anyway). I credit Joseph Samosky with inspiring me to try dropping - // the "both left or both right" part of my code. - if (yflag0 != yflag1) { - // Check intersection of pgon segment with +X ray. - // Note if >= point's X; if so, the ray hits it. - // The division operation is avoided for the ">=" test by checking - // the sign of the first vertex wrto the test point; idea inspired - // by Joseph Samosky's and Mark Haigh-Hutchinson's different - // polygon inclusion tests. - if ( ((vty1-ty) * (vtx0-vtx1) >= - (vtx1-tx) * (vty0-vty1)) == yflag1 ) { - inside_flag ^= 1; - } - } - - // Move to the next pair of vertices, retaining info as possible. - yflag0 = yflag1; - vtx0 = vtx1; - vty0 = vty1; - - vtx1 = x; - vty1 = y; - - if (code == agg::path_cmd_stop || - (code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) - break; - } - - if (inside_flag != 0) - return true; - - if (code == agg::path_cmd_stop) - return false; - } - - return false; -} - -bool point_in_path(double x, double y, PathIterator& path, agg::trans_affine& trans) { - typedef agg::conv_transform<PathIterator> transformed_path_t; - typedef agg::conv_curve<transformed_path_t> curve_t; - - transformed_path_t trans_path(path, trans); - curve_t curved_path(trans_path); - return point_in_path_impl(x, y, curved_path); -} - -bool point_on_path(double x, double y, double r, PathIterator& path, agg::trans_affine& trans) { - 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; - - transformed_path_t trans_path(path, trans); - curve_t curved_path(trans_path); - stroke_t stroked_path(curved_path); - stroked_path.width(r * 2.0); - return point_in_path_impl(x, y, stroked_path); -} - -Py::Object _backend_agg_module::point_in_path(const Py::Tuple& args) { - args.verify_length(4); - - double x = Py::Float(args[0]); - double y = Py::Float(args[1]); - PathIterator path(args[2]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[3]); - - if (::point_in_path(x, y, path, trans)) - return Py::Int(1); - return Py::Int(0); -} - -Py::Object _backend_agg_module::point_on_path(const Py::Tuple& args) { - args.verify_length(5); - - double x = Py::Float(args[0]); - double y = Py::Float(args[1]); - double r = Py::Float(args[2]); - PathIterator path(args[3]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[4]); - - if (::point_on_path(x, y, r, path, trans)) - return Py::Int(1); - return Py::Int(0); -} - -void get_path_extents(PathIterator& path, agg::trans_affine& trans, - double* x0, double* y0, double* x1, double* y1) { - typedef agg::conv_transform<PathIterator> transformed_path_t; - typedef agg::conv_curve<transformed_path_t> curve_t; - double x, y; - unsigned code; - - transformed_path_t tpath(path, trans); - curve_t curved_path(tpath); - - curved_path.rewind(0); - - while ((code = curved_path.vertex(&x, &y)) != agg::path_cmd_stop) { - if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) - continue; - if (x < *x0) *x0 = x; - if (y < *y0) *y0 = y; - if (x > *x1) *x1 = x; - if (y > *y1) *y1 = y; - } -} - -Py::Object _backend_agg_module::get_path_extents(const Py::Tuple& args) { - args.verify_length(2); - - PathIterator path(args[0]); - agg::trans_affine trans = py_to_agg_transformation_matrix(args[1]); - - double x0 = std::numeric_limits<double>::infinity(); - double y0 = std::numeric_limits<double>::infinity(); - double x1 = -std::numeric_limits<double>::infinity(); - double y1 = -std::numeric_limits<double>::infinity(); - - ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); - - Py::Tuple result(4); - result[0] = Py::Float(x0); - result[1] = Py::Float(y0); - result[2] = Py::Float(x1); - result[3] = Py::Float(y1); - return result; -} - -Py::Object _backend_agg_module::get_path_collection_extents(const Py::Tuple& args) { - args.verify_length(5); - - //segments, trans, clipbox, colors, linewidths, antialiaseds - agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[0]); - Py::SeqBase<Py::Object> paths = args[1]; - Py::SeqBase<Py::Object> transforms_obj = args[2]; - Py::Object offsets_obj = args[3]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[4], false); - - PyArrayObject* offsets = NULL; - double x0, y0, x1, y1; - - try { - offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) - throw Py::ValueError("Offsets array must be Nx2"); - - size_t Npaths = paths.length(); - size_t Noffsets = offsets->dimensions[0]; - size_t N = std::max(Npaths, Noffsets); - size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t i; - - // Convert all of the transforms up front - typedef std::vector<agg::trans_affine> transforms_t; - transforms_t transforms; - transforms.reserve(Ntransforms); - for (i = 0; i < Ntransforms; ++i) { - agg::trans_affine trans = py_to_agg_transformation_matrix - (transforms_obj[i], false); - trans *= master_transform; - transforms.push_back(trans); - } - - // The offset each of those and collect the mins/maxs - x0 = std::numeric_limits<double>::infinity(); - y0 = std::numeric_limits<double>::infinity(); - x1 = -std::numeric_limits<double>::infinity(); - y1 = -std::numeric_limits<double>::infinity(); - for (i = 0; i < N; ++i) { - PathIterator path(paths[i % Npaths]); - - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine trans = transforms[i % Ntransforms]; - trans *= transOffset; - - ::get_path_extents(path, trans, &x0, &y0, &x1, &y1); - } - } catch (...) { - Py_XDECREF(offsets); - throw; - } - - Py_XDECREF(offsets); - - Py::Tuple result(4); - result[0] = Py::Float(x0); - result[1] = Py::Float(y0); - result[2] = Py::Float(x1); - result[3] = Py::Float(y1); - return result; -} - -Py::Object _backend_agg_module::point_in_path_collection(const Py::Tuple& args) { - args.verify_length(9); - - //segments, trans, clipbox, colors, linewidths, antialiaseds - double x = Py::Float(args[0]); - double y = Py::Float(args[1]); - double radius = Py::Float(args[2]); - agg::trans_affine master_transform = py_to_agg_transformation_matrix(args[3]); - Py::SeqBase<Py::Object> paths = args[4]; - Py::SeqBase<Py::Object> transforms_obj = args[5]; - Py::SeqBase<Py::Object> offsets_obj = args[6]; - agg::trans_affine offset_trans = py_to_agg_transformation_matrix(args[7]); - bool filled = Py::Int(args[8]); - - PyArrayObject* offsets = (PyArrayObject*)PyArray_FromObject(offsets_obj.ptr(), PyArray_DOUBLE, 2, 2); - if (!offsets || offsets->dimensions[1] != 2) - throw Py::ValueError("Offsets array must be Nx2"); - - size_t Npaths = paths.length(); - size_t Noffsets = offsets->dimensions[0]; - size_t N = std::max(Npaths, Noffsets); - size_t Ntransforms = std::min(transforms_obj.length(), N); - size_t i; - - // Convert all of the transforms up front - typedef std::vector<agg::trans_affine> transforms_t; - transforms_t transforms; - transforms.reserve(Ntransforms); - for (i = 0; i < Ntransforms; ++i) { - agg::trans_affine trans = py_to_agg_transformation_matrix - (transforms_obj[i], false); - trans *= master_transform; - transforms.push_back(trans); - } - - Py::List result; - - for (i = 0; i < N; ++i) { - PathIterator path(paths[i % Npaths]); - - double xo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 0); - double yo = *(double*)PyArray_GETPTR2(offsets, i % Noffsets, 1); - offset_trans.transform(&xo, &yo); - agg::trans_affine_translation transOffset(xo, yo); - agg::trans_affine trans = transforms[i % Ntransforms]; - trans *= transOffset; - - if (filled) { - if (::point_in_path(x, y, path, trans)) - result.append(Py::Int((int)i)); - } else { - if (::point_on_path(x, y, radius, path, trans)) - result.append(Py::Int((int)i)); - } - } - - return result; -} - /* ------------ module methods ------------- */ Py::Object _backend_agg_module::new_renderer (const Py::Tuple &args, const Py::Dict &kws) Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/src/_backend_agg.h 2007-10-24 16:03:49 UTC (rev 3992) @@ -236,17 +236,6 @@ add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer, "RendererAgg(width, height, dpi)"); - add_varargs_method("point_in_path", &_backend_agg_module::point_in_path, - "point_in_path(x, y, path, trans)"); - add_varargs_method("point_on_path", &_backend_agg_module::point_on_path, - "point_on_path(x, y, r, path, trans)"); - add_varargs_method("get_path_extents", &_backend_agg_module::get_path_extents, - "get_path_extents(path, trans)"); - add_varargs_method("get_path_collection_extents", &_backend_agg_module::get_path_collection_extents, - "get_path_collection_extents(trans, paths, transforms, offsets, offsetTrans)"); - add_varargs_method("point_in_path_collection", &_backend_agg_module::point_in_path_collection, - "point_in_path_collection(x, y, r, trans, paths, transforms, offsets, offsetTrans, filled)"); - initialize( "The agg rendering backend" ); } @@ -255,11 +244,6 @@ private: Py::Object new_renderer (const Py::Tuple &args, const Py::Dict &kws); - Py::Object point_in_path(const Py::Tuple& args); - Py::Object point_on_path(const Py::Tuple& args); - Py::Object get_path_extents(const Py::Tuple& args); - Py::Object get_path_collection_extents(const Py::Tuple& args); - Py::Object point_in_path_collection(const Py::Tuple& args); }; Modified: branches/transforms/src/agg_py_path_iterator.h =================================================================== --- branches/transforms/src/agg_py_path_iterator.h 2007-10-23 21:25:24 UTC (rev 3991) +++ branches/transforms/src/agg_py_path_iterator.h 2007-10-24 16:03:49 UTC (rev 3992) @@ -1,5 +1,10 @@ +#ifndef __AGG_PY_PATH_ITERATOR_H__ +#define __AGG_PY_PATH_ITERATOR_H__ + +#include "CXX/Objects.hxx" #define PY_ARRAY_TYPES_PREFIX NumPy #include "numpy/arrayobject.h" +#include "agg_path_storage.h" class PathIterator { PyArrayObject* vertices; @@ -66,3 +71,5 @@ agg::path_cmd_curve3, agg::path_cmd_curve4, agg::path_cmd_end_poly | agg::path_flags_close}; + +#endif // __AGG_PY_PATH_ITERATOR_H__ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-24 18:49:11
|
Revision: 3996 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3996&view=rev Author: mdboom Date: 2007-10-24 11:49:08 -0700 (Wed, 24 Oct 2007) Log Message: ----------- Initial pass of Gtk, Qt, Qt4, Fltk and Wx GUI backends. Lots more examples passing. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/dynamic_demo_wx.py branches/transforms/examples/embedding_in_gtk.py branches/transforms/examples/embedding_in_gtk2.py branches/transforms/examples/embedding_in_gtk3.py branches/transforms/examples/embedding_in_tk.py branches/transforms/examples/embedding_in_tk2.py branches/transforms/examples/embedding_in_wx.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backends/backend_fltkagg.py branches/transforms/lib/matplotlib/backends/backend_gdk.py branches/transforms/lib/matplotlib/backends/backend_gtk.py branches/transforms/lib/matplotlib/backends/backend_qt.py branches/transforms/lib/matplotlib/backends/backend_qt4.py branches/transforms/lib/matplotlib/backends/backend_qt4agg.py branches/transforms/lib/matplotlib/backends/backend_qtagg.py branches/transforms/lib/matplotlib/backends/backend_wx.py branches/transforms/lib/matplotlib/backends/backend_wxagg.py branches/transforms/lib/matplotlib/backends/tkagg.py branches/transforms/lib/matplotlib/lines.py branches/transforms/setupext.py branches/transforms/src/_backend_agg.h branches/transforms/src/_gtkagg.cpp branches/transforms/src/_tkagg.cpp Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/PASSED_DEMOS 2007-10-24 18:49:08 UTC (rev 3996) @@ -2,14 +2,14 @@ agg_buffer_to_array.py O agg_oo.py O agg_resize.py [BROKEN IN TRUNK] -agg_test.py +agg_test.py ??? alignment_test.py O -animation_blit_fltk.py -animation_blit.py -animation_blit_qt4.py -animation_blit_qt.py -animation_blit_tk.py -animation_blit_wx.py +animation_blit_fltk.py [terminate called after throwing an instance of 'Swig::DirectorMethodException'] +animation_blit.py O +animation_blit_qt4.py O +animation_blit_qt.py O +animation_blit_tk.py O +animation_blit_wx.py O anim.py O [BUT SLOWER] annotation_demo.py O anscombe.py O @@ -56,24 +56,24 @@ date_demo_rrule.py O date_index_formatter.py O dynamic_collection.py O -dynamic_demo.py [GTK] -dynamic_demo_wx.py [WX] -dynamic_image_gtkagg.py -dynamic_image_wxagg2.py -dynamic_image_wxagg.py +dynamic_demo.py O +dynamic_demo_wx.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] +dynamic_image_gtkagg.py O +dynamic_image_wxagg2.py O +dynamic_image_wxagg.py ellipse_demo.py O ellipse_rotated.py O -embedding_in_gtk2.py -embedding_in_gtk3.py -embedding_in_gtk.py -embedding_in_qt4.py -embedding_in_qt.py -embedding_in_tk2.py -embedding_in_tk.py -embedding_in_wx2.py -embedding_in_wx3.py -embedding_in_wx4.py -embedding_in_wx.py +embedding_in_gtk2.py [REQUIRES NON-AGG GDK RENDERER, WHICH IS NOT YET IMPLEMENTED] +embedding_in_gtk3.py O +embedding_in_gtk.py [REQUIRES NON-AGG GDK RENDERER, WHICH IS NOT YET IMPLEMENTED] +embedding_in_qt4.py O +embedding_in_qt.py O +embedding_in_tk2.py O +embedding_in_tk.py O +embedding_in_wx2.py [IDENTICAL BUG IN TRUNK -- Y-AXIS VALUES ARE TRUNCATED] +embedding_in_wx3.py O +embedding_in_wx4.py O +embedding_in_wx.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] errorbar_demo.py O errorbar_limits.py O figimage_demo.py O @@ -91,20 +91,20 @@ font_table_ttf.py [N/A] ftface_props.py [N/A] ganged_plots.py O -glyph_to_path.py [Requires PIL] +glyph_to_path.py O gradient_bar.py O -gtk_spreadsheet.py +gtk_spreadsheet.py [REQUIRES NON-AGG GDK RENDERER, WHICH IS NOT YET IMPLEMENTED] hatch_demo.py O histogram_demo_canvasagg.py [???] histogram_demo.py O image_demo2.py O -image_demo3.py [Requires PIL] +image_demo3.py O image_demo.py O image_interp.py O image_masked.py O [Whew!] image_origin.py O image_slices_viewer.py [BROKEN ON TRUNK] -__init__.py +__init__.py [N/A] integral_demo.py O interactive2.py [N/A] interactive.py [N/A] @@ -119,7 +119,7 @@ legend_scatter.py O line_collection2.py O line_collection.py O -lineprops_dialog_gtk.py +lineprops_dialog_gtk.py O line_styles.py O load_converter.py O loadrec.py O @@ -132,7 +132,7 @@ masked_demo.py O mathtext_demo.py O mathtext_examples.py O -mathtext_wx.py +mathtext_wx.py O matplotlib_icon.py [N/A] matshow.py O movie_demo.py O Modified: branches/transforms/examples/dynamic_demo_wx.py =================================================================== --- branches/transforms/examples/dynamic_demo_wx.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/dynamic_demo_wx.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -62,7 +62,6 @@ FigureManager, NavigationToolbar2Wx from matplotlib.figure import Figure -from matplotlib.axes import Subplot import numpy from wx import * Modified: branches/transforms/examples/embedding_in_gtk.py =================================================================== --- branches/transforms/examples/embedding_in_gtk.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_gtk.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -6,7 +6,6 @@ import gtk -from matplotlib.axes import Subplot from matplotlib.figure import Figure from numpy import arange, sin, pi Modified: branches/transforms/examples/embedding_in_gtk2.py =================================================================== --- branches/transforms/examples/embedding_in_gtk2.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_gtk2.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -5,7 +5,6 @@ """ import gtk -from matplotlib.axes import Subplot from matplotlib.figure import Figure from numpy import arange, sin, pi Modified: branches/transforms/examples/embedding_in_gtk3.py =================================================================== --- branches/transforms/examples/embedding_in_gtk3.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_gtk3.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -5,7 +5,6 @@ import gtk -from matplotlib.axes import Subplot from matplotlib.figure import Figure from numpy import arange, sin, pi Modified: branches/transforms/examples/embedding_in_tk.py =================================================================== --- branches/transforms/examples/embedding_in_tk.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_tk.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -3,7 +3,6 @@ matplotlib.use('TkAgg') from numpy import arange, sin, pi -from matplotlib.axes import Subplot from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_tk2.py =================================================================== --- branches/transforms/examples/embedding_in_tk2.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_tk2.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -3,7 +3,6 @@ matplotlib.use('TkAgg') from numpy import arange, sin, pi -from matplotlib.axes import Subplot from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg from matplotlib.figure import Figure Modified: branches/transforms/examples/embedding_in_wx.py =================================================================== --- branches/transforms/examples/embedding_in_wx.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/examples/embedding_in_wx.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -43,7 +43,6 @@ FigureManager from matplotlib.figure import Figure -from matplotlib.axes import Subplot import numpy from wx import * Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -1538,7 +1538,8 @@ if other is not self: other.set_xlim(self.viewLim.intervalx, emit=False) - self.figure.canvas.draw_idle() + if self.figure.canvas is not None: + self.figure.canvas.draw_idle() return xmin, xmax @@ -1697,7 +1698,8 @@ if other is not self: other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False) - self.figure.canvas.draw_idle() + if self.figure.canvas is not None: + self.figure.canvas.draw_idle() return ymin, ymax def get_yscale(self): @@ -3036,39 +3038,13 @@ ''' where = kwargs.pop('where', 'pre') + if where not in ('pre', 'post', 'mid'): + raise ValueError("'where' argument to step must be 'pre', 'post' or 'mid'") + kwargs['linestyle'] = 'steps-' + where + + return self.plot(x, y, *args, **kwargs) - if not cbook.iterable(x): - x = ma.array([x], dtype=npy.float_) - if not cbook.iterable(y): - y = ma.array([y], dtype=npy.float_) - if where=='pre': - x2 = ma.zeros((2*len(x)-1,), npy.float_) - y2 = ma.zeros((2*len(y)-1,), npy.float_) - - x2[0::2], x2[1::2] = x, x[:-1] - y2[0::2], y2[1:-1:2] = y, y[1:] - - elif where=='post': - x2 = ma.zeros((2*len(x)-1,), npy.float_) - y2 = ma.zeros((2*len(y)-1,), npy.float_) - - x2[::2], x2[1:-1:2] = x, x[1:] - y2[0::2], y2[1::2] = y, y[:-1] - - elif where=='mid': - x2 = ma.zeros((2*len(x),), npy.float_) - y2 = ma.zeros((2*len(y),), npy.float_) - - x2[1:-1:2] = 0.5*(x[:-1]+x[1:]) - x2[2::2] = 0.5*(x[:-1]+x[1:]) - x2[0], x2[-1] = x[0], x[-1] - - y2[0::2], y2[1::2] = y, y - - return self.plot(x2, y2, *args, **kwargs) - - def bar(self, left, height, width=0.8, bottom=None, color=None, edgecolor=None, linewidth=None, yerr=None, xerr=None, ecolor=None, capsize=3, Modified: branches/transforms/lib/matplotlib/backends/backend_fltkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_fltkagg.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_fltkagg.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -140,16 +140,16 @@ self._oldsize =newsize self._source.resize(newsize) self._source.draw() - t1,t2,w,h = self._source.figure.bbox.get_bounds() + t1,t2,w,h = self._source.figure.bbox.bounds Fltk.fl_draw_image(self._source.buffer_rgba(0,0),0,0,int(w),int(h),4,0) self.redraw() def blit(self,bbox=None): if bbox is None: - t1,t2,w,h = self._source.figure.bbox.get_bounds() + t1,t2,w,h = self._source.figure.bbox.bounds else: - t1o,t2o,wo,ho = self._source.figure.bbox.get_bounds() - t1,t2,w,h = bbox.get_bounds() + t1o,t2o,wo,ho = self._source.figure.bbox.bounds + t1,t2,w,h = bbox.bounds x,y=int(t1),int(t2) Fltk.fl_draw_image(self._source.buffer_rgba(x,y),x,y,int(w),int(h),4,int(wo)*4) #self.redraw() @@ -222,7 +222,7 @@ class FigureCanvasFltkAgg(FigureCanvasAgg): def __init__(self, figure): FigureCanvasAgg.__init__(self,figure) - t1,t2,w,h = self.figure.bbox.get_bounds() + t1,t2,w,h = self.figure.bbox.bounds w, h = int(w), int(h) self.canvas=FltkCanvas(0, 0, w, h, "canvas",self) #self.draw() @@ -263,7 +263,7 @@ def __init__(self, canvas, num, window): FigureManagerBase.__init__(self, canvas, num) #Fltk container window - 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 = window self.window.size(w,h+30) @@ -405,7 +405,7 @@ Fltk.Fl_File_Icon.load_system_icons() self._fc = Fltk.Fl_File_Chooser( ".", "*", Fltk.Fl_File_Chooser.CREATE, "Save Figure" ) self._fc.hide() - t1,t2,w,h = canvas.figure.bbox.get_bounds() + t1,t2,w,h = canvas.figure.bbox.bounds w, h = int(w), int(h) self._group = Fltk.Fl_Pack(0,h+2,1000,26) self._group.type(Fltk.FL_HORIZONTAL) @@ -591,7 +591,7 @@ Fltk.Fl_File_Icon.load_system_icons() self._fc = Fltk.Fl_File_Chooser( ".", "*", Fltk.Fl_File_Chooser.CREATE, "Save Figure" ) self._fc.hide() - t1,t2,w,h = self.canvas.figure.bbox.get_bounds() + t1,t2,w,h = self.canvas.figure.bbox.bounds w, h = int(w), int(h) self._group = Fltk.Fl_Pack(0,h+2,1000,26) self._group.type(Fltk.FL_HORIZONTAL) Modified: branches/transforms/lib/matplotlib/backends/backend_gdk.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -353,7 +353,7 @@ def points_to_pixels(self, points): - return points/72.0 * self.dpi.get() + return points/72.0 * self.dpi class GraphicsContextGDK(GraphicsContextBase): Modified: branches/transforms/lib/matplotlib/backends/backend_gtk.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_gtk.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -249,7 +249,7 @@ return # empty fig # resize the figure (in inches) - dpi = self.figure.dpi.get() + dpi = self.figure.dpi self.figure.set_size_inches (w/dpi, h/dpi) self._need_redraw = True Modified: branches/transforms/lib/matplotlib/backends/backend_qt.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_qt.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -110,14 +110,14 @@ def mouseMoveEvent( self, event ): x = event.x() # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height() - event.y() + y = self.figure.bbox.height - event.y() FigureCanvasBase.motion_notify_event( self, x, y ) if DEBUG: print 'mouse move' def mouseReleaseEvent( self, event ): x = event.x() # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height() - event.y() + y = self.figure.bbox.height - event.y() button = self.buttond[event.button()] FigureCanvasBase.button_release_event( self, x, y, button ) if DEBUG: print 'button released' @@ -139,7 +139,7 @@ w = event.size().width() h = event.size().height() if DEBUG: print "FigureCanvasQt.resizeEvent(", w, ",", h, ")" - dpival = self.figure.dpi.get() + dpival = self.figure.dpi winch = w/dpival hinch = h/dpival self.figure.set_size_inches( winch, hinch ) @@ -150,7 +150,7 @@ qt.QWidget.resize( self, w, h ) # Resize the figure by converting pixels to inches. - pixelPerInch = self.figure.dpi.get() + pixelPerInch = self.figure.dpi wInch = w / pixelPerInch hInch = h / pixelPerInch self.figure.set_size_inches( wInch, hInch ) @@ -367,7 +367,7 @@ qt.QApplication.setOverrideCursor( qt.QCursor( cursord[cursor] ) ) def draw_rubberband( self, event, x0, y0, x1, y1 ): - height = self.canvas.figure.bbox.height() + height = self.canvas.figure.bbox.height y1 = height - y1 y0 = height - y0 @@ -384,8 +384,8 @@ toolfig = Figure(figsize=(6,3)) toolfig.subplots_adjust(top=0.9) - w = int (toolfig.bbox.width()) - h = int (toolfig.bbox.height()) + w = int (toolfig.bbox.width) + h = int (toolfig.bbox.height) canvas = self._get_canvas(toolfig) tool = SubplotTool(self.canvas.figure, toolfig) Modified: branches/transforms/lib/matplotlib/backends/backend_qt4.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_qt4.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -101,7 +101,7 @@ def mousePressEvent( self, event ): x = event.pos().x() # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height() - event.pos().y() + y = self.figure.bbox.height - event.pos().y() button = self.buttond[event.button()] FigureCanvasBase.button_press_event( self, x, y, button ) if DEBUG: print 'button pressed:', event.button() @@ -109,14 +109,14 @@ def mouseMoveEvent( self, event ): x = event.x() # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height() - event.y() + y = self.figure.bbox.height - event.y() FigureCanvasBase.motion_notify_event( self, x, y ) #if DEBUG: print 'mouse move' def mouseReleaseEvent( self, event ): x = event.x() # flipy so y=0 is bottom of canvas - y = self.figure.bbox.height() - event.y() + y = self.figure.bbox.height - event.y() button = self.buttond[event.button()] FigureCanvasBase.button_release_event( self, x, y, button ) if DEBUG: print 'button released' @@ -138,7 +138,7 @@ w = event.size().width() h = event.size().height() if DEBUG: print "FigureCanvasQtAgg.resizeEvent(", w, ",", h, ")" - dpival = self.figure.dpi.get() + dpival = self.figure.dpi winch = w/dpival hinch = h/dpival self.figure.set_size_inches( winch, hinch ) @@ -149,7 +149,7 @@ QtGui.QWidget.resize( self, w, h ) # Resize the figure by converting pixels to inches. - pixelPerInch = self.figure.dpi.get() + pixelPerInch = self.figure.dpi wInch = w / pixelPerInch hInch = h / pixelPerInch self.figure.set_size_inches( wInch, hInch ) Modified: branches/transforms/lib/matplotlib/backends/backend_qt4agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qt4agg.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_qt4agg.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -112,8 +112,8 @@ # we are blitting here else: bbox = self.replot - w, h = int(bbox.width()), int(bbox.height()) - l, t = bbox.ll().x().get(), bbox.ur().y().get() + l, b, w, h = bbox.bounds + t = b + h reg = self.copy_from_bbox(bbox) stringBuffer = reg.to_string() qImage = QtGui.QImage(stringBuffer, w, h, QtGui.QImage.Format_ARGB32) @@ -140,8 +140,8 @@ """ self.replot = bbox - w, h = int(bbox.width()), int(bbox.height()) - l, t = bbox.ll().x().get(), bbox.ur().y().get() + l, b, w, h = bbox.bounds + t = b + h self.update(l, self.renderer.height-t, w, h) def print_figure(self, *args, **kwargs): Modified: branches/transforms/lib/matplotlib/backends/backend_qtagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_qtagg.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_qtagg.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -115,8 +115,8 @@ # we are blitting here else: bbox = self.replot - w, h = int(bbox.width()), int(bbox.height()) - l, t = bbox.ll().x().get(), bbox.ur().y().get() + l, b, w, h = bbox.bounds + t = b + h reg = self.copy_from_bbox(bbox) stringBuffer = reg.to_string() qImage = qt.QImage(stringBuffer, w, h, 32, None, 0, qt.QImage.IgnoreEndian) Modified: branches/transforms/lib/matplotlib/backends/backend_wx.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -459,7 +459,7 @@ convert point measures to pixes using dpi and the pixels per inch of the display """ - return points*(PIXELS_PER_INCH/72.0*self.dpi.get()/72.0) + return points*(PIXELS_PER_INCH/72.0*self.dpi/72.0) class GraphicsContextWx(GraphicsContextBase, wx.MemoryDC): """ @@ -735,7 +735,7 @@ FigureCanvasBase.__init__(self, figure) # Set preferred window size hint - helps the sizer (if one is # connected) - l,b,w,h = figure.bbox.get_bounds() + l,b,w,h = figure.bbox.bounds w = int(math.ceil(w)) h = int(math.ceil(h)) @@ -981,6 +981,7 @@ drawDC.BeginDrawing() drawDC.DrawBitmap(self.bitmap, 0, 0) drawDC.EndDrawing() + wx.GetApp().Yield() filetypes = FigureCanvasBase.filetypes.copy() filetypes['bmp'] = 'Windows bitmap' @@ -1092,7 +1093,7 @@ if not self._isConfigured: self._isConfigured = True - dpival = self.figure.dpi.get() + dpival = self.figure.dpi winch = self._width/dpival hinch = self._height/dpival self.figure.set_size_inches(winch, hinch) @@ -1132,7 +1133,7 @@ def _onRightButtonDown(self, evt): """Start measuring on an axis.""" x = evt.GetX() - y = self.figure.bbox.height() - evt.GetY() + y = self.figure.bbox.height - evt.GetY() evt.Skip() self.CaptureMouse() FigureCanvasBase.button_press_event(self, x, y, 3, guiEvent=evt) @@ -1141,7 +1142,7 @@ def _onRightButtonUp(self, evt): """End measuring on an axis.""" x = evt.GetX() - y = self.figure.bbox.height() - evt.GetY() + y = self.figure.bbox.height - evt.GetY() evt.Skip() if self.HasCapture(): self.ReleaseMouse() FigureCanvasBase.button_release_event(self, x, y, 3, guiEvent=evt) @@ -1149,7 +1150,7 @@ def _onLeftButtonDown(self, evt): """Start measuring on an axis.""" x = evt.GetX() - y = self.figure.bbox.height() - evt.GetY() + y = self.figure.bbox.height - evt.GetY() evt.Skip() self.CaptureMouse() FigureCanvasBase.button_press_event(self, x, y, 1, guiEvent=evt) @@ -1157,7 +1158,7 @@ def _onLeftButtonUp(self, evt): """End measuring on an axis.""" x = evt.GetX() - y = self.figure.bbox.height() - evt.GetY() + y = self.figure.bbox.height - evt.GetY() #print 'release button', 1 evt.Skip() if self.HasCapture(): self.ReleaseMouse() @@ -1171,7 +1172,7 @@ """Start measuring on an axis.""" x = evt.GetX() - y = self.figure.bbox.height() - evt.GetY() + y = self.figure.bbox.height - evt.GetY() evt.Skip() FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=evt) @@ -1274,7 +1275,7 @@ pos = wx.DefaultPosition else: pos =wx.Point(20,20) - l,b,w,h = fig.bbox.get_bounds() + l,b,w,h = fig.bbox.bounds wx.Frame.__init__(self, parent=None, id=-1, pos=pos, title="Figure %d" % num, size=(w,h)) @@ -1730,7 +1731,7 @@ dc.ResetBoundingBox() dc.BeginDrawing() - height = self.canvas.figure.bbox.height() + height = self.canvas.figure.bbox.height y1 = height - y1 y0 = height - y0 @@ -2036,7 +2037,7 @@ # so that we can temporarily set them to the dpi of # the printer, and the bg color to white bgcolor = self.canvas.figure.get_facecolor() - fig_dpi = self.canvas.figure.dpi.get() + fig_dpi = self.canvas.figure.dpi # draw the bitmap, scaled appropriately vscale = float(ppw) / fig_dpi Modified: branches/transforms/lib/matplotlib/backends/backend_wxagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_wxagg.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/backend_wxagg.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -19,7 +19,6 @@ import wx import matplotlib from matplotlib.figure import Figure -from matplotlib.transforms import Bbox, Point, Value from backend_agg import FigureCanvasAgg import backend_wx @@ -74,7 +73,7 @@ self.gui_repaint() return - l, b, w, h = bbox.get_bounds() + l, b, w, h = bbox.bounds r = l + w t = b + h x = int(l) Modified: branches/transforms/lib/matplotlib/backends/tkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/tkagg.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/backends/tkagg.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -4,15 +4,19 @@ def blit(photoimage, aggimage, bbox=None, colormode=1): tk = photoimage.tk + if bbox is not None: + bbox_array = bbox.__array__() + else: + bbox_array = None try: - tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox)) + tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array)) except Tk.TclError, v: try: try: _tkagg.tkinit(tk.interpaddr(), 1) except AttributeError: _tkagg.tkinit(id(tk), 0) - tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox)) + tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array)) except (ImportError, AttributeError, Tk.TclError): raise Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -113,14 +113,17 @@ class Line2D(Artist): lineStyles = _lineStyles = { # hidden names deprecated - '-' : '_draw_solid', - '--' : '_draw_dashed', - '-.' : '_draw_dash_dot', - ':' : '_draw_dotted', - 'steps': '_draw_steps', - 'None' : '_draw_nothing', - ' ' : '_draw_nothing', - '' : '_draw_nothing', + '-' : '_draw_solid', + '--' : '_draw_dashed', + '-.' : '_draw_dash_dot', + ':' : '_draw_dotted', + 'steps' : '_draw_steps_pre', + 'steps-mid' : '_draw_steps_mid', + 'steps-pre' : '_draw_steps_pre', + 'steps-post' : '_draw_steps_post', + 'None' : '_draw_nothing', + ' ' : '_draw_nothing', + '' : '_draw_nothing', } markers = _markers = { # hidden names deprecated @@ -208,7 +211,7 @@ data: (npy.array xdata, npy.array ydata) figure: a matplotlib.figure.Figure instance label: any string - linestyle or ls: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ] + linestyle or ls: [ '-' | '--' | '-.' | ':' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' | 'None' | ' ' | '' ] linewidth or lw: float value in points lod: [True | False] marker: [ '+' | ',' | '.' | '1' | '2' | '3' | '4' @@ -566,7 +569,10 @@ """ Set the linestyle of the line - ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ] + 'steps' is equivalent to 'steps-pre' and is maintained for + backward-compatibility. + + ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' | 'None' | ' ' | '' ] """ if linestyle not in self._lineStyles: verbose.report('Unrecognized line style %s, %s' % @@ -668,11 +674,75 @@ renderer.draw_path(gc, path, trans) - def _draw_steps(self, renderer, gc, path, trans): - # MGDTODO: Implement me - raise NotImplementedError("'steps' linestyle should be returning soon...") + def _step(self, x, y, where): + if not cbook.iterable(x): + x = ma.array([x], dtype=npy.float_) + if not cbook.iterable(y): + y = ma.array([y], dtype=npy.float_) + + if where=='pre': + x2 = ma.zeros((2*len(x)-1,), npy.float_) + y2 = ma.zeros((2*len(y)-1,), npy.float_) + + x2[0::2], x2[1::2] = x, x[:-1] + y2[0::2], y2[1:-1:2] = y, y[1:] + + elif where=='post': + x2 = ma.zeros((2*len(x)-1,), npy.float_) + y2 = ma.zeros((2*len(y)-1,), npy.float_) + + x2[::2], x2[1:-1:2] = x, x[1:] + y2[0::2], y2[1::2] = y, y[:-1] + + elif where=='mid': + x2 = ma.zeros((2*len(x),), npy.float_) + y2 = ma.zeros((2*len(y),), npy.float_) + + x2[1:-1:2] = 0.5*(x[:-1]+x[1:]) + x2[2::2] = 0.5*(x[:-1]+x[1:]) + x2[0], x2[-1] = x[0], x[-1] + + y2[0::2], y2[1::2] = y, y + + return x2, y2 + + + def _draw_steps_pre(self, renderer, gc, path, trans): + vertices = self._xy + steps = ma.zeros((2*len(vertices)-1, 2), npy.float_) + + steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] + steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] + + path = Path(steps, closed=False) + self._draw_solid(renderer, gc, path, trans) + + + def _draw_steps_post(self, renderer, gc, path, trans): + vertices = self._xy + steps = ma.zeros((2*len(vertices)-1, 2), npy.float_) + + steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] + steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] + + path = Path(steps, closed=False) + self._draw_solid(renderer, gc, path, trans) + + def _draw_steps_mid(self, renderer, gc, path, trans): + vertices = self._xy + steps = ma.zeros((2*len(vertices), 2), npy.float_) + steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) + steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) + steps[0, 0] = vertices[0, 0] + steps[-1, 0] = vertices[-1, 0] + steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] + + path = Path(steps, closed=False) + self._draw_solid(renderer, gc, path, trans) + + def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle('dashed') if self._dashSeq is not None: @@ -922,7 +992,7 @@ [-1.0, 1.0], [1.0, -1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) - def _draw_x(self, renderer, gc, xt, yt): + def _draw_x(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._x_path, transform, Modified: branches/transforms/setupext.py =================================================================== --- branches/transforms/setupext.py 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/setupext.py 2007-10-24 18:49:08 UTC (rev 3996) @@ -813,7 +813,8 @@ add_agg_flags(module) add_ft2font_flags(module) add_pygtk_flags(module) - + add_numpy_flags(module) + ext_modules.append(module) BUILT_GTKAGG = True Modified: branches/transforms/src/_backend_agg.h =================================================================== --- branches/transforms/src/_backend_agg.h 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/src/_backend_agg.h 2007-10-24 18:49:08 UTC (rev 3996) @@ -233,6 +233,7 @@ : Py::ExtensionModule<_backend_agg_module>( "_backend_agg" ) { RendererAgg::init_type(); + BufferRegion::init_type(); add_keyword_method("RendererAgg", &_backend_agg_module::new_renderer, "RendererAgg(width, height, dpi)"); Modified: branches/transforms/src/_gtkagg.cpp =================================================================== --- branches/transforms/src/_gtkagg.cpp 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/src/_gtkagg.cpp 2007-10-24 18:49:08 UTC (rev 3996) @@ -12,6 +12,8 @@ #include "agg_basics.h" #include "_backend_agg.h" +#define PY_ARRAY_TYPES_PREFIX NumPy +#include "numpy/arrayobject.h" // the extension module class _gtkagg_module : public Py::ExtensionModule<_gtkagg_module> @@ -69,27 +71,30 @@ else { //bbox is not None; copy the image in the bbox // MGDTODO: Use PyArray rather than buffer interface here - PyObject* clipbox = args[2].ptr(); - const void* clipbox_buffer; - Py_ssize_t clipbox_buffer_len; - if (!PyObject_CheckReadBuffer(clipbox)) - throw Py::TypeError - ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); + PyArrayObject* bbox = NULL; + double l, b, r, t; - if (PyObject_AsReadBuffer(clipbox, &clipbox_buffer, &clipbox_buffer_len)) - throw Py::Exception(); + try { + bbox = (PyArrayObject*) PyArray_FromObject(clipbox, PyArray_DOUBLE, 2, 2); + + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { + throw Py::TypeError + ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); + } + + l = *(double*)PyArray_GETPTR2(bbox, 0, 0); + b = *(double*)PyArray_GETPTR2(bbox, 0, 1); + r = *(double*)PyArray_GETPTR2(bbox, 1, 0); + t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - if (clipbox_buffer_len != sizeof(double) * 4) - throw Py::TypeError - ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); - - double* clipbox_values = (double*)clipbox_buffer; - double l = clipbox_values[0]; - double b = clipbox_values[1]; - double r = clipbox_values[2]; - double t = clipbox_values[3]; - + Py_XDECREF(bbox); + bbox = NULL; + } catch (...) { + Py_XDECREF(bbox); + bbox = NULL; + throw; + } //std::cout << b << " " // << t << " "; @@ -146,6 +151,7 @@ { init_pygobject(); init_pygtk(); + import_array(); //suppress unused warning by creating in two lines static _gtkagg_module* _gtkagg = NULL; _gtkagg = new _gtkagg_module; Modified: branches/transforms/src/_tkagg.cpp =================================================================== --- branches/transforms/src/_tkagg.cpp 2007-10-24 18:12:19 UTC (rev 3995) +++ branches/transforms/src/_tkagg.cpp 2007-10-24 18:49:08 UTC (rev 3996) @@ -86,28 +86,28 @@ /* check for bbox/blitting */ bboxo = (PyObject*)atol(argv[4]); if (bboxo != Py_None) { - printf("bbox passed in"); - - const void* bbox_buffer; - Py_ssize_t bbox_buffer_len; - if (!PyObject_CheckReadBuffer(bboxo)) - throw Py::TypeError - ("Argument 5 to PyAggImagePhoto must be a Bbox object."); - - if (PyObject_AsReadBuffer(bboxo, &bbox_buffer, &bbox_buffer_len)) - throw Py::Exception(); - - if (bbox_buffer_len != sizeof(double) * 4) - throw Py::TypeError - ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); - has_bbox = true; + PyArrayObject* bbox = NULL; + try { + bbox = (PyArrayObject*) PyArray_FromObject(bboxo, PyArray_DOUBLE, 2, 2); + + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) { + throw Py::TypeError + ("Argument 3 to agg_to_gtk_drawable must be a Bbox object."); + } + + l = *(double*)PyArray_GETPTR2(bbox, 0, 0); + b = *(double*)PyArray_GETPTR2(bbox, 0, 1); + r = *(double*)PyArray_GETPTR2(bbox, 1, 0); + t = *(double*)PyArray_GETPTR2(bbox, 1, 1); - double* bbox_values = (double*)bbox_buffer; - l = bbox_values[0]; - b = bbox_values[1]; - r = bbox_values[2]; - t = bbox_values[3]; + Py_XDECREF(bbox); + bbox = NULL; + } catch (...) { + Py_XDECREF(bbox); + bbox = NULL; + throw; + } destx = (int)l; desty = srcheight-(int)t; @@ -228,5 +228,7 @@ extern "C" DL_EXPORT(void) init_tkagg(void) { - Py_InitModule("_tkagg", functions); + import_array(); + + Py_InitModule("_tkagg", functions); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-24 19:42:58
|
Revision: 3998 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3998&view=rev Author: mdboom Date: 2007-10-24 12:42:49 -0700 (Wed, 24 Oct 2007) Log Message: ----------- More examples working. Modified Paths: -------------- branches/transforms/examples/poly_editor.py branches/transforms/examples/wxcursor_demo.py branches/transforms/lib/matplotlib/backends/backend_wx.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/transforms.py Modified: branches/transforms/examples/poly_editor.py =================================================================== --- branches/transforms/examples/poly_editor.py 2007-10-24 19:22:00 UTC (rev 3997) +++ branches/transforms/examples/poly_editor.py 2007-10-24 19:42:49 UTC (rev 3998) @@ -68,10 +68,11 @@ def get_ind_under_point(self, event): 'get the index of the vertex under point if within epsilon tolerance' - x, y = zip(*self.poly.xy) # display coords - xt, yt = self.poly.get_transform().numerix_x_y(x, y) + xy = npy.asarray(self.poly.xy) + xyt = self.poly.get_transform().transform(xy) + xt, yt = xyt[:, 0], xyt[:, 1] d = sqrt((xt-event.x)**2 + (yt-event.y)**2) indseq = nonzero(equal(d, amin(d))) ind = indseq[0] @@ -130,7 +131,7 @@ x,y = event.xdata, event.ydata self.poly.xy[self._ind] = x,y self.line.set_data(zip(*self.poly.xy)) - + self.canvas.restore_region(self.background) self.ax.draw_artist(self.poly) self.ax.draw_artist(self.line) Modified: branches/transforms/examples/wxcursor_demo.py =================================================================== --- branches/transforms/examples/wxcursor_demo.py 2007-10-24 19:22:00 UTC (rev 3997) +++ branches/transforms/examples/wxcursor_demo.py 2007-10-24 19:42:49 UTC (rev 3998) @@ -3,6 +3,8 @@ """ import matplotlib +matplotlib.use('WXAgg') + from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas from matplotlib.backends.backend_wx import NavigationToolbar2Wx from matplotlib.figure import Figure @@ -65,6 +67,5 @@ return True if __name__=='__main__': - matplotlib.use('WXAgg') app = App(0) app.MainLoop() Modified: branches/transforms/lib/matplotlib/backends/backend_wx.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-10-24 19:22:00 UTC (rev 3997) +++ branches/transforms/lib/matplotlib/backends/backend_wx.py 2007-10-24 19:42:49 UTC (rev 3998) @@ -2043,7 +2043,7 @@ vscale = float(ppw) / fig_dpi # set figure resolution,bg color for printer - self.canvas.figure.dpi.set(ppw) + self.canvas.figure.dpi = ppw self.canvas.figure.set_facecolor('#FFFFFF') renderer = RendererWx(self.canvas.bitmap, self.canvas.figure.dpi) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-24 19:22:00 UTC (rev 3997) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-24 19:42:49 UTC (rev 3998) @@ -506,8 +506,8 @@ See Patch documentation for additional kwargs """ Patch.__init__(self, **kwargs) - self.xy = xy self._path = Path(xy, closed=True) + self.xy = self._path.vertices __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-24 19:22:00 UTC (rev 3997) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-24 19:42:49 UTC (rev 3998) @@ -927,6 +927,7 @@ The transformed point is returned as a sequence of length self.output_dims. """ + assert len(point) == 2 return self.transform(npy.asarray([point]))[0] def transform_path(self, path): This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-25 14:07:46
|
Revision: 4000 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4000&view=rev Author: mdboom Date: 2007-10-25 07:07:44 -0700 (Thu, 25 Oct 2007) Log Message: ----------- table_demo working. Lots of minor fixes. Faster transforms when debugging is turned off. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/contour_demo.py branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/table.py branches/transforms/lib/matplotlib/transforms.py Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/PASSED_DEMOS 2007-10-25 14:07:44 UTC (rev 4000) @@ -156,13 +156,13 @@ polar_demo.py O polar_legend.py O polar_scatter.py O -poly_editor.py [NEEDS OVERHAUL] +poly_editor.py O poormans_contour.py O -printing_in_wx.py +printing_in_wx.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] print_stdout.py [BROKEN?] psd_demo.py O -pstest.py -pylab_with_gtk.py +pstest.py O +pylab_with_gtk.py O pythonic_matplotlib.py O quadmesh_demo.py O [MASKED VALUES ARE SHOWN DUE TO A BUG IN TRUNK] quiver_demo.py O @@ -190,7 +190,7 @@ subplots_adjust.py O subplot_toolbar.py O system_monitor.py O -table_demo.py +table_demo.py O tex_demo.py O text_handles.py O text_rotation.py O @@ -204,7 +204,7 @@ vertical_ticklabels.py O vline_demo.py O webapp_demo.py -wxcursor_demo.py +wxcursor_demo.py O xcorr_demo.py O zoom_window.py O zorder_demo.py O Modified: branches/transforms/examples/contour_demo.py =================================================================== --- branches/transforms/examples/contour_demo.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/examples/contour_demo.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -92,8 +92,8 @@ # This makes the original colorbar look a bit out of place, # so let's improve its position. -l,b,w,h = gca().get_position() -ll,bb,ww,hh = CB.ax.get_position() +l,b,w,h = gca().get_position().bounds +ll,bb,ww,hh = CB.ax.get_position().bounds CB.ax.set_position([ll, b+0.1*h, ww, h*0.8]) Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -582,8 +582,6 @@ self._yaxis_transform = mtransforms.blended_transform_factory( self.axes.transAxes, self.axes.transData) - self.transData.write_graphviz(open("trans.dot", "w")) - def get_xaxis_transform(self): return self._xaxis_transform @@ -636,8 +634,10 @@ 'original' to change the second; 'both' to change both - ACCEPTS: len(4) sequence of floats + ACCEPTS: len(4) sequence of floats, or a Bbox object """ + if not isinstance(pos, mtransforms.BboxBase): + pos = mtransforms.Bbox.from_bounds(*pos) if which in ('both', 'active'): self._position.set(pos) if which in ('both', 'original'): Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -155,7 +155,7 @@ gc.set_clip_rectangle(cliprect) if clippath is not None: clippath = transforms.TransformedPath(clippath, clippath_trans) - gc.set_clippath(clippath) + gc.set_clip_path(clippath) if Nfacecolors == 0: rgbFace = None Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -1032,7 +1032,7 @@ def writeMarkers(self): for tup in self.markers.values(): name, object, path, trans, fillp, lw = tup - bbox = Bbox.from_extents(*path.get_extents(trans)) + bbox = path.get_extents(trans) bbox = bbox.padded(lw * 0.5) self.beginStream( object.id, None, Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -402,7 +402,6 @@ clipx,clipy,clipw,cliph = bbox.bounds clip.append('%s clipbox' % _nums_to_str(clipw, cliph, clipx, clipy)) if clippath is not None: - print "clippath" id = self._get_clip_path(clippath, clippath_trans) clip.append('%s' % id) clip = '\n'.join(clip) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -448,7 +448,6 @@ renderer.open_group('line2d') if not self._visible: return - self._newstyle = hasattr(renderer, 'draw_markers') gc = renderer.new_gc() self._set_gc_clip(gc) Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -102,7 +102,7 @@ self.set_fill(other.get_fill()) self.set_hatch(other.get_hatch()) self.set_linewidth(other.get_linewidth()) - self.set_transform(other.get_transform()) + self.set_transform(other.get_data_transform()) self.set_figure(other.get_figure()) self.set_alpha(other.get_alpha()) Modified: branches/transforms/lib/matplotlib/scale.py =================================================================== --- branches/transforms/lib/matplotlib/scale.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/scale.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -42,9 +42,6 @@ is_separable = True def transform(self, a): - # MGDTODO: Remove me - if len(a) > 10: - print "log transforming" return ma.log10(ma.masked_where(a <= 0.0, a * 10.0)) def inverted(self): Modified: branches/transforms/lib/matplotlib/table.py =================================================================== --- branches/transforms/lib/matplotlib/table.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/table.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -75,7 +75,6 @@ return self._text def set_fontsize(self, size): - self._text.set_fontsize(size) def get_fontsize(self): @@ -108,7 +107,7 @@ Currently support 'left', 'center' and 'right' """ bbox = self.get_window_extent(renderer) - l, b, w, h = bbox.get_bounds() + l, b, w, h = bbox.bounds # draw in center vertically self._text.set_verticalalignment('center') @@ -130,8 +129,8 @@ def get_text_bounds(self, renderer): """ Get text bounds in axes co-ordinates. """ bbox = self._text.get_window_extent(renderer) - bboxa = bbox.inverse_transformed(self.get_transform()) - return bboxa.get_bounds() + bboxa = bbox.inverse_transformed(self.get_data_transform()) + return bboxa.bounds def get_required_width(self, renderer): """ Get width required for this cell. """ @@ -246,8 +245,8 @@ for pos in self._cells.keys() if pos[0] >= 0 and pos[1] >= 0] - bbox = bbox_all(boxes) - return inverse_transform_bbox(self.get_transform(), bbox) + bbox = Bbox.union(boxes) + return bbox.inverse_transformed(self.get_transform()) def contains(self,mouseevent): """Test whether the mouse event occurred in the table. @@ -393,7 +392,7 @@ self._do_cell_alignment() bbox = self._get_grid_bbox(renderer) - l,b,w,h = bbox.get_bounds() + l,b,w,h = bbox.bounds if self._bbox is not None: # Position according to bbox @@ -530,7 +529,7 @@ if rowLabels is not None: for row in xrange(rows): table.add_cell(row+offset, -1, - width=rowLabelWidth, height=height, + width=rowLabelWidth or 1e-15, height=height, text=rowLabels[row], facecolor=rowColours[row], loc=rowLoc) if rowLabelWidth == 0: Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-24 22:14:57 UTC (rev 3999) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-25 14:07:44 UTC (rev 4000) @@ -32,7 +32,9 @@ import cbook from path import Path -DEBUG = False +DEBUG = True +if DEBUG: + import warnings class TransformNode(object): """ @@ -140,6 +142,9 @@ fobj: A Python file-like object """ + if not DEBUG: + return + seen = cbook.set() def recurse(root): @@ -189,6 +194,15 @@ def __init__(self): TransformNode.__init__(self) + if DEBUG: + def _check(points): + if ma.isMaskedArray(points): + warnings.warn("Bbox bounds are a masked array.") + if (points[1,0] - points[0,0] == 0 or + points[1,1] - points[0,1] == 0): + warnings.warn("Singular Bbox.") + _check = staticmethod(_check) + def frozen(self): return Bbox(self.get_points().copy()) frozen.__doc__ = TransformNode.__doc__ @@ -585,6 +599,16 @@ self._minpos = npy.array([0.0000001, 0.0000001]) self._ignore = True + if DEBUG: + ___init__ = __init__ + def __init__(self, points): + self._check(points) + self.___init__(points) + + def invalidate(self): + self._check(self._points) + TransformNode.invalidate(self) + #@staticmethod def unit(): """ @@ -809,8 +833,14 @@ self._points = self._transform.transform(self._bbox.get_points()) self._invalid = 0 return self._points + + if DEBUG: + _get_points = get_points + def get_points(self): + points = self._get_points() + self._check(points) + return points - class Transform(TransformNode): """ The base class of all TransformNodes that actually perform a @@ -1148,20 +1178,24 @@ matrix_from_values = staticmethod(matrix_from_values) def transform(self, values): - # 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 DEBUG and not isinstance(values, npy.ndarray): - import traceback - print '-' * 60 - print 'A non-numpy array of type %s was passed in for transformation.' % type(values) - print 'Please correct this.' - print "".join(traceback.format_stack()) mtx = self.get_matrix() points = npy.asarray(values, npy.float_) return points * mtx[0, 0] + mtx[0, 1] + + if DEBUG: + _transform = transform + def transform(self, values): + # 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(values, npy.ndarray): + warnings.warn( + ('A non-numpy array of type %s was passed in for ' + + 'transformation. Please correct this.') + % type(values)) + return self._transform(values) transform.__doc__ = AffineBase.transform.__doc__ - + transform_affine = transform transform_affine.__doc__ = AffineBase.transform_affine.__doc__ @@ -1385,22 +1419,26 @@ matrix_from_values = staticmethod(matrix_from_values) def transform(self, 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 DEBUG and not ma.isMaskedArray(points) and not isinstance(points, npy.ndarray): - import traceback - print '-' * 60 - print 'A non-numpy array of type %s was passed in for transformation.' % type(points) - print 'Please correct this.' - print "".join(traceback.format_stack()) mtx = self.get_matrix() if ma.isMaskedArray(points): points = ma.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:] else: - # points = npy.asarray(points, npy.float_) points = npy.dot(mtx[0:2, 0:2], points.transpose()) + mtx[0:2, 2:] return points.transpose() + + if DEBUG: + _transform = transform + def transform(self, 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 ma.isMaskedArray(points) and + not isinstance(points, npy.ndarray)): + warnings.warn( + ('A non-numpy array of type %s was passed in for ' + + 'transformation. Please correct this.') + % type(values)) + return self._transform(points) transform.__doc__ = AffineBase.transform.__doc__ transform_affine = transform @@ -1660,9 +1698,6 @@ create. """ # Here we ask: "Does it blend?" - # MGDTODO: Reinvoke these asserts? - # assert x_transform.is_separable() - # assert y_transform.is_separable() Transform.__init__(self) self._x = x_transform @@ -2111,6 +2146,7 @@ def get_affine(self): return self._transform.get_affine() + def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True): ''' @@ -2231,5 +2267,3 @@ points = npy.asarray([(random(), random()) for i in xrange(10000)]) t = timeit.Timer("trans_sum.transform(points)", "from __main__ import trans_sum, points") 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-10-25 14:10:57
|
Revision: 4001 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4001&view=rev Author: mdboom Date: 2007-10-25 07:10:16 -0700 (Thu, 25 Oct 2007) Log Message: ----------- Merged revisions 3984-4000 via svnmerge from http://matplotlib.svn.sf.net/svnroot/matplotlib/trunk/matplotlib ........ r3991 | efiring | 2007-10-23 17:25:24 -0400 (Tue, 23 Oct 2007) | 2 lines Bugfix: save colorbar axis label so it won't get lost ........ r3999 | efiring | 2007-10-24 18:14:57 -0400 (Wed, 24 Oct 2007) | 2 lines Added ax kwarg to pyplot.colorbar and Figure.colorbar ........ Modified Paths: -------------- branches/transforms/API_CHANGES branches/transforms/CHANGELOG branches/transforms/lib/matplotlib/colorbar.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/pyplot.py Property Changed: ---------------- branches/transforms/ Property changes on: branches/transforms ___________________________________________________________________ Name: svnmerge-integrated - /trunk/matplotlib:1-3983 + /trunk/matplotlib:1-4000 Modified: branches/transforms/API_CHANGES =================================================================== --- branches/transforms/API_CHANGES 2007-10-25 14:07:44 UTC (rev 4000) +++ branches/transforms/API_CHANGES 2007-10-25 14:10:16 UTC (rev 4001) @@ -1,6 +1,11 @@ - Changed cbook.reversed so it yields a tuple rather than a + Added ax kwarg to pyplot.colorbar and Figure.colorbar so that + one can specify the axes object from which space for the colorbar + is to be taken, if one does not want to make the colorbar axes + manually. + + Changed cbook.reversed so it yields a tuple rather than a (index, tuple). This agrees with the python reversed builtin, - and cbook only defines reversed if python doesnt provide the + and cbook only defines reversed if python doesnt provide the builtin. Made skiprows=1 the default on csv2rec Modified: branches/transforms/CHANGELOG =================================================================== --- branches/transforms/CHANGELOG 2007-10-25 14:07:44 UTC (rev 4000) +++ branches/transforms/CHANGELOG 2007-10-25 14:10:16 UTC (rev 4001) @@ -1,3 +1,5 @@ +2007-10-24 Added ax kwarg to Figure.colorbar and pyplot.colorbar - EF + 2007-10-19 Removed a gsave/grestore pair surrounding _draw_ps, which was causing a loss graphics state info (see "EPS output problem - scatter & edgecolors" on mpl-dev, 2007-10-29) @@ -12,7 +14,7 @@ unit/ellipse_compare.py to compare spline with vertex approx for both aspects. JDH -2007-10-05 remove generator expressions from texmanager and mpltraits. +2007-10-05 remove generator expressions from texmanager and mpltraits. generator expressions are not supported by python-2.3 - DSD 2007-10-01 Made matplotlib.use() raise an exception if called after Modified: branches/transforms/lib/matplotlib/colorbar.py =================================================================== --- branches/transforms/lib/matplotlib/colorbar.py 2007-10-25 14:07:44 UTC (rev 4000) +++ branches/transforms/lib/matplotlib/colorbar.py 2007-10-25 14:10:16 UTC (rev 4001) @@ -70,21 +70,27 @@ colorbar_doc = ''' Add a colorbar to a plot. -Function signatures: +Function signatures for the pyplot interface; all but the first are +also method signatures for the Figure.colorbar method: colorbar(**kwargs) - colorbar(mappable, **kwargs) + colorbar(mappable, cax=cax, **kwargs) + colorbar(mappable, ax=ax, **kwargs) - colorbar(mappable, cax, **kwargs) + arguments: + mappable: the image, ContourSet, etc. to which the colorbar applies; + this argument is mandatory for the Figure.colorbar + method but optional for the pyplot.colorbar function, + which sets the default to the current image. -The optional arguments mappable and cax may be included in the kwargs; -they are image, ContourSet, etc. to which the colorbar applies, and -the axes object in which the colorbar will be drawn. Defaults are -the current image and a new axes object created next to that image -after resizing the image. + keyword arguments: + cax: None | axes object into which the colorbar will be drawn + ax: None | parent axes object from which space for a new + colorbar axes will be stolen -kwargs are in two groups: + +**kwargs are in two groups: axes properties: %s colorbar properties: @@ -155,6 +161,7 @@ self.filled = filled self.solids = None self.lines = None + self.set_label('') if cbook.iterable(ticks): self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: @@ -183,6 +190,7 @@ self._config_axes(X, Y) if self.filled: self._add_solids(X, Y, C) + self._set_label() def _config_axes(self, X, Y): ''' @@ -220,12 +228,18 @@ ax.set_xticklabels(ticklabels) ax.xaxis.get_major_formatter().set_offset_string(offset_string) - def set_label(self, label, **kw): + def _set_label(self): if self.orientation == 'vertical': - self.ax.set_ylabel(label, **kw) + self.ax.set_ylabel(self._label, **self._labelkw) else: - self.ax.set_xlabel(label, **kw) + self.ax.set_xlabel(self._label, **self._labelkw) + def set_label(self, label, **kw): + self._label = label + self._labelkw = kw + self._set_label() + + def _outline(self, X, Y): ''' Return x, y arrays of colorbar bounding polygon, @@ -556,6 +570,10 @@ is changed. ''' cm.ScalarMappable.notify(self, mappable) + # We are using an ugly brute-force method: clearing and + # redrawing the whole thing. The problem is that if any + # properties have been changed by methods other than the + # colorbar methods, those changes will be lost. self.ax.cla() self.draw_all() #if self.vmin != self.norm.vmin or self.vmax != self.norm.vmax: Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-25 14:07:44 UTC (rev 4000) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-25 14:10:16 UTC (rev 4001) @@ -790,9 +790,9 @@ self.canvas.print_figure(*args, **kwargs) - def colorbar(self, mappable, cax=None, **kw): - orientation = kw.get('orientation', 'vertical') - ax = self.gca() + def colorbar(self, mappable, cax=None, ax=None, **kw): + if ax is None: + ax = self.gca() if cax is None: cax, kw = cbar.make_axes(ax, **kw) cb = cbar.Colorbar(cax, mappable, **kw) Modified: branches/transforms/lib/matplotlib/pyplot.py =================================================================== --- branches/transforms/lib/matplotlib/pyplot.py 2007-10-25 14:07:44 UTC (rev 4000) +++ branches/transforms/lib/matplotlib/pyplot.py 2007-10-25 14:10:16 UTC (rev 4001) @@ -1081,10 +1081,10 @@ from matplotlib.colorbar import colorbar_doc -def colorbar(mappable = None, cax=None,**kw): +def colorbar(mappable=None, cax=None, ax=None, **kw): if mappable is None: mappable = gci() - ret = gcf().colorbar(mappable, cax = cax, **kw) + ret = gcf().colorbar(mappable, cax = cax, ax=ax, **kw) draw_if_interactive() return ret colorbar.__doc__ = colorbar_doc This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-25 19:16:14
|
Revision: 4004 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4004&view=rev Author: mdboom Date: 2007-10-25 12:16:11 -0700 (Thu, 25 Oct 2007) Log Message: ----------- Increased coverage of backend_driver.py to include almost everything in axes.py. Lots of little bug fixes. Modified Paths: -------------- branches/transforms/PASSED_DEMOS branches/transforms/examples/arrow_demo.py branches/transforms/examples/backend_driver.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_pdf.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/backends/backend_template.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/collections.py branches/transforms/lib/matplotlib/contour.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/patches.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/lib/matplotlib/widgets.py branches/transforms/src/_gtkagg.cpp Added Paths: ----------- branches/transforms/examples/equal_aspect_ratio.py branches/transforms/examples/hline_demo.py Modified: branches/transforms/PASSED_DEMOS =================================================================== --- branches/transforms/PASSED_DEMOS 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/PASSED_DEMOS 2007-10-25 19:16:11 UTC (rev 4004) @@ -60,7 +60,7 @@ dynamic_demo_wx.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] dynamic_image_gtkagg.py O dynamic_image_wxagg2.py O -dynamic_image_wxagg.py +dynamic_image_wxagg.py [REQUIRES NON-AGG WX RENDERER, WHICH IS NOT YET IMPLEMENTED] ellipse_demo.py O ellipse_rotated.py O embedding_in_gtk2.py [REQUIRES NON-AGG GDK RENDERER, WHICH IS NOT YET IMPLEMENTED] Modified: branches/transforms/examples/arrow_demo.py =================================================================== --- branches/transforms/examples/arrow_demo.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/examples/arrow_demo.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -280,6 +280,7 @@ if __name__ == '__main__': from sys import argv + d = None if len(argv) > 1: if argv[1] == 'full': d = all_on_max @@ -293,7 +294,7 @@ elif argv[1] == 'sample': d = sample_data scaled = True - else: + if d is None: d = all_on_max scaled=False if len(argv) > 2: Modified: branches/transforms/examples/backend_driver.py =================================================================== --- branches/transforms/examples/backend_driver.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/examples/backend_driver.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -22,10 +22,16 @@ files = ( 'alignment_test.py', 'arctest.py', + 'arrow_demo.py', 'axes_demo.py', + 'axhspan_demo.py', 'bar_stacked.py', 'barchart_demo.py', + 'boxplot_demo.py', + 'broken_barh.py', + 'barh_demo.py', 'color_demo.py', + 'colorbar_only.py', 'contour_demo.py', 'contourf_demo.py', 'csd_demo.py', @@ -33,6 +39,8 @@ 'customize_rc.py', 'date_demo1.py', 'date_demo2.py', + 'equal_aspect_ratio.py', + 'errorbar_limits.py', 'figimage_demo.py', 'figlegend_demo.py', 'figtext.py', @@ -40,6 +48,7 @@ 'finance_demo.py', 'fonts_demo_kw.py', 'histogram_demo.py', + 'hline_demo.py', 'image_demo.py', 'image_demo2.py', 'image_masked.py', @@ -66,11 +75,18 @@ 'polar_demo.py', 'polar_scatter.py', 'psd_demo.py', + 'quadmesh_demo.py', 'quiver_demo.py', 'scatter_demo.py', 'scatter_demo2.py', + 'scatter_star_poly.py', + 'shared_axis_demo.py', + 'shared_axis_across_figures.py', 'simple_plot.py', 'specgram_demo.py', + 'spy_demos.py', + 'stem_plot.py', + 'step_demo.py', 'stock_demo.py', 'subplot_demo.py', # 'set_and_get.py', @@ -104,7 +120,7 @@ def run(arglist): os.system(' '.join(arglist)) -def drive(backend, python='python', switches = []): +def drive(backend, python=['python'], switches = []): exclude = failbackend.get(backend, []) switchstring = ' '.join(switches) @@ -151,17 +167,20 @@ tmpfile.write('savefig("%s", dpi=150)' % outfile) tmpfile.close() - run([python, tmpfile_name, switchstring]) + run(python + [tmpfile_name, switchstring]) #os.system('%s %s %s' % (python, tmpfile_name, switchstring)) os.remove(tmpfile_name) if __name__ == '__main__': times = {} default_backends = ['Agg', 'PS', 'SVG', 'PDF', 'Template'] - if sys.platform == 'win32': - python = r'c:\Python24\python.exe' + if '--coverage' in sys.argv: + python = ['coverage.py', '-x'] + sys.argv.remove('--coverage') + elif sys.platform == 'win32': + python = [r'c:\Python24\python.exe'] else: - python = 'python' + python = ['python'] all_backends = [b.lower() for b in mplbe.all_backends] all_backends.extend(['cairo.png', 'cairo.ps', 'cairo.pdf', 'cairo.svg']) backends = [] Added: branches/transforms/examples/equal_aspect_ratio.py =================================================================== --- branches/transforms/examples/equal_aspect_ratio.py (rev 0) +++ branches/transforms/examples/equal_aspect_ratio.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -0,0 +1,23 @@ +#!/usr/bin/env python +""" +Example: simple line plot. +Show how to make a plot that has equal aspect ratio +""" +from pylab import * + +t = arange(0.0, 1.0+0.01, 0.01) +s = cos(2*2*pi*t) +plot(t, s, '-', lw=2) + +xlabel('time (s)') +ylabel('voltage (mV)') +title('About as simple as it gets, folks') +grid(True) + +axes().set_aspect('equal', 'datalim') + + +#savefig('simple_plot.png') +savefig('equal_aspect') + +show() Property changes on: branches/transforms/examples/equal_aspect_ratio.py ___________________________________________________________________ Name: svn:executable + * Added: branches/transforms/examples/hline_demo.py =================================================================== --- branches/transforms/examples/hline_demo.py (rev 0) +++ branches/transforms/examples/hline_demo.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -0,0 +1,21 @@ +#!/usr/bin/env python +from matplotlib.pyplot import * +from numpy import sin, exp, absolute, pi, arange +from numpy.random import normal + +def f(t): + s1 = sin(2*pi*t) + e1 = exp(-t) + return absolute((s1*e1))+.05 + + +t = arange(0.0, 5.0, 0.1) +s = f(t) +nse = normal(0.0, 0.3, t.shape) * s + +plot(s+nse, t, 'b^') +hlines(t, [0], s) +xlabel('time (s)') +title('Comparison of model with data') +show() + Property changes on: branches/transforms/examples/hline_demo.py ___________________________________________________________________ Name: svn:executable + * Modified: branches/transforms/lib/matplotlib/artist.py =================================================================== --- branches/transforms/lib/matplotlib/artist.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/artist.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -1,5 +1,5 @@ from __future__ import division -import sys, re +import sys, re, warnings from cbook import iterable, flatten from transforms import Affine2D, Bbox, IdentityTransform, TransformedBbox, \ TransformedPath @@ -174,7 +174,7 @@ """ if callable(self._contains): return self._contains(self,mouseevent) #raise NotImplementedError,str(self.__class__)+" needs 'contains' method" - print str(self.__class__)+" needs 'contains' method" + warnings.warn("'%s' needs 'contains' method" % self.__class__.__name__) return False,{} def set_contains(self,picker): Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -821,16 +821,15 @@ Use self._aspect and self._adjustable to modify the axes box or the view limits. ''' - #MGDTODO: Numpify - - if self._aspect == 'auto': + aspect = self.get_aspect() + if aspect == 'auto': self.set_position( self._originalPosition , 'active') return - if self._aspect == 'equal': + if aspect == 'equal': A = 1 else: - A = self._aspect + A = aspect #Ensure at drawing time that any Axes involved in axis-sharing # does not have its position changed. @@ -843,7 +842,7 @@ box_aspect = A * self.get_data_ratio() pb = self._originalPosition.frozen() pb1 = pb.shrunk_to_aspect(box_aspect, pb, fig_aspect) - self.set_position(pb1.anchored(self._anchor, pb), 'active') + self.set_position(pb1.anchored(self.get_anchor(), pb), 'active') return xmin,xmax = self.get_xbound() @@ -1040,7 +1039,7 @@ a.set_clip_path(self.axesPatch) a._remove_method = lambda h: self.artists.remove(h) - def add_collection(self, collection, autolim=False): + def add_collection(self, collection, autolim=True): 'add a Collection instance to Axes' label = collection.get_label() if not label: @@ -1127,8 +1126,8 @@ self.ignore_existing_data_limits = False def update_datalim_bounds(self, bounds): - # MGDTODO: Document me - self.dataLim.bounds = Bbox.union([self.dataLim, bounds]).bounds + 'Update the datalim to include the given Bbox' + self.dataLim.set(Bbox.union([self.dataLim, bounds])) def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -2017,8 +2016,9 @@ Note this algorithm calculates distance to the vertices of the polygon, so if you want to pick a patch, click on the edge! """ + # MGDTODO: Needs updating if trans is not None: - xywin = trans.xy_tup((x,y)) + xywin = trans.transform_point((x,y)) else: xywin = x,y @@ -2036,12 +2036,12 @@ def dist(a): if isinstance(a, Text): bbox = a.get_window_extent() - l,b,w,h = bbox.get_bounds() + l,b,w,h = bbox.bounds verts = (l,b), (l,b+h), (l+w,b+h), (l+w, b) xt, yt = zip(*verts) elif isinstance(a, Patch): - verts = a.get_verts() - tverts = a.get_transform().seq_xy_tups(verts) + path = a.get_path() + tverts = a.get_transform().transform_path(path) xt, yt = zip(*tverts) elif isinstance(a, mlines.Line2D): xdata = a.get_xdata(orig=False) @@ -3278,19 +3278,19 @@ self.hold(holdstate) # restore previous hold state if adjust_xlim: - xmin, xmax = self.dataLim.intervalx().get_bounds() + xmin, xmax = self.dataLim.intervalx xmin = npy.amin(width) if xerr is not None: xmin = xmin - npy.amax(xerr) xmin = max(xmin*0.9, 1e-100) - self.dataLim.intervalx().set_bounds(xmin, xmax) + self.dataLim.intervalx = (xmin, xmax) if adjust_ylim: - ymin, ymax = self.dataLim.intervaly().get_bounds() + ymin, ymax = self.dataLim.intervaly ymin = npy.amin(height) if yerr is not None: ymin = ymin - npy.amax(yerr) ymin = max(ymin*0.9, 1e-100) - self.dataLim.intervaly().set_bounds(ymin, ymax) + self.dataLim.intervaly = (ymin, ymax) self.autoscale_view() return patches bar.__doc__ = cbook.dedent(bar.__doc__) % martist.kwdocd @@ -4197,7 +4197,7 @@ def quiver(self, *args, **kw): q = mquiver.Quiver(self, *args, **kw) - self.add_collection(q) + self.add_collection(q, False) self.update_datalim_numerix(q.X, q.Y) self.autoscale_view() return q @@ -5170,6 +5170,7 @@ 'get the subplot geometry, eg 2,2,3' return self._rows, self._cols, self._num+1 + # COVERAGE NOTE: Never used internally or from examples def change_geometry(self, numrows, numcols, num): 'change subplot geometry, eg from 1,1,1 to 2,2,3' self._rows = numrows @@ -5238,6 +5239,7 @@ def is_last_col(self): return self.colNum==self.numCols-1 + # COVERAGE NOTE: Never used internally or from examples def label_outer(self): """ set the visible property on ticklabels so xticklabels are Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -223,7 +223,7 @@ baseline (descent), in display coords of the string s with FontPropertry prop """ - return 1,1,1 + raise NotImplementedError def new_gc(self): """ Modified: branches/transforms/lib/matplotlib/backends/backend_pdf.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_pdf.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -1180,11 +1180,12 @@ def get_image_magnification(self): return self.image_magnification - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): #print >>sys.stderr, "draw_image called" + # MGDTODO: Support clippath here gc = self.new_gc() - gc.set_clip_rectangle(bbox.get_bounds()) + gc.set_clip_rectangle(bbox.bounds) self.check_gc(gc) h, w = im.get_size_out() @@ -1714,13 +1715,19 @@ """ cmds = [] for params, cmd in self.commands: - ours = [ getattr(self, p) for p in params ] - theirs = [ getattr(other, p) for p in params ] - try: - different = ours != theirs - except ValueError: - different = ours.shape != theirs.shape or npy.any(ours != theirs) - if ours is not theirs: + different = False + for p in params: + ours = getattr(self, p) + theirs = getattr(other, p) + try: + different = bool(ours != theirs) + except ValueError: + different = ours.shape != theirs.shape or npy.any(ours != theirs) + if different: + break + + if different: + theirs = [getattr(other, p) for p in params] cmds.extend(cmd(self, *theirs)) for p in params: setattr(self, p, getattr(other, p)) Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -994,12 +994,12 @@ tmpfile = os.path.join(gettempdir(), md5.md5(outfile).hexdigest()) fh = file(tmpfile, 'w') - self.figure.dpi.set(72) # ignore the dpi kwarg + self.figure.dpi = 72 # ignore the dpi kwarg width, height = self.figure.get_size_inches() xo = 0 yo = 0 - l, b, w, h = self.figure.bbox.get_bounds() + l, b, w, h = self.figure.bbox.bounds llx = xo lly = yo urx = llx + w Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -193,7 +193,8 @@ details = 'xlink:href="#%s" x="%f" y="%f"' % (name, x, y) self._draw_svg_element('use', details, gc, rgbFace) - def draw_image(self, x, y, im, bbox): + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): + # MGDTODO: Support clippath here trans = [1,0,0,1,0,0] transstr = '' if rcParams['svg.image_noscale']: Modified: branches/transforms/lib/matplotlib/backends/backend_template.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_template.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/backends/backend_template.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -66,24 +66,23 @@ rotation): pass - def draw_image(self, x, y, im, bbox): + def draw_path(self, gc, path, transform, rgbFace=None): pass - def draw_line(self, gc, x1, y1, x2, y2): + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): pass - def draw_lines(self, gc, x, y): + # draw_path_collection is optional, and we get more correct + # relative timings by leaving it out. +# def draw_path_collection(self, master_transform, cliprect, clippath, +# clippath_trans, paths, all_transforms, offsets, +# offsetTrans, facecolors, edgecolors, linewidths, +# linestyles, antialiaseds): +# pass + + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): pass - def draw_point(self, gc, x, y): - pass - - def draw_polygon(self, gcEdge, rgbFace, points): - pass - - def draw_rectangle(self, gcEdge, rgbFace, x, y, width, height): - pass - def draw_text(self, gc, x, y, s, prop, angle, ismath=False): pass Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/cbook.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -174,7 +174,6 @@ def __str__(self): return '<a list of %d %s objects>' % (len(self), self.type) -# MGDTODO: This is very incomplete def strip_math(s): 'remove latex formatting from mathtext' remove = (r'\rm', '\cal', '\tt', '\it', '\\', '{', '}') Modified: branches/transforms/lib/matplotlib/collections.py =================================================================== --- branches/transforms/lib/matplotlib/collections.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/collections.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -126,13 +126,21 @@ return self._transforms def get_datalim(self, transData): + transform = self.get_transform() + transOffset = self._transOffset + offsets = self._offsets + paths = self.get_paths() + if not transform.is_affine: + paths = [transform.transform_path_non_affine(p) for p in paths] + transform = transform.get_affine() + if not transOffset.is_affine: + offsets = transOffset.transform_non_affine(offsets) + transOffset = transOffset.get_affine() + result = path.get_path_collection_extents( - self.get_transform().frozen(), - self.get_paths(), - self.get_transforms(), - self._offsets, - self._transOffset.frozen()) - result = result.transformed(transData.inverted()) + transform.frozen(), paths, self.get_transforms(), + npy.asarray(offsets, npy.float_), transOffset.frozen()) + result = result.inverse_transformed(transData) return result def draw(self, renderer): @@ -143,7 +151,6 @@ offsets = self._offsets paths = self.get_paths() - # MGDTODO: Test me if self.have_units(): paths = [] for path in self._paths: @@ -163,7 +170,6 @@ if clippath_trans is not None: clippath_trans = clippath_trans.frozen() - # MGDTODO: This may benefit from using TransformedPath if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() @@ -193,7 +199,6 @@ paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() - # MGDTODO: Don't pick when outside of clip path / clip box ind = path.point_in_path_collection( mouseevent.x, mouseevent.y, self._pickradius, transform.frozen(), paths, self.get_transforms(), @@ -201,45 +206,6 @@ self._transOffset.frozen(), len(self._facecolors)) return len(ind)>0,dict(ind=ind) - # MGDTODO: Update - def get_transformed_patches(self): - """ - get a sequence of the polygons in the collection in display (transformed) space - - The ith element in the returned sequence is a list of x,y - vertices defining the ith polygon - """ - - verts = self._verts - offsets = self._offsets - usingOffsets = offsets is not None - transform = self.get_transform() - transOffset = self.get_transoffset() - Noffsets = 0 - Nverts = len(verts) - if usingOffsets: - Noffsets = len(offsets) - - N = max(Noffsets, Nverts) - - data = [] - #print 'verts N=%d, Nverts=%d'%(N, Nverts), verts - #print 'offsets; Noffsets=%d'%Noffsets - for i in xrange(N): - #print 'i%%Nverts=%d'%(i%Nverts) - polyverts = verts[i % Nverts] - if npy.any(npy.isnan(polyverts)): - continue - #print 'thisvert', i, polyverts - tverts = transform.seq_xy_tups(polyverts) - if usingOffsets: - #print 'using offsets' - xo,yo = transOffset.xy_tup(offsets[i % Noffsets]) - tverts = [(x+xo,y+yo) for x,y in tverts] - - data.append(tverts) - return data - def set_pickradius(self,pickradius): self.pickradius = 5 def get_pickradius(self): return self.pickradius @@ -414,8 +380,8 @@ self._meshHeight = meshHeight self._coordinates = coordinates self._showedges = showedges - - # MGDTODO: Numpify + + # MGDTODO: Is it possible to Numpify this? coordinates = coordinates.reshape((meshHeight + 1, meshWidth + 1, 2)) c = coordinates paths = [] @@ -542,24 +508,6 @@ def get_paths(self): return self._paths - - # MGDTODO: Update - def get_transformed_patches(self): - # Shouldn't need all these calls to asarray; - # the variables should be converted when stored. - # Similar speedups with numpy should be attainable - # in many other places. - verts = npy.asarray(self._verts) - offsets = npy.asarray(self._offsets) - Npoly = len(offsets) - scales = npy.sqrt(npy.asarray(self._sizes)*self._dpi.get()/72.0) - Nscales = len(scales) - if Nscales >1: - scales = npy.resize(scales, (Npoly, 1, 1)) - transOffset = self.get_transoffset() - xyo = transOffset.numerix_xy(offsets) - polys = scales * verts + xyo[:, npy.newaxis, :] - return polys class StarPolygonCollection(RegularPolyCollection): Modified: branches/transforms/lib/matplotlib/contour.py =================================================================== --- branches/transforms/lib/matplotlib/contour.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/contour.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -464,7 +464,7 @@ ls = mpl.rcParams['contour.negative_linestyle'] col.set_linestyle(ls) col.set_label('_nolegend_') - self.ax.add_collection(col) + self.ax.add_collection(col, False) self.collections.append(col) self.changed() # set the colors x0 = ma.minimum(x) Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/lines.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -25,6 +25,7 @@ (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8) +# COVERAGE NOTE: Never called internally or from examples def unmasked_index_ranges(mask, compressed = True): ''' Calculate the good data ranges in a masked 1-D npy.array, based on mask. @@ -72,45 +73,6 @@ 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. - """ - # Process single points specially - if len(x) < 2: - res, = npy.nonzero( (cx - x)**2 + (cy - y)**2 <= radius**2 ) - return res - - # We need to lop the last element off a lot. - xr,yr = x[:-1],y[:-1] - - # Only look at line segments whose nearest point to C on the line - # lies within the segment. - dx,dy = x[1:]-xr, y[1:]-yr - Lnorm_sq = dx**2+dy**2 # Possibly want to eliminate Lnorm==0 - u = ( (cx-xr)*dx + (cy-yr)*dy )/Lnorm_sq - candidates = (u>=0) & (u<=1) - #if any(candidates): print "candidates",xr[candidates] - - # Note that there is a little area near one side of each point - # which will be near neither segment, and another which will - # be near both, depending on the angle of the lines. The - # following radius test eliminates these ambiguities. - point_hits = (cx - x)**2 + (cy - y)**2 <= radius**2 - #if any(point_hits): print "points",xr[candidates] - candidates = candidates & ~point_hits[:-1] & ~point_hits[1:] - - # For those candidates which remain, determine how far they lie away - # from the line. - px,py = xr+u*dx,yr+u*dy - line_hits = (cx-px)**2 + (cy-py)**2 <= radius**2 - #if any(line_hits): print "lines",xr[candidates] - line_hits = line_hits & candidates - points, = point_hits.ravel().nonzero() - lines, = line_hits.ravel().nonzero() - #print points,lines - return npy.concatenate((points,lines)) - class Line2D(Artist): lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', @@ -381,12 +343,17 @@ else: x, y = args + not_masked = 0 if not ma.isMaskedArray(x): x = npy.asarray(x) + not_masked += 1 if not ma.isMaskedArray(y): y = npy.asarray(y) - if ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or - (y.shape != self._yorig.shape or npy.any(y != self._yorig))): + not_masked += 1 + + if (not_masked < 2 or + ((x.shape != self._xorig.shape or npy.any(x != self._xorig)) or + (y.shape != self._yorig.shape or npy.any(y != self._yorig)))): self._xorig = x self._yorig = y self.recache() Modified: branches/transforms/lib/matplotlib/patches.py =================================================================== --- branches/transforms/lib/matplotlib/patches.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/patches.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -224,7 +224,6 @@ path = self.get_path() transform = self.get_transform() - # MGDTODO: Use a transformed path here? tpath = transform.transform_path_non_affine(path) affine = transform.get_affine() @@ -328,7 +327,7 @@ def __str__(self): return str(self.__class__).split('.')[-1] \ - + "(%g,%g;%gx%g)"%(self.xy[0],self.xy[1],self.width,self.height) + + "(%g,%g;%gx%g)" % tuple(self._bbox.bounds) def __init__(self, xy, width, height, **kwargs): """ @@ -433,7 +432,7 @@ A regular polygon patch. """ def __str__(self): - return "Poly%d(%g,%g)"%(self.numVertices,self.xy[0],self.xy[1]) + return "Poly%d(%g,%g)"%(self._numVertices,self._xy[0],self._xy[1]) def __init__(self, xy, numVertices, radius=5, orientation=0, **kwargs): @@ -447,6 +446,7 @@ %(Patch)s """ self._xy = xy + self._numVertices = numVertices self._orientation = orientation self._radius = radius self._path = Path.unit_regular_polygon(numVertices) @@ -483,6 +483,13 @@ self._radius = xy self._update_transform() radius = property(_get_radius, _set_radius) + + def _get_numvertices(self): + return self._numVertices + def _set_numvertices(self, numVertices): + self._numVertices = numVertices + self._path = Path.unit_regular_polygon(numVertices) + numvertices = property(_get_numvertices, _set_numvertices) def get_path(self): return self._path @@ -495,7 +502,7 @@ A general polygon patch. """ def __str__(self): - return "Poly(%g, %g)" % tuple(self._path.vertices[0]) + return "Poly((%g, %g) ...)" % tuple(self._path.vertices[0]) def __init__(self, xy, **kwargs): """ @@ -507,15 +514,17 @@ """ Patch.__init__(self, **kwargs) self._path = Path(xy, closed=True) - self.xy = self._path.vertices __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): return self._path - def update(self): - self._path = Path(self.xy, closed=True) - + def _get_xy(self): + return self._path.vertices + def _set_xy(self, vertices): + self._path = Path(vertices, closed=True) + xy = property(_get_xy, _set_xy) + class Wedge(Patch): def __str__(self): return "Wedge(%g,%g)"%self.xy[0] @@ -539,16 +548,14 @@ def get_patch_transform(self): return self._patch_transform - + +# COVERAGE NOTE: Not used internally or from examples class Arrow(Polygon): """ An arrow patch """ def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "Arrow(%g,%g)"%(cx,cy) + return "Arrow()" _path = Path( [ [ 0.0, 0.1 ], [ 0.0, -0.1], @@ -584,10 +591,7 @@ """Like Arrow, but lets you set head width and head height independently.""" def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "FancyArrow(%g,%g)"%(cx,cy) + return "FancyArrow()" def __init__(self, x, y, dx, dy, width=0.001, length_includes_head=False, \ head_width=None, head_length=None, shape='full', overhang=0, \ @@ -608,7 +612,6 @@ %(Patch)s """ - # MGDTODO: Implement me if head_width is None: head_width = 3 * width if head_length is None: @@ -664,10 +667,7 @@ x1,y1 and a base at x2, y2. """ def __str__(self): - x1,y1 = self.xy[0] - x2,y2 = self.xy[1] - cx,cy = (x1+x2)/2.,(y1+y2)/2. - return "YAArrow(%g,%g)"%(cx,cy) + return "YAArrow()" def __init__(self, dpi, xytip, xybase, width=4, frac=0.1, headwidth=12, **kwargs): """ @@ -692,9 +692,8 @@ __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd def get_path(self): - # MGDTODO: Since this is dpi dependent, we need to recompute - # the path every time. Perhaps this can be plugged through the - # dpi transform instead (if only we know how to get it...) + # Since this is dpi dependent, we need to recompute the path + # every time. # the base vertices x1, y1 = self.xytip @@ -786,13 +785,16 @@ """ Patch.__init__(self, **kwargs) - self.center = xy - self.width, self.height = width, height - self.angle = angle - self._patch_transform = transforms.Affine2D() \ - .scale(self.width * 0.5, self.height * 0.5) \ - .rotate_deg(angle) \ - .translate(*xy) + self._center = xy + self._width, self._height = width, height + self._angle = angle + self._recompute_transform() + + def _recompute_transform(self): + self._patch_transform = transforms.Affine2D() \ + .scale(self._width * 0.5, self._height * 0.5) \ + .rotate_deg(self._angle) \ + .translate(*self._center) def get_path(self): """ @@ -808,7 +810,28 @@ x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) return (x*x + y*y) <= 1.0, {} + def _get_center(self): + return self._center + def _set_center(self, center): + self._center = center + self._recompute_transform() + center = property(_get_center, _set_center) + def _get_xy(self): + return self._xy + def _set_xy(self, xy): + self._xy = xy + self._recompute_transform() + xy = property(_get_xy, _set_xy) + + def _get_angle(self): + return self._angle + def _set_angle(self, angle): + self._angle = angle + self._recompute_transform() + angle = property(_get_angle, _set_angle) + + class Circle(Ellipse): """ A circle patch @@ -816,8 +839,7 @@ def __str__(self): return "Circle((%g,%g),r=%g)"%(self.center[0],self.center[1],self.radius) - def __init__(self, xy, radius=5, - **kwargs): + def __init__(self, xy, radius=5, **kwargs): """ Create true circle at center xy=(x,y) with given radius; unlike circle polygon which is a polygonal approcimation, this @@ -837,122 +859,6 @@ __init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd -class PolygonInteractor: - """ - An polygon editor. - - Key-bindings - - 't' toggle vertex markers on and off. When vertex markers are on, - you can move them, delete them - - 'd' delete the vertex under point - - 'i' insert a vertex at point. You must be within epsilon of the - line connecting two existing vertices - - """ - - showverts = True - epsilon = 5 # max pixel distance to count as a vertex hit - - def __str__(self): - return "PolygonInteractor" - - def __init__(self, poly): - if poly.figure is None: - raise RuntimeError('You must first add the polygon to a figure or canvas before defining the interactor') - canvas = poly.figure.canvas - self.poly = poly - self.poly.verts = list(self.poly.verts) - x, y = zip(*self.poly.verts) - self.line = lines.Line2D(x,y,marker='o', markerfacecolor='r') - #self._update_line(poly) - - cid = self.poly.add_callback(self.poly_changed) - self._ind = None # the active vert - - canvas.mpl_connect('button_press_event', self.button_press_callback) - canvas.mpl_connect('key_press_event', self.key_press_callback) - canvas.mpl_connect('button_release_event', self.button_release_callback) - canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) - self.canvas = canvas - - - def poly_changed(self, poly): - 'this method is called whenever the polygon object is called' - # only copy the artist props to the line (except visibility) - vis = self.line.get_visible() - artist.Artist.update_from(self.line, poly) - self.line.set_visible(vis) # don't use the poly visibility state - - - def get_ind_under_point(self, event): - 'get the index of the vertex under point if within epsilon tolerance' - x, y = zip(*self.poly.verts) - - # display coords - xt, yt = self.poly.get_transform().numerix_x_y(x, y) - d = npy.sqrt((xt-event.x)**2 + (yt-event.y)**2) - ind, = npy.nonzero(npy.equal(d, npy.amin(d))) - - if d[ind]>=self.epsilon: - ind = None - - return ind - - def button_press_callback(self, event): - 'whenever a mouse button is pressed' - if not self.showverts: return - if event.inaxes==None: return - if event.button != 1: return - self._ind = self.get_ind_under_point(event) - - def button_release_callback(self, event): - 'whenever a mouse button is released' - if not self.showverts: return - if event.button != 1: return - self._ind = None - - def key_press_callback(self, event): - 'whenever a key is pressed' - if not event.inaxes: return - if event.key=='t': - self.showverts = not self.showverts - self.line.set_visible(self.showverts) - if not self.showverts: self._ind = None - elif event.key=='d': - ind = self.get_ind_under_point(event) - if ind is not None: - self.poly.verts = [tup for i,tup in enumerate(self.poly.verts) if i!=ind] - self.line.set_data(zip(*self.poly.verts)) - elif event.key=='i': - xys = self.poly.get_transform().seq_xy_tups(self.poly.verts) - p = event.x, event.y # display coords - for i in range(len(xys)-1): - s0 = xys[i] - s1 = xys[i+1] - d = mlab.dist_point_to_segment(p, s0, s1) - if d<=self.epsilon: - self.poly.verts.insert(i+1, (event.xdata, event.ydata)) - self.line.set_data(zip(*self.poly.verts)) - break - - - self.canvas.draw() - - def motion_notify_callback(self, event): - 'on mouse movement' - if not self.showverts: return - if self._ind is None: return - if event.inaxes is None: return - if event.button != 1: return - x,y = event.xdata, event.ydata - self.poly.verts[self._ind] = x,y - self.line.set_data(zip(*self.poly.verts)) - self.canvas.draw_idle() - - def bbox_artist(artist, renderer, props=None, fill=True): """ This is a debug function to draw a rectangle around the bounding Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/path.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -405,4 +405,7 @@ wedge = classmethod(wedge) def get_path_collection_extents(*args): + from transforms import Bbox + if len(args[1]) == 0: + raise ValueError("No paths provided") return Bbox.from_extents(*_path.get_path_collection_extents(*args)) Modified: branches/transforms/lib/matplotlib/scale.py =================================================================== --- branches/transforms/lib/matplotlib/scale.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/scale.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -9,8 +9,6 @@ from transforms import Affine1DBase, IntervalTransform, Transform, \ composite_transform_factory, IdentityTransform -# MGDTODO: Should the tickers/locators be moved here? - class ScaleBase(object): def set_default_locators_and_formatters(self, axis): raise NotImplementedError Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -32,7 +32,7 @@ import cbook from path import Path -DEBUG = True +DEBUG = False if DEBUG: import warnings @@ -276,7 +276,7 @@ size = property(_get_size) def _get_bounds(self): - ((x0, y0), (x1, y1)) = self.get_points() + x0, y0, x1, y1 = self.get_points().flatten() return (x0, y0, x1 - x0, y1 - y0) bounds = property(_get_bounds) @@ -608,21 +608,24 @@ def invalidate(self): self._check(self._points) TransformNode.invalidate(self) - + + _unit_values = npy.array([[0.0, 0.0], [1.0, 1.0]], npy.float_) #@staticmethod def unit(): """ Create a new unit BBox from (0, 0) to (1, 1). """ - return Bbox.from_extents(0., 0., 1., 1.) + return Bbox(Bbox._unit_values.copy()) unit = staticmethod(unit) #@staticmethod - def from_bounds(left, bottom, width, height): + def from_bounds(x0, y0, width, height): """ - Create a new Bbox from left, bottom, width and height. + Create a new Bbox from x0, y0, width and height. + + width and height may be negative. """ - return Bbox.from_extents(left, bottom, left + width, bottom + height) + return Bbox.from_extents(x0, y0, x0 + width, y0 + height) from_bounds = staticmethod(from_bounds) #@staticmethod @@ -663,7 +666,6 @@ when False, include the existing bounds of the Bbox. when None, use the last value passed to Bbox.ignore(). """ - # MGDTODO: It may be more efficient for some callers to use update_from_data_xy instead if ignore is None: ignore = self._ignore @@ -830,7 +832,11 @@ def get_points(self): if self._invalid: - self._points = self._transform.transform(self._bbox.get_points()) + points = self._transform.transform(self._bbox.get_points()) + if ma.isMaskedArray(points): + points.putmask(0.0) + points = npy.asarray(points) + self._points = points self._invalid = 0 return self._points @@ -1429,8 +1435,8 @@ if DEBUG: _transform = transform def transform(self, points): - # MGDTODO: The major speed trap here is just converting to - # the points to an array in the first place. If we can use + # 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 ma.isMaskedArray(points) and not isinstance(points, npy.ndarray)): @@ -2074,7 +2080,7 @@ """ assert boxin.is_bbox assert boxout.is_bbox - + Affine2DBase.__init__(self) self._boxin = boxin self._boxout = boxout @@ -2092,6 +2098,8 @@ outl, outb, outw, outh = self._boxout.bounds x_scale = outw / inw y_scale = outh / inh + if DEBUG and (x_scale == 0 or y_scale == 0): + raise ValueError("Transforming from or to a singular bounding box.") self._mtx = npy.array([[x_scale, 0.0 , (-inl*x_scale+outl)], [0.0 , y_scale, (-inb*y_scale+outb)], [0.0 , 0.0 , 1.0 ]], @@ -2175,18 +2183,17 @@ return vmin, vmax -# MGDTODO: Optimize (perhaps in an extension) def interval_contains(interval, val): a, b = interval - return (((a < b) - and (a <= val and b >= val)) - or (b <= val and a >= val)) + return ( + ((a < b) and (a <= val and b >= val)) + or (b <= val and a >= val)) def interval_contains_open(interval, val): a, b = interval - return (((a < b) - and (a < val and b > val)) - or (b < val and a > val)) + return ( + ((a < b) and (a < val and b > val)) + or (b < val and a > val)) if __name__ == '__main__': import copy Modified: branches/transforms/lib/matplotlib/widgets.py =================================================================== --- branches/transforms/lib/matplotlib/widgets.py 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/lib/matplotlib/widgets.py 2007-10-25 19:16:11 UTC (rev 4004) @@ -240,9 +240,10 @@ self.set_val(val) def set_val(self, val): - self.poly.xy[-1] = val, 0 - self.poly.xy[-2] = val, 1 - self.poly.update() + xy = self.poly.xy + xy[-1] = val, 0 + xy[-2] = val, 1 + self.poly.xy = xy self.valtext.set_text(self.valfmt%val) if self.drawon: self.ax.figure.canvas.draw() self.val = val Modified: branches/transforms/src/_gtkagg.cpp =================================================================== --- branches/transforms/src/_gtkagg.cpp 2007-10-25 18:16:03 UTC (rev 4003) +++ branches/transforms/src/_gtkagg.cpp 2007-10-25 19:16:11 UTC (rev 4004) @@ -70,7 +70,6 @@ } else { //bbox is not None; copy the image in the bbox - // MGDTODO: Use PyArray rather than buffer interface here PyObject* clipbox = args[2].ptr(); PyArrayObject* bbox = NULL; double l, b, r, t; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-26 16:03:06
|
Revision: 4011 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4011&view=rev Author: mdboom Date: 2007-10-26 08:58:50 -0700 (Fri, 26 Oct 2007) Log Message: ----------- More coverage. Add draw_path_collection to SVG. Modified Paths: -------------- branches/transforms/examples/backend_driver.py branches/transforms/examples/legend_auto.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_ps.py branches/transforms/lib/matplotlib/backends/backend_svg.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/quiver.py branches/transforms/lib/matplotlib/scale.py branches/transforms/lib/matplotlib/transforms.py Modified: branches/transforms/examples/backend_driver.py =================================================================== --- branches/transforms/examples/backend_driver.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/examples/backend_driver.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -55,6 +55,7 @@ 'image_origin.py', 'invert_axes.py', 'layer_images.py', + 'legend_auto.py', 'legend_demo.py', 'legend_demo2.py', 'line_collection.py', Modified: branches/transforms/examples/legend_auto.py =================================================================== --- branches/transforms/examples/legend_auto.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/examples/legend_auto.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -79,7 +79,12 @@ if __name__ == '__main__': nfigs = 10 - figures = [int(f) for f in sys.argv[1:]] + figures = [] + for f in sys.argv[1:]: + try: + figures.append(int(f)) + except ValueError: + pass if len(figures) == 0: figures = range(1, nfigs+1) Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/axis.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -18,7 +18,7 @@ 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, IntervalTransform, IdentityTransform + interval_contains_open, IdentityTransform from patches import bbox_artist from scale import scale_factory Modified: branches/transforms/lib/matplotlib/backends/backend_ps.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/backends/backend_ps.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -505,12 +505,13 @@ path_codes = [] for i, (path, transform) in enumerate(self._iter_collection_raw_paths( master_transform, paths, all_transforms)): - ps_cmd = ['/p%x_%x {' % (self._path_collection_id, i), + name = 'p%x_%x' % (self._path_collection_id, i) + ps_cmd = ['/%s {' % name, 'newpath', 'translate'] ps_cmd.append(self._convert_path(path, transform)) ps_cmd.extend(['} bind def\n']) write('\n'.join(ps_cmd)) - path_codes.append("p%x_%x" % (self._path_collection_id, i)) + path_codes.append(name) for xo, yo, path_id, gc, rgbFace in self._iter_collection( path_codes, cliprect, clippath, clippath_trans, Modified: branches/transforms/lib/matplotlib/backends/backend_svg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/backends/backend_svg.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -42,6 +42,7 @@ self._clipd = {} self._char_defs = {} self._markers = {} + self._path_collection_id = 0 self.mathtext_parser = MathTextParser('SVG') self.fontd = {} svgwriter.write(svgProlog%(width,height,width,height)) @@ -192,7 +193,33 @@ for x, y in tpath.vertices: details = 'xlink:href="#%s" x="%f" y="%f"' % (name, x, y) self._draw_svg_element('use', details, gc, rgbFace) + + def draw_path_collection(self, master_transform, cliprect, clippath, + clippath_trans, paths, all_transforms, offsets, + offsetTrans, facecolors, edgecolors, linewidths, + linestyles, antialiaseds): + write = self._svgwriter.write + + path_codes = [] + write('<defs>\n') + for i, (path, transform) in enumerate(self._iter_collection_raw_paths( + master_transform, paths, all_transforms)): + name = 'coll%x_%x' % (self._path_collection_id, i) + transform = transform.frozen().scale(1.0, -1.0) + d = self._convert_path(path, transform) + write('<path id="%s" d="%s"/>\n' % (name, d)) + path_codes.append(name) + write('</defs>\n') + for xo, yo, path_id, gc, rgbFace in self._iter_collection( + path_codes, cliprect, clippath, clippath_trans, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds): + details = 'xlink:href="#%s" x="%f" y="%f"' % (path_id, xo, self.height - yo) + self._draw_svg_element('use', details, gc, rgbFace) + + self._path_collection_id += 1 + def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None): # MGDTODO: Support clippath here trans = [1,0,0,1,0,0] Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/figure.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -328,7 +328,7 @@ w,h = args dpival = self.dpi - self.bbox_inches.max = w, h + self.bbox_inches.p1 = w, h if forward: dpival = self.dpi @@ -339,7 +339,7 @@ manager.resize(int(canvasw), int(canvash)) def get_size_inches(self): - return self.bbox_inches.max + return self.bbox_inches.p1 def get_edgecolor(self): 'Get the edge color of the Figure rectangle' Modified: branches/transforms/lib/matplotlib/quiver.py =================================================================== --- branches/transforms/lib/matplotlib/quiver.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/quiver.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -238,8 +238,8 @@ self.set_transform(self.Q.ax.figure.transFigure) elif self.coord == 'inches': dx = ax.figure.dpi - bb = transforms.Bbox(transforms.origin(), transforms.Point(dx, dx)) - trans = transforms.get_bbox_transform(transforms.unit_bbox(), bb) + bb = transforms.Bbox.from_extents(0, 0, dx, dy) + trans = transforms.BboxTransform(Bbox.unit(), bb) self.set_transform(trans) else: raise ValueError('unrecognized coordinates') Modified: branches/transforms/lib/matplotlib/scale.py =================================================================== --- branches/transforms/lib/matplotlib/scale.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/scale.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -6,8 +6,7 @@ LogFormatter, LogFormatterMathtext from ticker import NullLocator, FixedLocator, LinearLocator, LogLocator, \ AutoLocator -from transforms import Affine1DBase, IntervalTransform, Transform, \ - composite_transform_factory, IdentityTransform +from transforms import Transform, composite_transform_factory, IdentityTransform class ScaleBase(object): def set_default_locators_and_formatters(self, axis): Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-10-26 03:40:33 UTC (rev 4010) +++ branches/transforms/lib/matplotlib/transforms.py 2007-10-26 15:58:50 UTC (rev 4011) @@ -128,62 +128,63 @@ might normally be used. """ return self - - def write_graphviz(self, fobj, highlight=[]): - """ - For debugging purposes. - Writes the transform tree rooted at 'self' to a graphviz "dot" - format file. This file can be run through the "dot" utility - to produce a graph of the transform tree. + if DEBUG: + def write_graphviz(self, fobj, highlight=[]): + """ + For debugging purposes. - Affine transforms are marked in blue. Bounding boxes are - marked in yellow. + Writes the transform tree rooted at 'self' to a graphviz "dot" + format file. This file can be run through the "dot" utility + to produce a graph of the transform tree. - fobj: A Python file-like object - """ - if not DEBUG: - return - - seen = cbook.set() + Affine transforms are marked in blue. Bounding boxes are + marked in yellow. - def recurse(root): - if root in seen: - return - seen.add(root) - props = {} - label = root.__class__.__name__ - if root._invalid: - label = '[%s]' % label - if root in highlight: - props['style'] = 'bold' - if root.is_affine: - props['shape'] = 'parallelogram' - if root.is_bbox: - props['shape'] = 'box' - props['label'] = '"%s"' % label - props = ' '.join(['%s=%s' % (key, val) for key, val in props.items()]) + fobj: A Python file-like object + """ + seen = cbook.set() - fobj.write('%s [%s];\n' % - (hash(root), props)) + def recurse(root): + if root in seen: + return + seen.add(root) + props = {} + label = root.__class__.__name__ + if root._invalid: + label = '[%s]' % label + if root in highlight: + props['style'] = 'bold' + if root.is_affine: + props['shape'] = 'parallelogram' + if root.is_bbox: + props['shape'] = 'box' + props['label'] = '"%s"' % label + props = ' '.join(['%s=%s' % (key, val) for key, val in props.items()]) - for child in root._children: - name = '?' - for key, val in root.__dict__.items(): - if val is child: - name = key - break - fobj.write('%s -> %s [label="%s", fontsize=10];\n' % ( - hash(root), - hash(child), - name)) - recurse(child) + fobj.write('%s [%s];\n' % + (hash(root), props)) - fobj.write("digraph G {\n") - recurse(self) - fobj.write("}\n") + for child in root._children: + name = '?' + for key, val in root.__dict__.items(): + if val is child: + name = key + break + fobj.write('%s -> %s [label="%s", fontsize=10];\n' % ( + hash(root), + hash(child), + name)) + recurse(child) + + fobj.write("digraph G {\n") + recurse(self) + fobj.write("}\n") + else: + def write_graphviz(self, fobj, highlight=[]): + return + - class BboxBase(TransformNode): """ This is the base class of all bounding boxes, and provides @@ -226,6 +227,14 @@ return self.get_points()[1, 1] y1 = property(_get_y1) + def _get_p0(self): + return self.get_points()[0] + p0 = property(_get_p0) + + def _get_p1(self): + return self.get_points()[1] + p1 = property(_get_p1) + def _get_xmin(self): return min(self.get_points()[:, 0]) xmin = property(_get_xmin) @@ -737,15 +746,15 @@ self.invalidate() y1 = property(BboxBase._get_y1, _set_y1) - def _set_min(self, val): + def _set_p0(self, val): self._points[0] = val self.invalidate() - min = property(BboxBase._get_min, _set_min) - - def _set_max(self, val): + p0 = property(BboxBase._get_p0, _set_p0) + + def _set_p1(self, val): self._points[1] = val self.invalidate() - max = property(BboxBase._get_max, _set_max) + p1 = property(BboxBase._get_p1, _set_p1) def _set_intervalx(self, interval): self._points[:, 0] = interval @@ -1137,240 +1146,6 @@ get_affine.__doc__ = Transform.get_affine.__doc__ -class Affine1DBase(AffineBase): - """ - The base class of all 1D affine transforms. - - Provides the read-only interface. - - 1D affine transformations are performed using a 2x2 numpy array: - - a b - 0 1 - - where a is scale and b is translation. - """ - input_dims = 1 - output_dims = 1 - is_separable = True - - def __init__(self): - AffineBase.__init__(self) - - def frozen(self): - return Affine1D(self.get_matrix().copy()) - frozen.__doc__ = AffineBase.frozen.__doc__ - - def __array__(self, *args, **kwargs): - return self.get_matrix() - - def to_values(self): - """ - Returns a, b - """ - mtx = self.get_matrix() - return mtx[0] - - #@staticmethod - def matrix_from_values(a, b): - """ - Create a new transformation matrix as a numpy array using the - values a, b, where: - - a: scale - b: translation - """ - return npy.array([[a, b], [0.0, 1.0]], npy.float_) - matrix_from_values = staticmethod(matrix_from_values) - - def transform(self, values): - mtx = self.get_matrix() - points = npy.asarray(values, npy.float_) - return points * mtx[0, 0] + mtx[0, 1] - - if DEBUG: - _transform = transform - def transform(self, values): - # 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(values, npy.ndarray): - warnings.warn( - ('A non-numpy array of type %s was passed in for ' + - 'transformation. Please correct this.') - % type(values)) - return self._transform(values) - transform.__doc__ = AffineBase.transform.__doc__ - - transform_affine = transform - transform_affine.__doc__ = AffineBase.transform_affine.__doc__ - - def inverted(self): - if self._inverted is None or self._invalid: - mtx = self.get_matrix() - self._inverted = Affine1D(inv(mtx)) - self._invalid = 0 - return self._inverted - inverted.__doc__ = AffineBase.inverted.__doc__ - - -class Affine1D(Affine1DBase): - """ - A concrete 1D affine transformation. - - 1D affine transformations are performed using a 2x2 numpy array: - - a b - 0 1 - - where a is scale and b is translation. - """ - def __init__(self, matrix = None): - """ - Initialize an Affine transform from a 2x2 numpy float array. - - If matrix is None, initialize with the identity transform. - """ - Affine1DBase.__init__(self) - if matrix is None: - matrix = npy.identity(2) - else: - matrix = npy.asarray(matrix, npy.float_) - assert matrix.shape == (2, 2) - self._mtx = matrix - self._invalid = 0 - - def __repr__(self): - return "Affine1D(%s)" % repr(self._mtx) - __str__ = __repr__ - - def __cmp__(self, other): - if (isinstance(other, Affine1D) and - (self.get_matrix() == other.get_matrix()).all()): - return 0 - return -1 - - #@staticmethod - def from_values(a, b): - """ - Create a new Affine1D instance from the given values. - - a: scale - b: translation - """ - return Affine1D(Affine1D.matrix_from_values(a, b)) - from_values = staticmethod(from_values) - - def get_matrix(self): - """ - Get the underlying transformation matrix as a 2x2 numpy array. - - a b - 0 1 - - where a is scale and b is translation. - """ - self._invalid = 0 - return self._mtx - - def set_matrix(self, mtx): - """ - Set the underlying transformation matrix from a 2x2 numpy array. - - a b - 0 1 - - where a is scale and b is translation. - """ - self._mtx = mtx - self.invalidate() - - def set(self, other): - """ - Set this transformation from a frozen copy of another - Affine1DBase instance. - """ - assert isinstance(other, Affine1DBase) - self._mtx = other.get_matrix() - self.invalidate() - - #@staticmethod - def identity(): - """ - Return a new Affine1D instance that is the identity transform. - - Unless this transform will be mutated later on, consider using - the faster IdentityTransform class instead. - """ - return Affine1D(npy.identity(2)) - identity = staticmethod(identity) - - def clear(self): - """ - Resets this transformation back to the identity transform. - """ - self._mtx = npy.identity(2) - self.invalidate() - return self - - def translate(self, t): - """ - Add a translation t to this transform. - - Returns self, so this method can easily be chained with more - calls to translate() and scale(). - """ - self._mtx[0, 1] += t - self.invalidate() - return self - - def scale(self, s): - """ - Add a scale s to this transform. - - Returns self, so this method can easily be chained with more - calls to translate() and scale(). - """ - self._mtx[0, 0] *= s - self.invalidate() - return self - - -class IntervalTransform(Affine1DBase): - """ - A 1D transformation that linearly transforms points along the - input interval (0.0, 1.0) to an arbitrary child interval. - """ - def __init__(self, bbox, direction): - """ - bbox: A Bbox instance containing the child interval. - direction: A string 'x' or 'y' indicating the interval of the - bbox to use as the child interval. - """ - assert direction in ('x', 'y') - assert bbox.is_bbox - - Affine1DBase.__init__(self) - self._bbox = bbox - self._direction = "interval" + direction - self.set_children(bbox) - self._mtx = None - - def __repr__(self): - return "IntervalTransform(%s)" % (getattr(self._bbox, self._direction)) - __str__ = __repr__ - - def get_matrix(self): - if self._invalid: - vmin, vmax = getattr(self._bbox, self._direction) - self._mtx = inv(npy.array([[vmax - vmin, vmin], - [0.0, 1.0]], npy.float_)) - self._inverted = None - self._invalid = 0 - return self._mtx - get_matrix.__doc__ = Affine1DBase.get_matrix.__doc__ - - class Affine2DBase(AffineBase): """ The base class of all 2D affine transformations. @@ -1780,58 +1555,8 @@ self._invalid = 0 return self._affine get_affine.__doc__ = Transform.get_affine.__doc__ - - -class BlendedAffine1D(Affine2DBase): - """ - A "blended" transform uses one transform for the x-direction, and - another transform for the y-direction. - - This version is an optimization for the case where both child - transforms are of type Affine1DBase. - """ - is_separable = True - def __init__(self, x_transform, y_transform): - """ - Create a new "blended" transform using x_transform to - transform the x-axis and y_transform to transform the y_axis. - - Both x_transform and y_transform must be 1D affine transforms. - - You will generally not call this constructor directly but use - the blended_transform_factory function instead, which can - determine automatically which kind of blended transform to - create. - """ - assert isinstance(x_transform, Affine1DBase) - assert isinstance(y_transform, Affine1DBase) - - Transform.__init__(self) - self._x = x_transform - self._y = y_transform - self.set_children(x_transform, y_transform) - - Affine2DBase.__init__(self) - self._mtx = None - - def __repr__(self): - return "BlendedAffine1D(%s,%s)" % (self._x, self._y) - __str__ = __repr__ - - def get_matrix(self): - if self._invalid: - x_mtx = self._x.get_matrix() - y_mtx = self._y.get_matrix() - self._mtx = npy.array([[x_mtx[0, 0], 0.0, x_mtx[0, 1]], - [0.0, y_mtx[0, 0], y_mtx[0, 1]], - [0.0, 0.0, 1.0]]) - self._inverted = None - self._invalid = 0 - return self._mtx - get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - class BlendedAffine2D(Affine2DBase): """ A "blended" transform uses one transform for the x-direction, and @@ -1900,9 +1625,6 @@ if (isinstance(x_transform, Affine2DBase) and isinstance(y_transform, Affine2DBase)): return BlendedAffine2D(x_transform, y_transform) - elif (isinstance(x_transform, Affine1DBase) - and isinstance(y_transform, Affine1DBase)): - return BlendedAffine1D(x_transform, y_transform) return BlendedGenericTransform(x_transform, y_transform) @@ -2235,7 +1957,7 @@ bbox_copy = copy.deepcopy(bbox) assert (bbox.extents == bbox_copy.extents).all() - bbox_copy.max = (14, 15) + bbox_copy.p1 = (14, 15) assert bbox.bounds == (10, 11, 12, 13) assert bbox_copy.bounds == (10, 11, 4, 4) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <md...@us...> - 2007-10-26 18:32:47
|
Revision: 4019 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4019&view=rev Author: mdboom Date: 2007-10-26 11:32:44 -0700 (Fri, 26 Oct 2007) Log Message: ----------- Can't drag zoom on a polar plot. Finessing Agg drawing quality a little bit. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/projections/polar.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-10-26 18:04:51 UTC (rev 4018) +++ branches/transforms/lib/matplotlib/axes.py 2007-10-26 18:32:44 UTC (rev 4019) @@ -1820,6 +1820,12 @@ #### Interactive manipulation + def can_zoom(self): + """ + Return True if this axes support the zoom box + """ + return True + def get_navigate(self): """ Get whether the axes responds to navigation commands Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-10-26 18:04:51 UTC (rev 4018) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-10-26 18:32:44 UTC (rev 4019) @@ -1361,7 +1361,8 @@ self._xypress=[] for i, a in enumerate(self.canvas.figure.get_axes()): - if x is not None and y is not None and a.in_axes(event) and a.get_navigate(): + if x is not None and y is not None and a.in_axes(event) \ + and a.get_navigate() and a.can_zoom(): self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen())) self.press(event) Modified: branches/transforms/lib/matplotlib/projections/polar.py =================================================================== --- branches/transforms/lib/matplotlib/projections/polar.py 2007-10-26 18:04:51 UTC (rev 4018) +++ branches/transforms/lib/matplotlib/projections/polar.py 2007-10-26 18:32:44 UTC (rev 4019) @@ -55,8 +55,11 @@ transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ def transform_path(self, path): - path = path.interpolated(self._resolution) - return Path(self.transform(path.vertices), path.codes) + vertices = path.vertices + if len(vertices) == 2 and vertices[0, 0] == vertices[1, 0]: + return Path(self.transform(vertices), path.codes) + ipath = path.interpolated(self._resolution) + return Path(self.transform(ipath.vertices), ipath.codes) transform_path.__doc__ = Transform.transform_path.__doc__ transform_path_non_affine = transform_path @@ -151,7 +154,7 @@ def refresh(self): return self.base.refresh() - RESOLUTION = 50 + RESOLUTION = 75 def __init__(self, *args, **kwargs): """ @@ -377,6 +380,12 @@ return 1.0 ### Interactive panning + + def can_zoom(self): + """ + Return True if this axes support the zoom box + """ + return False def start_pan(self, x, y, button): angle = self._r_label1_position.to_values()[4] / 180.0 * npy.pi Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-10-26 18:04:51 UTC (rev 4018) +++ branches/transforms/src/_backend_agg.cpp 2007-10-26 18:32:44 UTC (rev 4019) @@ -95,8 +95,8 @@ unsigned vertex(double* x, double* y) { unsigned cmd = m_source->vertex(x, y); if (m_quantize && agg::is_vertex(cmd)) { - *x = int(*x) + 0.5; - *y = int(*y) + 0.5; + *x = round(*x) + 0.5; + *y = round(*y) + 0.5; } return cmd; } @@ -389,7 +389,7 @@ } trans.transform(&x1, &y1); - if (!(fabs(x0 - x1) < 0.001 || fabs(y0 - y1) < 0.001)) { + if (!(fabs(x0 - x1) < 1e-4 || fabs(y0 - y1) < 1e-4)) { path.rewind(0); return false; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |