python/matplotlib - паразитное масштабирование двойной оси

Попытка построить спектр, т. е. скорость в зависимости от интенсивности, где нижняя ось 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 моей функцией для частоты?

Кто-нибудь знает, как это решить?


person Magnus Persson    schedule 30.06.2010    source источник


Ответы (2)


В итоге я использовал следующее решение:

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

Это работает идеально и гораздо менее сложное решение.

EDIT: нашел очень интересный ответ. EDIT2: изменен вызов преобразования в соответствии с комментарием @u55

Это в основном включает в себя определение нашего собственного преобразования/преобразования. Из-за отличной эквивалентности единиц AstroPy он становится еще проще для понимания и более наглядным.

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

Теперь это дает желаемые результаты: введите здесь описание изображения

person Magnus Persson    schedule 02.07.2010
comment
Это получилось правильно, случайно, потому что уравнение преобразования между частотой и длиной волны (νλ = c) симметрично относительно обмена частотой и длиной волны. Однако для общих преобразований это даст неправильные результаты. Вы должны заменить Freq2WavelengthTransform() на Wavelength2FreqTransform() в строке: aux_trans = mtransforms.BlendedGenericTransform(Freq2WavelengthTransform(), mtransforms.IdentityTransform()). - person u55; 13.10.2016

Ваша «линейная функция» — это «простой закон масштабирования» (со смещением). Просто замените определение pm_to_kms своей функцией.

person Benjamin Bannier    schedule 30.06.2010
comment
ну да... так вы имеете в виду, что я делаю два преобразования, одно масштабирование и одно преобразование? как 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) ?? - person Magnus Persson; 02.07.2010
comment
Итак, ответ на данный момент существует здесь: matplotlib. 1069221.n5.nabble.com/ если позволит время, я напишу здесь правильный. - person Magnus Persson; 17.02.2015