What is a Bbox?

What exactly is a Bbox, and what is its purpose? When would I want to use it?

To put this a more in context, I inherited some code. I see the code calculates the x,y data limits and then calls ax.update_datalim(corners). The documentation for ax.update_datalim() says that it is used to “Extend the dataLim BBox to include the given points.”

I am trying to understand how this differs from calling set_xlim() and set_ylim(), and why this code that I inherited is doing this. I commented out the line that calls ax.update_datalim(corners) and the plot is almost identical; visually you have to look very, very closely to see any differences, but using an image diff tool shows that there are clearly quit a lot of pixels that have moved ever so slightly.

I was unable to find anything in the matplotlib documentation that clearly defines what a Bbox is. But it did find another web site that seems to indicate that a bbox is simple a visual box that can be placed on the figure, and that there are some 7 different box styles. If so, then I am guessing from the ax.update_datalim() documentation that every instance of an Axes also contains an instance of a bbox which is the outline surrounding the Axes. Am I on the right track here? Also, did I miss something or is there some basic matplotlib documentation (that I could not find) on what a bbox is and how and wen to use it?

Hi Daniel,

In short: a Bbox is supposed to be an abstraction for a rectangle that represents the bounds of something in the plane (hence Bounding Box).

Without your full code, I can’t be 100% sure, but it is typically the case that if you have [xmin, xmax] and [ymin, ymax], then

ax.update_datalim([[xmin, ymin], [xmax, ymax]])

should be equivalent to

ax.set_xlim([xmin, xmax])
ax.set_ylim([ymin, ymax])

The main difference comes up when you start using these functions multiple times in a row. So, for example, if I follow up with

ax.update_datalim([[xmin, ymin], [xmax - 1, ymax - 1]])

then the axes won’t be updated. The docs say this:

If no data is set currently…[do the expected thing]…Otherwise, it will compute the bounds of the union of its current data and the data in xys.

A Bbox is just a rectangle (think of it like a set of points in the plane). So a union here means that the limits will only increase if you add new corners that were outside of the original box, otherwise, the box will remain as-is.

On the other hand, if you do

ax.set_xlim([xmin, xmax - 1])
ax.set_ylim([ymin, ymax - 1])

then this will update the limits no matter what, ignoring the previous limits altogether.

Several internal functions use update_datalim, so the behavior could also be different if you first make the plot then set the limits, since the dataLim might inherit whatever values were set internally.

but if you have a specific issue where the two functions are not producing the same results, feel free to post a little micro-example here, and I can definitely tell you whether it’s intended behavior, or if we should move the discussion to Github (as a bug report that I could work on).

@brunobeltran Thanks Bruno. That’s definitely helpful. Now that I understand it better, I have an idea what to expect … I can play with the code and make sure its behaving as I would expect. Much appreciated. --Daniel

Question regarding this definition: would it be correct to say that, although a Bbox is an abstraction, nonetheless by default, a Bbox will be visible (as a visible rectangle on the Figure)?

Good question! Most Bbox’s correspond to visible rectangles somewhere on the figure, but I would not think of the Bbox itself as being visible.

It is simply an abstract description of some box in the plane.

If you want to visualize where a Bbox is, you can use RectanglePatch to see where it is:

import matplotlib.pyplot as plt
from matplotlib.patches import Rectangle
from matplotlib.transforms import Bbox

bbox = Bbox([[0, 0], [1, 1]])  # same as Bbox.unit()

fig1, ax1 = plt.subplots()

ax1.set_xlim([1/4, 3/4])
ax1.set_ylim([1/4, 3/4])

r1 = Rectangle(bbox.p0, bbox.width, bbox.height)

# in this figure, rectangle's bbox is not visible, 
# because it is "clipped" by the axes bbox
ax1.add_artist(r1) 

fig2, ax2 = plt.subplots()

ax2.set_xlim([-1/4, 1 + 1/4])
ax2.set_ylim([-1/4, 1 + 1/4])

r2 = Rectangle(bbox.p0, bbox.width, bbox.height)

# in this axes, the bbox is fully visible
ax2.add_artist(r2)

Although just in case this trips you up, not all Bbox’s are in data units. Axes, for example, can compute Bbox that describes what pixels it is contained within, instead of what the data limits are (ax1.get_window_extent()), you’d have to change this into data units to use it like I’m using it above.

You can read more about the transformation system (i.e. how matplotlib keeps tracks of different bbox’s that are in different units) here: https://matplotlib.org/3.2.1/tutorials/advanced/transforms_tutorial.html

And if you were really curious (but it’s not typically important when using the library), you can read about the class of objects that are “visible”, which are called "Artist"s in matplotlib, here:
https://matplotlib.org/tutorials/intermediate/artists.html

Or feel free to keep asking :slight_smile:

Also feel free to let me know if there’s anywhere in the documentation that you wish would have had this information already for you!