Python/Matplotlib - 副坐标轴比例尺问题

3
尝试绘制频谱图,即速度与强度之间的关系,其中下部x轴为速度,上部双轴为频率。它们之间的关系(多普勒公式)是:
f = (1-v/c)*f_0 

其中f是结果频率,v是速度,c是光速,f_0是在v=0时的频率,即v_lsr。

我曾试过通过查看http://matplotlib.sourceforge.net/examples/axes_grid/parasite_simple2.html来解决它,该网站上提供了以下解决方案:

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

我的问题是,如何用我的频率函数替换pm_to_kms?

有人知道如何解决吗?

2个回答

5
我最终使用的解决方案是:
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))

这个方法非常完美,而且解决方案更加简单。编辑:找到了一个非常新颖的答案。编辑2:根据@u55的评论更改了转换调用。这基本上涉及定义我们自己的转换/变形。由于AstroPy Units等效性的出色表现,它变得更容易理解和更具说明性。
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() 

这现在产生了所需的结果: 这里输入图片描述

1
这种情况之所以能够正确工作,纯属巧合,因为频率和波长之间的转换方程(νλ = c)在频率和波长交换时是对称的。然而,对于一般的变换,这将会给出错误的结果。您应该将 Freq2WavelengthTransform() 替换为 Wavelength2FreqTransform(),在以下代码行中: aux_trans = mtransforms.BlendedGenericTransform(Freq2WavelengthTransform(), mtransforms.IdentityTransform()) - u55

0

你的“线性函数”是一个“简单的比例关系”(带有偏移量)。只需用你的函数替换pm_to_kms的定义即可。


好的,你的意思是我需要进行两次变换,一次是缩放,一次是平移? 就像这样: kms_to_deltafreq = -f0/c deltafreq_to_freq = f0 matplotlib.transforms.Affine2D().scale(kms_to_deltafreq, 1.).translate(deltafreq_to_freq,1) ax_freq = ax_kms.twin(aux_trans) ax_freq.set_viewlim_mode("transform")?? - Magnus Persson
如果时间允许,我会在这里写一个正式的答案。目前可以在这里找到答案:http://matplotlib.1069221.n5.nabble.com/Dual-x-axes-with-transformation-td10865.html - Magnus Persson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接