У меня есть простой линейный график, на котором я показываю последовательность ДНК по оси X, сделанную следующим образом с помощью ggplot2
:
myseq <- "AGAATATTATACATTCATCT"
set.seed(123)
mydata <- data.frame(time=1:100, value=rnorm(100, mean=10, sd=2))
indices <- seq(5, 100, length.out=20)
seqsplit <- unlist(strsplit(myseq, ""))
ind_df <- data.frame(call=seqsplit, time=indices)
final_df <- dplyr::left_join(mydata, ind_df, by = "time")
xcolors <- ifelse(seqsplit= = "A", "green", ifelse(seqsplit= = "C", "blue", ifelse(seqsplit= = "G", "black", "red")))
P <- ggplot2::ggplot(final_df, ggplot2::aes(x=time, y=value)) +
ggplot2::geom_line(linewidth=0.5) +
ggplot2::scale_x_continuous(breaks=indices, labels=seqsplit) +
ggplot2::scale_y_continuous(limits=c(5,17)) +
ggplot2::theme_light() +
ggplot2::theme(axis.title.x=ggplot2::element_blank(),
axis.text.x=ggtext::element_markdown(face = "bold", color=xcolors))
grDevices::pdf(file = "test.pdf", height=3, width=10)
print(P)
grDevices::dev.off()
который производит:
Теперь у меня есть связанная аминокислотная последовательность длиной 4, для которой я знаю начальное и конечное положения последовательности ДНК. Каждая буква аминокислотной последовательности соответствует 3 буквам последовательности ДНК.
aaseq <- "WXYZ"
start <- 5
end <- 17
Здесь аминокислотная последовательность WXYZ
начинается на T-5
и заканчивается на C-17
последовательности ДНК, указанной выше, и я хочу построить их вместе.
Это будет моя конечная цель (это могут быть просто квадраты вместо «стрелок»):
Есть ли простой способ сделать это в ggplot2
?
Самый простой вариант без стрелок — использовать geom_segment
:
geom_segment(
data = df_arrows,
aes(x = x, xend = xend, y = 16, yend = 16, color = I(color)),
linewidth = 8
)
Но если вам нужны стрелки, я бы посоветовал использовать geom_polygon
, что, однако, требует некоторых усилий для создания кадра данных с координатами многоугольника:
library(ggplot2)
library(dplyr)
aaseq <- "WXYZ"
start <- 5
end <- 17
df_arrows <- data.frame(
x = indices[seq(start, end - 3, 3)],
xend = indices[seq(start + 3, end, 3)],
y = 16, yend = 16,
color = c("blue", "green", "orange", "purple"),
label = strsplit(aaseq, "")[[1]]
)
df_polygon <- df_arrows |>
dplyr::mutate(label = factor(label, rev(unique(label)))) |>
dplyr::reframe(
data.frame(
x = c(x, xend, xend, xend, x) + c(0, 0, 4, 0, 0),
y = y + .5 * c(1, 1, 0, -1, -1),
color = color,
label = label
),
.by = label
)
ggplot(final_df, aes(x = time, y = value)) +
scale_x_continuous(breaks = indices, labels = seqsplit) +
scale_y_continuous(limits = c(5, 17)) +
theme_light() +
theme(
axis.title.x = element_blank(),
axis.text.x = ggtext::element_markdown(face = "bold", color = xcolors)
) +
annotate(
"rect",
xmin = indices[start], xmax = indices[end],
ymin = -Inf, ymax = Inf,
fill = "grey", alpha = .4
) +
geom_polygon(
data = df_polygon,
aes(x = x, y = y, fill = I(color), group = label)
) +
geom_text(
data = df_arrows,
aes(x = (x + xend) / 2 + 1, y = y, label = label),
color = "white", fontface = "bold"
) +
geom_line(linewidth = 0.5)
Самый простой подход — добавить или имитировать линии «сетки», используя geom_vline
.
да, я просто подумал об этом, когда печатал свой комментарий, хе-хе... спасибо!
добавляю свой ответ о том, как я наконец это сделал, если вам тоже интересно!
Основываясь на ответе @stefan, я решил, что мне все еще нужно направление стрелки, но с моими реальными данными многоугольник стал настолько сложным...
Это могло бы войти в приложение Shiny, которое принимает в качестве входных данных разные данные, а значения y
могут сильно различаться, поэтому определение многоугольника может стать путаницей.
Я поигрался с аргументом arrow
geom_segment
, но не получил того, что хотел. Однако простое построение geom_point
на xend
с ромбовидной формой и размером, равным linewidth
в geom_segment
, делает идеальный трюк очень простым способом.
myseq <- "AGAATATTATACATTCATCT"
set.seed(123)
mydata <- data.frame(time=1:100, value=rnorm(100, mean=10, sd=2))
indexes <- seq(5, 100, length.out=20)
seqsplit <- unlist(strsplit(myseq, ""))
ind_df <- data.frame(call=seqsplit, time=indexes)
final_df <- dplyr::left_join(mydata, ind_df, by = "time")
xcolors <- ifelse(seqsplit= = "A", "green", ifelse(seqsplit= = "C", "blue", ifelse(seqsplit= = "G", "black", "red")))
#
#aa sequence
aaseq <- "WXYZ"
start <- 5
end <- 17
df_arrows <- data.frame(x=indexes[seq(start, end-3, 3)] -2.5,
xend=indexes[seq(start+3, end, 3)] -2.5,
y=16, yend=16,
color=c("blue", "green", "orange", "purple"),
label=strsplit(aaseq, "")[[1]])
##
P <- ggplot2::ggplot(final_df, ggplot2::aes(x=time, y=value)) +
ggplot2::annotate("rect", xmin=indexes[start]-2.5, xmax=indexes[end]-2.5, ymin=-Inf, ymax=Inf, fill = "grey", alpha=0.25) +
ggplot2::geom_vline(data=df_arrows[-1,], ggplot2::aes(xintercept=x), color = "grey", linetype=2, linewidth=0.5) +
ggplot2::geom_line(linewidth=0.5) +
ggplot2::scale_x_continuous(breaks=indexes, labels=seqsplit) +
ggplot2::scale_y_continuous(limits=c(5,17)) +
ggplot2::geom_segment(data=df_arrows, ggplot2::aes(x=x, xend=xend, y=16, yend=16, color=I(color)), linewidth=8) +
ggplot2::geom_point(data=df_arrows, ggplot2::aes(x=xend, y=16, color=I(color)), shape=18, size=8) +
ggplot2::geom_text(data=df_arrows, ggplot2::aes(x=(x+xend)/2+1, y=y, label=label), color = "white", fontface = "bold") +
ggplot2::theme_light() +
ggplot2::theme(axis.title.x=ggplot2::element_blank(),
axis.text.x=ggtext::element_markdown(face = "bold", color=xcolors))
grDevices::pdf(file = "test.pdf", height=3, width=10)
print(P)
grDevices::dev.off()
который производит:
Это потрясающе спасибо!!!