enable
enable copied to clipboard
Updating the aspect_ratio of a Component causes the bounds to shrink
For the use case of drawing an image plot in Chaco with a fixed aspect ratio, setting a new aspect ratio when the image data changes can cause the bounds to shrink until the component's parent widget is resized.
The code which handles this is in Component._enforce_aspect_ratio, so technically this applies to all components which update their aspect ratio.
A potential solution to this might be to consult the size of the Component.window (AbstractWindow) instance. However, that will only work if the component in question completely fills its window. For smaller components, we need to remember the maximum size available to be filled.
(Also, ConstraintsContainer might be a better option here)
Example Code
import numpy as np
from chaco.api import ArrayPlotData, CMapImagePlot, Plot
from enable.api import ComponentEditor
from traits.api import (
Array, cached_property, Enum, HasTraits, Instance, Property
)
from traitsui.api import HGroup, UItem, View
IMAGE_DATA = np.random.randint(0, 256, size=(20, 10), dtype=np.uint8)
class PatchedPlot(Plot):
def draw(self, gc, **kwargs):
print(self.bounds)
# Uncomment to "fix"
# self.position = [0, 0]
# self.bounds = [gc.width(), gc.height()]
super().draw(gc, **kwargs)
class Demo(HasTraits):
plot = Instance(Plot)
data = Instance(ArrayPlotData)
img_plot = Instance(CMapImagePlot)
choice = Enum('tall', 'wide')
image_data = Property(Array, depends_on='choice')
@cached_property
def _get_image_data(self):
if self.choice == 'tall':
return IMAGE_DATA
else:
return IMAGE_DATA.T
def _data_default(self):
return ArrayPlotData(img=self.image_data)
def _plot_default(self):
plot = PatchedPlot(
self.data,
default_origin='top left',
aspect_ratio=self.image_data.shape[1] / self.image_data.shape[0]
)
self.img_plot = plot.img_plot('img')[0]
return plot
def _image_data_changed(self):
data = self.image_data
# Update the plot data source and aspect ratio
self.data.set_data('img', data)
self.plot.aspect_ratio = data.shape[1] / data.shape[0]
# Update the grid mapper
xrange = np.arange(data.shape[1])
yrange = np.arange(data.shape[0])
self.img_plot.index.set_data(xrange, yrange)
self.plot.request_redraw()
view = View(
UItem('plot', editor=ComponentEditor()),
HGroup(
UItem('choice', springy=True),
),
resizable=True,
)
if __name__ == '__main__':
Demo().configure_traits()
I'm highly suspicious of aspect_ratio in Enable - it generally doesn't do what people think it does when used in Chaco (but almost does, so people are fooled until it goes wrong). In particular, this example code doesn't guarantee that the pixels are square. That should be done via setting the aspect_ratio of the mapper: https://github.com/enthought/chaco/blob/1c276997517b94f39f159ef9d8d348343b94ac93/chaco/grid_mapper.py#L60-L64
Duplicate of #93... My search for existing issues was not sophisticated enough. (The proposed solution there doesn't actually preserve the aspect ratio when using the example here)