Revision: 3869 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3869&view=rev Author: mdboom Date: 2007-09-20 11:00:32 -0700 (Thu, 20 Sep 2007)
Log Message: ----------- First baby step in getting arbitrary non-linear transformations into the pipeline. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/path.py branches/transforms/lib/matplotlib/text.py branches/transforms/lib/matplotlib/transforms.py Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -633,10 +633,16 @@ self.transAxes = mtransforms.BboxTransform( mtransforms.Bbox.unit(), self.bbox) # self.set_transform(self.transAxes) - self.transData = mtransforms.BboxTransform( - self.viewLim, self.bbox) +# self.transData = mtransforms.BboxTransform( +# self.viewLim, self.bbox) + self.preDataTransform = mtransforms.BboxTransform( + self.viewLim, mtransforms.Bbox.unit()) + self.dataTransform = mtransforms.TestLogTransform() + # self.dataTransform = mtransforms.Affine2D().scale(1.5) + self.transData = self.preDataTransform + self.dataTransform + mtransforms.BboxTransform( + mtransforms.Bbox.unit(), self.bbox) + - def get_position(self, original=False): 'Return the axes rectangle left, bottom, width, height' if original: Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -1032,18 +1032,17 @@ else: bbox = Bbox.union(bboxes) bottom = bbox.ymin - - self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi / 72.0)) - + self.label.set_position( (x, bottom - self.LABELPAD*self.figure.dpi / 72.0)) + else: if not len(bboxes2): top = self.axes.bbox.ymax else: bbox = bbox_union(bboxes2) top = bbox.ymax + + self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi / 72.0)) - self.label.set_position( (x, top+self.LABELPAD*self.figure.dpi.get()/72.0)) - def _update_offset_text_position(self, bboxes, bboxes2): """ Update the offset_text position based on the sequence of bounding Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -84,7 +84,8 @@ from matplotlib.font_manager import findfont from matplotlib.ft2font import FT2Font, LOAD_DEFAULT from matplotlib.mathtext import MathTextParser -from matplotlib.transforms import Bbox +from matplotlib.path import Path +from matplotlib.transforms import Affine2D, Bbox from _backend_agg import RendererAgg as _RendererAgg @@ -117,8 +118,8 @@ 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_image = self._renderer.draw_image self.copy_from_bbox = self._renderer.copy_from_bbox self.restore_region = self._renderer.restore_region @@ -129,6 +130,17 @@ if __debug__: verbose.report('RendererAgg.__init__ done', 'debug-annoying') + # MGDTODO: This is a hack for now to allow for arbitrary transformations + def draw_path(self, gc, path, trans, rgbFace=None): + new_path, affine = path.transformed_without_affine(trans) + self._renderer.draw_path(gc, new_path, affine, rgbFace) + + # MGDTODO: This is a hack for now to allow for arbitrary transformations + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + assert marker_trans.is_affine() + new_path, affine = path.transformed_without_affine(trans) + self._renderer.draw_markers(gc, marker_path, marker_trans, new_path, affine, rgbFace) + def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -1102,12 +1102,14 @@ """ return self._dashcapstyle + def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle + def is_dashed(self): 'return True if line is dashstyle' return self._linestyle in ('--', '-.', ':') Modified: branches/transforms/lib/matplotlib/path.py =================================================================== --- branches/transforms/lib/matplotlib/path.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/path.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -70,6 +70,13 @@ yield vertices[i] i += 1 + def transformed(self, transform): + return Path(transform.transform(self.vertices), self.codes) + + def transformed_without_affine(self, transform): + vertices, affine = transform.transform_without_affine(self.vertices) + return Path(vertices, self.codes), affine + _unit_rectangle = None [EMAIL PROTECTED] def unit_rectangle(cls): Modified: branches/transforms/lib/matplotlib/text.py =================================================================== --- branches/transforms/lib/matplotlib/text.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/text.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -185,7 +185,8 @@ 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: @@ -260,27 +261,21 @@ else: offsety = ty - ymin xmin += offsetx - xmax += offsetx ymin += offsety - ymax += offsety bbox = Bbox.from_lbwh(xmin, ymin, width, height) - - # now rotate the positions around the first x,y position xys = M.transform(offsetLayout) - tx = xys[:, 0] - ty = xys[:, 1] - tx += offsetx - ty += offsety + xys[:, 0] += offsetx + xys[:, 1] += offsety # now inverse transform back to data coords inverse_transform = self.get_transform().inverted() xys = inverse_transform.transform(xys) - xs, ys = zip(*xys) - + xs, ys = xys[:, 0], xys[:, 1] + ret = bbox, zip(lines, whs, xs, ys) self.cached[key] = ret return ret @@ -331,15 +326,15 @@ 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, self._fontproperties, angle, ismath=self.is_math_text(line)) - + def get_color(self): "Return the color of the text" return self._color @@ -407,7 +402,9 @@ return (x, y, self._text, self._color, self._verticalalignment, self._horizontalalignment, hash(self._fontproperties), self._rotation, - self.get_transform(), + # MGDTODO: Find a better way to determine if the + # transform as changed + str(self.get_transform()) ) def get_text(self): Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-20 14:26:27 UTC (rev 3868) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-20 18:00:32 UTC (rev 3869) @@ -256,10 +256,10 @@ self.invalidate() def transformed(self, transform): - return Bbox(transform(self._points)) + return Bbox(transform.transform(self._points)) def inverse_transformed(self, transform): - return Bbox(transform.inverted()(self._points)) + return Bbox(transform.inverted().transform(self._points)) def expanded(self, sw, sh): width = self.width @@ -408,13 +408,13 @@ # MGDTODO: The major speed trap here is just converting to # the points to an array in the first place. If we can use # more arrays upstream, that should help here. - if not isinstance(points, npy.ndarray): - import traceback - print '-' * 60 - print 'A non-numpy array was passed in for transformation. Please ' - print 'correct this.' - print "".join(traceback.format_stack()) - print points +# if not isinstance(points, npy.ndarray): +# import traceback +# print '-' * 60 +# print 'A non-numpy array was passed in for transformation. Please ' +# print 'correct this.' +# print "".join(traceback.format_stack()) +# print points mtx = self.get_matrix() points = npy.asarray(points, npy.float_) points = points.transpose() @@ -563,6 +563,10 @@ self._y = y_transform self.set_children(['_x', '_y']) + def __repr__(self): + return "BlendedGenericTransform(%s,%s)" % (self._x, self._y) + __str__ = __repr__ + def transform(self, points): # MGDTODO: Optimize the case where one of these is # an affine @@ -590,28 +594,6 @@ return True -class BlendedSeparableTransform(Transform): - input_dims = 2 - output_dims = 2 - - def __init__(self, x_transform, y_transform): - # Here we ask: "Does it blend?" - assert x_transform.is_separable() - assert y_transform.is_separable() - assert x_transform.input_dims == x.transform.output_dims == 1 - assert y_transform.input_dims == y.transform.output_dims == 1 - - Transform.__init__(self) - self._x = x_transform - self._y = y_transform - self.set_children(['_x', '_y']) - - def transform(self, points): - x_points = self._x(points[:, 0]) - y_points = self._y(points[:, 1]) - return npy.vstack((x_points[:, 0:1], y_points[:, 1:2])).transpose() - - class BlendedAffine2D(Affine2DBase, Transform): def __init__(self, x_transform, y_transform): assert x_transform.is_affine() @@ -666,6 +648,10 @@ self._a = a self._b = b self.set_children(['_a', '_b']) + + def __repr__(self): + return "CompositeGenericTransform(%s, %s)" % (self._a, self._b) + __str__ = __repr__ def transform(self, points): return self._b.transform(self._a.transform(points)) @@ -724,10 +710,21 @@ input_dims = 2 output_dims = 2 def transform(self, xy): - return xy * 2 + marray = npy.ma.masked_where(xy <= 0.0, xy * 10.0) + return npy.log10(marray) + + def inverted(self): + return TestInvertLogTransform() + +class TestInvertLogTransform(Transform): + input_dims = 2 + output_dims = 2 + def transform(self, xy): + return npy.power(10, xy) / 10.0 + def inverted(self): - return self + return TestLogTransform() class BboxTransform(Affine2DBase): @@ -825,7 +822,7 @@ assert bbox.bounds == (10, 15, 10, 10) - print npy.asarray(bbox) + assert tuple(npy.asarray(bbox).flatten()) == (10, 15, 20, 25) bbox.intervalx = (11, 21) bbox.intervaly = (16, 26) @@ -859,29 +856,35 @@ scale = Affine2D().scale(10, 20) assert scale.to_values() == (10, 0, 0, 20, 0, 0) rotation = Affine2D().rotate_deg(30) - print rotation.to_values() == (0.86602540378443871, 0.49999999999999994, + assert rotation.to_values() == (0.86602540378443871, 0.49999999999999994, -0.49999999999999994, 0.86602540378443871, 0.0, 0.0) points = npy.array([[1,2],[3,4],[5,6],[7,8]], npy.float_) - translated_points = translation(points) + translated_points = translation.transform(points) assert (translated_points == [[11., 22.], [13., 24.], [15., 26.], [17., 28.]]).all() - scaled_points = scale(points) + scaled_points = scale.transform(points) print scaled_points - rotated_points = rotation(points) + rotated_points = rotation.transform(points) print rotated_points - tpoints1 = rotation(translation(scale(points))) + tpoints1 = rotation.transform(translation.transform(scale.transform(points))) trans_sum = scale + translation + rotation - tpoints2 = trans_sum(points) - print tpoints1, tpoints2 - print tpoints1 == tpoints2 + tpoints2 = trans_sum.transform(points) # Need to do some sort of fuzzy comparison here? - # assert (tpoints1 == tpoints2).all() + assert (tpoints1.round() == tpoints2.round()).all() + print points + + comp = TestLogTransform() + Affine2D().rotate_deg(15) + tpoints = comp.transform(points) + itpoints = comp.inverted().transform(tpoints) + print tpoints, itpoints + assert (points.round() == itpoints.round()).all() + # Here are some timing tests points = npy.asarray([(random(), random()) for i in xrange(10000)]) - t = timeit.Timer("trans_sum(points)", "from __main__ import trans_sum, points") + 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. ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Matplotlib-checkins mailing list Matplotlib-checkins@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins