Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: Center text in its bbox

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: enter image description here

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: enter image description here Unfortunately in my case there is no 'g' or anything with a similar descent. Does anyone have any further ideas?

like image 617
user35915 Avatar asked Dec 04 '15 11:12

user35915


2 Answers

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')
like image 63
iMo51 Avatar answered Nov 13 '22 14:11

iMo51


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()

enter image description here

like image 4
Felix Avatar answered Nov 13 '22 16:11

Felix