Trazado de datos de rastreo de cromatograma de ADN

7

La secuenciación de ADN de Sanger produce una traza de cromatograma que se puede visualizar con varios programas, incluidos FinchTV o ChromasLite. Los datos brutos consisten en coordenadas para cada una de las cuatro bases de ADN (A, C, G y T). Sin embargo, los gráficos se muestran como picos suavizados, como se muestra en la imagen anteriormente. Muchos programas permiten que los ejes x e y de la gráfica se escalen más o menos para cambiar la forma de la gráfica. ¿Qué método matemático se utiliza para trazar curvas suaves como estas a partir de un (pequeño) número de puntos de datos sin procesar?

Ejemplo de seguimiento de cromatograma

SabreWolfy
fuente
1
¿circunvolución? ¿Cuál es el pequeño número de puntos de datos sin procesar? ¿Qué te dice la suavidad? Estoy confundido, pensé que la señal suave fue la que salió del secuenciador, y estás interesado en la letra correcta que corresponde.
Henry Gomersall
@HenryGomersall: Sí y no :) Lo que sale del secuenciador son puntos que, cuando se trazan, se encuentran en esa bonita línea suavizada. Quiero trazar la línea suavizada. La letra correspondiente al pico es un problema diferente, pero relacionado, según tengo entendido.
SabreWolfy
1
Ah, ¿entonces su pregunta es sobre la interpolación para una bonita representación? Para ser claros, ¿no se trata de procesar los datos per se ?
Henry Gomersall
@HenryGomersall: En última instancia, quería hacer un procesamiento de los datos, pero quería comenzar descubriendo cómo trazar las curvas.
SabreWolfy

Respuestas:

5

Implementación

Suponiendo que ya tiene una rutina de dibujo lineal, solo necesita complementarla con algún tipo de interpolación. Las curvas se crean dibujando suficientes líneas cortas interpoladas para que el resultado se vea suave. Un buen punto de partida sería utilizar una rutina de interpolación existente, como las que da Paul Bourke aquí .

Ilustraré esto usando las rutinas cúbicas que proporciona, ya que esas son algunas de las más simples que aún darán resultados razonables. Aquí está el primero (traducido a python) como referencia:

def cubic(mu,y0,y1,y2,y3):
    mu2 = mu*mu
    a0 = y3 - y2 - y0 + y1
    a1 = y0 - y1 - a0
    a2 = y2 - y0
    a3 = y1
    return a0*mu*mu2 + a1*mu2 + a2*mu + a3

Cada rutina tiene un parámetro muque representa la parte fraccionaria del índice que desea interpolar. Dependiendo de la rutina, los otros parámetros serán cierto número de muestras que rodean el índice en cuestión. En el caso cúbico, necesitará cuatro muestras. Por ejemplo, si los datos es y[n], y desea que el valor en 10.3, musería .3, y que le pasa en y[9], y[10], y[11], y y[12].

Luego, en lugar de dibujar una sola línea con puntos finales, digamos, (10,y10)(11,y11), dibujaría un montón de valores más cortos utilizando los valores interpolados (p. ej. (10,y10)(10,1,cúbico(.1,y9 9,y10,y11,y12))...) Obviamente esos puntos tendrían que ser escalados aX y y dimensiones de la imagen a renderizar.

Teoría

Ahora, dado que la página / rutina a la que hice referencia no cita ninguna fuente, vale la pena explicar de dónde provienen esas rutinas cúbicas (y cómo funcionan). Tanto el que reproduje arriba como el spline Catmull-Rom muy similar que menciona justo debajo de él, son dos casos específicos de usar el siguiente núcleo de convolución cúbica:

ψ(X)={(α+2)El |XEl |3-(α+3)El |XEl |2+1, Si 0 0El |XEl |<1αEl |XEl |3-5 5αEl |XEl |2+8αEl |XEl |-4 4α, Si 1El |XEl |<20 0, Si 2El |XEl |

La rutina mencionada anteriormente corresponde a un valor de α=-1, y la spline Catmull-Rom corresponde a α=-1/ /2. No entraré en demasiados detalles sobre cómo se deriva la forma general del núcleo, pero implica varias restricciones, como asegurarse de queψ(X) es uno en cero y cero en todos los demás enteros.

Esto es lo que parece:

Kernel de convolución cúbica

Las dos opciones para el valor de αprovienen de intentos de igualar varios aspectos de la función sinc , el núcleo de reconstrucción ideal. Ajusteα=-1 hace la derivada de ψ coincidir con la derivada de la función sinc en X=1y haciéndolo igual a -1/ /2proporciona la mejor aproximación de baja frecuencia en su lugar. Por todas las cuentas, un valor deα=-1/ /2tiene propiedades mucho mejores en general, por lo que es probablemente el mejor valor para usar en la práctica. Se puede encontrar una discusión mucho más extensa en el siguiente documento, comenzando en la página 328:

Meijering, Erik. "Una cronología de la interpolación: de la astronomía antigua al procesamiento moderno de señales e imágenes". Actas del IEEE. vol. 90, no. 3, págs. 319-42. Marzo de 2002.

Visión

Ahora, solo mirando ese núcleo en relación con la implementación real del código de interpolación, puede que no esté claro cómo se relacionan los dos. Básicamente, el proceso de interpolación puede considerarse como la suma de copias desplazadas del núcleo, que se escalan por las muestras de los datos, así:

Reconstrucción basada en el núcleo

De hecho, si tiene una implementación del núcleo, puede usarlo directamente para hacer la interpolación, de la siguiente manera:

def kernel(x, a=-1.0):
    x = abs(x)
    if x >= 0.0 and x < 1.0:
        return (a + 2.0)*x**3.0 - (a + 3.0)*x**2.0 + 1
    elif x >= 1.0 and x < 2.0:
        return a*x**3.0 - 5.0*a*x**2.0 + 8.0*a*x - 4.0*a
    else:
        return 0.0

def cubic(mu,y0,y1,y2,y3):
    a = -1.0        
    result  = y0 * kernel(mu + 1, a)
    result += y1 * kernel(mu, a)     
    result += y2 * kernel(mu - 1, a)
    result += y3 * kernel(mu - 2, a)
    return result

Sin embargo, es mucho menos eficiente desde el punto de vista informático hacerlo de esa manera. Como un puente desde el enfoque de kernel directo al más simplificado anterior, considere que con un poco de manipulación algebraica, la primera implementación se puede poner de la siguiente forma:

def cubic(mu,y0,y1,y2,y3):
    mu2 = mu*mu
    mu3 = mu*mu2
    c0 = -mu3 + 2*mu2 - mu
    c1 =  mu3 - 2*mu2 + 1
    c2 = -mu3 + mu2 + mu
    c3 =  mu3 - mu2    
    return c0*y0 + c1*y1 + c2*y2 + c3*y3

En esta formulación, los c0...c3valores pueden considerarse como los coeficientes de un filtro FIR que se aplica a los valores de la muestra. Ahora es mucho más fácil ver cómo derivar la rutina del núcleo. Considere el núcleo conα=-1, al igual que:

ψ(X)={El |XEl |3-2El |XEl |2+1, Si 0 0El |XEl |<1-El |XEl |3+5 5El |XEl |2-8El |XEl |+4 4, Si 1El |XEl |<20 0, Si 2El |XEl |

Ahora evalúe ese núcleo simbólicamente en varios desplazamientos desplazados, teniendo en cuenta que mu(μ) varía de 0a 1:

ψ(μ+1)=-(μ+1)3+5 5(μ+1)2-8(μ+1)+4 4=-μ3+2μ2-μ(C0 0)ψ(μ)=μ3-2μ2+1=μ3-2μ2+1(C1)ψ(μ-1)=(1-μ)3-2(1-μ)2+1=-μ3+μ2+μ(C2)ψ(μ-2)=-(2-μ)3+5 5(2-μ)2-8(2-μ)+4 4=μ3-μ2(C3)

Tenga en cuenta que μ-1,μ-2 obtener "volteado" a 1-μ,2-μ respectivamente debido al valor absoluto en Xen la definición del núcleo. Ahora tenemos los polinomios exactos que se usan en la "versión FIR" de la rutina de interpolación. La evaluación de esos polinomios se puede hacer más eficiente a través de técnicas estándar (por ejemplo, el método de Horner ). Se pueden hacer cosas similares con otros núcleos, y también hay otras formas de construir implementaciones eficientes (véase la página de inicio de muestreo de audio digital ).

Datageist
fuente