Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: one line, plotted against two related x axes in different units?

I have one y variable, which I am trying to plot against two related x axes, on the top and bottom of the figure (e.g. y="number of things in cube", x1="side length of cube", x2="volume of cube"). I have y, x1, x2 in numpy arrays. The relationship between my x1 and x2 is one-to-one and monotonic, but not simple, and they increase in different directions, like "side length" and "inverse volume". I've tried using twiny() and twin(), but these seem to be designed for plotting different y variables. Any ideas? Thanks everyone!

Below is an example of the kind of thing I'm trying to do, except with a single line rather than symbols. The idea is that, say, sigma=0.4 and M=2e15 are equivalent and interchangeable labels for one point.

alt text http://img580.imageshack.us/img580/4554/screenshotuy.png

like image 202
Kyle Avatar asked Jun 28 '10 23:06

Kyle


2 Answers

For different x-scales use twiny() (think of this as "shared y-axes"). An example slightly adapted from the matplotlib documentation:

import numpy as np
import matplotlib.pyplot as plt

# plot f(x)=x for two different x ranges
x1 = np.linspace(0, 1, 50)
x2 = np.linspace(0, 2, 50)
fig = plt.figure()

ax1 = fig.add_subplot(111)
ax1.plot(x1, x1,'b--')

ax2 = ax1.twiny()
ax2.plot(x2, x2, 'go')

plt.show()

If you just wanted a second axis plot the second data set as invisible.

ax2.plot(x2, x2, alpha=0)
like image 63
Benjamin Bannier Avatar answered Nov 01 '22 00:11

Benjamin Bannier


Just for completeness: There exists 'secondary axes' (matplotlib docs):

ax.secondary_xaxis('top', functions=(to_new_axis, from_new_axis))

the two functions

to_new_axis(), from_new_axis()

need to give proper scaling between say, your current units, and different units.

Code from the documentation:

fig, ax = plt.subplots(constrained_layout=True)
x = np.arange(0, 360, 1)
y = np.sin(2 * x * np.pi / 180)
ax.plot(x, y)
ax.set_xlabel('angle [degrees]')
ax.set_ylabel('signal')
ax.set_title('Sine wave')

def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('angle [rad]')
plt.show()

Here, they show the sinus function, in units of degrees and radians. In case you do not have well defined functions to switch between scales, you can use numpy interpolation:

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)
like image 33
bklebel Avatar answered Nov 01 '22 00:11

bklebel