Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specify a fixed width for an annotation box in matplotlib

I want to have some box annotations inside a plot with matplotlib. Is there a way to specify a fixed width for the textbox? I want to be able to have some random text inside my annotation that gets adjusted automatically, not to the sides, but top down.

Here is a minimal example:

import matplotlib
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnnotationBbox, TextArea

fig, ax = plt.subplots()
t = TextArea("Test 1")
xi, yi = 0.05, 0.1
ab = AnnotationBbox(t, xy=(xi, yi))
ax.add_artist(ab)

t = TextArea("Test 2 blah blah blah")
xi, yi = 0.1, 0.15
ab = AnnotationBbox(t, xy=(xi, yi))
ax.add_artist(ab)
    
# something along the lines of creating a rectangle of fixed width and having some text inside it
width, height = 0.025, 0.05
xi, yi = 0.2, 0.1
m = matplotlib.patches.Rectangle((xi - width / 2, yi - height / 2), width, height)
ax.add_patch(m)

ax.set_ylim([0, 0.3])
ax.set_xlim([0, 0.3])

This produces the following plot:

example plot

As you can see, Test 2 blah blah blah adjusts the surrounding box automatically to the sides, whereas I'd like to specify a certain width, past which the remaining text would be written on the next line. I know matplotlib.offsetbox.AnnotationBbox has some parameters such as xybox, xycoords and boxcoords, but I haven't found any way to set them up so that the annotation behaves like this. I have also looked at the text() function in the pyplot module (or text method of the Axes class) and I haven't found any way to specify a width. Any help is appreciated.

like image 908
Camilo Martinez M. Avatar asked Apr 02 '26 11:04

Camilo Martinez M.


1 Answers

matplotlib has something to auto wrap the text, see this example, or this example.

I don't think you can do it with him AnnotationBbox, but using the plt.text, with the parameter wrap=True:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

text = "Test 2 blah blah blah"
xi, yi = 0.2, 0.15
txt = ax.text(xi, yi, text, wrap=True)
# Override the object's method for getting available width
# Note width is in pixels.
txt._get_wrap_line_width = lambda : 70.

# the same but with a box
text = "Iggy Pop blah blah blah blah blah blah blah"
txt = ax.text(.5, .6, text, ha='left', va='top', wrap=True,
              bbox=dict(boxstyle='square', fc='w', ec='r'))    
txt._get_wrap_line_width = lambda : 60.

example_wrap_text_mpl

like image 51
Lucas Avatar answered Apr 12 '26 01:04

Lucas