From: <md...@us...> - 2007-09-18 19:29:24
|
Revision: 3856 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3856&view=rev Author: mdboom Date: 2007-09-18 12:29:21 -0700 (Tue, 18 Sep 2007) Log Message: ----------- Optimize shared axes (to prevent calling set_xlim/set_ylim more than once per axes per update). Save figure at correct dpi. General cleanup and optimizations. Modified Paths: -------------- branches/transforms/lib/matplotlib/axes.py branches/transforms/lib/matplotlib/axis.py branches/transforms/lib/matplotlib/backend_bases.py branches/transforms/lib/matplotlib/backends/backend_agg.py branches/transforms/lib/matplotlib/backends/backend_gtkagg.py branches/transforms/lib/matplotlib/backends/backend_tkagg.py branches/transforms/lib/matplotlib/cbook.py branches/transforms/lib/matplotlib/figure.py branches/transforms/lib/matplotlib/legend.py branches/transforms/lib/matplotlib/lines.py branches/transforms/lib/matplotlib/transforms.py branches/transforms/src/_backend_agg.cpp Modified: branches/transforms/lib/matplotlib/axes.py =================================================================== --- branches/transforms/lib/matplotlib/axes.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/axes.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -435,6 +435,9 @@ 1 : 'log', } + _shared_x_axes = cbook.Grouper() + _shared_y_axes = cbook.Grouper() + def __str__(self): return "Axes(%g,%g;%gx%g)" % tuple(self._position.bounds) def __init__(self, fig, rect, @@ -491,6 +494,10 @@ # must be set before set_figure self._sharex = sharex self._sharey = sharey + if sharex is not None: + self._shared_x_axes.join(self, sharex) + if sharey is not None: + self._shared_y_axes.join(self, sharey) # Flag: True if some other Axes instance is sharing our x or y axis self._masterx = False self._mastery = False @@ -502,7 +509,6 @@ # this call may differ for non-sep axes, eg polar self._init_axis() - if axisbg is None: axisbg = rcParams['axes.facecolor'] self._axisbg = axisbg self._frameon = frameon @@ -616,55 +622,28 @@ #these will be updated later as data is added self._set_lim_and_transforms() - def _shared_xlim_callback(self, ax): - xmin, xmax = ax.get_xlim() - self.set_xlim(xmin, xmax, emit=False) - self.figure.canvas.draw_idle() - - def _shared_ylim_callback(self, ax): - ymin, ymax = ax.get_ylim() - self.set_ylim(ymin, ymax, emit=False) - self.figure.canvas.draw_idle() - def _set_lim_and_transforms(self): """ set the dataLim and viewLim BBox attributes and the transData and transAxes Transformation attributes """ - Bbox = mtransforms.Bbox - self.viewLim = Bbox.unit() + self.viewLim = mtransforms.Bbox.unit() + self.dataLim = mtransforms.Bbox.unit() - if self._sharex is not None: - # MGDTODO: This may be doing at least one too many updates - # than necessary - self._sharex.callbacks.connect( - 'xlim_changed', self._shared_xlim_callback) - self.viewLim.intervalx = self._sharex.viewLim.intervalx - if self._sharey is not None: - self._sharey.callbacks.connect( - 'ylim_changed', self._shared_ylim_callback) - self.viewLim.intervaly = self._sharex.viewLim.intervaly - - self.dataLim = Bbox.unit() - self.transAxes = mtransforms.BboxTransform( - Bbox.unit(), self.bbox) - + mtransforms.Bbox.unit(), self.bbox) self.transData = mtransforms.BboxTransform( self.viewLim, self.bbox) def get_position(self, original=False): 'Return the axes rectangle left, bottom, width, height' - # MGDTODO: This changed from returning a list to returning a Bbox - # If you get any errors with the result of this function, please - # update the calling code if original: - return copy.copy(self._originalPosition) + return self._originalPosition else: - return copy.copy(self._position) - # return [val.get() for val in self._position] + return self._position + def set_position(self, pos, which='both'): """ Set the axes position with pos = [left, bottom, width, height] @@ -699,8 +678,7 @@ self.xaxis.cla() self.yaxis.cla() - # MGDTODO - # self.dataLim.ignore(1) + self.ignore_existing_data_limits = True self.callbacks = cbook.CallbackRegistry(('xlim_changed', 'ylim_changed')) if self._sharex is not None: @@ -886,7 +864,7 @@ return - l,b,w,h = self.get_position(original=True) + l,b,w,h = self.get_position(original=True).bounds box_aspect = fig_aspect * (h/w) data_ratio = box_aspect / A @@ -1152,7 +1130,7 @@ # Otherwise, it will compute the bounds of it's current data # and the data in xydata xys = npy.asarray(xys) - self.dataLim.update_numerix_xy(xys, -1) + self.update_datalim_numerix(xys[:, 0], xys[:, 1]) def update_datalim_numerix(self, x, y): @@ -1161,10 +1139,9 @@ # limits and set the bound to be the bounds of the xydata. # Otherwise, it will compute the bounds of it's current data # and the data in xydata - #print type(x), type(y) - # MGDTODO ## self.dataLim.update_numerix(x, y, -1) - self.dataLim.update_from_data(x, y) + self.dataLim.update_from_data(x, y, self.ignore_existing_data_limits) + self.ignore_existing_data_limits = False def _get_verts_in_data_coords(self, trans, xys): if trans == self.transData: @@ -1264,9 +1241,7 @@ if not self.get_visible(): return renderer.open_group('axes') self.apply_aspect() - # MGDTODO -- this is where we can finalize all of the transforms - # self.transData.freeze() # eval the lazy objects - # self.transAxes.freeze() + if self.axison and self._frameon: self.axesPatch.draw(renderer) artists = [] @@ -1314,17 +1289,13 @@ if self.axison and self._frameon: artists.append(self.axesFrame) - # keep track of i to guarantee stable sort for python 2.2 - dsu = [ (a.zorder, i, a) for i, a in enumerate(artists) - if not a.get_animated()] + dsu = [ (a.zorder, a) for a in artists + if not a.get_animated() ] dsu.sort() - for zorder, i, a in dsu: + for zorder, a in dsu: a.draw(renderer) - # MGDTODO - # self.transData.thaw() # release the lazy objects - # self.transAxes.thaw() # release the lazy objects renderer.close_group('axes') self._cachedRenderer = renderer @@ -1509,7 +1480,6 @@ ACCEPTS: len(2) sequence of floats """ - if xmax is None and iterable(xmin): xmin,xmax = xmin @@ -1534,11 +1504,10 @@ self.viewLim.intervalx = (xmin, xmax) if emit: self.callbacks.process('xlim_changed', self) - # MGDTODO: It would be nice to do this is in the above callback list, - # but it's difficult to tell how to initialize this at the - # right time - if self._sharex: - self._sharex.set_xlim(*self.viewLim.intervalx) + # Call all of the other x-axes that are shared with this one + for other in self._shared_x_axes.get_siblings(self): + if other is not self: + other.set_xlim(self.viewLim.xmin, self.viewLim.xmax, emit=False) return xmin, xmax @@ -1665,11 +1634,10 @@ self.viewLim.intervaly = (ymin, ymax) if emit: self.callbacks.process('ylim_changed', self) - # MGDTODO: It would be nice to do this is in the above callback list, - # but it's difficult to tell how to initialize this at the - # right time - if self._sharey: - self._sharey.set_ylim(*self.viewLim.intervaly) + # Call all of the other y-axes that are shared with this one + for other in self._shared_y_axes.get_siblings(self): + if other is not self: + other.set_ylim(self.viewLim.ymin, self.viewLim.ymax, emit=False) return ymin, ymax Modified: branches/transforms/lib/matplotlib/axis.py =================================================================== --- branches/transforms/lib/matplotlib/axis.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/axis.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -1033,8 +1033,7 @@ bbox = Bbox.union(bboxes) bottom = bbox.ymin - self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi/72.0)) -# self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi.get()/72.0)) MGDTODO + self.label.set_position( (x, bottom-self.LABELPAD*self.figure.dpi / 72.0)) else: if not len(bboxes2): @@ -1057,7 +1056,6 @@ bbox = Bbox.union(bboxes) bottom = bbox.ymin self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0)) -# self.offsetText.set_position((x, bottom-self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO def set_ticks_position(self, position): """ @@ -1225,7 +1223,6 @@ left = bbox.xmin self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0, y)) - # self.label.set_position( (left-self.LABELPAD*self.figure.dpi.get()/72.0, y)) MGDTODO else: if not len(bboxes2): @@ -1245,7 +1242,6 @@ x,y = self.offsetText.get_position() top = self.axes.bbox.ymax self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi/72.0)) -# self.offsetText.set_position((x, top+self.OFFSETTEXTPAD*self.figure.dpi.get()/72.0)) MGDTODO def set_offset_position(self, position): assert position == 'left' or position == 'right' Modified: branches/transforms/lib/matplotlib/backend_bases.py =================================================================== --- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -18,8 +18,9 @@ """An abstract base class to handle drawing/rendering operations """ # This will cache paths across rendering instances - # Each subclass of RenderBase should define this --> - # _paths = weakref.WeakKeyDictionary() + # Each subclass of RenderBase should define this a weak-keyed + # dictionary to hold native paths + # _native_paths = weakref.WeakKeyDictionary() def __init__(self): self._texmanager = None @@ -44,7 +45,7 @@ self._native_paths[path] = native_path return native_path - def draw_path(self, gc, path, transform, rgbFace = None): + def draw_path(self, gc, path, transform, rgbFace=None): """ Handles the caching of the native path associated with the given path and calls the underlying backend's _draw_path to @@ -67,17 +68,31 @@ passed to them in draw_path. """ return path + + def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): + native_marker_path = self._get_cached_native_path(marker_path) + self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) - def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, - rotation): + def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): """ - Draw an arc using GraphicsContext instance gcEdge, centered at x,y, - with width and height and angles from 0.0 to 360.0 - 0 degrees is at 3-o'clock - positive angles are anti-clockwise - draw rotated 'rotation' degrees anti-clockwise about x,y + This method is currently underscore hidden because the + draw_markers method is being used as a sentinel for newstyle + backend drawing - If the color rgbFace is not None, fill the arc with it. + path - a matplotlib.agg.path_storage instance + + Draw the marker specified in path with graphics context gc at + each of the locations in arrays x and y. trans is a + matplotlib.transforms.Transformation instance used to + transform x and y to display coords. It consists of an + optional nonlinear component and an affine. You can access + these two components as + + if transform.need_nonlinear(): + x,y = transform.nonlinear_only_numerix(x, y) + # the a,b,c,d,tx,ty affine which transforms x and y + vec6 = transform.as_vec6_val() + ...backend dependent affine... """ raise NotImplementedError @@ -109,30 +124,21 @@ """ return False - def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None): - native_marker_path = self._get_cached_native_path(marker_path) - self._draw_native_markers(gc, native_marker_path, marker_trans, path, trans, rgbFace) - - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): + ###################################################################### + ## OLD API IS BELOW + ## These functions no longer need to be implemented in the backends -- + ## they now perform all of their functions in terms of the new API. + + def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2, + rotation): """ - This method is currently underscore hidden because the - draw_markers method is being used as a sentinel for newstyle - backend drawing + Draw an arc using GraphicsContext instance gcEdge, centered at x,y, + with width and height and angles from 0.0 to 360.0 + 0 degrees is at 3-o'clock + positive angles are anti-clockwise + draw rotated 'rotation' degrees anti-clockwise about x,y - path - a matplotlib.agg.path_storage instance - - Draw the marker specified in path with graphics context gc at - each of the locations in arrays x and y. trans is a - matplotlib.transforms.Transformation instance used to - transform x and y to display coords. It consists of an - optional nonlinear component and an affine. You can access - these two components as - - if transform.need_nonlinear(): - x,y = transform.nonlinear_only_numerix(x, y) - # the a,b,c,d,tx,ty affine which transforms x and y - vec6 = transform.as_vec6_val() - ...backend dependent affine... + If the color rgbFace is not None, fill the arc with it. """ raise NotImplementedError @@ -346,8 +352,10 @@ If rgbFace is not None, fill the rectangle with it. """ - raise NotImplementedError - + warnings.warn("draw_rectangle called", warnings.PendingDeprecationWarning) + transform = transforms.Affine2D().scale(width, height).translate(x, y) + self.draw_path(gcEdge, Path.unit_rectangle(), transform, rgbFace) + def draw_regpoly_collection( self, clipbox, offsets, transOffset, verts, sizes, facecolors, edgecolors, linewidths, antialiaseds): @@ -1221,8 +1229,6 @@ origfacecolor = self.figure.get_facecolor() origedgecolor = self.figure.get_edgecolor() - # MGDTODO - # self.figure.dpi.set(dpi) self.figure.dpi = dpi self.figure.set_facecolor(facecolor) self.figure.set_edgecolor(edgecolor) @@ -1236,12 +1242,12 @@ orientation=orientation, **kwargs) finally: - # MGDTODO - # self.figure.dpi.set(origDPI) self.figure.dpi = origDPI self.figure.set_facecolor(origfacecolor) self.figure.set_edgecolor(origedgecolor) self.figure.set_canvas(self) + + self.draw() return result @@ -1623,8 +1629,8 @@ lims.append( (xmin, xmax, ymin, ymax) ) # Store both the original and modified positions pos.append( ( - a.get_position(True), - a.get_position() ) ) + copy.copy(a.get_position(True)), + copy.copy(a.get_position() )) ) self._views.push(lims) self._positions.push(pos) self.set_history_buttons() Modified: branches/transforms/lib/matplotlib/backends/backend_agg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_agg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -114,9 +114,6 @@ self.height = height if __debug__: verbose.report('RendererAgg.__init__ width=%s, \ height=%s'%(width, height), 'debug-annoying') - # MGDTODO -# self._renderer = _RendererAgg(int(width), int(height), dpi.get(), -# debug=False) self._renderer = _RendererAgg(int(width), int(height), dpi, debug=False) if __debug__: verbose.report('RendererAgg.__init__ _RendererAgg done', @@ -136,35 +133,6 @@ def _draw_native_path(self, gc, path, transform, rgbFace): return self._renderer.draw_path(gc, path, transform.get_matrix(), rgbFace) - def draw_arc(self, gcEdge, rgbFace, x, y, width, height, angle1, angle2, rotation): - """ - Draw an arc centered at x,y with width and height and angles - from 0.0 to 360.0 - - If rgbFace is not None, fill the rectangle with that color. gcEdge - is a GraphicsContext instance - - Currently, I'm only supporting ellipses, ie angle args are - ignored - """ - if __debug__: verbose.report('RendererAgg.draw_arc', 'debug-annoying') - self._renderer.draw_ellipse( - gcEdge, rgbFace, x, y, width/2, height/2, rotation) # ellipse takes radius - - - def draw_line(self, gc, x1, y1, x2, y2): - """ - x and y are equal length arrays, draw lines connecting each - point in x, y - """ - if __debug__: verbose.report('RendererAgg.draw_line', 'debug-annoying') - x = npy.array([x1,x2], float) - y = npy.array([y1,y2], float) - self._renderer.draw_lines(gc, x, y) - - def draw_lines(self, gc, x, y, transform): - return self._renderer.draw_lines(gc, x, y, transform.to_values()) - def _draw_native_markers(self, gc, native_marker_path, marker_trans, path, trans, rgbFace=None): return self._renderer.draw_markers( gc, @@ -172,18 +140,6 @@ path.vertices, path.codes, trans.get_matrix(), rgbFace) - def draw_polygon(self, *args): - return self._renderer.draw_polygon(*args) - - def draw_point(self, gc, x, y): - """ - Draw a single point at x,y - """ - if __debug__: verbose.report('RendererAgg.draw_point', 'debug-annoying') - rgbFace = gc.get_rgb() - self._renderer.draw_ellipse( - gc, rgbFace, x, y, 0.5, 0.5, 0.0) - def draw_mathtext(self, gc, x, y, s, prop, angle): """ Draw the math text using matplotlib.mathtext @@ -192,8 +148,6 @@ 'debug-annoying') ox, oy, width, height, descent, font_image, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) -# ox, oy, width, height, descent, font_image, used_characters = \ -# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO x = int(x) + ox y = int(y) - oy @@ -227,7 +181,6 @@ # (in vector space) in the above call to font.set_text. self._renderer.draw_text_image(font.get_image(), int(x), int(y) + 1, angle, gc) - def get_text_width_height_descent(self, s, prop, ismath, rgb=(0,0,0)): """ get the width and height in display coords of the string s @@ -241,7 +194,7 @@ # todo: handle props size = prop.get_size_in_points() texmanager = self.get_texmanager() - Z = texmanager.get_rgba(s, size, self.dpi.get(), rgb) + Z = texmanager.get_rgba(s, size, self.dpi, rgb) m,n,tmp = Z.shape # TODO: descent of TeX text (I am imitating backend_ps here -JKS) return n, m, 0 @@ -249,8 +202,6 @@ if ismath: ox, oy, width, height, descent, fonts, used_characters = \ self.mathtext_parser.parse(s, self.dpi, prop) -# ox, oy, width, height, descent, fonts, used_characters = \ -# self.mathtext_parser.parse(s, self.dpi.get(), prop) MGDTODO return width, height, descent font = self._get_agg_font(prop) font.set_text(s, 0.0, flags=LOAD_DEFAULT) # the width and height of unrotated string @@ -265,7 +216,7 @@ # todo, handle props, angle, origins rgb = gc.get_rgb() size = prop.get_size_in_points() - dpi = self.dpi.get() + dpi = self.dpi flip = angle==90 w,h,d = self.get_text_width_height_descent(s, prop, 'TeX', rgb) @@ -306,7 +257,6 @@ 'return the canvas width and height in display coords' return self.width, self.height - def _get_agg_font(self, prop): """ Get the font for text instance t, cacheing for efficiency @@ -325,11 +275,9 @@ font.clear() size = prop.get_size_in_points() font.set_size(size, self.dpi) - # font.set_size(size, self.dpi.get()) MGDTODO return font - def points_to_pixels(self, points): """ convert point measures to pixes using dpi and the pixels per @@ -337,8 +285,6 @@ """ if __debug__: verbose.report('RendererAgg.points_to_pixels', 'debug-annoying') - # MGDTODO - # return points*self.dpi.get()/72.0 return points*self.dpi/72.0 def tostring_rgb(self): @@ -404,9 +350,7 @@ self.figure.draw(self.renderer) def get_renderer(self): - l,b,w,h = self.figure.bbox.bounds - # MGDTODO - # key = w, h, self.figure.dpi.get() + l, b, w, h = self.figure.bbox.bounds key = w, h, self.figure.dpi try: self._lastKey, self.renderer except AttributeError: need_new_renderer = True Modified: branches/transforms/lib/matplotlib/backends/backend_gtkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_gtkagg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -60,7 +60,6 @@ w,h = widget.window.get_size() if w==1 or h==1: return # empty fig - # dpival = self.figure.dpi.get() MGDTODO # compute desired figure size in inches dpival = self.figure.dpi winch = w/dpival Modified: branches/transforms/lib/matplotlib/backends/backend_tkagg.py =================================================================== --- branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/backends/backend_tkagg.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -175,7 +175,6 @@ self._resize_callback(event) # compute desired figure size in inches - # dpival = self.figure.dpi.get() MGDTODO dpival = self.figure.dpi winch = width/dpival hinch = height/dpival Modified: branches/transforms/lib/matplotlib/cbook.py =================================================================== --- branches/transforms/lib/matplotlib/cbook.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/cbook.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -955,6 +955,84 @@ outstream.write("Examining: %r\n" % (obj,)) recurse(obj, obj, { }, []) +class Grouper(object): + """ + This class provides a lightweight way to group arbitrary objects + together into disjoint sets when a full-blown graph data structure + would be overkill. + + Objects can be joined using .join(), tested for connectedness + using .joined(), and all disjoint sets can be retreived using + .get(). + + The objects being joined must be hashable. + + For example: + + >>> g = grouper.Grouper() + >>> g.join('a', 'b') + >>> g.join('b', 'c') + >>> g.join('d', 'e') + >>> list(g.get()) + [['a', 'b', 'c'], ['d', 'e']] + >>> g.joined('a', 'b') + True + >>> g.joined('a', 'c') + True + >>> g.joined('a', 'd') + False""" + def __init__(self, init=[]): + mapping = self._mapping = {} + for x in init: + mapping[x] = [x] + + def join(self, a, *args): + """ + Join given arguments into the same set. + Accepts one or more arguments. + """ + mapping = self._mapping + set_a = mapping.setdefault(a, [a]) + + for arg in args: + set_b = mapping.get(arg) + if set_b is None: + set_a.append(arg) + mapping[arg] = set_a + elif set_b is not set_a: + if len(set_b) > len(set_a): + set_a, set_b = set_b, set_a + set_a.extend(set_b) + for elem in set_b: + mapping[elem] = set_a + + def joined(self, a, b): + """ + Returns True if a and b are members of the same set. + """ + mapping = self._mapping + try: + return mapping[a] is mapping[b] + except KeyError: + return False + + def __iter__(self): + """ + Returns an iterator returning each of the disjoint sets as a list. + """ + seen = set() + for elem, group in self._mapping.iteritems(): + if elem not in seen: + yield group + seen.update(group) + + def get_siblings(self, a): + """ + Returns all of the items joined with the given item, including + itself. + """ + return self._mapping.get(a, [a]) + if __name__=='__main__': assert( allequal([1,1,1]) ) assert(not allequal([1,1,0]) ) Modified: branches/transforms/lib/matplotlib/figure.py =================================================================== --- branches/transforms/lib/matplotlib/figure.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/figure.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -161,10 +161,8 @@ def _get_dpi(self): return self._dpi def _set_dpi(self, dpi): - print "setting dpi" self._dpi = dpi self._dpi_scale_trans.clear().scale(dpi, dpi) - print self._dpi_scale_trans dpi = property(_get_dpi, _set_dpi) def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): @@ -178,10 +176,7 @@ bottom : the bottom of the subplots for subplots_adjust rotation: the rotation of the xtick labels ha : the horizontal alignment of the xticklabels - - """ - for ax in self.get_axes(): if not hasattr(ax, 'is_last_row'): raise RuntimeError('Axes must be subplot instances; found %s'%type(ax)) @@ -333,11 +328,8 @@ dpival = self.dpi self.bbox_inches.max = w, h - # self.figwidth.set(w) MGDTODO - # self.figheight.set(h) if forward: - # dpival = self.dpi.get() dpival = self.dpi canvasw = w*dpival canvash = h*dpival @@ -347,7 +339,6 @@ def get_size_inches(self): return self.bbox_inches.max - # return self.figwidth.get(), self.figheight.get() MGDTODO def get_edgecolor(self): 'Get the edge color of the Figure rectangle' @@ -360,7 +351,6 @@ def get_figwidth(self): 'Return the figwidth as a float' return self.bbox_inches.xmax - # return self.figwidth.get() MGDTODO def get_figheight(self): 'Return the figheight as a float' @@ -369,7 +359,6 @@ def get_dpi(self): 'Return the dpi as a float' return self.dpi - # return self.dpi.get() MGDTODO def get_frameon(self): 'get the boolean indicating frameon' @@ -397,7 +386,6 @@ ACCEPTS: float """ - # self.dpi.set(val) MGDTODO self.dpi = val def set_figwidth(self, val): @@ -406,7 +394,6 @@ ACCEPTS: float """ - # self.figwidth.set(val) MGDTODO self.bbox_inches.xmax = val def set_figheight(self, val): @@ -415,7 +402,6 @@ ACCEPTS: float """ - # MGDTODO (set()) self.bbox_inches.ymax = val def set_frameon(self, b): @@ -598,8 +584,6 @@ #print 'figure draw' if not self.get_visible(): return renderer.open_group('figure') - # MGDTODO - # self.transFigure.freeze() # eval the lazy objects if self.frameon: self.figurePatch.draw(renderer) @@ -633,8 +617,6 @@ for legend in self.legends: legend.draw(renderer) - # MGDTODO - # self.transFigure.thaw() # release the lazy objects renderer.close_group('figure') self._cachedRenderer = renderer Modified: branches/transforms/lib/matplotlib/legend.py =================================================================== --- branches/transforms/lib/matplotlib/legend.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/legend.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -21,7 +21,7 @@ up the legend """ from __future__ import division -import sys, warnings +import copy, sys, warnings import numpy as npy @@ -558,9 +558,7 @@ handle.set_height(h/2) # Set the data for the legend patch - # MGDTODO: This copy may no longer be needed now that Bboxes are - # essentially immutable - bbox = self._get_handle_text_bbox(renderer).copy() + bbox = copy.copy(self._get_handle_text_bbox(renderer)) bbox = bbox.scaled(1 + self.pad, 1 + self.pad) l,b,w,h = bbox.get_bounds() Modified: branches/transforms/lib/matplotlib/lines.py =================================================================== --- branches/transforms/lib/matplotlib/lines.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/lines.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -352,32 +352,18 @@ self._picker = p def get_window_extent(self, renderer): - self._newstyle = hasattr(renderer, 'draw_markers') - if self._newstyle: - x = self._x - y = self._y - else: - x, y = self._get_plottable() + xys = self.get_transform()(self._xys) - # MGDTODO: Put this in a single Nx2 array, rather than these - # separate ones - #### Conversion code - a = npy.vstack((x, y)).swapaxes(0, 1) - #### - x, y = self.get_transform()(a) - print "get_window_extent", self.get_transform() - - #x, y = self.get_transform().seq_x_y(x, y) + x = xys[:, 0] + y = xys[:, 1] + left = x.min() + bottom = y.min() + width = x.max() - left + height = y.max() - bottom - left = min(x) - bottom = min(y) - width = max(x) - left - height = max(y) - bottom - # correct for marker size, if any if self._marker is not None: - ms = self._markersize/72.0*self.figure.dpi - # ms = self._markersize/72.0*self.figure.dpi.get() MGDTODO + ms = self._markersize / 72.0 * self.figure.dpi left -= ms/2 bottom -= ms/2 width += ms @@ -411,6 +397,7 @@ def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units + # MGDTODO: Deal with units x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) @@ -435,15 +422,15 @@ else: self._segments = None - self._x = npy.asarray(x, float) - self._y = npy.asarray(y, float) - self._path = Path(npy.vstack((self._x, self._y)).transpose(), - closed=False) + self._xy = npy.vstack((npy.asarray(x, npy.float_), + npy.asarray(y, npy.float_))).transpose() + self._x = self._xy[:, 0] + self._y = self._xy[:, 1] + self._path = Path(self._xy, closed=False) self._logcache = None - def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 Modified: branches/transforms/lib/matplotlib/transforms.py =================================================================== --- branches/transforms/lib/matplotlib/transforms.py 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/lib/matplotlib/transforms.py 2007-09-18 19:29:21 UTC (rev 3856) @@ -19,9 +19,9 @@ self._parents = Set() def invalidate(self): - if not self._do_invalidation(): - for parent in self._parents: - parent.invalidate() + self._do_invalidation() + for parent in self._parents: + parent.invalidate() def _do_invalidation(self): return False @@ -187,14 +187,16 @@ return 'Bbox(%s)' % repr(self._points) __str__ = __repr__ - # JDH: the update method will update the box limits from the - # existing limits and the new data; it appears here you are just - # using the new data. We use an "ignore" flag to specify whether - # you want to include the existing data or not in the update def update_from_data(self, x, y, ignore=True): - self._points = npy.array( - [[x.min(), y.min()], [x.max(), y.max()]], - npy.float_) + if ignore: + self._points = npy.array( + [[x.min(), y.min()], [x.max(), y.max()]], + npy.float_) + else: + self._points = npy.array( + [[min(x.min(), self.xmin), min(y.min(), self.ymin)], + [max(x.max(), self.xmax), max(y.max(), self.ymax)]], + npy.float_) self.invalidate() # MGDTODO: Probably a more efficient ways to do this... @@ -409,9 +411,7 @@ return self.get_matrix() def _do_invalidation(self): - result = self._inverted is None self._inverted = None - return result #@staticmethod def _concat(a, b): @@ -494,6 +494,7 @@ if matrix is None: matrix = npy.identity(3) else: + matrix = npy.asarray(matrix, npy.float_) assert matrix.shape == (3, 3) self._mtx = matrix self._inverted = None @@ -629,8 +630,6 @@ if self._mtx is not None: self._mtx = None Affine2DBase._do_invalidation(self) - return False - return True def is_separable(self): return True @@ -684,7 +683,7 @@ def _do_invalidation(self): self._mtx = None - Affine2DBase._do_invalidation(self) + return Affine2DBase._do_invalidation(self) def get_matrix(self): if self._mtx is None: @@ -718,8 +717,6 @@ if self._mtx is not None: self._mtx = None Affine2DBase._do_invalidation(self) - return False - return True def is_separable(self): return True Modified: branches/transforms/src/_backend_agg.cpp =================================================================== --- branches/transforms/src/_backend_agg.cpp 2007-09-18 16:21:37 UTC (rev 3855) +++ branches/transforms/src/_backend_agg.cpp 2007-09-18 19:29:21 UTC (rev 3856) @@ -456,7 +456,7 @@ //return the agg::rect for bbox, flipping y PyArrayObject *bbox = (PyArrayObject *) PyArray_ContiguousFromObject(o.ptr(), PyArray_DOUBLE, 2, 2); - if (!bbox || bbox->nd != 2 bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) + if (!bbox || bbox->nd != 2 || bbox->dimensions[0] != 2 || bbox->dimensions[1] != 2) throw Py::TypeError ("Expected a Bbox object."); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |