For the first plot, I recommend axisartist
. The automatic scaling of the two y
-axis on the left-hand-side is achieved through a simple scaling factor that applies to the specified y
-limits. This first example is based on the explanations on parasite axes:
import numpy as np
from mpl_toolkits.axes_grid1 import host_subplot
import mpl_toolkits.axisartist as AA
import matplotlib.pyplot as plt
# initialize the three axis:
host = host_subplot(111, axes_class=AA.Axes)
plt.subplots_adjust(left=0.25)
par1 = host.twinx()
par2 = host.twinx()
# secify the offset for the left-most axis:
offset = -60
new_fixed_axis = par2.get_grid_helper().new_fixed_axis
par2.axis["right"] = new_fixed_axis(loc="left", axes=par2, offset=(offset, 0))
par2.axis["right"].toggle(all=True)
# data ratio for the two left y-axis:
y3_to_y1 = 1/7.5
# y-axis limits:
YLIM = [0.0, 150.0,
0.0, 150.0]
# set up dummy data
x = np.linspace(0,70.0,70.0)
y1 = np.asarray([xi**2.0*0.032653 for xi in x])
y2 = np.asarray([xi**2.0*0.02857 for xi in x])
# plot data on y1 and y2, respectively:
host.plot(x,y1,'b')
par1.plot(x,y2,'r')
# specify the axis limits:
host.set_xlim(0.0,70.0)
host.set_ylim(YLIM[0],YLIM[1])
par1.set_ylim(YLIM[2],YLIM[3])
# when specifying the limits for the left-most y-axis
# you utilize the conversion factor:
par2.set_ylim(YLIM[2]*y3_to_y1,YLIM[3]*y3_to_y1)
# set y-ticks, use np.arange for defined deltas
# add a small increment to the last ylim value
# to ensure that the last value will be a tick
host.set_yticks(np.arange(YLIM[0],YLIM[1]+0.001,10.0))
par1.set_yticks(np.arange(YLIM[2],YLIM[3]+0.001,10.0))
par2.set_yticks(np.arange(YLIM[2]*y3_to_y1,YLIM[3]*y3_to_y1+0.001, 2.0))
plt.show()
You will end up with this plot:

You can try to modify the above example to give you the second plot, too. One idea is, to reduce offset
to zero. However, with the axisartist
, certain tick functions are not supported. One of them is specifying if the ticks go inside or outside the axis.
Therefore, for the second plot, the following example (based on matplotlib: overlay plots with different scales?) is appropriate.
import numpy as np
import matplotlib.pyplot as plt
# initialize the three axis:
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
ax3 = ax1.twinx()
# data ratio for the two left y-axis:
y3_to_y1 = 1/7.5
# y-axis limits:
YLIM = [0.0, 150.0,
0.0, 150.0]
# set up dummy data
x = np.linspace(0,70.0,70.0)
y1 = np.asarray([xi**2.0*0.032653 for xi in x])
y2 = np.asarray([xi**2.0*0.02857 for xi in x])
# plot the data
ax1.plot(x,y1,'b')
ax2.plot(x,y2,'r')
# define the axis limits
ax1.set_xlim(0.0,70.0)
ax1.set_ylim(YLIM[0],YLIM[1])
ax2.set_ylim(YLIM[2],YLIM[3])
# when specifying the limits for the left-most y-axis
# you utilize the conversion factor:
ax3.set_ylim(YLIM[2]*y3_to_y1,YLIM[3]*y3_to_y1)
# move the 3rd y-axis to the left (0.0):
ax3.spines['right'].set_position(('axes', 0.0))
# set y-ticks, use np.arange for defined deltas
# add a small increment to the last ylim value
# to ensure that the last value will be a tick
ax1.set_yticks(np.arange(YLIM[0],YLIM[1]+0.001,10.0))
ax2.set_yticks(np.arange(YLIM[2],YLIM[3]+0.001,10.0))
ax3.set_yticks(np.arange(YLIM[2]*y3_to_y1,YLIM[3]*y3_to_y1+0.001, 2.0))
# for both letf-hand y-axis move the ticks to the outside:
ax1.get_yaxis().set_tick_params(direction='out')
ax3.get_yaxis().set_tick_params(direction='out')
plt.show()
This results in this figure:

Again, the set_tick_params(direction='out')
does not work with the axisartist
from the first example.
Somewhat counter-intuitive, both the y1
and y3
ticks have to be set to 'out'
. For y1
, this makes sense, and for y3
you have to remember that it started as a right-hand-side axis. Therefore, those ticks would appear outside (with the default 'in'
setting) when the axis is moved to the left.