Mateo Jarry
2026-01-22
This notebook needs in input “Data/coverage/” (get here).
We extracted coverage values for each of the deduplicated .bam files
(UMI-unique) using bedtools.
for f in deduplicated*.bam; do
bedtools genomecov -ibam $f -d > ./Data/coverage/Coverage_$f.txt
done
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
setwd('./Data/coverage/')
temp <- list.files(pattern = glob2rx("Coverage*NG*.txt"), full.names=T)
myfiles <- lapply(temp, read.table, skip = "#")
myfiles <- lapply(myfiles, function(x) filter(x, x$V1=='pWCP')) # plasmid
names(myfiles) <- temp
intergenic_ranges <- list(
c(134, 230), c(1179, 1385), c(2403, 2485), c(2696, 2764),
c(3839, 4014), c(5170, 5213), c(5647, 5713), c(6368, 6532),
c(7244, 7371), c(8065, 8175), c(8649, 8863)
)
names(intergenic_ranges) <- c("IG-1", "IG-2", "IG-3", "IG-4", "IG-5",
"IG-6", "IG-7", "IG-8", "IG-9", "IG-10", "IG-11")
coding_ranges <- list(
c(1,143), c(231,1179), c(1386,1884), c(1880,2189), c(2169,2403), c(2486,2696), c(2765,3839), c(4015,5170),
c(5214,5475), c(5455,5647), c(5714,6368), c(6533,7244), c(7372,8065), c(8176,8407), c(8382,8649), c(8864,9228) # Adjust based on real coding regions
)
names(coding_ranges) <- c("DnaB_2b", "IS110", "DnaB_1", "RelE_1", "RelB_1", "GP-05", "GP-06", "GP-07","GP-08", "GP-09", "ParA", "GP-11", "GP-12", "RelB_2", "RelE_2", "DnaB_2a")
amplicons_ranges <- list(
c(9081,9209), c(1680,1836), c(1941,2093), c(2201,2375), c(2501,2638), c(2954,3600), c(4487,4870), c(5226,5441), c(5464,5617), c(5888,6268), c(6817,7146), c(7417,7875), c(8240,8358), c(8416,8570)
)
names(amplicons_ranges) <- c("DnaB_2", "DnaB_1", "RelE_1", "RelB_1", "GP-05", "GP-06", "GP-07","GP-08", "GP-09", "ParA", "GP-11", "GP-12", "RelB_2", "RelE_2")
plotrange <- function(myfiles, range, coding_ranges, intergenic_ranges, amplicons_ranges,
genome_length = 9228, main_from_name_parts = 3:7) {
# Set multi-panel layout; cap rows to a reasonable number
n_panels <- length(range)
par(mfrow = c(n_panels, 1), mar = c(2, 2, 2, 1), oma = c(0, 0, 0, 0))
# Helper: draw a (start, end) interval, allowing wrap-around
draw_interval <- function(start, end, y_max, col, border, lwd) {
# Normalize into [1, genome_length]
if (is.na(start) || is.na(end)) return(invisible(NULL))
# If interval wraps around (end < start), draw two parts
if (end < start) {
rect(1, 0, end, y_max, col = col, border = border, lwd = lwd)
rect(start, 0, genome_length, y_max, col = col, border = border, lwd = lwd)
} else {
rect(start, 0, end, y_max, col = col, border = border, lwd = lwd)
}
}
# Iterate over requested indices
for (i in range) {
# Defensive checks
if (i < 1 || i > length(myfiles)) {
plot.new(); title(main = paste("Index", i, "out of bounds"))
next
}
df <- myfiles[[i]]
# Coerce to numeric safely
x <- suppressWarnings(as.numeric(df$V2))
y <- suppressWarnings(as.numeric(df$V3))
# Remove non-finite rows
keep <- is.finite(x) & is.finite(y)
x <- x[keep]; y <- y[keep]
# If empty after cleaning, skip with a message
if (length(x) == 0 || length(y) == 0) {
plot.new(); title(main = paste("No finite data for index", i))
next
}
# Titles from filename parts
main_title <- NA
nm <- names(myfiles)[i]
if (!is.null(nm)) {
split_string <- strsplit(nm, "_")[[1]]
if (length(split_string) >= max(main_from_name_parts)) {
main_title <- paste(split_string[main_from_name_parts], collapse = "_")
} else {
main_title <- nm
}
} else {
main_title <- paste("Series", i)
}
# Plot limits
x_min <- max(1, min(x, na.rm = TRUE))
x_max <- min(genome_length, max(x, na.rm = TRUE))
y_max <- max(y, na.rm = TRUE)
y_min <- min(y, na.rm = TRUE)
if (!is.finite(x_min) || !is.finite(x_max) || x_min == x_max) {
# Fall back to genome range if x collapsed
x_min <- 1; x_max <- genome_length
}
if (!is.finite(y_max) || y_max <= 0) {
# Fall back to a small range if y is degenerate
y_max <- 1
}
ylim <- c(0, y_max)
xlim <- c(x_min, x_max)
# Plot main line
plot(x, y, type = "l", xlim = xlim, ylim = ylim,
main = main_title, xlab = "", ylab = "", col = "black")
# --- Shaded regions: coding (blue, semi-transparent)
for (j in seq_along(coding_ranges)) {
cr <- coding_ranges[[j]]
if (length(cr) == 2 && all(is.finite(cr))) {
draw_interval(cr[1], cr[2], y_max, col = rgb(0, 0, 1, 0.18), border = NA, lwd = 1)
}
}
# --- Shaded regions: intergenic (red, semi-transparent)
for (j in seq_along(intergenic_ranges)) {
ir <- intergenic_ranges[[j]]
if (length(ir) == 2 && all(is.finite(ir))) {
draw_interval(ir[1], ir[2], y_max, col = rgb(1, 0, 0, 0.18), border = NA, lwd = 1)
}
}
# --- Amplicon boxes (subtle grey with label)
for (j in seq_along(amplicons_ranges)) {
ar <- amplicons_ranges[[j]]
if (length(ar) == 2 && all(is.finite(ar))) {
draw_interval(ar[1], ar[2], y_max, col = rgb(0, 0, 0, 0.1), border = "grey50", lwd = 1)
# Place label at mid of the (non-wrapped) interval if inside xlim
start <- ar[1]; end <- ar[2]
if (end >= start) {
xm <- (start + end) / 2
if (xm >= xlim[1] && xm <= xlim[2]) {
text(xm, y_max * 0.9, labels = names(amplicons_ranges)[j],
col = "black", cex = 0.6, font = 2)
}
} else {
# For wrapped intervals, put two labels near both halves
xm1 <- (1 + end) / 2
xm2 <- (start + genome_length) / 2
text(xm1, y_max * 0.9, labels = names(amplicons_ranges)[j],
col = "black", cex = 0.6, font = 2)
text(xm2, y_max * 0.9, labels = names(amplicons_ranges)[j],
col = "black", cex = 0.6, font = 2)
}
}
}
}
}
plotrange(myfiles, 1:5, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)

plotrange(myfiles, 6:10, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)

plotrange(myfiles, 11:15, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)

plotrange(myfiles, 16:20, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)

plotrange(myfiles, 21:25, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)

plotrange(myfiles, 26:30, coding_ranges, intergenic_ranges, amplicons_ranges, genome_length = 9228)
