Strange resize behaviour with ImageGrid #955

Closed
jpterlouw opened this Issue Jun 18, 2012 · 7 comments

Projects

None yet

5 participants

If in the first example under http://matplotlib.sourceforge.net/mpl_toolkits/axes_grid/users/overview.html#imagegrid the "aspect" argument of imshow() is not equal to 1.0, the images are irreversibly squashed in one direction when the window is resized.

To reproduce, for instance change
grid[i].imshow(im)
into:
grid[i].imshow(im, aspect=1.3)

Contributor

We set the four images to an aspect ratio of 1.3 and expected the aspect ratio to be preserved upon window resizing. In practice, window resizing changes the figure's aspect ratio and reduces the plotting area to an infinitesmal space.

When the aspect ratio is changed to 1, the code listed in the issue report generates a figure that performs as we expect when the window is resized. The aspect ratio for each of the four images remains 1:1.

We noticed that the comments in /matplotlib/lib/mpl_toolkits/axes_grid1/axes_grid.py explain that ImageGrid should not be used for images with specified aspect ratios. If ImageGrid should only be used with aspect ratio equal to 1, it should raise an error when the user tries to plot data. Otherwise, the aspect option should be removed entirely.

The plot described above can be achieved with regular subplotting (not using ImageGrid). Using this method, the window can be resized without error.

import matplotlib.pyplot as plt
import numpy as np

im = np.arange(100)
im.shape = 10, 10

plt.figure(1,(4.,4.))
for i in range(1,5):
    plt.subplot(2,2,i),plt.imshow(im,aspect=1.3)

plt.show()

Submitted by (oxling, happy4crazy, bev-a-tron, vwxy) at Hacker School.

From what I can gather, the aspect info is never getting sent to the axes geometry helper class (axes_size), so the divider locator (axes_divider.Divider.locate) mis-sizes the axes. With the shared axis ranges in ImageGrid, this leads to runaway resizing. For the particular example with a constant aspect ratio, you could run this after calling imshow, but before rendering the figure:

for sizer in grid._divider._vertical:
    if hasattr(sizer, '_aspect'):
        sizer._aspect = sizer._axes.get_aspect()

This sets all the axes_size.AxesY aspects to their respective axes aspect value. Different aspect ratios will still result in problems, as all the axes get shared. Perhaps axes_size.AxesY.get_size could pull the current aspect out of the axis instead of having it set once on init.

@oxling oxling added a commit to oxling/matplotlib that referenced this issue Jul 10, 2012
@oxling oxling Fix for issue #955
The Y axis will reset its aspect ratio to the aspect of its parent axes when get_size is called.
141716e
Contributor
oxling commented Jul 10, 2012

Made this change following your suggestion. See pull request #1003.

-(oxling, happy4crazy) at Hacker School.

Contributor

I must confess that I did not pay much attention for aspect!=1 for the ImageGrid. And I agree that there is lots of room for improvements.

However, there is a limitation that you cannot have arbitrary aspect ratio for any axes. And (I think) this is why axes_size does not fetch the aspect value from the axes.

For the proposed solution (PR #1003), I think it only works if axes along a row have same aspect ratio.

For example, example below does now work correctly.

fig = plt.figure(1, (4., 4.))
grid = ImageGrid(fig, 111, # similar to subplot(111)
                 nrows_ncols = (1, 2), # creates 2x2 grid of axes
                 axes_pad=0.1, # pad between axes in inch.
                 aspect=True,
                 )

grid[0].set_aspect(1.0)
grid[1].set_aspect(2.0)

plt.show(); plt.show();

Also, note that it does not work well when aspect=False or share_all=True.

So, I am not inclined to accept the PR as in the current form, but I would happy to see this improved to address these issues.

My current impression is that this could be a bit tricky, but I will be happy to be proven wrong.

@leejjoon leejjoon was assigned Jul 17, 2012

@leejjoon: A couple questions then -

What's the intended behavior for ImageGrid for arbitrary aspect ratios and/or arbitrary image sizes? Can it be sketched out on paper? Using the correct axes aspect for size calculations fixes the unstable scaling problem for self-consistent collections of aspect values given the shared axes limits, but I think a better fix to ImageGrid would require knowledge of the intended behavior.

In the Divider class, what's the intended meaning of axes_size.AxesY.get_size() and axes_size.AxesX.get_size() - are they supposed to represent relative physical (pixel) sizes of the axes?

Contributor

Well I guess there is no "defined" intended behavior.
The proposed PR works when the axes in a row have a same aspect ratio, so at least, I think it should behave similarly when the axes in a column have a same aspect ratio.

In theory, this is can be done by modifying the AxesX in a similar manner.
But this change required tweaking in other places.

Above is what I have managed so far. There might be some side effects but it seems to work for me.

Contributor

I am closing this as I think I fixed it with f6b344e. Feel free to reopen it if there is any remaining issue.

@leejjoon leejjoon closed this Nov 30, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment