1

I am trying to draw a bounding box across text such as :

from matplotlib.pyplot import text
from matplotlib.patches import FancyBboxPatch
import matplotlib.transforms as mtransforms

import numpy as np
import matplotlib.pyplot as plt



def draw_bbox(ax, bb):
    # boxstyle=square with pad=0, i.e. bbox itself.
    p_bbox = FancyBboxPatch((bb.xmin, bb.ymin),
                            abs(bb.width), abs(bb.height),
                            boxstyle="round,pad=0.1, rounding_size=0.2",
                            ec="k", fc="none", zorder=10.,facecolor='pink')
    ax.add_patch(p_bbox)

np.random.seed(19680801)

fig, ax = plt.subplots()
x = 30*np.random.randn(10000)
mu = x.mean()
median = np.median(x)
sigma = x.std()
textstr = '\n'.join((
    r'$\mu=%.2f$' % (mu, ),
    r'$\mathrm{median}=%.2f$' % (median, ),
    r'$\sigma=%.2f$' % (sigma, )))

ax.hist(x, 50)

# these are matplotlib.patch.Patch properties
props = dict(boxstyle='square, pad=0.2', facecolor='wheat', alpha=0.5 )

# place a text box in upper left in axes coords
ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14,
        verticalalignment='top', bbox=props
       )

plt.show()

enter image description here

In the docs matplotlib.pyplot.text return an instance of Text which can take a kwarg 'bbox' . and this bbox argument accepts a dict() type object with properties for patches.FancyBboxPatch . The FancyBboxPatch has a position arg width which if I am trying to give,

props2 =FancyBboxPatch(xy=(0., 0.),width=1.,height=1.,boxstyle='Round, pad=0.2', facecolor='pink', alpha=0.5 )
ax.text(0.1, 0.95, textstr, transform=ax.transAxes, fontsize=14,
        verticalalignment='top', bbox=props2
       )

it gives the following error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-59-0c8ad0d773a9> in <module>
     32 props2 =FancyBboxPatch((0., 0.),1.,1.,boxstyle='Round, pad=0.2', facecolor='pink', alpha=0.5 )
     33 ax.text(0.1, 0.95, textstr, transform=ax.transAxes, fontsize=14,
---> 34         verticalalignment='top', bbox=props2
     35        )
     36 

~\AppData\Local\Continuum\anaconda3\envs\automation_work\lib\site-packages\matplotlib\cbook\deprecation.py in wrapper(*args, **kwargs)
    367                 f"%(removal)s.  If any parameter follows {name!r}, they "
    368                 f"should be pass as keyword, not positionally.")
--> 369         return func(*args, **kwargs)
    370 
    371     return wrapper

~\AppData\Local\Continuum\anaconda3\envs\automation_work\lib\site-packages\matplotlib\axes\_axes.py in text(self, x, y, s, fontdict, withdash, **kwargs)
    781         else:
    782             t = mtext.Text(x, y, text=s)
--> 783         t.update(effective_kwargs)
    784 
    785         t.set_clip_path(self.patch)

~\AppData\Local\Continuum\anaconda3\envs\automation_work\lib\site-packages\matplotlib\text.py in update(self, kwargs)
    177         super().update(kwargs)
    178         if bbox is not sentinel:
--> 179             self.set_bbox(bbox)
    180 
    181     def __getstate__(self):

~\AppData\Local\Continuum\anaconda3\envs\automation_work\lib\site-packages\matplotlib\text.py in set_bbox(self, rectprops)
    443 
    444         if rectprops is not None:
--> 445             props = rectprops.copy()
    446             boxstyle = props.pop("boxstyle", None)
    447             pad = props.pop("pad", None)

AttributeError: 'FancyBboxPatch' object has no attribute 'copy'

This error doesn't make sense to me. I feel it's a bug in the FancyBboxPatch implementation? Can anyone help to find the issue?

8
  • You are passing the FancyBboxPatch itself. But the bbox argument needs a dictionary as input. Commented Sep 19, 2019 at 23:28
  • I tried passing a dictionary object, props = dict(boxstyle='Round, pad=0.2', facecolor='wheat', alpha=0.5 ) works but, props = dict(xy=(0., 0.), width= 1., height=1.,boxstyle='Round, pad=0.2', facecolor='wheat', alpha=0.5 ) doesn't ! it throws an error TypeError: __init__() got multiple values for argument 'xy' and if I use props =dict((0., 0.),1., 1.,boxstyle='Round, pad=0.2', facecolor='wheat', alpha=0.5 ) then I get TypeError: dict expected at most 1 arguments, got 3. How I can use width in that dict() or FancyBboxPatch(). Any suggestions? Commented Sep 20, 2019 at 1:50
  • Oh, you can't. The width is determined by the width of the text. You cannot change that. What exactly do you want to achieve? Commented Sep 20, 2019 at 1:55
  • I want to adjust the width of the box so that I can overlay multiple boxes on the plot. Commented Sep 23, 2019 at 20:11
  • You can draw a "box" with a plt.Rectangle(). So there might be more requirements? Commented Sep 23, 2019 at 20:16

1 Answer 1

1

The following would add two texts below each other in the upper left corner of the axes. The width of the boxes is 200 pixels, independent of the size of the text.

import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredOffsetbox, HPacker, VPacker, TextArea, PaddedBox

fig, ax = plt.subplots()

text1 = TextArea("Short\nText")
of1 = HPacker(width=200, height=None, pad=2, sep=5, align="center", mode="expand", children=[text1])
pb1 = PaddedBox(of1, pad=4, draw_frame=True)

text2 = TextArea("Long text in one line")
of2 = HPacker(width=200, height=None, pad=2, sep=5, align="center", mode="expand",  children=[text2])
pb2 = PaddedBox(of2, pad=4, draw_frame=True)

oft = VPacker(width=200, height=None, pad=2, sep=5, align="baseline", children=[pb1, pb2])
t = AnchoredOffsetbox("upper left", pad=0.4, frameon=False, child=oft)

ax.add_artist(t)

plt.show()

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.