Multiple Y-axis conversion scales

Conversion scale with 'parasitic' parallel y axis

Conversion scale with shared y axis

Hello

I'm trying to create plots that include parallel conversion scales for two sets of y-axis units; using two different styles:

  • offset ("stray") y-axis and
  • superimposed / shared y-axes

to reproduce the style of the left y-axes in the attached example images.

I would like to find the simplest common way to create both of the above plots, which also allows me to generate y-axis transformation scales by defining the relationship between the two sets of units as a function (in this example: mmHg = kPa * 7.5).

If in these examples it is possible to add the third right y-axes (vapor concentration and water content) that are not related to the left hand weights, that would be a bonus.

I have read the related stackoverflow.com posts and examples of using multiple x and y axes using double and close functions - for example here - and the Matplotlib cookbook, but I cannot find an example that solves this problem.

I would greatly appreciate any minimal working examples or links.

I am using Matplotlib in Spyder 2.2.1 / Python 2.7.5

Thanks a lot pending

Dave

+3


source to share


1 answer


For the first graph, I recommend axisartist

. The autoscaling of the axis y

on the left is achieved with a simple scaling factor that is applied to the specified y

-limits. This first example is based on the explanations of parasitic 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 end up with this plot:

first figure

You can try modifying the above example to get the second plot. One idea is to reduce offset

to zero. However, axisartist

some of the tick functions are not supported . One of them indicates whether the pliers are in or out of axis.
So the following example is suitable for the second plot (based on matplotlib: overlays with different scales? ).



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()

      

As a result of this drawing:

second figure

Again, set_tick_params(direction='out')

doesn't work with axisartist

from the first example.
Somewhat counterintuitively, both tags y1

and y3

should be set to 'out'

. For y1

this it makes sense, and for y3

you have to remember that it started out as a right axis. Therefore, these ticks will be displayed outside (with the default setting 'in'

) when the axis is moved to the left.

+6


source







All Articles