Discussion:
[Matplotlib-users] axes.get_position() inaccurate until after savefig()?
gdm
2015-02-18 09:27:12 UTC
Permalink
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.
Ryan Nelson
2015-02-18 17:51:37 UTC
Permalink
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
Post by gdm
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.
#########################
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()
##########################
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]])')
http://stackoverflow.com/questions/11900654/get-position-does-strange-things-when-using-a-colorbar
--
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
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Eric Firing
2015-02-19 07:19:16 UTC
Permalink
Post by Ryan Nelson
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
Post by Ryan Nelson
Ryan
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.
#########################
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()
##########################
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]])')
http://stackoverflow.com/questions/11900654/get-position-does-strange-things-when-using-a-colorbar
--
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
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
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
gdm
2015-02-19 08:58:37 UTC
Permalink
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.
Loading...