Trying to plot a spectrum, ie, velocity versus intensity, with lower x axis = velocity, on the upper twin axis = frequency
The relationship between them (doppler for
Your "linear function" is a "simple scaling law" (with an offset). Just replace the pm_to_kms
definition with your function.
The solution I ended up using was:
ax_hz = ax_kms.twiny()
x_1, x_2 = ax_kms.get_xlim()
# i want the frequency in GHz so, divide by 1e9
ax_hz.set_xlim(calc_frequency(x_1,data.restfreq/1e9),calc_frequency(x_2,data.restfreq/1e9))
This works perfect, and much less complicated solution.
EDIT : Found a very fancy answer. EDIT2 : Changed the transform call according to the comment by @u55
This basically involves defining our own conversion/transform. Because of the excellent AstroPy Units equivalencies, it becomes even easier to understand and more illustrative.
from matplotlib import transforms as mtransforms
import astropy.constants as co
import astropy.units as un
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('ggplot')
from mpl_toolkits.axes_grid.parasite_axes import SubplotHost
class Freq2WavelengthTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = False
has_inverse = True
def __init__(self):
mtransforms.Transform.__init__(self)
def transform_non_affine(self, fr):
return (fr*un.GHz).to(un.mm, equivalencies=un.spectral()).value
def inverted(self):
return Wavelength2FreqTransform()
class Wavelength2FreqTransform(Freq2WavelengthTransform):
input_dims = 1
output_dims = 1
is_separable = False
has_inverse = True
def __init__(self):
mtransforms.Transform.__init__(self)
def transform_non_affine(self, wl):
return (wl*un.mm).to(un.GHz, equivalencies=un.spectral()).value
def inverted(self):
return Freq2WavelengthTransform()
aux_trans = mtransforms.BlendedGenericTransform(Wavelength2FreqTransform(), mtransforms.IdentityTransform())
fig = plt.figure(2)
ax_GHz = SubplotHost(fig, 1,1,1)
fig.add_subplot(ax_GHz)
ax_GHz.set_xlabel("Frequency (GHz)")
xvals = np.arange(199.9, 999.9, 0.1)
# data, noise + Gaussian (spectral) lines
data = np.random.randn(len(xvals))*0.01 + np.exp(-(xvals-300.)**2/100.)*0.5 + np.exp(-(xvals-600.)**2/400.)*0.5
ax_mm = ax_GHz.twin(aux_trans)
ax_mm.set_xlabel('Wavelength (mm)')
ax_mm.set_viewlim_mode("transform")
ax_mm.axis["right"].toggle(ticklabels=False)
ax_GHz.plot(xvals, data)
ax_GHz.set_xlim(200, 1000)
plt.draw()
plt.show()
This now produces the desired results: