enable
enable copied to clipboard
Component bounds shrink with repeated changes to aspect ratio.
Component._enforce_aspect_ratio
rescales the component using the most recent component bounds as an upper bound. As a result, repeatedly changing between low and high aspect ratios will shrink the component bounds to a point.
For example, run chaco's aspect_ratio.py and click on the "Screen" (?) check box. Then, set the aspect ratio to 2, then 0.5, then 2, ... You should see a plot that shrinks to a point eventually.
Note that resizing the window (by dragging a corner of the window) will fix the plot bounds. This is because resizing resets the bounds. These "maximum bounds" are never saved because outer_bounds
(a.k.a. outer_width
and outer_height
) gets overwritten when figuring out the plot layout.
This will probably be fixed automatically if the layout gets rewritten to use constraints-based layouts.
I am running into the same issue with Chaco. As a temporary solution, I have monkey-patched the Component._enforce_aspect_ratio
to not "use the current width and height as a bounding box and find the largest rectangle of the desired aspect ratio that will fit". It works, but I'd like to find a more "future-safe" fix.
Can anyone with more experience give me advice on what the best solution would be now in 2016? Are the constraint-based layouts a feature now and could I use them with Chaco?
Edit: If anyone runs into this in the future, my changes are the following, which you can compare to the original.
def _enforce_aspect_ratio_without_resize(self, notify=True):
""" This method adjusts the width and/or height of the component so
that the new width and height match the aspect ratio. It uses the
current width and height as a bounding box and finds the largest
rectangle of the desired aspect ratio that will fit.
If **notify** is True, then fires trait events for bounds and
position changing.
"""
ratio = self.aspect_ratio
old_w, old_h = [self.container.width, self.container.height]
if ratio is None:
return
elif ratio == 0:
self.width = 0
return
elif old_h == 0:
return
elif int(old_w) == int(ratio * old_h):
pass
old_aspect = old_w / float(old_h)
new_pos = None
if ratio > old_aspect:
# desired rectangle is wider than bounding box, so use the width
# and compute a smaller height
new_w = old_w
new_h = new_w / ratio
else:
# desired rectangle is taller than bounding box, so use the height
# and compute a smaller width
new_h = old_h
new_w = new_h * ratio
if self.auto_center:
new_pos = [(old_w-new_w)/2.0, (old_h-new_h)/2.0]
self.set(bounds=[new_w, new_h], trait_change_notify=notify)
if new_pos:
self.set(position=new_pos, trait_change_notify=notify)
return
To monkey-patch, you can simply:
import types
plot._enforce_aspect_ratio = types.MethodType(_enforce_aspect_ratio_without_resize, plot)
or subclass the plot if you prefer.