Nathann Cohen, on 20101226 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 quickanddirty 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 handrolled solution nicely using something
like:
http://matplotlib.sourceforge.net/examples/api/line_with_text.html
best,

Paul Ivanov
314 address only used for lists, offlist direct email at:
http://pirsquared.org  GPG/PGP key id: 0x0F3E28F7
