Skip to content

tight_layout() doesn't work properly on plots with a WCSAxes projection #8703

Description

@dstansby

A Matpltolib Axes created with projection=wcs does not play well with Matplotlib's tight_layout() method, that is supposed to re-size elements of a figure such that there are no overlapping labels/axes etc.

Consdier the following example:

import matplotlib.pyplot as plt

from astropy.wcs import WCS
from astropy.io import fits
from astropy.utils.data import get_pkg_data_filename

filename = get_pkg_data_filename('galactic_center/gc_msx_e.fits')

hdu = fits.open(filename)[0]
wcs = WCS(hdu.header)

fig = plt.figure(figsize=(8, 6))
n = 2
for i in range(n):
    projection = wcs
    # projection = None
    plt.subplot(n, 1, i + 1, projection=projection)
    # plt.imshow(hdu.data, vmin=-2.e-5, vmax=2.e-4, origin='lower')
    plt.grid(color='white', ls='solid')
    plt.xlabel('Galactic Longitude')
    plt.ylabel('Galactic Latitude')
    plt.title('WCSAxes plot')

fig.tight_layout()
plt.show()

projection=None, no tight_layout:
Figure_1
projection=None, with tight_layout:
Figure_1
(note how this re-organises things nicely)
projection='wcs', no tight_layout:
Figure_1
projection='wcs', with tight_layout:
Figure_1
Note how things actually get worse!

  • astropy 3.1.2
  • Matplotlib 3.0.3

Activity

  1. pllim commented on May 15, 2019

    @pllim
    Member

    Is this related to #8678 (comment) ?

  2. dstansby commented on May 15, 2019

    @dstansby
    ContributorAuthor

    I don't think so, that is only a problem on Matplotlib dev (post version 3.0.3), whereas this is an issue on a version of Maptlotlib (3.0.3) that predates that change.

  3. astrofrog commented on May 15, 2019

    @astrofrog
    Member

    I have some ideas :)

  4. self-assigned this
    on May 17, 2019
  5. astrofrog commented on May 17, 2019

    @astrofrog
    Member

    A workaround for now is to call:

    fig.canvas.draw()
    

    before

    fig.tight_layout()
    

    Basically the fundamental issue is that get_tightbbox actually requires the figure to be drawn once before it returns correct results. We should probably find a way to avoid this - but in the mean time we could overload tight_layout in WCSAxes and just force a draw first.

  6. dstansby commented on Oct 4, 2020

    @dstansby
    ContributorAuthor

    For reference, some simpler code to reproduce this:

    import matplotlib.pyplot as plt
    
    from astropy.wcs import WCS
    from astropy.io import fits
    from astropy.utils.data import get_pkg_data_filename
    
    filename = get_pkg_data_filename('galactic_center/gc_msx_e.fits')
    
    hdu = fits.open(filename)[0]
    wcs = WCS(hdu.header)
    
    fig = plt.figure(figsize=(8, 6))
    axs = [fig.add_subplot(2, 1, i, projection=wcs) for i in [1, 2]]
    
    fig.tight_layout()
    plt.show()
  7. dstansby commented on Oct 5, 2020

    @dstansby
    ContributorAuthor

    As I slowly descend into madness trying to work this out, a note that the end goal to get this working is to have TickLabels and AxisLabels have their own get_tight_bbox() methods that can calculate their own Bboxes. This is going to need a lot of refactoring, but I suspect in the long run it should significantly tidy up the WCSAxes code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions