Nathann Cohen, on 2010-12-26 22:27, wrote:

Hello everybody !!!

When adding some text to a plot, is there a way to know the actual

size of the letters as they appear, in such a way that I could, for

instance, draw a circle around a 'A', so that the A perfectly fits

inside ("the smallest circle containing the letter"), regardless of

the actual size of the picture I'm drawing ?

Hi Nathann,

Here's a quick and dirty way of getting what you want:

import matplotlib.pyplot as plt

import numpy as np

ax = plt.subplot(111)

t = plt.text(0.5,0.5,'A', ha='center', va='center')

plt.draw()

b = t.get_window_extent() # bounding box in pixel coordinates

r = np.sqrt((b.bounds[-2]/2)**2 + (b.bounds[-1]/2)**2)

plt.scatter(0.5,0.5, s=np.pi*r**2, marker='o', edgecolor='k', facecolor='w', lw=1,zorder=-1)

I don't think there's a super simple way of doing this by hand -

because text keeps its size constant regardless of how you

manipulate the axes. Here's an example that does what you want,

if you only need the circle in one particular view (i.e. if you

won't be rescaling/zooming in or out the axes:

ax = plt.subplot(111)

plt.plot([0,1,1],[0,0,1]) # keep the axes from resizing when we draw our circle

t = plt.text(0.5,0.5,'A')

plt.axis('equal')

plt.draw()

b = t.get_window_extent() # bounding box in pixel coordinates

bbox = b.inverse_transformed(ax.transData)

xc,yc = bbox.get_points().mean(0)

r = np.sqrt((bbox.bounds[-2]/2)**2 + (bbox.bounds[-1]/2)**2)

theta = np.linspace(0,2*np.pi,200)

x,y = r*(np.cos(theta)), r*np.sin(theta)

l = plt.plot(x+xc, y+yc)

This does exactly what you want, but now, anytime you resize the

axes, the A will stay the same size, but that circle will get

resized.

ax = plt.subplot(111)

plt.plot([0,1,1],[0,0,1]) # keep the axes from resizing when we draw our circle

t = plt.text(0.5,0.5,'A')

plt.axis('equal')

plt.draw()

b = t.get_window_extent() # bounding box in pixel coordinates

bbox = b.inverse_transformed(ax.transAxes)

xc,yc = bbox.get_points().mean(0)

r = np.sqrt((bbox.bounds[-2]/2)**2 + (bbox.bounds[-1]/2)**2)

theta = np.linspace(0,2*np.pi,200)

x,y = r*(np.cos(theta)), r*np.sin(theta)

l = plt.plot(x+xc, y+yc, transform=ax.transAxes)

The above will keep the circle from resizing when you move - but

now it prevents the circle from following 'A' as you pan around.

I see that matplotlib.collections (which is what plt.scatter

creates in the quick-and-dirty example) uses offset and

transOffset to get the job done, but I couldn't figure out a way

to get my last two examples to do something similar by just

manipulating the transforms.

Hopefully someone chimes in with a better solution. For more on

transformations see:

http://matplotlib.sourceforge.net/users/transforms_tutorial.html

And you can wrap my hand-rolled solution nicely using something

like:

http://matplotlib.sourceforge.net/examples/api/line_with_text.html

best,

## ···

--

Paul Ivanov

314 address only used for lists, off-list direct email at:

http://pirsquared.org | GPG/PGP key id: 0x0F3E28F7