Я создаю простой линейный график с ggplot2
с пиками «сигнала» во времени по оси X.
Для справки: этот конкретный график представляет собой так называемую «хроматограмму» и показывает интенсивность сигнала в относительных единицах флуоресценции, построенную с течением времени. Основания ДНК (одно из A, C, G, T) «вызываются» (назначаются) при каждом пике интенсивности.
Ниже я использую пример файла sangerseqR
ab1 для своего MWE. Я просто загружаю данные, создаю фрейм данных с данными трассировки для построения графика (значения интенсивности) и определяю последовательность ДНК как каждое из оснований, вызываемых пиками в определенные моменты времени по оси X.
Для простоты я просто нарисовал небольшую часть последовательности ДНК (обрезанную спереди и сзади).
Все в порядке и работает так, как ожидалось:
#read in data from sangerseqR example
seq_obj <- sangerseqR::readsangerseq(system.file("extdata", "heterozygous.ab1", package = "sangerseqR"))
#create data frame with trace data to plot
trace_df <- as.data.frame(seq_obj@traceMatrix) #columns for A, C, G, T
names(trace_df) <- c('A','C','G','T')
trace_df$time <- seq_len(nrow(trace_df))
trace_df <- as.data.frame(tidyr::pivot_longer(trace_df, -time, names_to = "base", values_to = "signal"))
#create data frame with base (letter) calls at the specific times (corresponding with trace peaks)
basecall <- unlist(strsplit(toString(seq_obj@primarySeq), ""))
basepos <- seq_obj@peakPosMatrix[,1] #first column for primary seq
base_df <- data.frame(call=basecall, time=basepos, callnum5=seq_along(basepos), callnum3=rev(seq_along(basepos)))
#join both data frames
trace_df <- dplyr::left_join(trace_df, base_df, by = "time")
trace_df$call <- ifelse(trace_df$call==trace_df$base, trace_df$call, NA)
#trim data from 5' (top) and 3' (bottom) to plot only a small section of the sequence
trim5 <- 50
trim3 <- 500
startpos <- min(which(trace_df$callnum5==trim5))
endpos <- max(which(trace_df$callnum3==trim3))
trace_sub <- trace_df[startpos:endpos,]
#define colors, x-axis breaks and labels
basecolors <- c("green","blue","black","red")
xbreaks <- trace_sub$time[which(trace_sub$call==trace_sub$base)]
xlabels <- trace_sub$call[which(trace_sub$call==trace_sub$base)]
#make plot in ggplot2
P <- ggplot2::ggplot(trace_sub, ggplot2::aes(x=time, y=signal, group=base, colour=base)) +
ggplot2::geom_line(linewidth=0.5) +
ggplot2::scale_color_manual(values=basecolors) +
ggplot2::scale_x_continuous(breaks=xbreaks, labels=xlabels) +
ggplot2::theme_light()
grDevices::pdf(file = "test.pdf", height=2, width=20)
print(P)
grDevices::dev.off()
В результате получается следующий график, который выглядит идеально (идентично выводу функции sangerseqR::chromatogram()
), но не совсем так, как мне хотелось.
Обратите внимание на следующее. В идеальной хроматограмме мы должны видеть равномерно расположенные пики (и основания, называемые пиками), но это бывает редко, и уж точно не в этом примере.
Для моих целей (я хочу сравнить несколько почти идентичных последовательностей путем выравнивания/совмещения их хроматограмм) мне нужно, чтобы разрывы оси X на пиках (соответствующие названным основаниям) были равномерно распределены.
Я хочу игнорировать переменную времени и сделать так, чтобы базы располагались на равном расстоянии друг от друга. С технической точки зрения «окна базового вызова» должны иметь одинаковую ширину.
Для этого пики на графике необходимо соответственно расширить или сузить. Это то, что делают различные коммерческие программы, но я не могу придумать, какую формулу применить к данным, поэтому я могу визуализировать график таким образом.
Любая помощь будет принята с благодарностью! Большое спасибо.
Я бы не знал, как это сделать... чтобы буквы на оси X были ближе друг к другу и располагались равномерно, а пики соответственно "сжимались"
Создайте фрейм данных, содержащий время и новые разрывы оси X, используя seq
.
Xbreaks <- data.frame(time=xbreaks,
xbreaks=seq(from=min(xbreaks),
to=max(xbreaks),
length.out=length(xbreaks)))
Затем соедините это с исходным кадром данных по «времени» и замените NA линейной интерполяцией.
trace_sub |>
dplyr::full_join(Xbreaks, by = "time") |>
dplyr::mutate(time=zoo::na.approx(xbreaks), .by=base) |>
ggplot(aes(x=time, y=signal, group=base, colour=base)) +
geom_line(linewidth=0.5) +
scale_color_manual(values=basecolors) +
scale_x_continuous(breaks=Xbreaks$xbreaks, labels=xlabels) +
theme_light()
это именно то, что мне нужно!
большое спасибо!!!!
Есть ли шанс, что вы сможете привести пример ожидаемой цифры?