Python / matplotlib - gemelo parásito escala de los ejes
-
01-10-2019 - |
Pregunta
Tratando de trazar un espectro, es decir, la velocidad frente a la intensidad, con una menor eje x = velocidad, en el gemelo superior AXIS = frecuencia
La relación entre ellos (fórmula doppler) es
f = (1-v/c)*f_0
donde f es la frecuencia resultante, v la velocidad, c la velocidad de la luz, y F_0 la frecuencia a v = 0, es decir. la v_lsr.
Me han tratado de resolverlo examinado http: //matplotlib.sourceforge. ejemplos / net / axes_grid / parasite_simple2.html , donde se resuelve mediante
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")
mi problema es, ¿cómo puedo reemplazar los pm_to_kms con mi función de la frecuencia?
conozco a nadie cómo resolver esto?
Solución
La solución Terminé usando era:
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))
Esto funciona perfecto, y mucho menos complicada solución.
EDIT:. Encontrado una respuesta de lujo muy Edit2: Se ha cambiado la llamada transformarse de acuerdo con el comentario de @ U55
Esta consiste básicamente en la definición de nuestra propia conversión / a transformar. Debido a las excelentes equivalencias Unidades AstroPy, se hace aún más fácil de entender y más ilustrativa.
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()
Esto ahora produce los resultados deseados:
Otros consejos
Su "función lineal" es una "ley de escala simple" (con un desplazamiento). Basta con sustituir la definición pm_to_kms
con su función.