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 formula) is
f = (1-v/c)*f_0
where f is the resulting frequency, v the velocity, c the speed of light, and f_0 the frequency at v=0, ie. the v_lsr.
I have tried to solve it by looking at http://matplotlib.sourceforge.net/examples/axes_grid/parasite_simple2.html , where it is solved by
pm_to_kms = 1./206265.*2300*3.085e18/3.15e7/1.e5 aux_trans = matplotlib.transforms.Affine2D().scale(pm_to_kms, 1.) ax_pm = ax_kms.twin(aux_trans) ax_pm.set_viewlim_mode("transform")
my problem is, how do I replace the pm_to_kms with my function for frequency?
Anyone know how to solve this?
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:
Your "linear function" is a "simple scaling law" (with an offset). Just replace the pm_to_kms
definition with your function.