I have to plot some data and some vertical lines to delimit interesting intervals and then I would like to add some labels to that using text
. I can not entirely avoid the labels overlapping with the data or the vertical lines, so I decided to put a bbox
around the text to keep it readable. My problem is that I am not able to align it centrally within this box and this is clearly visible and quite annoying in my opinion.
I'm doing something like this:
import numpy
import matplotlib
import matplotlib.pyplot as plt
fig=plt.figure()
plot=fig.add_subplot(111)
x=numpy.linspace(1,10,50)
y=numpy.random.random(50)
plot.plot(x,y)
plot.text(4.5,.5,'TEST TEST',\
bbox={'facecolor':'white','alpha':1,'edgecolor':'none','pad':1})
plot.axvline(5,color='k',linestyle='solid')
plt.show()
Which creates the following plot:
It is quite apparent, that the text is not centered in its bbox
. How can I change this? I've spent quite some time on Google but I could not find anything.
EDIT:
Thanks for the suggestions so far.
This suggests that what I see is actually desired behavior. Apparently the bbox
in new versions of matplotlib
is chosen taking into account the possible maximum descent of the text it contains (the descent of 'g').
When a 'g' appears in the text, this does indeed look good: Unfortunately in my case there is no 'g' or anything with a similar descent. Does anyone have any further ideas?
Use the text properties ha and va:
plot.text(5.5,.5,'TEST TEST TEST TEST',
bbox={'facecolor':'white','alpha':1,'edgecolor':'none','pad':1},
ha='center', va='center')
To check, draw lines in the center of your plot:
plot.axvline(5.5,color='k',linestyle='solid')
plot.axhline(0.5,color='k',linestyle='solid')
It seems that there are now options to properly position the text in the coordinate system (in particular the new va = 'baseline'
). However, as pointed out by user35915, this does not change the alignment of the box relative to the text. The misalignment is particularly obvious in single digit numbers, in particular number '1' (see also this bug). Until this is fixed, my workaround is to place the rectangle by hand, not via the bbox parameter:
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# define the rectangle size and the offset correction
rect_w = 0.2
rect_h = 0.2
rect_x_offset = 0.004
rect_y_offset =0.006
# text coordinates and content
x_text = 0.5
y_text = 0.5
text = '1'
# create the canvas
fig,ax = plt.subplots(figsize=(1,1),dpi=120)
ax.set_xlim((0,1))
ax.set_ylim((0,1))
# place the text
ax.text(x_text, y_text, text, ha="center", va="center", zorder=10)
# compare: vertical alignment with bbox-command: box is too low.
ax.text(x_text+0.3, y_text, text, ha="center", va="center",
bbox=dict(facecolor='wheat',boxstyle='square',edgecolor='black',pad=0.1), zorder=10)
# compare: horizontal alignment with bbox-command: box is too much to the left.
ax.text(x_text, y_text+0.3, text, ha="center", va="center",
bbox=dict(facecolor='wheat',boxstyle='square',edgecolor='black',pad=0.2), zorder=10)
# create the rectangle (below the text, hence the smaller zorder)
rect = patches.Rectangle((x_text-rect_w/2+rect_x_offset, y_text-rect_h/2+rect_y_offset),
rect_w,rect_h,linewidth=1,edgecolor='black',facecolor='white',zorder=9)
# add rectangle to plot
ax.add_patch(rect)
# show figure
fig.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With