Расширьте/сузьте линейные участки графика, чтобы разрывы оси X в пиках располагались равномерно

Я создаю простой линейный график с 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 на пиках (соответствующие названным основаниям) были равномерно распределены.

Я хочу игнорировать переменную времени и сделать так, чтобы базы располагались на равном расстоянии друг от друга. С технической точки зрения «окна базового вызова» должны иметь одинаковую ширину.

Для этого пики на графике необходимо соответственно расширить или сузить. Это то, что делают различные коммерческие программы, но я не могу придумать, какую формулу применить к данным, поэтому я могу визуализировать график таким образом.

Любая помощь будет принята с благодарностью! Большое спасибо.

Есть ли шанс, что вы сможете привести пример ожидаемой цифры?

Edward 20.08.2024 08:08

Я бы не знал, как это сделать... чтобы буквы на оси X были ближе друг к другу и располагались равномерно, а пики соответственно "сжимались"

DaniCee 20.08.2024 08:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Создайте фрейм данных, содержащий время и новые разрывы оси 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()

это именно то, что мне нужно!

DaniCee 21.08.2024 04:46

большое спасибо!!!!

DaniCee 21.08.2024 05:01

Другие вопросы по теме