converting text size into data coordinates
In matplotlib, what is a way of converting the text box size into data coordinates? For example, in this toy script I'm fine-tuning the coordinates of the text box so that it's next to a data point.
#!/usr/bin/python
import matplotlib.pyplot as plt
xx=[1,2,3]
yy=[2,3,4]
dy=[0.1,0.2,0.0开发者_开发问答5]
fig=plt.figure()
ax=fig.add_subplot(111)
ax.errorbar(xx,yy,dy,fmt='ro-',ms=6,elinewidth=4)
# HERE: can one get the text bbox size?
txt=ax.text(xx[1]-0.1,yy[1]-0.4,r'$S=0$',fontsize=16)
ax.set_xlim([0.,3.4])
ax.set_ylim([0.,4.4])
plt.show()
Is there a way of doing something like this pseudocode instead?
x = xx[1] - text_height
y = yy[1] - text_width/2
ax.text(x,y,text)
Generally speaking, you can't get the size of the text until after it's drawn (thus the hacks in @DSM's answer).
For what you're wanting to do, you'd be far better off using annotate.
E.g. ax.annotate('Your text string', xy=(x, y), xytext=(x-0.1, y-0.4))
Note that you can specify the offset in points as well, and thus offset the text by it's height (just specify textcoords='offset points'
)
If you're wanting to adjust vertical alignment, horizontal alignment, etc, just add those as arguments to annotate
(e.g. horizontalalignment='right'
or equivalently ha='right'
)
I'm not happy with it at all, but the following works; I was getting frustrated until I found this code for a similar problem, which suggested a way to get at the renderer.
import matplotlib.pyplot as plt
xx=[1,2,3]
yy=[2,3,4]
dy=[0.1,0.2,0.05]
fig=plt.figure()
figname = "out.png"
ax=fig.add_subplot(111)
ax.errorbar(xx,yy,dy,fmt='ro-',ms=6,elinewidth=4)
# start of hack to get renderer
fig.savefig(figname)
renderer = plt.gca().get_renderer_cache()
# end of hack
txt = ax.text(xx[1], yy[1],r'$S=0$',fontsize=16)
tbox = txt.get_window_extent(renderer)
dbox = tbox.transformed(ax.transData.inverted())
text_width = dbox.x1-dbox.x0
text_height = dbox.y1-dbox.y0
x = xx[1] - text_height
y = yy[1] - text_width/2
txt.set_position((x,y))
ax.set_xlim([0.,3.4])
ax.set_ylim([0.,4.4])
fig.savefig(figname)
OTOH, while this might get the text box out of the actual data point, it doesn't necessarily get the box out of the way of the marker, or the error bar. So I don't know how useful it'll be in practice, but I guess it wouldn't be that hard to loop over all the drawn objects and move the text until it's out of the way. I think the linked code tries something similar.
Edit: Please note that this was clearly a courtesy accept; I would use Joe Kington's solution if I actually wanted to do this, and so should everyone else. :^)
精彩评论