Quiero tener algunas anotaciones de caja dentro de una gráfica con matplotlib. ¿Hay alguna forma de especificar un ancho fijo para el cuadro de texto? Quiero poder tener un texto aleatorio dentro de mi anotación que se ajuste automáticamente, no a los lados, sino de arriba hacia abajo.

Aquí está un ejemplo mínimo:

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

Esto produce la siguiente trama:

example plot

Como puede ver, Test 2 blah blah blah ajusta el cuadro circundante automáticamente a los lados, mientras que me gustaría especificar un cierto ancho, más allá del cual el texto restante se escribiría en la siguiente línea. Sé que matplotlib.offsetbox.AnnotationBbox tiene algunos parámetros como xybox, xycoords y boxcoords, pero no he encontrado ninguna forma de configurarlos para que la anotación se comporte así. También he examinado la función text() en el módulo pyplot (o el método de texto de la clase Axes) y no he encontrado ninguna forma de especificar un ancho. Se agradece cualquier ayuda.

1
Camilo Martínez 8 may. 2021 a las 01:25

1 respuesta

La mejor respuesta

Matplotlib tiene algo para ajustar automáticamente el texto, consulte este ejemplo o este ejemplo.

No creo que puedas hacerlo con él AnnotationBbox, pero usando plt.text, con el parámetro 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

1
Lucas 7 may. 2021 a las 23:55