axes.get_position() inaccurate until after savefig()?

New matplotlib user here. Sometimes I like to make figures with multiple
axes, and have lines that cross multiple axes. I've run in to problems with
coordinates when doing this. One such problem is that axes.get_position()
seems to return incorrect coordinates for an axes with a fixed aspect ratio.
However, after calling pyplot.show() (or fig.savefig()), it returns the
correct coordinates.

Here is some example code:

···

#########################
import numpy
import matplotlib.pyplot as plt

# make up some data
x = numpy.arange(10)
y = numpy.sin(x)
y2 = numpy.cos(x)

# generate the figure
fig = plt.figure()

# setup the first axes
ax1 = fig.add_subplot(121)
plt.plot(x,y)

# setup the second axes with axis ratio
ax2 = fig.add_subplot(122, aspect=6)
plt.plot(x, y2)

# Print out the axes position after various operations
print "aaa", ax2.get_position()

plt.draw()
print "bbb", ax2.get_position()

fig.canvas.draw()
print "ccc", ax2.get_position()

plt.show(block=False)
print "yyy", ax2.get_position()
##########################

Running this code produces the following output:
aaa Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
]])')
bbb Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
]])')
ccc Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
]])')
yyy Bbox('array([[ 0.54772727, 0.18686869],\n [ 0.9 ,
0.81313131]])')

P.S.: I think this might be related to an issue noted here:
http://stackoverflow.com/questions/11900654/get-position-does-strange-things-when-using-a-colorbar

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/axes-get-position-inaccurate-until-after-savefig-tp44954.html
Sent from the matplotlib - users mailing list archive at Nabble.com.

I don’t have an answer to your question exactly. But I’ll just say that this does make sense. The aspect-corrected axes (after show) is a subset of what you originally asked for, i.e. the bottom is higher, and the height is smaller. My guess is that this is not calculated until the final rendering on save on some computational effort. Otherwise, these values might need to be recalculated every time you add e.g. a colorbar. There is certainly a way to “trick” the plot into rendering, but I wonder if you could post a small (maybe two axes) version that demonstrates the effect your trying to accomplish. Perhaps someone might have a simpler/more robust solution.

Ryan

···

On Wed, Feb 18, 2015 at 4:27 AM, gdm <jgabor.astro@…287…> wrote:

New matplotlib user here. Sometimes I like to make figures with multiple

axes, and have lines that cross multiple axes. I’ve run in to problems with

coordinates when doing this. One such problem is that axes.get_position()

seems to return incorrect coordinates for an axes with a fixed aspect ratio.

However, after calling pyplot.show() (or fig.savefig()), it returns the

correct coordinates.

Here is some example code:

#########################

import numpy

import matplotlib.pyplot as plt

make up some data

x = numpy.arange(10)

y = numpy.sin(x)

y2 = numpy.cos(x)

generate the figure

fig = plt.figure()

setup the first axes

ax1 = fig.add_subplot(121)

plt.plot(x,y)

setup the second axes with axis ratio

ax2 = fig.add_subplot(122, aspect=6)

plt.plot(x, y2)

Print out the axes position after various operations

print “aaa”, ax2.get_position()

plt.draw()

print “bbb”, ax2.get_position()

fig.canvas.draw()

print “ccc”, ax2.get_position()

plt.show(block=False)

print “yyy”, ax2.get_position()

##########################

Running this code produces the following output:

aaa Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9

]])’)

bbb Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9

]])’)

ccc Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9

]])’)

yyy Bbox('array([[ 0.54772727, 0.18686869],\n [ 0.9 ,

0.81313131]])’)

P.S.: I think this might be related to an issue noted here:

http://stackoverflow.com/questions/11900654/get-position-does-strange-things-when-using-a-colorbar

View this message in context: http://matplotlib.1069221.n5.nabble.com/axes-get-position-inaccurate-until-after-savefig-tp44954.html

Sent from the matplotlib - users mailing list archive at Nabble.com.


Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server

from Actuate! Instantly Supercharge Your Business Reports and Dashboards

with Interactivity, Sharing, Native Excel Exports, App Integration & more

Get technology previously reserved for billion-dollar corporations, FREE

http://pubads.g.doubleclick.net/gampad/clk?id=190641631&iu=/4140/ostg.clktrk


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

I don't have an answer to your question exactly. But I'll just say that
this does make sense. The aspect-corrected axes (after show) is a subset
of what you originally asked for, i.e. the bottom is higher, and the
height is smaller. My guess is that this is not calculated until the
final rendering on save on some computational effort. Otherwise, these
values might need to be recalculated every time you add e.g. a colorbar.
There is certainly a way to "trick" the plot into rendering, but I
wonder if you could post a small (maybe two axes) version that
demonstrates the effect your trying to accomplish. Perhaps someone might
have a simpler/more robust solution.

There is an Axes method called apply_aspect() that is called by the Axes.draw() method. Normally there is no need to call it before that, but I think you could do so.

I think the problem, though, is that until the figure is rendered to a real device or saved in a file, its dimensions in inches are not known, and apply_aspect needs that information.

Try including the figsize_inches kwarg when you make the figure, and then see if calling apply_aspect makes the position settle down to its final value.

Eric

···

On 2015/02/18 7:51 AM, Ryan Nelson wrote:

Ryan

On Wed, Feb 18, 2015 at 4:27 AM, gdm <jgabor.astro@…287… > <mailto:jgabor.astro@…287…>> wrote:

    New matplotlib user here. Sometimes I like to make figures with
    multiple
    axes, and have lines that cross multiple axes. I've run in to
    problems with
    coordinates when doing this. One such problem is that
    axes.get_position()
    seems to return incorrect coordinates for an axes with a fixed
    aspect ratio.
    However, after calling pyplot.show() (or fig.savefig()), it returns the
    correct coordinates.

    Here is some example code:
    #########################
    import numpy
    import matplotlib.pyplot as plt

    # make up some data
    x = numpy.arange(10)
    y = numpy.sin(x)
    y2 = numpy.cos(x)

    # generate the figure
    fig = plt.figure()

    # setup the first axes
    ax1 = fig.add_subplot(121)
    plt.plot(x,y)

    # setup the second axes with axis ratio
    ax2 = fig.add_subplot(122, aspect=6)
    plt.plot(x, y2)

    # Print out the axes position after various operations
    print "aaa", ax2.get_position()

    plt.draw()
    print "bbb", ax2.get_position()

    fig.canvas.draw()
    print "ccc", ax2.get_position()

    plt.show(block=False)
    print "yyy", ax2.get_position()
    ##########################

    Running this code produces the following output:
    aaa Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
    ]])')
    bbb Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
    ]])')
    ccc Bbox('array([[ 0.54772727, 0.1 ],\n [ 0.9 , 0.9
    ]])')
    yyy Bbox('array([[ 0.54772727, 0.18686869],\n [ 0.9 ,
    0.81313131]])')

    P.S.: I think this might be related to an issue noted here:
    http://stackoverflow.com/questions/11900654/get-position-does-strange-things-when-using-a-colorbar

    --
    View this message in context:
    http://matplotlib.1069221.n5.nabble.com/axes-get-position-inaccurate-until-after-savefig-tp44954.html
    Sent from the matplotlib - users mailing list archive at Nabble.com.

    ------------------------------------------------------------------------------
    Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
    from Actuate! Instantly Supercharge Your Business Reports and Dashboards
    with Interactivity, Sharing, Native Excel Exports, App Integration &
    more
    Get technology previously reserved for billion-dollar corporations, FREE
    http://pubads.g.doubleclick.net/gampad/clk?id=190641631&iu=/4140/ostg.clktrk
    _______________________________________________
    Matplotlib-users mailing list
    Matplotlib-users@lists.sourceforge.net
    <mailto:Matplotlib-users@lists.sourceforge.net>
    https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server
from Actuate! Instantly Supercharge Your Business Reports and Dashboards
with Interactivity, Sharing, Native Excel Exports, App Integration & more
Get technology previously reserved for billion-dollar corporations, FREE
http://pubads.g.doubleclick.net/gampad/clk?id=190641631&iu=/4140/ostg.clktrk

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Ok, axes.apply_aspect() seems to work. The other obvious kluge I had found
was to save the figure twice, once before and once after I accessed the axes
position.

It seems the more elegant solution might be to use a somewhat-complicated
transform, so that that the two endpoints of a Line2d segment can have
coordinates in different coordinate systems (e.g. one end is in data
coordinates on ax1, and the other end is in data coordinates on ax2). The
"axes zoom effect" is similar to what I'm trying to do:

http://matplotlib.org/users/annotations_guide.html#zoom-effect-between-axes

Thanks!

···

--
View this message in context: http://matplotlib.1069221.n5.nabble.com/axes-get-position-inaccurate-until-after-savefig-tp44954p44990.html
Sent from the matplotlib - users mailing list archive at Nabble.com.