From: Chris B. <Chr...@no...> - 2005-02-18 19:23:54
|
Hi all, Is there a way to get the size of a text object? I can't seem to find a method that does that. The functionality must be in there somewhere, or having different reference points wouldn't work. -thanks, Chris -- Christopher Barker, Ph.D. Oceanographer NOAA/OR&R/HAZMAT (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chr...@no... |
From: John H. <jdh...@ac...> - 2005-02-18 20:41:55
|
>>>>> "Chris" == Chris Barker <Chr...@no...> writes: Chris> Hi all, Is there a way to get the size of a text object? I Chris> can't seem to find a method that does that. The Chris> functionality must be in there somewhere, or having Chris> different reference points wouldn't work. The size of a text object is tricky. Do you mean the width and height in points? Or in data coords? The x,y location of text is in one coordinate system (axes, figure or data), but the width and height are not. To convert between coordinate systems (eg points or display versus data) the way mpl does it is to one transform coord system to display and use the other coordinate system to inverse transform. This would enable you to get, for example, a text bounding box in data coords, but could be screwed up by a figure resize. If you tell me more precisely what you are trying to achieve, I might be able to help you or think about design changes to accommodate it. FYI, this is an issue that crops up a lot and is vexing. What one would like to be able to do is use a layout engine and say, place object one above and to the right of object 2 with a pad of 2 points. The text instance can give you its bounding box in display if you pass it the backend renderer -- this is required because the width and height can be backend dependent. I suppose you are using OO agg based on your previous posts. One problem with the current design that is that the agg canvas doesn't generate it's renderer until draw time (with caching), but you need access to the renderer before draw time for layout that depends on text. If we move this logic to a get_renderer method, you can use it at draw time. I'll attach a replacement backend_agg.FigureCanvasAgg class to support this below from matplotlib.figure import Figure from matplotlib.backends.backend_agg import FigureCanvasAgg fig = Figure() canvas = FigureCanvasAgg(fig) renderer = canvas.get_renderer() ax = fig.add_subplot(111) ax.plot([1,2,3]) t = ax.text(1,2,'hi mom') bbox = t.get_window_extent(renderer) print 'display', bbox.get_bounds() #l,b,w,h # get the axes data coords bbox of this display bounding box from matplotlib.transforms import inverse_transform_bbox axbox = inverse_transform_bbox(ax.transData, bbox) print 'data coords', axbox.get_bounds() fig.savefig('test') In backend_agg.py FigureCanvasAgg, replace the draw method with the following 2 methods def draw(self): """ Draw the figure using the renderer """ if __debug__: verbose.report('FigureCanvasAgg.draw', 'debug-annoying') renderer = self.get_renderer() self.figure.draw(renderer) def get_renderer(self): l,b,w,h = self.figure.bbox.get_bounds() key = w, h, self.figure.dpi.get() try: self._lastKey, self.renderer except AttributeError: need_new_renderer = True else: need_new_renderer = (self._lastKey != key) if need_new_renderer: self.renderer = RendererAgg(w, h, self.figure.dpi) self._lastKey = key return self.renderer Hope this gets you started -- if you provide more details we maybe able to improve from here. JDG |
From: Chris B. <Chr...@no...> - 2005-02-22 23:05:13
|
John, Thanks for the reply. Sorry for the delay, I've been off line for a few days. John Hunter wrote: >>>>>>"Chris" == Chris Barker <Chr...@no...> writes: > Chris> Hi all, Is there a way to get the size of a text object? > Do you mean the width and height > in points? At this point, points. The other option is figure coordinates. The problem at hand is that we're generating a figure that has some fairly large labels on the Y axis, so we're having to do the layout of subplots ourselves. We've got it looking OK with trial and error, but if we change a label, it might not layout right anymore, so I thought it would be helpful to be able to check the sizes of things to do it automagically. Besides, aren't there methods to convert between the various coord. systems anyway? > but could be screwed up by a figure resize. Yeah, it would , but right now I'm working with the AGG backend, so I can stick with one figure size. > FYI, this is an issue that crops up a lot and is vexing. What one > would like to be able to do is use a layout engine and say, place > object one above and to the right of object 2 with a pad of 2 points. Yes, that would be nice. In fact, I've been planning to do exactly that for my wxFloatCanvas. It's easier there because I've only got wx as a back end, but still a bit tricky. One thing I've done to help is simply declare that I'm always assuming 72dpi, rather than trying to use the system's idea of the display resolution. This has helped keep results consistent across systems. I have had to re-scale text, however. > The text instance can give you its bounding box in display if you pass > it the backend renderer -- this is required because the width and > height can be backend dependent. I suppose you are using OO agg based > on your previous posts. Mostly, it's a mix as I'm working with someone else and most of the examples are in the pylab interface. > One problem with the current design that is > that the agg canvas doesn't generate it's renderer until draw time > (with caching), but you need access to the renderer before draw time > for layout that depends on text. Right. So, do any of the default layout's take text into account (subplot, for example?) > If we move this logic to a > get_renderer method, you can use it at draw time. I'll attach a > replacement backend_agg.FigureCanvasAgg class to support this below > > from matplotlib.figure import Figure > from matplotlib.backends.backend_agg import FigureCanvasAgg > > fig = Figure() > canvas = FigureCanvasAgg(fig) Didn't you add canvas as a Figure() attribute to support the new Figure.savefig() method? (added for me, such service!) > renderer = canvas.get_renderer() > ax = fig.add_subplot(111) > ax.plot([1,2,3]) > t = ax.text(1,2,'hi mom') > bbox = t.get_window_extent(renderer) > print 'display', bbox.get_bounds() #l,b,w,h > > # get the axes data coords bbox of this display bounding box > from matplotlib.transforms import inverse_transform_bbox > axbox = inverse_transform_bbox(ax.transData, bbox) > > print 'data coords', axbox.get_bounds() > > fig.savefig('test') Thanks for this example. I hope I"ll get a chance to play with this soon. My schedule is a nightmare for a while. thanks, -Chris -- Christopher Barker, Ph.D. Oceanographer NOAA/OR&R/HAZMAT (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chr...@no... |