0

I'm trying to generate a matplotlib figure with a specific aspect ration, 2 x-axes and 2 y-axes with different scales, and reformatted tick labels, along the lines of the following figure:

enter image description here

In matplotlib I get as far as

x_power_min = -2
x_power_max =  3
y_power_min = -5
y_power_max =  2
fig_ratio = 1.2

fig, axy = plt.subplots()

axy.set(xscale='log', xlim=[10**x_power_min,10**x_power_max], xlabel='X1')
axy.set(yscale='log', ylim=[10**y_power_min,10**y_power_max], ylabel='Y1')

axy.set_aspect(float(x_power_max-x_power_min) / float(y_power_max-y_power_min) * fig_ratio)

axy.xaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: '{:0d}'.format(int(math.log10(x)))))
axy.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda y, pos: '{:0d}'.format(int(math.log10(y)))))

which gives me

enter image description here

but when I introduce additional axes, I get an error: ValueError: math domain error - dL_width = math.log10(dL.x1) - math.log10(dL.x0) so that I can only proceed by commenting out the set_aspect line with

fig, axy = plt.subplots()
ay2 = axy.twinx()
ax2 = axy.twiny()

axy.set(xscale='log', xlim=[10**x_power_min,10**x_power_max], xlabel='X1')
axy.set(yscale='log', ylim=[10**y_power_min,10**y_power_max], ylabel='Y1')
ay2.set(yscale='log', ylim=[317.83*10**y_power_min,317.83*10**y_power_max], ylabel='Y2')
ax2.set(xscale='log', xlim=[10**(3*x_power_min/2.0),10**(3*x_power_max/2.0)], xlabel='X2')

#axy.set_aspect(float(x_power_max-x_power_min) / float(y_power_max-y_power_min) * fig_ratio)

axy.xaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: '{:0d}'.format(int(math.log10(x)))))
axy.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda y, pos: '{:0d}'.format(int(math.log10(y)))))
ay2.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda y, pos: '{:0d}'.format(int(math.log10(y)))))
ax2.xaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: '{:0d}'.format(int(math.log10(x)))))

which results in a graph with the wrong aspect ratio:

enter image description here

orome
  • 45,163
  • 57
  • 202
  • 418

1 Answers1

1

aspect sets the ratio between the length in axes-space of one unit along the x-axis to one unit along the y-axis. This makes no sense for log scales as they are non linear and the ratio depends on where along the axes you look at it.

You want to use fig.set_size_inches to make the aspect ratio what you want.

tacaswell
  • 84,579
  • 22
  • 210
  • 199
  • If it "makes no sense" for log scales, why did it work initially? – orome Dec 20 '13 at 20:03
  • What's the "default" size (i.e., how do I reproduce the aspect ration and scaling I get with the other method). Something like `fig.set_size_inches(fig.get_size_inches()[0], fig_ratio*fig.get_size_inches()[0])` seems the direction to go, but it produces a larger figure. – orome Dec 20 '13 at 20:09
  • 2
    It should not have worked and raises a warning on master now. If `fig_ratio` is bigger than one then your figure will get bigger. – tacaswell Dec 20 '13 at 20:16
  • No: `fig.set_size_inches(fig.get_size_inches()[1]/fig_ratio, fig.get_size_inches()[1])` does it. – orome Dec 20 '13 at 20:18
  • because you are dividing ;) – tacaswell Dec 20 '13 at 21:04