-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Shorten various offsetbox implementations #21699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -263,32 +263,35 @@ def set_offset(self, xy): | |||||
xy : (float, float) or callable | ||||||
The (x, y) coordinates of the offset in display units. These can | ||||||
either be given explicitly as a tuple (x, y), or by providing a | ||||||
function that converts the extent into the offset. This function | ||||||
must have the signature:: | ||||||
function that dynamically computes an offset (taking the arguments | ||||||
passed to `.OffsetBox.get_offset`). It is recommended to make such | ||||||
functions take no arguments. | ||||||
|
||||||
Before version 3.6, the callable had to have the signature:: | ||||||
|
||||||
def offset(width, height, xdescent, ydescent, renderer) \ | ||||||
-> (float, float) | ||||||
|
||||||
For backwards compatibility, callables with arbitrary signatures | ||||||
are currently accepted as long as compatible arguments are | ||||||
passed in calls to `.set_offset`. This should be considered an | ||||||
implementation detail, and may be deprecated in the future. | ||||||
""" | ||||||
self._offset = xy | ||||||
self.stale = True | ||||||
|
||||||
def get_offset(self, width, height, xdescent, ydescent, renderer): | ||||||
def get_offset(self, *args, **kwargs): | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is deeply confusing. It's almost impossible for the user to figure out whether he has to pass anything and if so what. We can't have that on public API. At the very least, you should make the parameters explicit
Suggested change
But even with that I'm very concerned with the API. "The method needs arguments depending on the subclass and/or some configurable state." is not a contract you can program against. It's bad enough that we currently have the inconsistency that some subclasses do not take arguments. But at least that's explicit and when you know the class, you know what to pass. This change here would make that more implicit. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I still propose to leave the parameters explicit until they are removed completely. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The way the API currently is is just as bad though. In some cases you have to pass arguments .... just for us to drop them on the floor! I think that this is going the right direction (no inputs anywhere), but I think I agree we need more steps to get there. |
||||||
""" | ||||||
Return the offset as a tuple (x, y). | ||||||
|
||||||
The extent parameters have to be provided to handle the case where the | ||||||
offset is dynamically determined by a callable (see | ||||||
`~.OffsetBox.set_offset`). | ||||||
|
||||||
Parameters | ||||||
---------- | ||||||
width, height, xdescent, ydescent | ||||||
Extent parameters. | ||||||
renderer : `.RendererBase` subclass | ||||||
Return the (x, y) offset. | ||||||
|
||||||
Parameters are usually not necessary. The only exception can occur | ||||||
if you have defined a callable to calculate the offset dynamically (see | ||||||
`~.OffsetBox.set_offset`). It is now recommended that such a | ||||||
callable does not take parameters. However, for backward-compatibility, | ||||||
callables with parameters are still supported; these parameters must be | ||||||
provided to `.get_offset` so that we can pass them on. | ||||||
""" | ||||||
return (self._offset(width, height, xdescent, ydescent, renderer) | ||||||
if callable(self._offset) | ||||||
return (self._offset(*args, **kwargs) if callable(self._offset) | ||||||
else self._offset) | ||||||
|
||||||
def set_width(self, width): | ||||||
|
@@ -347,8 +350,10 @@ def get_extent(self, renderer): | |||||
|
||||||
def get_window_extent(self, renderer): | ||||||
# docstring inherited | ||||||
w, h, xd, yd, offsets = self.get_extent_offsets(renderer) | ||||||
px, py = self.get_offset(w, h, xd, yd, renderer) | ||||||
w, h, xd, yd = self.get_extent(renderer) | ||||||
# dynamic offset compute callables may need to access the renderer. | ||||||
self._cached_renderer = renderer | ||||||
px, py = self.get_offset() | ||||||
return mtransforms.Bbox.from_bounds(px - xd, py - yd, w, h) | ||||||
|
||||||
def draw(self, renderer): | ||||||
|
@@ -357,7 +362,7 @@ def draw(self, renderer): | |||||
to the given *renderer*. | ||||||
""" | ||||||
w, h, xdescent, ydescent, offsets = self.get_extent_offsets(renderer) | ||||||
px, py = self.get_offset(w, h, xdescent, ydescent, renderer) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any user who has used |
||||||
px, py = self.get_offset() | ||||||
for c, (ox, oy) in zip(self.get_visible_children(), offsets): | ||||||
c.set_offset((px + ox, py + oy)) | ||||||
c.draw(renderer) | ||||||
|
@@ -538,7 +543,7 @@ def get_extent_offsets(self, renderer): | |||||
def draw(self, renderer): | ||||||
# docstring inherited | ||||||
w, h, xdescent, ydescent, offsets = self.get_extent_offsets(renderer) | ||||||
px, py = self.get_offset(w, h, xdescent, ydescent, renderer) | ||||||
px, py = self.get_offset() | ||||||
for c, (ox, oy) in zip(self.get_visible_children(), offsets): | ||||||
c.set_offset((px + ox, py + oy)) | ||||||
|
||||||
|
@@ -622,21 +627,9 @@ def set_offset(self, xy): | |||||
xy : (float, float) | ||||||
The (x, y) coordinates of the offset in display units. | ||||||
""" | ||||||
self._offset = xy | ||||||
self.offset_transform.clear() | ||||||
self.offset_transform.translate(xy[0], xy[1]) | ||||||
self.stale = True | ||||||
|
||||||
def get_offset(self): | ||||||
"""Return offset of the container.""" | ||||||
return self._offset | ||||||
|
||||||
def get_window_extent(self, renderer): | ||||||
# docstring inherited | ||||||
w, h, xd, yd = self.get_extent(renderer) | ||||||
ox, oy = self.get_offset() # w, h, xd, yd) | ||||||
|
||||||
return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) | ||||||
super().set_offset(xy) | ||||||
|
||||||
def get_extent(self, renderer): | ||||||
"""Return width, height, xdescent, ydescent of box.""" | ||||||
|
@@ -782,20 +775,9 @@ def set_offset(self, xy): | |||||
xy : (float, float) | ||||||
The (x, y) coordinates of the offset in display units. | ||||||
""" | ||||||
self._offset = xy | ||||||
self.offset_transform.clear() | ||||||
self.offset_transform.translate(xy[0], xy[1]) | ||||||
self.stale = True | ||||||
|
||||||
def get_offset(self): | ||||||
"""Return offset of the container.""" | ||||||
return self._offset | ||||||
|
||||||
def get_window_extent(self, renderer): | ||||||
# docstring inherited | ||||||
w, h, xd, yd = self.get_extent(renderer) | ||||||
ox, oy = self.get_offset() | ||||||
return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) | ||||||
super().set_offset(xy) | ||||||
|
||||||
def get_extent(self, renderer): | ||||||
_, h_, d_ = renderer.get_text_width_height_descent( | ||||||
|
@@ -883,20 +865,9 @@ def set_offset(self, xy): | |||||
xy : (float, float) | ||||||
The (x, y) coordinates of the offset in display units. | ||||||
""" | ||||||
self._offset = xy | ||||||
self.offset_transform.clear() | ||||||
self.offset_transform.translate(xy[0], xy[1]) | ||||||
self.stale = True | ||||||
|
||||||
def get_offset(self): | ||||||
"""Return offset of the container.""" | ||||||
return self._offset | ||||||
|
||||||
def get_window_extent(self, renderer): | ||||||
# docstring inherited | ||||||
w, h, xd, yd = self.get_extent(renderer) | ||||||
ox, oy = self.get_offset() # w, h, xd, yd) | ||||||
return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) | ||||||
super().set_offset(xy) | ||||||
|
||||||
def get_extent(self, renderer): | ||||||
# clear the offset transforms | ||||||
|
@@ -1076,29 +1047,20 @@ def set_bbox_to_anchor(self, bbox, transform=None): | |||||
|
||||||
def get_window_extent(self, renderer): | ||||||
# docstring inherited | ||||||
self._update_offset_func(renderer) | ||||||
# Update the offset func, which depends on the dpi of the renderer | ||||||
# (because of the padding). | ||||||
w, h, xd, yd = self.get_extent(renderer) | ||||||
ox, oy = self.get_offset(w, h, xd, yd, renderer) | ||||||
return Bbox.from_bounds(ox - xd, oy - yd, w, h) | ||||||
|
||||||
def _update_offset_func(self, renderer, fontsize=None): | ||||||
""" | ||||||
Update the offset func which depends on the dpi of the | ||||||
renderer (because of the padding). | ||||||
""" | ||||||
if fontsize is None: | ||||||
fontsize = renderer.points_to_pixels( | ||||||
self.prop.get_size_in_points()) | ||||||
fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) | ||||||
|
||||||
def _offset(w, h, xd, yd, renderer): | ||||||
def _offset(*args, **kwargs): # args are ignored; left for backcompat. | ||||||
bbox = Bbox.from_bounds(0, 0, w, h) | ||||||
borderpad = self.borderpad * fontsize | ||||||
pad = self.borderpad * fontsize | ||||||
bbox_to_anchor = self.get_bbox_to_anchor() | ||||||
x0, y0 = _get_anchored_bbox( | ||||||
self.loc, bbox, bbox_to_anchor, borderpad) | ||||||
x0, y0 = _get_anchored_bbox(self.loc, bbox, bbox_to_anchor, pad) | ||||||
return x0 + xd, y0 + yd | ||||||
|
||||||
self.set_offset(_offset) | ||||||
return super().get_window_extent(renderer) | ||||||
|
||||||
def update_frame(self, bbox, fontsize=None): | ||||||
self.patch.set_bounds(bbox.bounds) | ||||||
|
@@ -1110,17 +1072,13 @@ def draw(self, renderer): | |||||
if not self.get_visible(): | ||||||
return | ||||||
|
||||||
fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) | ||||||
self._update_offset_func(renderer, fontsize) | ||||||
|
||||||
# update the location and size of the legend | ||||||
bbox = self.get_window_extent(renderer) | ||||||
fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) | ||||||
self.update_frame(bbox, fontsize) | ||||||
self.patch.draw(renderer) | ||||||
|
||||||
width, height, xdescent, ydescent = self.get_extent(renderer) | ||||||
|
||||||
px, py = self.get_offset(width, height, xdescent, ydescent, renderer) | ||||||
px, py = self.get_offset() | ||||||
|
||||||
self.get_child().set_offset((px, py)) | ||||||
self.get_child().draw(renderer) | ||||||
|
@@ -1230,10 +1188,6 @@ def set_zoom(self, zoom): | |||||
def get_zoom(self): | ||||||
return self._zoom | ||||||
|
||||||
def get_offset(self): | ||||||
"""Return offset of the container.""" | ||||||
return self._offset | ||||||
|
||||||
def get_children(self): | ||||||
return [self.image] | ||||||
|
||||||
|
@@ -1603,8 +1557,7 @@ def __init__(self, ref_artist, offsetbox, use_blit=False): | |||||
def save_offset(self): | ||||||
offsetbox = self.offsetbox | ||||||
renderer = offsetbox.figure._cachedRenderer | ||||||
w, h, xd, yd = offsetbox.get_extent(renderer) | ||||||
offset = offsetbox.get_offset(w, h, xd, yd, renderer) | ||||||
offset = offsetbox.get_offset() | ||||||
self.offsetbox_x, self.offsetbox_y = offset | ||||||
self.offsetbox.set_offset(offset) | ||||||
|
||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs an API change note.