Reputation: 3217
I have a sequence myseq
associated to some data that I want to plot. Besides, I have another sequence checkseq
that I want to compare myseq
to.
The objective is to make a plot like the one below (with myseq
as x-axis labels), but highlighting somehow the letters in myseq
that are different from checkseq
in that position.
To do that, I cannot change their color with element_markdown
cause I already do so for other purposes in my real life case. I think the next best thing is to draw a circle or square around such letters.
This is my MWE:
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)
mysplit <- unlist(strsplit(myseq, ""))
#
checkseq <- "AGATTATTATAGGTTCATAT"
checksplit <- unlist(strsplit(checkseq, ""))
#
ind_df <- data.frame(call=mysplit, check=checksplit, time=indices)
ind_df$highlight <- ifelse(ind_df$call!=ind_df$check, TRUE, FALSE)
#
finaldf <- dplyr::left_join(mydata, ind_df, by="time")
P <- ggplot2::ggplot(finaldf, ggplot2::aes(x=time, y=value)) +
ggplot2::geom_line(linewidth=0.5) +
ggplot2::scale_x_continuous(breaks=indices, labels=seqsplit) +
ggplot2::theme_light()
grDevices::pdf(file="test.pdf", height=4, width=10)
print(P)
grDevices::dev.off()
which produces this plot:
What I would like is the following plot, highlighting the letters with highlight==TRUE
by drawing a circle (or square) around them.
Upvotes: 1
Views: 62
Reputation: 11908
You can post-process the circle annotations in with grid:
circle_x_axis_labels <- function(index, radius = 1, ...) {
grid::grid.force() # Ensure ggplot2 content is generated.
grid::seekViewport("axis.3-1-3-1")
axis_grob <- grid::grid.get("axis.3-1-3-1")
axis_text_grob <- grid::getGrob(axis_grob, "text", grep = TRUE)
grid::grid.draw(
grid::circleGrob(
x = axis_text_grob$x[index],
y = grid::unit(0.5, "npc"),
r = radius,
gp = grid::gpar(...)
)
)
}
ggplot2::ggplot(finaldf, ggplot2::aes(x=time, y=value)) +
ggplot2::geom_line(linewidth=0.5) +
ggplot2::scale_x_continuous(breaks=indices, labels=mysplit) +
ggplot2::theme_light()
circle_x_axis_labels(which(mysplit != checksplit), col = "red", fill = NA, lwd = 2)
Upvotes: 1
Reputation: 132969
Plot them with geom_point
, specify axis limits and turn off clipping:
library(ggplot2)
P +
coord_cartesian(ylim = c(5.5, 14), clip = 'off') +
geom_point(data = ind_df[ind_df$highlight,],
aes(x = time,
y = 4.85), color = "red", shape = 1, size = 6)
Unfortunately, you need to adjust y
according to the dimensions of the plotting device because the size of the label text is fixed.
Upvotes: 0
Reputation: 11908
I’d recommend adding the check sequence as secondary axis labels:
ggplot2::ggplot(finaldf, ggplot2::aes(x = time, y = value)) +
ggplot2::geom_line(linewidth = 0.5) +
ggplot2::scale_x_continuous(
name = "Sequence",
breaks = indices,
labels = mysplit,
sec.axis = ggplot2::sec_axis(
transform = identity,
name = "Check Sequence",
breaks = indices,
labels = checksplit
)
) +
ggplot2::geom_rect(
data = finaldf[finaldf$highlight, ],
ggplot2::aes(
xmin = time - 0.5,
xmax = time + 0.5,
ymin = -Inf,
ymax = Inf
),
fill = "red", alpha = 0.2
) +
ggplot2::theme_light()
#> Warning: Removed 80 rows containing missing values or values outside the scale range
#> (`geom_rect()`).
Very curious to see though if someone comes up with a way to add the annotations on the axis.
Upvotes: 2